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

Metabot 101: Создание простого бота с использованием REST API

Уважаемые разработчики! В этом уроке вы познакомитесь с основами разработки приложений с помощью платформы Metabot. Вместе мы создадим простой бот, который будет присылать в мессенджер по запросу изображение с сайта Pexels.com.

Обращаясь к сторонним веб-сервисам с помощью REST API, мы создадим простой диалоговый сценарий, запрашивающий ключевое слово, по которому вы хотели бы найти изображение. Затем бот обращается к сервису API и возвращает найденное изображение. Далее мы добавим кнопку "Прислать следующее изображение". Таким образом, через бота вы сможете посмотреть поочерёдно все изображения, найденные на сервисе.

В ходе урока вы узнаете:

1. Как разрабатывается REST API интеграция с помощью вызова точек интеграции, называемых "endpoints".
2. Как использовать JavaScript для обращения к сторонним ресурсам.
3. Как работать с данными, которые хранятся в лиде (lead) и во временной памяти (memory).
4. Как работать с режимом отладки кода, который позволит вам получать уведомления об ошибках выполнения вашего кода.

Приятного обучения!

Создание первого скрипта бота

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

image.png

Первым делом требуется создать скрипт-приветствие и добавить в него сообщение с приветствием и меню.

Как это сделать вы можете узнать из урока "Hello Humans: ваше руководство по быстрому старту"

Для нашего бота в начальном скрипте понадобится только команда отправки текста. Примерное содержимое команды может быть таким: "Приветствую! Это бот для просмотра фотографий на сервисе Pexels.com".

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

Подключение каналов

В данном боте будет создано два канала: Telegram и Metabot Widget

1. Создадим канал Telegram.

Как это сделать вы можете узнать из инструкции "Интеграция канала Telegram с платформой Metabot"

2. Создадим канал Metabot Widget.

Как это сделать вы можете узнать из инструкции "Metabot Widget"

Подключение маршрутов

Создадим маршрут, который будет ссылаться на стартовый скрипт.

Как это сделать вы можете узнать из инструкции "Маршруты"

Запускаем первую версию бота

1. Находим бот в Telegram и запускаем /start.

image.png

2. В справочнике каналов открываем канал «Metabot Widget» и в справочнике каналов последовательно нажимаем на кнопки «Загрузить|Предварительный просмотр».

image.png

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

Включение режима отладки

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

1. Для включения отладки следует зайти в меню "Лиды" и нажать на кнопку переключения отладчика.

image.png

2. Затем нужно выбрать уровень отладки. В данном случае выбирайте уровень "editor".

image.png

Если режим отладки включен, в мессенджер или виджет (в зависимости от канала, с которым связан лид), то в случае ошибок в JS-коде, будут выдаваться сообщения об ошибках. Если лид, под которым выполнялась отладка используется на продуктовом сервере, после завершения разработки отладчик следует отключить.

image.png

Расширяем скрипт с приветствием и меню

1. Добавляем пункты меню "Выбрать тему" и "Следующее фото" в стартовый скрипт.

Как это сделать вы можете узнать из инструкции "Создание меню"

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

2. Следующим шагом отредактируем свойства автоматически созданных скриптов, а точнее их имя и JS-код. Это делается при помощи кнопки редактирования в меню скриптов.

image.png

  • Название - это имя скрипта, которое может содержать в себе любые символы. Скриптам связанные с интеграциями, которые содержат большой объем JavaScript команд, рекомендуется присваивать англоязычные имена, так как это область работы JS программистов.
  • Код - это дополнительный уникальный идентификатор. Используется для поиска скрипта, например, в JavaScript функциях, а также для поиска и запуска скрипта через NLP. Он всегда обозначается одним словом без пробелов.

image.png

Для скрипта выбора темы вводим в поля название и код значение select_theme_photo, а в скрипт переключения на следующее фото значение show_next_photo.

В итоге получаем следующие скрипты после изменения свойств:

image.png

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

Теперь мы готовы выполнить интеграцию с сервисом Pixels.com.

Подключаемся к API Pixels.com

Для начала получим токен к API Pixels.com.

1. Переходим к документации API Pixels.com по ссылке: https://www.pexels.com/api/documentation/

2. Регистрируемся на платформе. Переходим в раздел "Авторизация" и переходим по ссылке "запросить ключ API".

image.png

3. Затем заполняем информацию о том для чего будет использован ключ и как результат получаем API Key:

image.png

4. В «Настройки бота» меню «Атрибуты» создаем системный атрибут sysApiHeaders и присваиваем ему значение:

{"Accept":"application/json",  "Authorization": "Bearer <ваш скопированный токен>"}

Внимание! Между Bearer и токеном должен быть ровно один пробел!

