-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #183 from salute-developers/statemachine
Statemachine
- Loading branch information
Showing
300 changed files
with
17,728 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
""" | ||
# Пакет NLPF StateMachine. | ||
*Фреймворк для удобного написания сценариев для голосовых ассистентов Салют на Python.* | ||
В основе своей фреймворк имеет [SmartApp Framework](https://github.com/sberdevices/smart_app_framework), | ||
он же **NLP Framework** или **NLPF**. | ||
![sber](static/assistant.png){:.sber-icon style="width: 100px"} | ||
## Основные понятия | ||
### Canvas App | ||
--- web-приложение с голосовым управлением. | ||
([документация](https://developers.sber.ru/docs/ru/salute/basics/canvasapp), | ||
[видео на youtube](https://www.youtube.com/watch?v=2_AbcyfzHTo&t=0s)) | ||
### Фронт | ||
--- JS-вёрстка, которая крутится на клиенте. (девайс, мобильное приложение, ...) | ||
#### Экран (или страница) | ||
--- Раздел приложения, ограниченный конкретной логикой. | ||
**Примеры экранов:** | ||
* Промо-экран; | ||
* Экран авторизации; | ||
* Экран корзины; | ||
* ... | ||
### Запрос (message) | ||
--- Сообщение, которое прилетает в нашу систему. | ||
Все запросы/ответы описываются в виде [pydantic моделей](https://pydantic-docs.helpmanual.io/). | ||
Подробнее все модели можно посмотреть в разделе `nlpf_statemachine.models`. | ||
**Запросы могут быть разные:** | ||
* Голосовой запрос от пользователя (Создаётся объект наследние `nlpf_statemachine.models.MessageToSkill`); | ||
* ServerAction --- событие, прилетевшее с фронта | ||
(Создаётся объект наследник `nlpf_statemachine.models.ServerActionMessage`); | ||
* Интеграцонные сообщения --- события, прилетевшие от интеграций, памяти ассистента, сторонних систем | ||
(наследник `nlpf_statemachine.models.IntegrationMessage`); | ||
### Слот | ||
--- Параметр в голосовом запросе. Это может быть город, время, любая другая структурированная информация, которую может | ||
сказать пользователь. | ||
### Форма | ||
--- Набор слотов, извлечённых из запроса. | ||
Подробнее про экшены можно посмотреть в разделе `nlpf_statemachine.kit.form`. | ||
### Событие (event) | ||
--- любое событие, которое произошло в системе, на что наше приложение может отреагировать. *Определяется из запроса!* | ||
**Примеры событий** | ||
* У пользователя есть потребность (интент), он выражает её вербально. | ||
К нам прилетает запрос `nlpf_statemachine.models.MessageToSkill`. | ||
Из него мы можем определить интент, который, в свою очередь, и является событием; | ||
* Прилетел `nlpf_statemachine.models.ServerActionMessage` с фронта; | ||
* В системе сработал таймер; (этот тоже `nlpf_statemachine.models.ServerActionMessage`) | ||
* Произошёл таймаут --- прилетел запрос `nlpf_statemachine.models.LocalTimeout`. | ||
* ... | ||
Как правило событие можно описать конкретным ключом (строкой). | ||
### Классификатор | ||
--- объект, который может из запроса определить конкретное событие, которое произошло. | ||
То есть вернуть его ключ. | ||
Подробнее про классификаторы можно посмотреть в разделе `nlpf_statemachine.kit.classifier`. | ||
### Экшен (Action) | ||
--- обработчик конкертного запроса. | ||
Подробнее про экшены можно посмотреть в разделе `nlpf_statemachine.kit.actions`. | ||
### Сценарий (Scenario) | ||
--- коллекция классификаторов, экшенов, форм. | ||
Подробнее про экшены можно посмотреть в разделе `nlpf_statemachine.kit.scenario`. | ||
### Контекстный менеджер. | ||
--- объект, отвечающий за основную логику работы приложения. | ||
Подробнее про экшены можно посмотреть в разделе `nlpf_statemachine.kit.context_manager`. | ||
""" | ||
|
||
__version__ = "0.0.1" | ||
|
||
__all__ = [ | ||
__version__, | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
""" | ||
# Описание конфигов. | ||
Конфиги можно настраивать в своём проекте через переменные окружения. | ||
""" | ||
from decouple import config | ||
|
||
from nlpf_statemachine.models.enums import ResponseMessageName | ||
|
||
|
||
class SMConfig: | ||
default_integration_behaviour_id = config("DEFAULT_INTEGRATION_BEHAVIOR_ID", cast=str, default="nlpf_statemachine") | ||
transaction_timeout = config("TRANSACTION_TIMEOUT", cast=int, default=10) | ||
transaction_massage_name_finish_list = config( | ||
"TRANSACTION_MESSAGE_NAME_FINISH_LIST", | ||
cast=lambda scenarios: [ | ||
message_name.strip() for message_name in scenarios.split(",") | ||
], | ||
default=", ".join(list(ResponseMessageName)), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
""" | ||
# Общие константы, удобные для использования. | ||
1. Список всех ассистентов: AssistantJoy, AssistantAthena, AssistantSber. | ||
""" | ||
|
||
from nlpf_statemachine.models import AssistantAppeal, AssistantGender, AssistantId, AssistantName, Character | ||
|
||
AssistantJoy = Character( | ||
id=AssistantId.joy, | ||
name=AssistantName.joy, | ||
gender=AssistantGender.male, | ||
appeal=AssistantAppeal.no_official, | ||
) | ||
|
||
AssistantAthena = Character( | ||
id=AssistantId.athena, | ||
name=AssistantName.athena, | ||
gender=AssistantGender.female, | ||
appeal=AssistantAppeal.official, | ||
) | ||
|
||
AssistantSber = Character( | ||
id=AssistantId.sber, | ||
name=AssistantName.sber, | ||
gender=AssistantGender.male, | ||
appeal=AssistantAppeal.official, | ||
) | ||
|
||
CONTEXT_MANAGER_ID = "StateMachineScenarios" | ||
DEFAULT = "DEFAULT" | ||
DEFAULT_ACTION = "DEFAULT_ACTION" | ||
GLOBAL_NODE_NAME = "GLOBAL_NODE" | ||
INTEGRATION_TIMEOUT = 5 | ||
STATE_MACHINE_REPOSITORY_NAME = "StateMachineScenarios" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Тестовое приложение | ||
|
||
Данный сценарий является примером по использованию NLPF StateMachine . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
""" | ||
# Пример работы с проектом на NLPF StateMachine. | ||
В данном разделе собраны примеры подходов по использованию пакета. | ||
Коллекция будет постоянно пополняться. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
""" | ||
# Бизнес-логика всего приложения. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
""" | ||
# Пример использования ContextManager. | ||
""" | ||
from core.logging.logger_utils import behaviour_log | ||
from nlpf_statemachine.example.app.sc.example_1_static_storage import scenario as static_storage_scenario | ||
from nlpf_statemachine.example.app.sc.example_2_integration import scenario as integration_scenario | ||
from nlpf_statemachine.example.app.sc.example_3_server_action_and_commands import scenario as server_action_scenario | ||
from nlpf_statemachine.example.app.sc.example_4_form_and_intersection_clf import scenario as form_filling_scenario | ||
from nlpf_statemachine.example.app.sc.example_5_isolated_scenario import run_app_condition | ||
from nlpf_statemachine.example.app.sc.example_5_isolated_scenario import scenario as run_app_scenario | ||
from nlpf_statemachine.example.app.sc.example_6_pre_process import pre_process_condition | ||
from nlpf_statemachine.example.app.sc.example_6_pre_process import scenario as pre_process_scenario | ||
from nlpf_statemachine.example.app.sc.fallback import fallback | ||
from nlpf_statemachine.example.app.sc.pre_post_process import post_process, pre_process | ||
from nlpf_statemachine.kit import ContextManager, Form | ||
|
||
behaviour_log("==== ИНИЦИАЛИЗАЦИЯ ContextManager ====") | ||
|
||
# 1. Создаём инстанс ContextManager для нашего аппа. | ||
context_manager = ContextManager() | ||
|
||
# 2. Создаём глобальную форму для нашего аппа. | ||
# Не обязательный шаг, но удобен для отдельных кейсов. | ||
form = Form() | ||
context_manager.add_form(form=form) | ||
|
||
# 3. Добавление изолированных сценариев в ContextManager. | ||
context_manager.add_isolated_scenario( | ||
condition=run_app_condition, | ||
scenario=run_app_scenario, | ||
) | ||
context_manager.add_isolated_scenario( | ||
condition=pre_process_condition, | ||
scenario=pre_process_scenario, | ||
) | ||
|
||
# 4. Добавление сценариев в ContextManager. | ||
context_manager.add_scenario(scenario=static_storage_scenario) | ||
context_manager.add_scenario(scenario=integration_scenario) | ||
context_manager.add_scenario(scenario=server_action_scenario) | ||
context_manager.add_scenario(scenario=form_filling_scenario) | ||
|
||
# 4. Добавление Fallback Action. | ||
context_manager.add_fallback_action(action=fallback) | ||
|
||
# 5. Добавление Pre и Post процессов | ||
context_manager.add_pre_process(process=pre_process) | ||
context_manager.add_post_process(process=post_process) | ||
behaviour_log("==== ИНИЦИАЛИЗАЦИЯ ContextManager ОКОНЧЕНА ====") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
""" | ||
# Пример SmartAppResources. | ||
Для работы проекта необходимо относледовать свой `SmartAppResources` от базового класса | ||
`nlpf_statemachine.override.model_config.SMSmartAppResources`. | ||
И указать в параметре CONTEXT_MANAGER ссылку на инстанс вашего ContextManager. | ||
""" | ||
from nlpf_statemachine.example.app.context_manager import context_manager | ||
from nlpf_statemachine.override.model_config import SMSmartAppResources | ||
|
||
|
||
class ExampleResources(SMSmartAppResources): | ||
""" | ||
# Переопределение SmartAppResources для проекта. | ||
""" | ||
|
||
CONTEXT_MANAGER = context_manager |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
""" | ||
# Пример модуля со сценариями. | ||
Сценарии - сердце нашего приложения. Все обработчики запросов, классификаторы и формы лежат именно в этом модуле. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
""" | ||
# Коллекция классификаторов для работы сценария. | ||
""" |
63 changes: 63 additions & 0 deletions
63
nlpf_statemachine/example/app/sc/classifiers/original_text_classifier.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
""" | ||
# Пример простого классификатора (анализ запроса). | ||
""" | ||
|
||
from typing import Dict, Optional | ||
|
||
from core.text_preprocessing.constants import NUM_TOKEN | ||
from nlpf_statemachine.example.const import STATIC_PARAPHRASE | ||
from nlpf_statemachine.kit import Classifier | ||
from nlpf_statemachine.models import Context, MessageToSkill, SmartEnum | ||
|
||
|
||
class Events(SmartEnum): | ||
""" | ||
# Список возможных событий. | ||
События соответствуют конкретным кейсам в примере: | ||
1. Фиксированный ответ на верхнем уровне в static-файле; | ||
2. Ответ для соответствующего ассистента; | ||
3. Ответ для любого ассистента; | ||
4. Ответ с добавлением простой команды. | ||
""" | ||
|
||
SIMPLE_ASSISTANT_ANSWER = "SIMPLE_ASSISTANT_ANSWER" | ||
CHOICE_ASSISTANT_ANSWER = "CHOICE_ASSISTANT_ANSWER" | ||
ANY_ASSISTANT_ANSWER = "ANY_ASSISTANT_ANSWER" | ||
ANSWER_WITH_COMMAND = "ANSWER_WITH_COMMAND" | ||
|
||
|
||
class OriginalTextClassifier(Classifier): | ||
""" | ||
# Пример простого классификатора. | ||
Данный классификатор проверяет наличие слова в запросе. | ||
""" | ||
|
||
def run(self, message: MessageToSkill, context: Context, form: Dict) -> Optional[str]: | ||
""" | ||
## Запуск классификации. | ||
*Основной метод для переопределения*. | ||
Args: | ||
message (nlpf_statemachine.models.message.protocol.assistant_message.BaseMessage): Тело запроса. | ||
context (nlpf_statemachine.models.context.Context): Контекст. | ||
form (Dict[str, Any]): Форма | ||
Returns: | ||
str: результат классификации (event). | ||
""" | ||
if STATIC_PARAPHRASE in message.payload.message.original_text: | ||
for token in message.payload.message.tokenized_elements_list: | ||
if token.get("token_type") == NUM_TOKEN: | ||
text = token.get("text") | ||
if text == "1": | ||
return Events.SIMPLE_ASSISTANT_ANSWER | ||
elif text == "2": | ||
return Events.CHOICE_ASSISTANT_ANSWER | ||
elif text == "3": | ||
return Events.ANY_ASSISTANT_ANSWER | ||
elif text == "4": | ||
return Events.ANSWER_WITH_COMMAND |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
""" | ||
# Генераторы команд. | ||
""" | ||
from typing import Dict, Union | ||
|
||
from nlpf_statemachine.models import AssistantCommand, CanvasAppItem, SmartAppDataCommand | ||
from .models.commands import CustomCommand | ||
|
||
|
||
def generate_item(smart_app_data: Union[AssistantCommand, Dict]) -> CanvasAppItem: | ||
""" | ||
## Генерация item-команды для списка items в ответе. | ||
Args: | ||
smart_app_data (AssistantCommand): Команда для фронта; | ||
Returns: | ||
CanvasAppItem: Элемент списка items в ответе. | ||
""" | ||
return CanvasAppItem( | ||
command=SmartAppDataCommand( | ||
smart_app_data=smart_app_data, | ||
), | ||
) | ||
|
||
|
||
def custom_command(field_1: str, field_2: int) -> CanvasAppItem: | ||
""" | ||
# Пример генерации кастомной команды c 2 полями. | ||
Args: | ||
field_1 (str): параметр 1 - строка; | ||
field_2: параметр 2 - число; | ||
Returns: | ||
CanvasAppItem: Элемент списка items в ответе с данной командой. | ||
""" | ||
return generate_item(smart_app_data=CustomCommand(field_1=field_1, field_2=field_2)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
""" | ||
# Коллекция SmartEnum-ов для работы сценария. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
""" | ||
# Список возможных значений филлера из примера #4. | ||
""" | ||
from nlpf_statemachine.models import SmartEnum | ||
|
||
|
||
class ApproveValues(SmartEnum): | ||
""" | ||
# Возможные значения слота ApproveFiller. | ||
""" | ||
|
||
AGREEMENT = "AGREEMENT" | ||
REJECTION = "REJECTION" |
14 changes: 14 additions & 0 deletions
14
nlpf_statemachine/example/app/sc/enums/integration_message_names.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
"""Описание моделей для интеграций.""" | ||
from nlpf_statemachine.models import SmartEnum | ||
|
||
|
||
class IntegrationRequestMessageName(SmartEnum): | ||
"""Список наименований запросов в интеграцию.""" | ||
|
||
GENERATE_DATA = "GENERATE_DATA_REQUEST" | ||
|
||
|
||
class IntegrationResponseMessageName(SmartEnum): | ||
"""Список наименований ответов от интеграции.""" | ||
|
||
GENERATE_DATA = "GENERATE_DATA_RESPONSE" |
Oops, something went wrong.