Перейти к содержанию
telegram AI Бот

События диалогов

Виды обрабатываемых событий

onInputDialogBegin

Данный обработчик вызывается перед началом работы элемента ввода данных, с которым связана переменная (с указанным кодом или вообще любая). Если в сценарии бота есть несколько элементов ввода, связанных с указанной переменной, этот обработчик будет вызываться для каждого из них.

С помощью этого обработчика можно настраивать работу элемента, устанавливая различные свойства в объекте context.output.result:

  • context.output.result.promptText — строка, которая будет отправлена пользователю в качестве запроса ввода.
  • context.output.result.suggestedActions — массив строк или объектов CardAction, которые будут показаны пользователю в виде кнопок.
  • context.output.result.unrecognizedPromptText — строка, которая будет отправлена пользователю в случае нераспознанного ввода.

onInputDialogBegin

TypeScript
1
2
3
4
5
6
function onInputDialogBegin(
  variableCode: OptionalParameter<VariableCodeType>,
  callback: (
    botEvent: InputDialogBeginEvent
  ) => Promise<void>
): void
  • variableCode — код переменной, с которой связан элемент ввода (см. VariableCodeType). При указании null, undefined, "*" или пустой строки обработчик вызывается для любой переменной (см. OptionalParameter).
  • callback — функция, которая будет вызвана в начале работы элемента ввода.
  • botEvent — объект события, который можно использовать в теле функции (см. InputDialogBeginEvent).

Пример

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

TypeScript
onInputDialogBegin('store_name', async () => {
  if (context.input.variables.store_name) {
    // Если переменная с названием магазина уже записана (например, если был один подходящий вариант),
    // можно ничего не делать, т. к. если у свойства «Спрашивать» элемента ввода текста выбран вариант
    // «Только если значение не заполнено», то текущий элемент ввода будет полностью пропущен
    return;
  }

  const fuseArray = context.input.variables.fuse_results as any[];

  // Если есть несколько подходящих вариантов, но не больше пяти,
  if (fuseArray && fuseArray.length > 1 && fuseArray.length <= 5) {
    // то пользователю сразу предлагается выбор из подходящих вариантов
    context.output.result.promptText = 'Мы нашли несколько магазинов с похожим названием. Выберите один из них.';
    context.output.result.suggestedActions = fuseArray.map(result => result.item);
  }

  // Если подходящих вариантов нет или слишком много, элемент ввода работает как обычно.
});

onInputDialogBeforeInterruption

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

С помощью этого обработчика можно настраивать работу элемента, устанавливая свойство в объекте context.output.result:

  • context.output.result.allowInterruptions — поле, в которое можно записать логическое значение (true/false), которое определит, можно ли прерывать работу текущего элемента ввода. Например, можно запретить прерывать работу элемента ввода распознаванием интента в прерывающем сценарии, если ввод пользователя полностью совпал с одним из заранее известных вариантов ответов.

onInputDialogBeforeInterruption

TypeScript
1
2
3
4
5
6
function onInputDialogBeforeInterruption(
  variableCode: OptionalParameter<VariableCodeType>,
  callback: (
    botEvent: InputDialogBeforeInterruptionEvent
  ) => Promise<void>
): void
  • variableCode — код переменной, с которой связан элемент ввода (см. VariableCodeType). При указании null, undefined, "*" или пустой строки обработчик вызывается для любой переменной (см. OptionalParameter).
  • callback — функция, которая будет вызвана после выполнения ввода пользователем.
  • botEvent — объект события, который можно использовать в теле функции (см. InputDialogBeforeInterruptionEvent).

onInputDialogValueRecognized

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

С помощью этого обработчика можно проводить дополнительную обработку распознанного значения, устанавливая различные свойства в объекте context.output.result:

  • context.output.result.recognized — логическое значение (true/false), которое переопределяет, было ли распознано введенное пользователем значение.
  • context.output.result.outputValue — переопределенное распознанное значение, которое будет записано в переменную, связанную с элементом ввода.

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

onInputDialogValueRecognized

TypeScript
1
2
3
4
5
6
function onInputDialogValueRecognized(
  variableCode: OptionalParameter<VariableCodeType>,
  callback: (
    botEvent: InputDialogValueRecognizedEvent
  ) => Promise<void>
): void
  • variableCode — код переменной, с которой связан элемент ввода (см. VariableCodeType). При указании null, undefined, "*" или пустой строки обработчик вызывается для любой переменной (см. OptionalParameter).
  • callback — функция, которая будет вызвана после успешного распознавания ввода пользователя.
  • botEvent — объект события, который можно использовать в теле функции (см. InputDialogValueRecognizedEvent).

Пример

В этом примере при каждом вводе пользователем названия магазина происходит нечеткий поиск по списку всех магазинов, после чего поведение элемента ввода меняется в зависимости от результатов поиска.