Подробнее про атрибуты вы можете узнать из инструкции Атрибуты

image.png

Иcследуем endpoints API Pixels.com

1. На главной странице документации в правом верхнем углу находим базовый URL для работы с фото.

image.png

2. Аналогично предыдущему пункту, в «Настройки бота» меню «Атрибуты» заносим системный атрибут sysApiHttpClientConfig  и присваиваем значение: {"base_uri":"https://api.pexels.com/v1/"}

В итоге имеем в нашем боте следующие атрибуты:

image.png

Подробнее про работу с API на платформе Metabot вы можете узнать из инструкции Конструктор API

Заполняем скрипт select_theme_photo

Данный скрипт запрашивает тему фото, выполняет REST запрос к сервису и выводит первую выбранную фотографию.

1. Для реализации данного функционала создадим команду "Запросить значение". Зададим команде параметр "Имя переменной" = photoTheme. Именно в этом атрибуте будет храниться результат запроса.

Подробнее о команде "Запросить значение" вы можете узнать из соответствующей инструкции.

2. Следующей командой будет "Выполнить JavaScript". Она будет содержать JS код для доступа к API.

// раздел 1: подготовка параметров REST запроса

var photoTheme = lead.getAttr('photoTheme');
var url = "search?query=" + photoTheme + '&per_page=1';
var jsonBody = {};
var headers = {};

//--------------------------------------------------------

// раздел 2: подготовка вспомогательной переменной и начальная установка атрибутов лида

var total_results = 0;
lead.setAttr('url', url);
memory.setAttr('rsps.nextPage', '');
lead.setAttr('rsps.totalResults', 0);
memory.setAttr('rsps.photographer', '');
memory.setAttr('rsps.original', '');
memory.setAttr('rsps.medium', '');
lead.setAttr('photoThemeIndex', 1);

//--------------------------------------------------------

В разделе 1 выбирается из атрибутов лида введенная ранее пользователем тема photoTheme и подготавливаются параметры REST запроса.

В разделе 2 присваиваем начальные значения атрибутов:

  • url - REST запрос.
  • total_results – всего фото по заданной теме
  • photo_theme_found - признак, что запрос вернул фото
  • next_page - следующая страница
  • photographer – фотограф
  • original - cсылка на оригинальное фото
  • medium – ссылка на уменьшенную копию medium
  • photo_theme_index - текущиее фото в теме

При этом одни переменные сохраняются в атрибутах лида (в lead), а другие во временном хранилище в памяти (в memory). 

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

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

Используются некоторые параметры из JSON объекта, который возвращает REST запрос.

Ниже подробно расписаны все атрибуты запроса:

Атрибут Тип Описание
query

string | required

Поисковой запрос. Например: Океан, Тигры, Груши и т.д.
orientation

string | optional

Желаемая ориентация фотографии. Текущие поддерживаемые ориентации: landscape, portrait or square.
size

string | optional

Минимальный размер фото. В настоящее время поддерживаются следующие размеры: large(24MP), medium(12MP) or small(4MP).
color

string | optional

