bind


Функция bind предназначена для установки обработчиков.

Обработчики — особые функции, которые вызываются на различных этапах обработки запроса или при возникновении внештатных ситуаций в диалоге.

Принцип работы

Рассмотрим общий принцип работы обработчиков.

  1. Создается функция, которая как аргумент принимает объект $context — текущий контекст обработки запроса. В теле функции производятся любые действия, необходимые по сценарию.
  2. При установке функции в качестве обработчика при помощи функции bind указывается его тип. Тип определяет ситуацию, в которой обработчик будет вызван.
  3. Также при установке обработчик привязывается к определенному пути в иерархии стейтов сценария. По умолчанию это корневой путь /.
  4. Обработчик и вызов функции bind помещается либо в отдельный файл с расширением .js, который импортируется в сценарий при помощи тега require, либо в тело тега init.

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

Синтаксис

Функция bind принимает 4 аргумента.


Аргумент Тип Описание Обязательный
type Строка Тип обработчика Да
handler Функция Функция-обработчик Да
path Строка Абсолютный путь для привязки обработчика Нет
name Строка Имя обработчика Нет

Рассмотрим пример вызова функции bind:

bind(
    "postProcess",
    function($context) {
        $context.session.lastState = $context.currentState;
    },
    "/Start",
    "Remember last state"
);
  • Тип обработчика postProcess, переданный в качестве первого аргумента, означает, что он будет вызываться после основного цикла обработки запроса.
  • Функция, переданная как второй аргумент, задает целевое действие. В данном случае оно заключается в том, что путь к текущему стейту сохраняется в $session как предыдущий стейт.
  • Обработчик привязывается к пути /Start. Он будет вызываться в стейте /Start и во всех его дочерних стейтах — например, /Start/Hello, /Start/Hello/1 и т. д.

При привязке к корневому пути обработчик будет вызван при нахождении в любом стейте сценария.

Обработчики этапов обработки запроса

Обработчики следующих типов вызываются в ходе общего цикла обработки запроса:

preMatch

Обработчик preMatch вызывается перед классификацией запроса. Ниже перечислены основные случаи его использования.

Принудительное изменение текущего стейта

В следующем примере при обработке запроса в стейте /Hello контекст будет переведен в стейт /Start. Это может быть полезно при переименовании стейтов для обратной совместимости версий сценария.

bind(
    "preMatch",
    function($context) {
        $context.temp.targetState = "/Start";
    },
    "/Hello"
);

Изменение текста запроса

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

bind("preMatch", function($context) {
    if ($context.client.hasActiveAuthorization) {
        $context.request.query += " (клиент авторизован)";
    }
});

Чтобы иметь возможность изменить текст запроса, задайте специальную настройку в конфигурационном файле chatbot.yaml:

nlp:
  modifyRequestInPreMatch: true

selectNLUResult

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

Если такое поведение нежелательно, с помощью обработчика selectNLUResult можно его изменить. Он вызывается после классификации запроса и переопределяет механизм выбора нужного правила.

Подробнее об обработчике selectNLUResult

preProcess

Обработчик preProcess вызывается после классификации запроса и определения целевого стейта, но перед выполнением действий, заданных в стейте. Например, он может быть использован для инициализации каких-либо данных или проверки предварительных условий для перехода в другие стейты.

В следующем примере предполагается, что в $session хранится параметр громкости устройства. Если громкость не задана, для нее устанавливается значение по умолчанию.

var DEFAULT_VOLUME = 40;

bind("preProcess", function($context) {
    if (!$context.session.volume) {
        $context.session.volume = DEFAULT_VOLUME;
    }
});

postProcess

Обработчик postProcess выполняется после завершения обработки запроса и может быть использован, например, для добавления в ответ дополнительных полей или записи статистических данных.

В приведенном примере обработчик добавляет во все ответы бота в канале Telegram поле, которое указывает, что к ним применена разметка Markdown.

bind("postProcess", function($context) {
    if ($context.response.channelType === "telegram") {
        $context.response.replies = $context.response.replies.map(function(reply) {
            if (reply.type === "text") {
                reply.markup = "markdown";
            }
            return reply;
        });
    }
});

Из postProcess также возможно использовать метод $reactions.transition для перехода обратно в сценарий и принудительного продолжения обработки запроса.

Обработчики ошибок

Обработчики ошибок служат для обработки внештатных ситуаций в ходе работы бота:

В теле обработчиков ошибок в поле $context.exception.message содержатся сообщения возникших ошибок.

onScriptError

Обработчик onScriptError вызывается при возникновении необработанного исключения в коде на JavaScript. Также его можно использовать для настройки поведения при генерации собственных исключений при помощи инструкции throw.

Рассмотрим следующий пример использования обработчика для записи сообщения об ошибке в отчет по сессиям через метод $analytics.setSessionData.

bind("onScriptError", function($context) {
    $analytics.setSessionData("Ошибка", $context.exception.message);
});

После onScriptError может быть выполнен обработчик postProcess, а также переход в другой стейт при помощи $reactions.transition.

onDialogError

Обработчик onDialogError вызывается при возникновении ошибок сценария, не связанных с исключениями на JavaScript. Примеры таких ошибок:


Ошибка Сообщение об ошибке
Для запроса клиента не определен целевой стейт. No target state was determined for query
Сделан переход в несуществующий стейт. State not found for path <path>
Бот попал в бесконечный цикл переходов по стейтам. Infinite loop was detected for state <state> in postProcess transition
bind("onDialogError", function($context) {
    if ($context.exception.message
            && $context.exception.message === "No target state was determined for query") {
        $reactions.answer(
            "Для запроса «" + $context.request.query + "» не найден стейт!"
        );
    }
});

После onDialogError может быть выполнен обработчик postProcess, а также переход в другой стейт при помощи $reactions.transition.

onAnyError

Обработчик onAnyError выполняется в нескольких случаях:

  1. В коде сценария возникло исключение, для которого не предусмотрен обработчик onScriptError.
  2. В ходе диалога возникла ошибка, для которой не предусмотрен обработчик onDialogError.
  3. Возникла непредвиденная ошибка сервера, не связанная с логикой сценария.
bind("onAnyError", function($context) {
    var answers = [
        "Что-то пошло не так.",
        "Произошла ошибка. Пожалуйста, повторите запрос позже.",
        "Все сломалось. Попробуйте еще раз."
    ];
    var randomAnswer = answers[$reactions.random(answers.length)];
    $reactions.answer(randomAnswer);
});

После onAnyError обработчик postProcess не выполняется. Переход в другой стейт при помощи $reactions.transition невозможен.