@salutejs/scenario
Библиотека описания структры, матчинга и хендлеров пользовательского сценария.
npm i -S @salutejs/scenario
Словарь интентов и сущностей
Словарь описывается локально в файле с заданной схемой. В зависимости от типа рекогнайзера, словарь может синхронизроваться с удалённой моделью распознования.
./src/intents.ts
import { createIntents } from '@salutejs/scenario';
export const intents = createIntents({
openItem: {
matchers: ['покажи', 'открой', 'открой номер'],
},
slotFilling: {
matchers: ['захвати яблок', 'захвати @number ялок'],
variables: {
number: {
required: true,
questions: ['Сколько яблок?', 'Сколько?'],
},
},
},
});
Пользовательский сценарий
import { createUserScenario } from '@salutejs/scenario';
const userScenario = createUserScenario({
OpenItemState: {
match: intent('OpenItem'),
handle: ({ req, res }) => {
const { number } = req.variables;
res.appendCommand({ type: 'OpenItem', payload: selectItem({ number })(req) });
},
},
slotFillingState: {
match: intent('slotFilling'),
handle: ({ res, req }) => res.setPronounceText(`Вы попросили ${req.variables.number} яблок`),
},
});
Матчеры
Хелперы декларативного описания условия выполнения хендела на поступивший запрос.
import { createMatchers, createUserScenario, SaluteRequest } from '@salutejs/scenario';
import { intents } from './intents';
const {
match,
intent,
text,
action,
state,
regexp
} = createMatchers<SaluteRequest, typeof intents>();
const userScenario = createUserScenario({
state1: {
match: match(intent('OpenItem'), state({ screen: 'main' }),
handle: () => {},
},
state2: {
match: text('да'),
handle: () => {},
},
state3: {
match: action('LOAD_DATA'),
handle: () => {},
},
});
Системный сценарий
NLP-платформа обладает набором специальных интентов, которые указывают на жизненный цикл смартапа: run_up
, close_app
. Кроме них случаются ситуации, когда фраза пользователя не попала ни под один матчер состояния. Грубо говоря, мы не поняли что хотел сказать пользователь. Такие состояние описываются в отдельном обработчике системного сценария.
import { createSystemScenario } from '@salutejs/scenario';
const systemScenario = createSystemScenario({
RUN_APP: ({ res }) => {
res.setPronounceText('Привет!');
},
CLOSE_APP: ({ res, session }) => {
db.save(session);
},
NO_MATCH: ({ res }) => {
res.setPronounceText('Я не понимаю');
},
});
SmartPay
Чтобы оплата работала, необходимо добавить переменную SMARTPAY_TOKEN
в environment.
Инициация диалога оплаты
Для отображения диалога оплаты на экране смартаппа, необходимо:
- Создать счет (вызвать
createInvoice
). - Отправить команду на открытие окна оплаты (вызвать хелпер
res.askPayment
).
import { createInvoice, SaluteHandler } from '@salutejs/scenario';
const handler: SaluteHandler = async ({ req, res }) => {
const { delivery_info, order } = req.variables;
const { invoice_id } = await createInvoice({ invoice: { delivery_info, order } });
res.askPayment(invoice_id);
};
Завершение оплаты
Чтобы узнать о завершении диалога оплаты пользователем,
необходимо подписаться на системный сценарий PAY_DIALOG_FINISHED
.
import { createSystemScenario, findInvoice, PayDialogStatuses, PaymentInvoiceStatuses } from '@salutejs/scenario';
createSystemScenario({
PAY_DIALOG_FINISHED: async ({ req, res }) => {
const { parameters } = req.serverAction;
if (parameters.payment_response.response_code === PayDialogStatuses.success) {
const { invoice_status } = await findInvoice({ invoiceId: parameters.payment_response.invoice_id });
if (invoice_status === PaymentInvoiceStatuses.confirmed) {
}
}
}
});
SmartPush
Пуши требуют наличия переменных окружения - SMARTPUSH_CLIENTID
и SMARTPUSH_SECRET
, не забудьте добавить их в environment.
Ниже пример подготовки и отправки пуша:
import { createSmartPushSender, SendPushConfiguration, SmartPushResponse } from 'salutejs/scenario';
const pushes: SendPushConfiguration[] = [{
projectId: '',
clientIdSub: '',
deliveryConfig: {
deliveryMode: 'BROADCAST',
destinations: [
{
surface: 'COMPANION',
templateContent: {
id: '',
headerValues: { },
bodyValues: { },
},
},
],
},
}];
const sendPush = await createSmartPushSender();
pushes.forEach((push) =>
sendPush(push).then(({ payload }: SmartPushResponse) => {
if (payload.validation.results.some(({ status }) => status.code !== 0)) {
throw new Error('Уведомление не отправлено');
}
}),
);
SmartProfile
Для получения данных о пользователе из сервиса SmartProfile, необходимо:
- Отправить запрос на получение данных (
SaluteResponse.getProfileData()
). - Обработать входящее сообщение
messageName='TAKE_PROFILE_DATA'
.
Пример:
import { createSystemScenario, createUserScenario, NLPRequestTPD } from '@salutejs/scenario';
const systemScenario = createSystemScenario({
RUN_APP: ({ res }) => {
res.getProfileData();
},
});
const userScenario = createUserScenario({
Profile: {
match: (req) => req.request.messageName === 'TAKE_PROFILE_DATA',
handle: ({ res, req }) => {
const name = req.profile?.customer_name;
if (name) {
res.setPronounceText(`Привет, ${name}`);
return;
}
const statusCode = (req.request.payload as NLPRequestTPD['payload']).status_code;
res.setPronounceText(`Почему-то не получили ваше имя, статус ошибки ${statusCode.code}`);
},
},
});
i18n
Интерфейс для адаптации текста с динамическими параметрами и плюрализацией в рамках персонажей семейства виртуальных ассистентов Салют.
Создание словарей
Файлы с адаптацией лежат рядом с кодом, к которому они логически относятся.
src/handlers/mainPage
├── mainPage.i18n
│ ├── sber.ts — словарь для персонажа Сбер
│ ├── joy.ts — словарь для персонажа Джой
│ ├── athena.ts — словарь для персонажа Афина
│ └── index.ts — карта персонажей
Файл словаря — модуль, в котором лежит кейсет для одного языка с парами { ключ, перевод }
:
export const sber = {
Пока: 'Bye',
Привет: 'Example',
};
Все словари должны быть объявлены в карте персонажей. Картой оперирует модуль i18n.
export * from './sber';
export * from './joy';
export * from './athena';
Использование
import * as keyset from './mainPage.i18n';
handle: ({ req, res }) => {
const greeting = req.i18n(keyset);
res.setPronounceText(greeting('Привет'));
},
Параметризация
Параметры объявляются в синтаксисе схожем с параметрами для template strings.
export const sber = {
'Добрый день, {name}!': 'Добрый день, {name}!',
}
export const joy = {
'Добрый день, {name}!': 'Привет, {name}!',
}
import * as keyset from './mainPage.i18n';
handle: ({ req, res }) => {
const greeting = req.i18n(keyset);
res.setPronounceText(greeting('Добрый день, {name}!', {
name: 'Костя',
}));
},
Плюрализация
Для выражения плюрализация существует специальный параметр count
. Который соотносится с вариантами написания ключа через вложенные параметры: many
, some
, one
, none
.
export const sber = {
'{count} операций': {
many: '{count} операция',
none: 'нет операций',
one: '{count} операция',
some: '{count} операции',
}
}
import * as keyset from './mainPage.i18n';
handle: ({ req, res }) => {
const transactions = req.i18n(keyset);
res.setPronounceText(transactions('{count} операций', {
count: 2,
}));
},