SmartApp Framework позволяет изменить поведение базовых классов путем наследования. Это необязательная опция, которая позволяет внести изменения в функциональность смартапа.
Для расширения фреймворка необходимо:
- Создать наследника от класса.
- Добавить новую функциональность, которой нет в базовом классе.
- Зарегистрировать новый класс в
app_config
.
Ниже перечислены основные базовые классы, от которых можно создать наследника.
BaseMainLoop — цикл обработки сообщений
BaseMainLoop — является базовым классом, который реализует рабочий цикл обработки сообщений от пользователя. Создав наследника от этого класса, можно переопределить следующие методы:
def run(self)
Метод, в котором реализуется цикл работы смартапа.
def stop(self, signum, frame)
Метод для остановки выполнения метода run
.
async def load_user(self, db_uid, message)
Асинхронный метод загрузки текущего состояния пользователя из используемой БД. В качестве результата ожидается получение экземпляра класса User или производной от этого класса.
Метод имеет следующие объекты:
db_uid
— уникальный идентификатор, по которому хранится запись о состоянии пользователя в БД;message
— входящее сообщение от пользователя. Объект класса FromMessage или наследника от него.
async def save_user(self, db_uid, user, message)
Асинхронный метод сохранения состояния пользователя в БД. В качестве результата ожидается получение bool
флага, который отражает, произошла коллизия записи в БД или нет (то есть при сохранении обнаружено, что кто-то уже изменил данные).
Метод имеет следующие объекты:
db_uid
— уникальный идентификатор, по которому хранится запись о состоянии пользователя в БД;user
— объект класса User или производный от этого класса;message
— входящее сообщение от пользователя. Объект класса FromMessage или наследника от него.
def _generate_answers(self, user, commands, message, **kwargs)
Метод для создания объектов ответов от смартапа к пользователю. Используется внутри MainLoop для дополнительной работы объектов Command. Предполагается, что внутри будут созданы объекты класса SmartKitKafkaReqeust
/ RestRequest
или другой пользовательский тип запроса. На основании объектов Command
, message
, request
будет создан объект класса SmartAppToMessage
. В качестве результата ожидается получение списка объектов класса SmartAppToMessage
.
Метод имеет следующие объекты:
user
— объект класса User или производный от этого класса;commands
— list объектов класса Command (например, обогащение, изменение, удаление полей);message
— входящее сообщение от пользователя. Объект класса FromMessage или наследника от него;**kwargs
— дополнительные именованные аргументы.
SmartAppModel — обработка сообщения
SmartAppModel — является базовым классом, который обрабатывает входящее сообщение и возвращает ответ на него обратно в MainLoop
.
Внутри конструктора можно переопределить маппинг MessageName:Handler
, за который отвечает переменная self._handlers
. Сейчас в этой переменной определяются обработчики сообщений следующего типа:
MESSAGE_TO_SKILL
,RUN_APP
,LOCAL_TIMEOUT
,SERVER_ACTION
,CLOSE_APP
.
Создав наследника от класса SmartAppModel, можно переопределить следующие методы:
def __init__(self, resources: SmartAppResources, dialogue_manager_cls, custom_settings, **kwargs)
resources
— объект класса SmartAppResources;dialogue_manager_cls
— объект класса DialogueManager;custom_settings
— объект класса Settings.
@exc_handler(on_error_obj_method_name="on_answer_error")
Декоратор для ошибок во время обработки входящего сообщения внутри метода answer.
def answer(self, message, user)
Метод, в котором выбирается и вызывается обработчик в зависимости от типа входящего сообщения. В качестве результата ожидается list
объектов класса Command
, которые в дальнейшем будут использоваться в методе _generate_answers
внутри MainLoop
.
Метод имеет следующие объекты:
message
— входящее сообщение от пользователя. Объект классаFromMessage
или наследника от него;user
— объект классаUser
или производный от этого класса.
def on_answer_error(self, message, user)
Метод, который вызывается в случае ошибки внутри метода answer
.
Метод имеет следующие объекты:
message
— входящее сообщение от пользователя. Объект классаFromMessage
или наследника от него;user
— объект класса User или производный от этого класса.
def get_handler(self, message_type)
Логика выбора обработчика для сообщения в зависимости от типа сообщения. Тип входящего сообщения передается в message_type
. В качестве результата ожидается объект класса HandlerBase или его наследник.
HandlerBase — обработка сообщений по типам
HandlerBase — базовый класс для обработчиков, в которых реализована различная логика обработки определенного типа сообщения. Создав наследника от класса HandlerBase, можно переопределить следующие методы:
def __init__(self, app_name)
app_name
— название созданного смартапа. Используется внутри HandlerBase для мониторинга.
def run(self, payload, user)
В качестве результата работы метода ожидается list объектов класса Command, которые в дальнейшем будут использоваться в методе _generate_answers
внутри MainLoop
.
Метод имеет следующие объекты:
payload
— полеpayload
, которое можно получить из объекта классаFromMessage
—message.payload
;user
— объект класса User или производный от этого класса.
DialogueManager — работа со сценариями
DialogueManager — базовый класс, который на основании интента из message.payload выбирает и запускает новый сценарий или продолжает работу текущего. Создав наследника от класса DialogueManager, можно переопределить следующие методы:
def __init__(self, scenario_descriptions, app_name, **kwargs)
scenario_descriptions
— json-файлы, загруженные в память из папки referenses: сценарии, формы, actions, requirements и т.д. Метод нужен для получения актуального списка сценариев;app_name
— название созданного смартапа. Используется внутри DialogueManager для мониторинга;**kwargs
— дополнительные именованные аргументы.
def _nothing_found_action(self)
Метод выполняется, когда входящее сообщение не подходит текущему запущенному сценарию. Например, пользователь спросил что-то другое.
В этом случае, если на основе входящего сообщения ни одно поле формы не может быть заполнено, срабатывает NOTHING_FOUND action, который возвращает соответствующее сообщение ассистенту. Как результат работы, ожидается объект класса Action.
def run(self, text_preprocessing_result, user)
Метод запуска работы сценария на основе интента из входящего сообщения. Предполагается, что внутри этого метода будет выбран сценарий и запущен метод run_scenario для обработки выбранного сценария.
Метод имеет следующие объекты:
text_preprocessing_result
— объект класса TextPreprocessingResult, который получается на основе поляpayload.message
из входящего сообщения;user
— объект класса User или производный от этого класса.
def run_scenario(self, scen_id, text_preprocessing_result, user)
Метод запуска и получения результатов от выбранного сценария на основе входящего сообщения. В качестве результата работы методы ожидается list объектов класса Command
, которые в дальнейшем будут использоваться в методе _generate_answers
внутри MainLoop
. Список может быть пустой.
Метод имеет следующие объекты:
scen_id
— id сценария из коллекции scenario_descriptions['scenarios'];text_preprocessing_result
— объект класса TextPreprocessingResult, который получается на основе поля payload.message из входящего сообщения;user
— объект класса User или производный от этого класса.
SmartAppResources — регистрация сущностей
SmartAppResources — класс, который используется для загрузки ресурсов из json и регистрации базовых сущностей: actions, requirements, fillers и т.д. в соответствующих фабриках. Создав наследника от класса SmartAppResources, можно переопределить следующие методы:
def _subfolder(self)
Свойство для указания папки, из которой будут загружаться ресурсы.
def override_repositories(self, repositories: list)
Метод предназначен для добавления новых репозиториев в дочерних классах. На выходе ожидается дополненный список repositories с новыми сущностями, которые характерны для конкретного смартапа.
Метод имеет следующие объекты:
repositories
— список репозиториев класса SmartAppResources.
def init(self)
Метод, в котором подряд запускаются методы для добавления новых сущностей в соответствующие фабрики.
def init_field_filler_description(self)
Метод регистрации новых филлеров. Например:
import scenarios.scenario_models.field.field_filler_description as ffd
def init_field_filler_description(self):
super(CustomAppResourses, self).init_field_filler_description()
где ffd.field_filler_description
— фабрика филлеров.
def init_actions(self)
Метод регистрации новых actions. Например:
from core.basic_models.actions.basic_actions import actions
def init_actions(self):
super(CustomAppResourses, self).init_actions()
actions["simple_action"] = SamlpeAction
где actions
— фабрика actions.
def init_requirements(self)
Метод регистрации новых requirements. Например:
from core.basic_models.requirement.basic_requirements import requirements
def init_requirements(self):
super(CustomAppResourses, self).init_requirements()
requirements["sample_requirement"] = SampleRequirement
где requirements
— фабрика requirements.
def init_db_adapters(self)
Методы регистрации новых адаптеров для БД. Например:
from core.db_adapter.db_adapter import db_adapters
def init_db_adapters(self):
super(CustomAppResourses, self).init_db_adapters()
db_adapters["custom_db_adapter"] = CustomDBAdapter
где db_adapters
— фабрика адаптеров.
BaseUser — состояние пользователя
В SmartApp Framework реализован класс BaseUser и его наследник User, которые описывают состояние пользователя:
- Если есть необходимость иметь максимально собственный класс для хранения состояний пользователя, без использования полей для корректной работы сценарной логики, то рекомендуется делать наследника от класса BaseUser.
- Если нужна сценарная логика и нужно добавить новые поля, то рекомендуется делать наследника от класса User. Создав наследника от класса, можно переопределить следующие методы:
@lazy
def parametrizer(self)
Свойство, которое возвращает объект класса BasicParametrizer или его наследников.
@property
def fields(self)
Свойство, которое возвращает список объектов класса Field, являющиеся свойствами пользователя
@property
def raw(self)
Свойство, которое возвращает словарь типа {field.name: {"field.attr1":..}, ...}
@property
def raw_str(self)
Свойство, которое возвращает json представление словаря из метода raw. Используется для сохранения пользователя в БД.
def expire(self)
Метод, в котором последовательно вызываются expire от Field класса User. Используется для очистки данных, которые уже потеряли со временем свою актуальность для пользователя.
BasicParametrizer — сборка словаря
BasicParametrizer — класс, который собирает словарь из различных доступных объектов системы: User, Settings, Forms и т.д., чтобы использовать данные при рендеренге jinja-шаблона. Создав наследника от класса, можно переопределить следующие методы:
def collect(self, text_preprocessing_result=None, filter_params=None)
Метод сборки данных из доступных объектов системы. Метод имеет следующие объекты:
text_preprocessing_result
— объект классаTextPreprocessingResult
, который получается на основе поляpayload.message
из входящего сообщения;filter_params
— параметры, которые будут удалены при создании словаря.
def _get_user_data(self, text_preprocessing_result=None)
Метод, в котором задается набор данных, возвращаемый из метода collect
. Метод имеет следующий объект:
text_preprocessing_result
— объект классаTextPreprocessingResult
, который получается на основе поляpayload.message
из входящего сообщения.
@lazy
def filter(self)
Свойство, которое возвращает объект класса Filter
.
def filter_out(self, data, filter_params=None)
Метод, который отфильтровывает данные из созданного словаря в методе _get_user_data
. Метод имеет следующие объекты:
data
— словарь, созданный в методе_get_user_data
;filter_params
— параметры, которые нужно удалить из словаря.
В большинстве случаев при создании смартапа достаточно переопределить в классе наследника метод _get_user_data
, в котором можно обогатить новыми данными текущий словарь с параметрами.
LoggerMessageCreator — расширение параметров логирования
LoggerMessageCreator — класс, который используется для ведения логов смартапа. Переопределив методы класса можно указать какие параметры будут отображаться в логах.
Создав наследника от класса, можно переопределить следующие методы:
def update_user_params(cls, user, params)
Метод вызывается в make_message
до маскирования и добавляет в сообщение лога параметры заданные в массиве ART_NAME
. Переопределите метод, чтобы изменить список параметров.
user
— объект класса User или производный от этого класса;
def update_other_params(cls, user, params, cls_name='', log_store_for=0)
Метод вызывается в make_message
после маскирования и добавляет в сообщение лога дополнительные параметры. Переопределите метод, чтобы изменить или дополнить параметры сообщения лога.
user
— объект класса User или производный от этого класса;
def make_message(cls, user=None, params=None, cls_name='', log_store_for=0)
Метод возвращает параметры, которые передаются в сообщении лога смартапа. Часть параметров маскируется, например, персональные данные пользователей.
user
— объект класса User или производный от этого класса;
Settings — загрузка конфигов
Settings — класс, который загружает конфиги смартапа. Например: template_config.yml
, kafka_config.yml
, ceph_config.yml
. Создав наследника от класса, можно переопределить следующие методы:
def override_repositories(self, repositories: list)
Метод предназначен для добавления новых репозиториев в дочерних классах. Метод принимает объект repositories
— список репозиториев класса SmartAppResources. На выходе ожидается дополненный список repositories новыми сущностями, характерными для конкретного смартапа.
def get_source(self)
Метод определяет, каким адаптером будут загружены конфиги:
OSAdapter
— используется по умолчанию. Адаптер ищет файлы локально.CephAdapter
— позволяет загружать файлы из s3 хранилища
Как результат работы ожидается объект наследник от класса DBAdapter.
Как подключить свои классы
После создания собственных классов необходимо добавить их в смартап. Для этого необходимо:
- Зарегистрировать собственные классы в
app_config.py
. - C помощью конструкции
from ... import
подключить класс. - Присвоить переменной соответствующий ей класс:
LOCAL_TESTING
— наследник от класса CLInterface;RESOURCES
— наследник от класса SmartAppResources;USER
— наследник от класса BaseUser;MAIN_LOOP
— наследник от класса MainLoop;PARAMETRIZER
— наследник от класса BasicParametrizer;MODEL
— наследник от класса SmartAppModel;DIALOG_MANAGER
— наследник от класса DialogManager;SETTINGS
— наследник от класса Settings.
Например:
from app.local_testing.custom_local_testing import CustomLocalTesting
from app.resources.custom_app_resourses import CustomAppResourses
LOCAL_TESTING = CustomLocalTesting
RESOURCES = CustomAppResourses