Желаемый цвет фото. Поддерживаемые цвета: red, orange, yellow, green, turquoise, blue, violet, pink, brown, black, gray, white или любой шестнадцатеричный код цвета (например, #ffffff).
locale

string | optional

Регион поиска, из которого вы делаете запрос. Текущие поддерживаемые регионы: 'en-US' 'pt-BR' 'es-ES' 'ca-ES' 'de-DE' 'it-IT' 'fr-FR' 'sv-SE' 'id-ID' 'pl-PL' 'ja-JP' 'zh-TW' 'zh-CN' 'ko-KR' 'th-TH' 'nl-NL' 'hu-HU' 'vi-VN' 'cs-CZ' 'da-DK' 'fi-FI' 'uk-UA' 'el-GR' 'ro-RO' 'nb-NO' 'sk-SK' 'tr-TR' 'ru-RU'.
page

integer | optional

Номер страницы, которую вы запрашиваете. По умолчанию: 1.
per_page
integer | optional Количество результатов, которые вы запрашиваете на странице. По умолчанию: 15 Макс.: 80.

Все атрибуты ответа:

Атрибут Тип Описание
photos

array of Photo

Массив объектов Photo.
page

integer

Номер текущей страницы.
per_page

integer

Количество фото на текущей странице.
total_results

integer

Общее количество результатов по запросу.
prev_page
string | optional URL-адрес предыдущей страницы, если она есть.
next_page
string | optional URL-адрес следующей страницы, если она есть.

3. Продолжаем разрабатывать скрипт в той же команде.

// раздел 3: выполнение REST запроса

memory.setAttr('photoThemeFound', 0);
jsonResponse = api.getJson(url, jsonBody, headers);
if (jsonResponse) {

//------------------------------------------------
  
// раздел 4: сохранение результата запроса в атрибутах лида
  
  var rsps = jsonResponse;
  totalResults = rsps['total_results'] * 1;
  if (total_results > 0) {
    memory.setAttr('photoThemeFound', 1);
    lead.setAttr('rsps.totalResults', totalResults);
    memory.setAttr('rsps.photographer', rsps['photos'][0]['photographer']);
    memory.setAttr('rsps.original', rsps['photos'][0]['src'][ 'original' ]);
    memory.setAttr('rsps.medium', rsps['photos'][0]['src'][ 'medium' ]);
    memory.setAttr('rsps.nextPage', rsps['next_page']);
  }
  
//------------------------------------------------

// раздел 5
  
  memory.setJsonAttr("lastHttpResponse", api.getLastResponseContent());
  memory.setAttr("lastHttpResponseCode", api.getLastResponseCode());
}

//------------------------------------------------

В разделе 3 выполняется REST запрос к сервису и проверяется что запрос выполнился.

В разделе 4 проверяется что в данной теме имеются фото и переносятся необходимые параметры REST запроса в атрибуты лида.

В разделе 5 для удобства отладки запоминаем в атрибуте лида полный ответ и код ответа сервиса.

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

4. Далее выводим ответ в канал, используя данные, сохраненные в атрибутах лида. Для этого используем две команды вывода текста с условием. Одна срабатывает когда атрибут photoThemeFound равен 1, вторая, наоборот, он не равен 1.

image.png

Так выглядят данные команды после создания:

image.png

Условие выполнения Текст команды
return (lead.getAttr("photoThemeFound") == 1); "{{$photoTheme}}": {{$rsps.totalResults}} / {{$photoThemeIndex}}
Фотограф: {{$rsps.photographer}}
Изображение: {{$rsps.medium}}
Высокое разрешение: {{$rsps.original}}
return !(lead.getAttr("photoThemeFound") == 1); Фото по теме "{{$photoTheme}}" не найдены.

Заполняем скрипт show_next_photo

1. Входим в редактор команд скрипта и набираем скрипт, который аналогично предыдущему состоит из трех частей: 

  • 1 извлечение из лида параметров запроса;
  • 2 выполнение запроса и заполнение атрибутов в memory и lead;
  • 3 сохранение переменных для отладки. 

Команда запроса темы не нужна, так как она определена в скрипте выбора темы и сохранена в атрибуте photoTheme.

// раздел 1: подготовка параметров REST запроса

var photoTheme = lead.getAttr('photoTheme');
var photoThemeIndex = lead.getAttr('photoThemeIndex') * 1;
photoThemeIndex = photoThemeIndex + 1;
var url = "search?query=" + photoTheme + "&page=" + photoThemeIndex + "&per_page=1"
var jsonBody = {};
var headers = {};

//----------------------------------------------------------

// раздел 2

lead.setAttr('url', url);
memory.setAttr('photoThemeFound', 0);
jsonResponse = api.getJson(url, jsonBody, headers);
if (jsonResponse) {
  var rsps = jsonResponse;
  totalResults = rsps['total_results'] * 1;
  if (totalResults > 0 && photoThemeIndex <= totalResults) {
    memory.setAttr('photoThemeFound', 1);
    lead.setAttr('rsps.totalResults', totalResults);
    lead.setAttr('photoTheme', photoTheme);
    lead.setAttr('photoThemeIndex', photoThemeIndex);
    memory.setAttr('rsps.photographer', rsps['photos'][0]['photographer']);
    memory.setAttr('rsps.original', rsps['photos'][0]['src'][ 'original' ]);
    memory.setAttr('rsps.medium', rsps['photos'][0]['src'][ 'medium' ]);
    memory.setAttr('rsps.nextPage', rsps['next_page']);
  }
  
//----------------------------------------------------------
  
// раздел 3
  
  memory.setJsonAttr("lastHttpResponse", api.getLastResponseContent());
  memory.setAttr("lastHttpResponseCode", api.getLastResponseCode());
}

//----------------------------------------------------------

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

image.png

Условие выполнения Текст команды
return (memory.getAttr("photoThemeFound") == 1); "{{$photoTheme}}": {{$rsps.totalResults}} / {{$photoThemeIndex}}
Фотограф: {{$rsps.photographer}}
Изображение: {{$rsps.medium}}
Высокое разрешение: {{$rsps.original}}
return !(memory.getAttr("photoThemeFound") == 1); Фото не найдено.

Запускаем бот!

1. Запускаем в канале Telegram.

image.png

2. Запускаем в канале виджета Metabot.

image.png

Поздравляем с успешным созданием бота! Рекомендуем так же ознакомиться с остальными нашими уроками по созданию ботов.