TypeScript
onInputDialogValueRecognized('store_name', async (botEvent) => {
  if (context.input.variables.store_name) {
    return;
  }

  const searchOptions = {
      method: 'GET',
      url: baseUrl + storesEndpointRoute,
  };
  const storesResponse = await axios.request(searchOptions);

  const store = storesResponse.data.find(s => s.toLowerCase() == botEvent.userInputText.toLowerCase());

  if (store) {
    // Если найдено полное совпадение, записываем найденный элемент в результат
    context.output.result.recognized = true;
    context.output.result.outputValue = store;
    return;
  }

  const fuse = new Fuse(storesResponse.data, fuseOptions);

  const searchResults = fuse.search(botEvent.userInputText);
  console.log(searchResults);

  if (!searchResults.length) {
    context.output.result.recognized = false;
    context.output.result.unrecognizedPromptText = 'Мы не нашли ничего похожего. Уточните название.';
    context.output.result.suggestedActions = null;
    return;
  }

  if (searchResults.length == 1) {
    context.output.result.recognized = true;
    context.output.result.outputValue = searchResults[0].item;
    return;
  }

  if (searchResults.length > 1 && searchResults.length <= 5) {
    context.output.result.recognized = false;
    context.output.result.unrecognizedPromptText = 'Мы нашли несколько магазинов с похожим названием. Выберите один из них.';
    context.output.result.suggestedActions = searchResults.map(result => result.item);
    return;
  }

  if (searchResults.length > 5) {
    context.output.result.recognized = false;
    context.output.result.unrecognizedPromptText = 'Мы нашли слишком много магазинов с похожим названием. Уточните название.';
    context.output.result.suggestedActions = null;
    return;
  }
});

onUserInputProcessed

Данный обработчик вызывается после любого ввода пользователя. Выполнение обработчика можно связать с ожидаемым результатом обработки пользовательского ввода, при котором он будет выполняться, для этого нужно указать параметр processingResult (см. UserInputProcessedResultType). При обработке события доступен объект с результатами попытки распознавания, результатами валидации и строкой ввода пользователя. С помощью обработчика этого события можно, например, обратиться к LLM/GPT и сгенерировать с помощью нее ответ для пользователя.

onUserInputProcessed

TypeScript
1
2
3
4
5
6
function onUserInputProcessed(
  processingResult: OptionalParameter<UserInputProcessedResultType>,
  callback: (
    botEvent: UserInputProcessedEvent
  ) => Promise<void>
): void
  • processingResult — результат обработки введенных пользователем данных (см. UserInputProcessedResultType). При указании null, undefined, "*" или пустой строки обработчик вызывается при любом результате (см. OptionalParameter).
  • callback — функция, которая будет вызвана после ввода пользователя.
  • botEvent — объект события, который можно использовать в теле функции (см. UserInputProcessedEvent).

Пример

В этом примере мы подписываемся на событие обработки пользовательского ввода при любом нераспознанном вводе пользователя и передаем этот ввод в Yandex GPT. На основании ответа от Yandex GPT мы формируем ответное сообщение для пользователя.

TypeScript
// Импортируем Axios.
const axios = require('axios');

// Указываем учетные данные.
const iamToken = '********';
const folderId = '********';

// Создаем HTTP-клиент.
const httpClient = axios.create({
  baseURL: 'https://llm.api.cloud.yandex.net/foundationModels/v1/completion',
  timeout: 5000,
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${iamToken}`,
    'x-folder-id': folderId
  }
});

// Создаем запрос.
const buildRequest = (messages: {}[]) => {
  return {
    "modelUri": `gpt://${folderId}/yandexgpt-lite`,
    "completionOptions": {
      "stream": false,
      "temperature": 0.6,
      "maxTokens": "2000"
    },
    messages: messages,
  };
}

// Отправляем запрос.
const sendRequest = async (request: {}) => {
  const response = await httpClient.post('', request);
  return response.data;
};

// Отправляем сообщение.
const sendMessages = async (messages: {}[]) => {
  const request = buildRequest(messages);
  return await sendRequest(request);
}

// Отправляем ввод пользователя.
const sendUtterance = async (utterance: string) => {
  const messages = [
    {
      "role": "system",
      "text": "Пользователь задал вопрос, но мы не знаем на него ответ. Ответь на этот вопрос, пожалуйста."
    },
    {
      "role": "user",
      "text": utterance
    }
  ];
  return await sendMessages(messages);
};

// Подписываемся на событие обработки пользовательского ввода
onUserInputProcessed('input_unrecognized', async (botEvent) => {
  // Отправляем ввод пользователя в LLM.
  const result = await sendUtterance(botEvent.userInputText);

  // Формируем сообщение на основании ответа LLM для отправки пользователю.
  context.output.activities.push({
    type: ScriptActivityTypes.Message,
    text: {
      format: TextFormatTypes.Plain,
      content: result.completion.text,
    },
  });
});