Чат-боты прекрасно привлекают клиентов. В этом руководстве приведен пример создания веб-перехватчика с нуля для разработки чат-бота с реальной добавленной стоимостью.

О чем этот урок?

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

В этом руководстве я шаг за шагом проведу вас через реализацию полного веб-перехватчика с Dialogflow и Node.js. Мы собираемся создать потрясающего чат-бота, который предоставит нам информацию о криптовалютах, когда об этом попросят!
Прежде чем начать, я делаю следующие предположения относительно того, что вы уже знаете:

- Вы знакомы с основными понятиями чат-бота, такими как намерения, сущности, события и контексты
- Вы знаете, как восстановить агента из заархивированного в консоли Dialogflow
- Вы знаете, как связать агента с его веб-перехватчиком
- Вы знаете, как протестировать свой веб-перехватчик локально (с помощью ngrok) или отправить его в онлайн (на Heroku).

Убедитесь, что вы освоили эти шаги, потому что они не рассматриваются в этом руководстве. Мы в порядке.

Агент чат-бота

Поскольку в этом руководстве основное внимание уделяется серверной части, мы постараемся упростить работу агента до мозга костей. У чат-бота одна миссия: узнать цену криптовалюты. Если чат-бот не может найти никакой информации о криптовалюте, он сообщает об этом пользователю.

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

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

Chatbot-agent.zip

Убедитесь, что ваш агент использует версию API V1. Его можно установить в настройках агента.

Чат-бот Webhook

Допустим, у нас есть агент, который может инициировать действие fetchPriceCryptoCurrency для получения некоторой информации о криптовалюте. Название криптовалюты указывается в параметре symbol вместе с действием.

Настройка проекта

На данный момент наш сервер является базовым и будет расти по мере прохождения обучения. Создайте каталог на своем компьютере и вставьте в него два файла ниже. Чтобы установить зависимости, запустите npm install из каталога. Затем запустите проект с npm start.

Здесь мы настраиваем сервер с экспрессом, который прослушивает порт 8080.

Подождите, что такое веб-перехватчик?

Если вам не нравится концепция веб-перехватчиков, считайте ее внутренней частью веб-приложения. Он действует как микросервис и содержит логику приложения. В этом сравнении агент - это интерфейсная часть чат-бота. Агент обрабатывает поток обсуждения, но не может выполнять никаких логических действий, таких как отправка электронного письма или получение информации из базы данных. Вот почему агенту нужен боковой удар, которому можно доверять, для выполнения требуемых действий: веб-перехватчик.

Чтобы попросить веб-перехватчик выполнить действия, агент отправляет HTTP-запрос, который содержит имя выполняемого действия и параметры, необходимые для выполнения действия. В нашем случае действие - это fetchPriceCryptoCurrency, а его обязательный параметр - это symbol криптовалюты. Думайте о действиях как о разных конечных точках вашего микросервиса. Веб-перехватчик выполняет действие и возвращает ответ, содержащий информацию, которую искал агент.

Обработка запросов от агента

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

Теперь каждый запрос, сделанный агентом к конечной точке https://<your_server_name>/webhook, будет обрабатываться функцией, определенной в модуле webhook прямо ниже:

  1. Сначала мы извлекаем имя действия и параметры из запроса агента (см. Dialogflow doc V1 о формате запроса агента).
  2. Затем действие fetchPriceCryptoCurrency обрабатывается в случае, если
  3. Наконец, агенту возвращается ответ.

Если мы хотим обрабатывать больше действий, нам нужно только добавить больше таких случаев:

Новая структура проекта:

Хорошо, хорошо! Это выглядит хорошо. Давайте погрузимся в реализацию запроса на получение STOP! Нет. Это неприятно, и это не выглядит хорошо. Я тебя одурачил.

То, как мы обрабатывали действия, является причиной, по которой я пишу это руководство. То, что мы сделали, - это самый простой способ сделать это, и он работает хорошо, пока проект остается небольшим. Но что происходит, когда он растет и количество действий, которые нужно обрабатывать, увеличивается? В конечном итоге вы получаете нечитаемый if-case. Как проверить наличие всех необходимых параметров для каждого действия? В итоге вы получаете массу дополнительных случаев. Как обрабатывать как синхронные, так и асинхронные действия, поскольку они по своей сути ведут себя по-разному? Как даже протестировать действие, чтобы убедиться, что оно работает должным образом? Поскольку обработчики действий взаимосвязаны, незначительная модификация одного из них может нарушить тесты других. Это бардак! И этого легко избежать.

Лучше обрабатывать запросы от агента

