Перейти к основному содержимому

JavaScript-действия

В JAICP DSL есть особые теги действий, которые позволяют вызвать из стейта отдельный сценарий. В этом подсценарии бот может реализовать любое поведение: выполнять произвольное число реакций, переходить по стейтам самого подсценария. При этом в основном сценарии эта сложная логика представлена как один тег.

Иногда в сценарии нужно выполнить действие без переключения контекста в отдельный подсценарий. В таком случае из стейта достаточно просто вызвать JavaScript-функцию, которая реализует нужное поведение.

Помимо сценарных действий JAICP DSL поддерживает JavaScript-действия (JS-действия). Для них теги действий реализованы не как переход в подсценарий, а как обычный вызов функции внутри тега script.

Как создать JS-действие

В этом разделе мы разработаем тег JS-действия, который:

  1. Принимает в качестве параметров два числа и формат ответа.
  2. Отправляет ответ с суммой этих чисел в указанном формате.
подсказка
В статье Как создать свои теги действий рассмотрен такой же пример, но с реализацией через сценарное действие. Рекомендуется ознакомиться с ней прежде, чем приступать к этой.

JavaScript-функция

  1. Авторизуйтесь в JAICP и выберите нужный проект.
  2. На панели управления слева перейдите в Редактор → Код.
  3. Создайте в директории src файл functions.js и напишите в нем функцию для вашего тега.
function sumTwoNumbers(numberOne, numberTwo, answerFormat) {
var result = parseFloat(numberOne) + parseFloat(numberTwo);

if (!isNaN(result)) {
if (answerFormat === "number") {
$reactions.answer(result);
} else if (answerFormat === "full") {
$reactions.answer(numberOne + " + " + numberTwo + " = " + result);
}
} else {
$reactions.answer("Я не знаю, как посчитать " + numberOne + " + " + numberTwo + ".");
}
}

Разберем код функции:

  • Функция принимает три аргумента.
  • Параметры numberOne и numberTwo приводятся к числам при помощи функции parseFloat. Числа складываются, и сумма сохраняется в переменную result.
  • Если сумма имеет значение NaN, бот отправляет сообщение об ошибке, иначе — ответ в одном из форматов.
  • Если answerFormat имеет значение "number", то бот в ответе указывает только сумму, например: «7». Если answerFormat имеет значение "full", то бот в ответе указывает полное выражение, например: «3 + 4 = 7».

Настройки тега

Чтобы использовать сценарий выше как тег действия, его нужно описать в специальном JSON-файле с настройками.

  1. Создайте в директории src поддиректорию для тегов действий, например blocks.
  2. Создайте в директории blocks поддиректорию SumTwoNumbers, а в ней файл block.json.
  3. В файл запишите JSON-объект с настройками тега. Для JS-действий некоторые настройки отличаются:
ПолеТипОписание
customTagTypeСтрокаТип тега действия: SC или JS. Чтобы сделать тег JS-действием, укажите значение JS.
scenarioFileСтрокаПуть к нужному JavaScript-файлу относительно директории src.
functionNameСтрокаНазвание функции в файле scenarioFile, которая будет вызвана при использовании тега. Заменяет поле startState.
подсказка
Все остальные поля, включая настройки параметров и отображения в J‑Graph, заполняются и работают так же, как для тегов сценарных действий.

Полный пример настроек:

{
"tagName": "SumTwoNumbers",
"customTagType": "JS",
"scenarioFile": "functions.js",
"functionName": "sumTwoNumbers",
"caption": {
"ru": "Сложить два числа",
"eng": "Sum two numbers"
},
"description": {
"ru": "Используйте этот блок, чтобы сложить два числа и отправить ответ со значением суммы.",
"eng": "Use this block to calculate the sum of two numbers and send a reply with the result."
},
"hint": {
"ru": "Сложить два числа и отправить ответ со значением суммы",
"eng": "Calculate the sum of two numbers and send a reply with the result"
},
"parameters": [
{
"name": "numberOne",
"type": "integer",
"required": true,
"localization": {
"ru": "Первое число",
"eng": "First number"
}
},
{
"name": "numberTwo",
"type": "integer",
"required": true,
"localization": {
"ru": "Второе число",
"eng": "Second number"
}
},
{
"name": "answerFormat",
"type": "string",
"required": true,
"localization": {
"ru": "Формат ответа",
"eng": "Answer format"
},
"userInterfaceField": {
"type": "select",
"options": [
{
"value": "number",
"localization": {
"eng": "Number only",
"ru": "Только число"
}
},
{
"value": "full",
"localization": {
"eng": "Full expression",
"ru": "Полное выражение"
}
}
]
}
}
]
}

Дальнейшие шаги не отличаются от сценарных действий:

Преимущества JS-действий

С точки зрения разработки сценария через редактор кода JS-действия не дают больших преимуществ. Если подключить файл с функцией через require и вызвать ее из тега script, поведение бота не изменится:

theme: /

state: SumTwoNumbers
q!: * [чему равно] @duckling.number::numberOne (плюс/$regex<\+>) @duckling.number::numberTwo *
SumTwoNumbers:
numberOne = {{$parseTree._numberOne}}
numberTwo = {{$parseTree._numberTwo}}
answerFormat = number
a: Посчитать для вас что-нибудь еще?

Однако если сценарий разрабатывается через графический редактор J‑Graph, функцию можно использовать как блок действия и работать с ней в удобном интерфейсе.

Если функция оформлена как JS-действие, с ней удобно работать в J‑Graph
Работать с обычной функцией можно только через блок Код

Отличия от сценарных действий

Сценарное действиеJS-действие
Эквивалентно переходу в другой стейт через тег go! с передачей параметров.Эквивалентно вызову функции через тег script.
В одном стейте может быть не более одного тега. Если их больше, то будет выполнено только первое действие.Может быть произвольное число тегов в одном стейте. Все действия будут выполнены.
Значения параметров можно извлечь через объект $request.data.args.Значения параметров можно извлечь как стандартные аргументы функции.
Желательно предусмотреть параметры для стейтов основного сценария, в которые бот должен вернуться после действия (например, okState).После действия продолжает выполняться основной сценарий, поэтому параметры для стейтов предусматривать не обязательно.