Чат боты — довольно интересная тема, которой интересуются как гики-энтузиасты,
так и компании, которые хотят организовать взаимодействие со своими клиентами
наиболее удобным для них способом
Сегодня я опишу вам простой пример создания бота Telegram с использованием
платформы для создания разговорных интерфейсов API.AI, который будет
приветствовать пользователя и отвечать на вопросы о погоде. По большей части я
следовал инструкциям с https://api.ai/docs/getting-started/basics, в реальной практике, можно не ограничиваться погодой и реализовать интерфейсы
для автоматизированной поддержки или продаж.
Шаг первый: Подготовка инфраструктуры.
В этом кейсе мы будем использовать только Telegram бота и API.AI, оба сервиса
предоставляются бесплатно — нам остается только завести учетные записи.
Создайте бота Telegram
Чтобы создать бота — просто напишите @BotFather (это такой бот, которые умеет
создавать и настраивать другие боты):
- Отправьте команду /newbot — так мы сообщаем @BotFather, что нам нужен новый бот
- Теперь @BotFather попросит нас дать имя новому боту. Это имя будут видеть наши
будущие пользователи, поэтому название нужно давать понятное и простое. - Последним шагом укажем для бота username, в конце которого нужно обязательно
написать “bot”. - Если имя не занято, получаем сообщение с подтверждением и токен доступа.
Чтобы было понятнее — ниже скриншот со всеми действиям:
Немного теории
Пришло время создать агента API.AI, который в сущности является проектом или
контейнером (как вам удобнее называть). Агент содержит настройки контекстов,
сущностей и ответов:
- “контекст” (Intent) отражает связь между тем, что сказал пользователь и
тем что должна сделать наша программа - “сущности” (Entities) — это инструмент извлечения значений параметров для
нашей программы из естественного языка (того что сказал или написал
пользователь) - “ответы” — это конечный результат работы нашей программы, который мы
отправляем пользователю на его сообщение
Иногда для ответа пользователю достаточно информации из текущего диалога, в
таком случае можно можно настроить статичные ответы в контекстах. В
реальности для получения конкретного ответа нам может потребоваться внешний
сервис или своя бизнес логика, например, чтобы получить информацию о погоде на
завтра, нужно вызвать внешний API соответствующего сервиса. Позже я расскажу вам
получать информацию из внешних систем, но для начала подготовим базу.
Создайте проект в API.AI
Для регистрации в API.AI вам потребуется аккаунт Google (достаточно завести в
почту в Gmail). Теперь перейдите по адресу https://api.ai/,
нажмите на кнопку “SIGN UP FOR FREE”, а за тем выберите аккаунт, от имени
которого хотите авторизоваться.
Теперь переходим к созданию самого агента. Нажмите на “Create agent” и укажите
как минимум Имя(Name), Язык(Language) и Часовой пояс (Time Zone)
Шаг второй: Настройте агента.
Контекст отражает связь между тем, что говорит пользователь, и что должен
сделать наш агент. В нашем случае, рассмотрим случай с прогнозом погоды:
- Кликните на в разделе “Контекст” (Intents). В агенте уже настроены “контексты”
на приветствие и ошибки, оставим их пока без изменений. - Укажите название для “контекста” — любое, главное чтобы оно было понятно вам и
вашим коллегам. - В разделе “Реплики пользователя” (User Says) приведите примеры вопросов, который
может ваш пользователь. Так как мы говорим о погоде, человек может задать вопрос
в привязке ко времени и место — учтем это. Чем больше примеров вы предоставите в
настройках, тем точнее будет работать агент. Некоторые примеры я привел на
скриншоте:
В последнем примере слова “завтра” и “Нижнем Тагиле” подсвечены разными цветами
— таким образом слова связываются с сущностями (Entities) (в нашем случае
сущности системные). Используя эти параметры агент “поймет” в каком городе и для
какой даты нужно узнавать погоду.
Добавьте еще парочку своих примеров и нажмите “Сохранить” (SAVE).
Тестируем!
Проверим работу агента на простых вопросах, например, “Погода в Перми в среду”:
Все это время в правой верхней части экрана маячила надпись “Try it now” —
напишите в это поле или произнесите простой вопрос о погоде и нажмите “Ввод”.
Мы еще не настраивали автоматический ответ, но некоторые параметры агент уже
научился определять! В разделе INTENT отражено, что по “мнению” агента пользователь интересуется погодой (настроенный нами “контекст”), в PARAMETER — дату и название города в
соответствующих переменных.
Добавьте автоматические ответы
Сделаем нашего агента разговорчивей! Пока мы не научились получать информацию о
погоде из внешних источников, добавим в качестве ответов простые фразы.
Перейдите в раздел “ Ответы” (Response) и введите простые ответы аналогично
тому, как вы заполняли “Реплики пользователя”:
Как видите — в ответах можно использовать ссылки на выявленные сущности, начните
набирать $ — и интерфейс предложит вам выбрать конкретную переменную.
При формировании ответа агент учитывает количество определенных сущностей и не
использует ответы, данных для которых недостаточно. Например, на вопрос без
указания города агент использует ответ из второй строки.
Сохраните настройки и протестируйте еще раз:
Теперь у нас есть еще и ответ!
Шаг третий: Добавьте внешний сервис.
Наш агент уже “понимает” в каких случая пользователь хочет узнать погоду, на
какое число и в каком городе. Теперь осталось получить эти данные из подходящего
сервиса и передать агенту. Для этого вам нужно написать парочку скриптов на JS и
разместить их в облачном сервисе, в нашем случае — Google Cloud Project.
Создайте стартовый JS файл
Для начала, создайте и перейдите в директорию с именем вашего проекта :
-
Linux или Mac OS X:
mkdir ~/[PROJECT_NAME]
cd ~/[PROJECT_NAME] -
Windows:
mkdir %HOMEPATH%[PROJECT_NAME]
cd %HOMEPATH%[PROJECT_NAME]
Теперь создайте файл index.js со следующим содержанием:
/*
* HTTP Cloud Function.
*
* @param {Object} req Cloud Function request context.
* @param {Object} res Cloud Function response context.
*/
exports.itsm365Weather = function itsm365Weather (req, res) {
response = "This is a sample response from your webhook!" //Default response from the webhook to show it's working
res.setHeader('Content-Type', 'application/json'); //Requires application/json MIME type
res.send(JSON.stringify({ "speech": response, "displayText": response
//"speech" is the spoken version of the response, "displayText" is the visual version
}));
Настройте Google Cloud Project
- Выполните настройки “Before you
begin” с 1 по 5 пункты -
Разверните функцию в облаке выполнив в консоли:
gcloud beta functions deploy itsm365Weather --stage-bucket [BUCKET_NAME] --trigger-http
где, itsm365Weather — название функции, а [BUCKET_NAME] — наименование хранилища
данных для проекта.
После завершения операции вы увидите результат с URL http триггера:
Включите Webhook в API.AI
- Убедитесь, что находитесь в нужном агенте, а затем кликните “Fulfillment” в
левом скрывающемся меню. - Включите использование Webhook в правой верхней части экрана.
- Введите URL, полученный на предыдущем этапе.
- Сохраните изменения.
Подключите исполнение новой функции в настройках “контекста”
- Перейдите в настройки “контекста” прогноза погоды
- Разверните блок Fulfillment в нижней части страницы
- Отметьте галочкой “Использовать Webhook”
- Сохраните настройки и проверьте результат:
Настройте API для получения погоды
Для простоты, воспользуемся сервисом WWO (World Weather Online), в котором вам
нужно получить ключ API (просто
зарегистрируйтесь через Facebook или Github).
Обновите код стартового JS файла, не забыв ввести ключ API для получения
информации о погоде:
// Copyright 2017, Google, Inc.
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
'use strict';
const http = require('http');
const host = 'api.worldweatheronline.com';
const wwoApiKey = '98cfb8e40ecc47c4a2f205209172608';
exports.itsm365Weather = (req, res) => {
// Get the city and date from the request
let city = req.body.result.parameters['geo-city']; // city is a required param
// Get the date for the weather forecast (if present)
let date = '';
if (req.body.result.parameters['date']) {
date = req.body.result.parameters['date'];
console.log('Date: ' + date);
}
// Call the weather API
callWeatherApi(city, date).then((output) => {
// Return the results of the weather API to API.AI
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ 'speech': output, 'displayText': output }));
}).catch((error) => {
// If there is an error let the user know
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ 'speech': error, 'displayText': error }));
});
};
function callWeatherApi (city, date) {
return new Promise((resolve, reject) => {
// Create the path for the HTTP request to get the weather
let path = '/premium/v1/weather.ashx?format=json&num_of_days=1' +
'&q=' + encodeURIComponent(city) + '&key=' + wwoApiKey + '&date=' + date + '&lang=ru';
console.log('API Request: ' + host + path);
// Make the HTTP request to get the weather
http.get({host: host, path: path}, (res) => {
let body = ''; // var to store the response chunks
res.on('data', (d) => { body += d; }); // store each response chunk
res.on('end', () => {
// After all the data has been received parse the JSON for desired data
let response = JSON.parse(body);
let forecast = response['data']['weather'][0];
let location = response['data']['request'][0];
let conditions = response['data']['current_condition'][0];
let currentConditions = conditions['lang_ru'][0]['value'];
// Create response
let output = `На ${forecast['date']} в ${location['query']} ${currentConditions}, температура воздуха от ${forecast['mintempC']}°C до ${forecast['maxtempC']}°C.`;
// Resolve the promise with the output text
console.log(output);
resolve(output);
});
res.on('error', (error) => {
reject(error);
});
});
});
}
Заново разверните функцию в облачном проекте.
Шаг четвертый: настройка ветвей диалога
Взаимодействуя с пользователем мы не можем быть уверены в том, что он
предоставит нам всю информацию, необходимую для подготовки ответа во внешнем
сервисе сразу в самом первом сообщении. В нашем примере для получения прогноза
сервису потребуется дата и город. Если дата не известна, мы можем с успехом
предположить, что пользователь подразумевает “сегодня”, но о городе мы можем
узнать только от самого пользователя.
Сделайте “расположение” обязательным параметром
Откройте настройки контекста “Прогноз погоды” и укажите параметр geo-city
обязательным к заполнению. Затем настройте уточняющий вопрос по ссылке в колонке
“Prompts”.
Сохраните настройки и проверьте поведение агента, задав ему простой вопрос
“погода”:
Агент задал нам уточняющий вопрос, в консоли отображены параметры текущей
ситуации.
Создайте возвращаемое уточнение для расположения
Чтобы использовать данные полученные на предыдущих этапа взаимодействия с
пользователем, вам потребуется настроить соответствующие уточнения.
В настройка контекста “прогноз погоды” вбейте в поле “Add output context”
название возвращаемого уточнения “location” и сохраните настройки.
Создайте новый контекст для уточнения
Удобно, когда по одному и тому же расположению можно задавать несколько
вопросов, при этом не уточнять у пользователя, какой город он имеет ввиду. Вы
уже настроили возвращаемое уточнение, которе как можно использовать для
обработки уточняющих вопросов.
- Создайте новый контекст в разделе Intents или кликните по значку в строке
Intents левого выдвигающегося меню. - Назовите новый контекст “Уточнение погоды” (или любое другое понятное вам
название). - Установите входящие и исходящие уточнения как “location”
- Добавьте реплики пользователя, например, “Что на счет завтра”
- Добавьте параметр сущности со следующими значениями:
— Parameter Name:
geo-city
— Value: #location.geo-city - Добавьте ответ для пользователя в раздел “Response”:
— “Извини, но я не
могу получить прогноз на $date-period в #location.geo-city” - Включите использование webhook в меню Fulfillment.
- Сохраните настройки и протестируйте в консоли:
Шаг пятый: Приветствие и обработка непредвиденных ситуаций
Основной костяк агента готов, теперь неплохо сделать так, чтобы робот
приветствовал пользователя, а также знал что отвечать на непредвиденные вопросы.
Настройте ответы “по умолчанию” для непредвиденных ситуаций
Если пользовать задаст непредвиденный вопрос (в нашем случае — не о погоде)
агент включит в работу контекст для обработки непредвиденных ситуаций (Default
Fallback Intent):
Перейдите в настройке этого контекста, при необходимости настройте свои варианты
ответов.
Настройте контекст приветствия
Приветствие можно настроить аналогичным способом в соответствующем контенте —
Default Welcome Intent
Шаг шестой: запустите бота
Подключите Telegram бота к агенту
Перейдите в настройки “Интеграций” (Integrations) и включите бота в разделе
“One-click integrations”:
Скопируйте в поле “Telegram token” токен, который вы получили у @botFather и
нажмите на START.
Проверьте работу бота
Перейдите в своего бота и попробуйте ему что-нибудь написать, в моем случае это
@itsm365_weather_bot (я пользовался
бесплатными аккаунтами погоды, поэтому после 500 запросов в день бот превратится
в тыкву).
Заключение
API.AI уже вполне можно пользоваться для построения диалоговых интерфейсов в
мессенджерах, чатах поддержки с соцсетях. С учетом того, что инструмент можно
легко интегрировать со своими сервисами — это удобная рабочая лошадка для
автоматизации коммуникации с вашими пользователями.
P.S. Этой мой первый пост, буду признателен за конструктивную обратную связь!
Автор: qtask