Основная проблема приведенной выше структуры заключается в том, что все обработчики действий реализованы в одном файле. Эти обработчики могут иметь разную структуру, так как одни из них синхронны, а другие - асинхронны. Чтобы решить эту проблему, мы собираемся использовать мощный инструмент из набора инструментов javascript: файл Promise`s. Если вы не знаете, что такое Promise и как их использовать, найдите время, чтобы прочитать эту потрясающую статью Эрика Эллиотта. Это действительно поучительно.
Вот как будет работать обработка действий:

- Вместо того, чтобы иметь часть if-case для каждого обработчика, каждый обработчик будет реализован в своем собственном выделенном файле
- Вместо того, чтобы иметь огромный нечитаемый if-case, мы собираемся используйте объект для хранения всех обработчиков, где ключи - это названия действий, а значения - обработчики.
- Для беспрепятственной обработки асинхронных действий каждый обработчик будет Promise- на основе

Хватит разговоров, давайте применим это на практике, чтобы лучше понять, как это работает.
Во-первых, мы собираемся создать папку для хранения обработчиков. Затем мы собираемся создать наш первый обработчик:

Как видите, внутри webhook была создана папка handlers. У нас также есть папка core внутри handlers. Таким образом, мы сможем классифицировать обработчики в зависимости от их использования. Я использую папку core для обработки действий, которые напрямую связаны с функциями чат-бота, например, fetchPriceCryptoCurrency.js, который извлекает цену криптовалюты. Например, мы также можем использовать категорию validators для хранения всех обработчиков, которые используются для проверки ввода пользователя, например проверки возраста пользователя или отклонения адресов электронной почты yopmail . Категоризация зависит от вас и помогает структурировать проект.

Это скелет нашего первого обработчика действий на основе обещаний! Вот что мы делаем:

  1. Проверяем наличие необходимых параметров. Если параметр symbol отсутствует, обещание отклоняется с ошибкой.
  2. Получена цена криптовалюты (подробнее об этом позже).
  3. Обещание решает сказать, что обработчик завершил выполнение действия.

Хорошо, а как насчет аргумента взаимодействия обработчика?

Актуальный вопрос. Вы помните строки в webhook/index.js файле, где мы получили действие и параметры из запроса агента?

Вспоминая две строчки из webhook / index.js

Ага, вот эти. Аргумент interaction - это простой объект, который содержит эти параметры. Он встроен в webhook/index.js и передается обработчику. Вот новый webhook/index.js:

Объект interaction.response построен обработчиком на основе документации Dialogflow (V1 API). Он может содержать последующее событие для запуска определенного намерения на стороне агента, сообщения для отправки обратно на платформу обмена сообщениями или новые контексты разговора.

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

Обратите внимание, что в объекте обработчиков обработчик fetchPriceCryptoCurrency теперь связан с действием core/fetchPriceCryptoCurrency вместо действия fetchPriceCryptoCurrency. Теперь агент должен будет вызвать действие core/fetchPriceCryptoCurrency, чтобы узнать цену криптовалюты. И снова этот рефакторинг сделан, чтобы улучшить читаемость в консоли Dialogflow. Теперь мы с первого взгляда знаем, что намерение запускает основное действие.

Получить цену криптовалюты

Стоимость криптовалюты можно узнать, позвонив в CryptoCompare API. Мы собираемся использовать axios для HTTP-запроса. Установите его с помощью npm i --save axios.
на основе документа конечной точки, которую мы собираемся вызвать, вот запрос с аксиомами:

Сначала мы выполняем запрос GET к конечной точке https://min-api.cryptocompare.com/data/price. Метод axios .get возвращает обещание, которое разрешается с HTTP-ответом axiosResponse. Возвращенные данные содержатся в объекте axiosResponse.data. Это объект, который содержит валюты в качестве ключей и цену криптовалюты в этой валюте в качестве значений. Здесь у нас есть два ключа: USD и EUR.

Затем мы проверяем успешность вызова API. Если ошибки нет, мы можем установить событие отслеживания prices-found. Это вызовет намерение на стороне агента, которое отправит пользователю цены на криптовалюту. Если возникает ошибка, мы устанавливаем событие отслеживания на prices-not-found, чтобы активировать намерение, которое сообщает пользователю, что чат-бот не может найти никакой информации. В обоих случаях создается объект interaction.response.

Наконец, Promise разрешает сказать, что обработчик выполнил действие без каких-либо ошибок.

Вот окончательная версия нашего обработчика fetchPriceCryptoCurrency:

Большой! Теперь у нас есть полностью рабочий веб-перехватчик. Вы можете протестировать чат-бота, создав агента в Dialogflow и спросив сколько биткойн в консоли.

Вот репозиторий проекта: https://github.com/Baboo7/node-dialogflow-webhook-boilerplate.

Заключение

Использование обработчиков на основе обещаний поможет вам создавать масштабируемых чат-ботов, поскольку оно улучшает:

- Удобочитаемость: у обработчика есть свой собственный выделенный файл
- Обработка асинхронности: когда обработчики на основе Promise выполняют вызов базы данных / внешнего API без проблем
- Тестируемость: обработчик можно легко протестировать