Как сделать бота в Яндекс Мессенджере
Как работает бот в Яндекс Мессенджере
Создание ботов в Яндекс Мессенджере доступно организациям в Яндекс 360 для бизнеса на большинстве тарифов. Для написания ботов используются методы Bot API. Документация по ним есть в Справке. Готовых официальных библиотек на каких-либо языках программирования сейчас нет, поэтому можно использовать любой удобный язык, который позволяет отправлять HTTP-запросы.
С помощью Bot API можно:
создавать каналы, групповые чаты и добавлять туда участников;
отправлять сообщения лично пользователям, в групповые чаты или каналы;
проводить опросы и обрабатывать их результаты;
отправлять изображения и файлы.
Для взаимодействия с ботом используют кнопки с командами или сообщения в чатах.
Создание бота и токена
Давайте сделаем простого бота, который будет получать сообщение от пользователя и отвечать ему обратно тем же текстом лично или в групповой чат.
Для начала админ организации Яндекс 360 для бизнеса должен создать бота, чтобы получить для него токен аутентификации. Токен даёт возможность аутентифицироваться в сервисе Яндекс Мессенджера, получать и отправлять сообщения.
Нужно в интерфейсе администрирования перейти в раздел ботов и нажать «+Добавить». В новом окне задайте имя. Аватарку для бота можно загрузить сразу при создании или позже. Подробнее процедура описана в документации.
После нажатия на кнопку «Создать» появится сообщение, что создан токен бота. Он автоматом копируется в буфер обмена — сохраните его. Токен бота не отображается ни в каких настройках: в случае потери его придётся перевыпустить.
Теперь все обращения к Bot API Яндекс Мессенджера должны выполняться с этим токеном в HTTP-заголовке Authorization. Заголовок должен выглядеть так:
Authorization: OAuth ТУТ_ТОКЕН
Отправка сообщений
Создали бота и теперь пробуем отправить сообщение от него какому-нибудь пользователю. Для этого можно воспользоваться любой программой для отправки запросов. Самый простой вариант — Curl.
Полное описание отправки сообщений ищите в Справке.
Все действия бота осуществляются через отправку HTTP-запросов в формате JSON. Чтобы написать от имени бота, нам надо отправить в теле запроса небольшой JSON, содержащий имейл пользователя и текст:
{
"login": "user@organization.ru",
"text": "Привет!"
}
Отправим запрос:
curl -X POST -H "Authorization: OAuth y0_AgAAAAB***********"
-H "Content-Type: application/json" -d '{"login": " user@organization.ru ", "text": "Привет!"}' https://botapi.messenger.yandex.net/bot/v1/messages/sendText/
Если всё ок, то от сервиса получаем ответ, что сообщение отправлено успешно, и ID сообщения:
{
"message_id": 1720683276110016,
"ok": true
}
А в Яндекс Мессенджер от бота приходит сообщение:
Чтобы отправить сообщение в групповой чат или канал, вместо login
надо указать chat_id
. Но как его найти?
Бот может получить ID группового чата, когда кто-то пишет в группу, в которую он добавлен. Но об этом чуть позже. Пока для теста можно открыть Мессенджер в браузере, перейти в группу и скопировать ID чата из строки поиска:
В нашем случае ID чата вот такой 0%2F0%2Ffa15f152-****-************
. Надо только заменить URL-encoded %2F на / — и получаем такой JSON-запрос, который надо отправить в Bot API:
{
"chat_id": "0/0/fa15f152-****-************",
"text": "Привет!"
}
Отправляем запрос:
curl -X POST -H "Authorization: OAuth y0_AgAAAAB***********" -H "Content-Type: application/json" -d '{"chat_id": "0/0/fa15f152-****-************", "text": "Привет!"}' https://botapi.messenger.yandex.net/bot/v1/messages/sendText/
И получаем такой ответ:
{
"code": "permission_denied",
"description": "Bot is not a member of the chat",
"ok": false
}
Сообщение говорит нам о том, что бот не добавлен в групповой чат. Он не сможет написать, так как не является участником или администратором этого группового чата.
Добавляем нашего бота в групповой чат по имени, которым администратор его «наградил» при создании
Отправляем повторно запрос. Получаем ответ:
{
"message_id": 1720686773125045,
"ok": true
}
Бот также может начинать обсуждения (треды) и отвечать в существующих. Чтобы ответить в существующем треде, надо указать в запросе thread_id
, в который надо отправить сообщение:
Пример запроса:
{
"chat_id": "0/0/fa15f152-****-****",
"text": "Привет!",
"thread_id": "1722936165619034"
}
Отправляем запрос:
curl -X POST -H "Authorization: OAuth y0_AgAAAAB******" -H "Content-Type: application/json" -d '{"chat_id": "0/0/fa15f152-****-****", "text": "Отвечаю в обсуждение (а не тред)!","thread_id": "1722936165619034"}' https://botapi.messenger.yandex.net/bot/v1/messages/sendText/
И видим наше сообщение в треде
ID треда можно получить из сообщений, отправленных пользователем. А что делать, если надо, чтобы бот сам начал новое обсуждение? Здесь всё просто: в качестве thread_id
надо отправить ID сообщения
, для которого мы хотим начать обсуждение.
Взаимодействие с ботом через кнопки
Бот Яндекс Мессенджера может отправлять кнопки — так пользователю проще работать с ним. Чтобы их сделать, при отправке сообщения надо добавить в тело запроса ключ inline_keyboard. Он будет включать массив объектов наших кнопок, в том числе:
text
— то, что будет написано на кнопке;callback_data
— то, что будет отправлено в сообщении, когда пользователь нажмёт на кнопку.
callback_data
может содержать любой JSON-объект, который, помимо текста, будет отправлен пользователем в чат или боту при нажатии на кнопку. Эти данные можно в дальнейшем использовать в работе бота.
JSON-запрос, который покажет пользователю кнопки, может выглядеть так:
{
"login": "user@organization.ru",
"text": "Вам нравится Яндекс Мессенджер?",
"inline_keyboard": [
{
"text": "Да",
"callback_data": {
"data": "ButtonYes",
"request_id": 543252345
}
},
{
"text": "Очень нравится!",
"callback_data": {
"data": "ButtonVery",
"request_id": 543252345
}
}
]
}
Отправим запрос:
curl -X POST -H "Authorization: OAuth y0_AgAAAAB***********-*****" -H "Content-Type: application/json" -d '{"login":"user@organization.ru", "text": "Вам нравится Яндекс Мессенджер?", "inline_keyboard": [{"text": "Да", "callback_data": {"data": "ButtonYes", "request_id": 543252345 }},{"text": "Очень нравится!", "callback_data": {"data": "ButtonVery", "request_id": 543252345}}]}' https://botapi.messenger.yandex.net/bot/v1/messages/sendText/
Обработка сообщений ботом
Теперь разберёмся, как бот получает сообщения от пользователей или чатов. Эти сообщения я дальше буду называть обновлениями, т. к. любое из них приходит боту в виде JSON-объекта Update.
Есть два метода получения обновлений в чатах: платформа Мессенджера может «дёргать» бота через Webhook, либо бот может сам запрашивать новые сообщения (polling).
Способ 1: через Webhook
Сервис Яндекс Мессенджера сам обращается на адрес, указанный в настройках бота, и отправляет новые сообщения в виде POST-запроса.
Если у нас по адресу, указанному в Вебхук, есть HTTP-сервис, который готов принять запрос, то при отправке «Привет» в групповой чат мы сможем получить данные в формате JSON:
{
"updates": [
{
"chat": {
"id": "0/0/fa15f152-****-************",
"type": "group"
},
"from": {
"display_name": "Anton Bugrin",
"id": "22ef5004-fff1-****-****-************",
"login": "user@organization.ru",
"robot": false
},
"message_id": 1720696221359045,
"text": "Привет",
"timestamp": 1720696221,
"update_id": 1385335372
}
]
}
Из такого запроса мы можем извлечь информацию о пользователе, написавшем сообщение, о чате, куда это сообщение было отправлено, и само сообщение, включая его идентификатор update_id. Также можно определить, групповой это чат или написали напрямую боту:
если поле
type = group
, то сообщение было отправлено в групповой чат;если поле равно
private
, то сообщение было отправлено напрямую боту.
Способ 2: через polling
Теперь рассмотрим, как получать обновления через polling. Подробное описание процесса есть по ссылке: https://yandex.ru/dev/messenger/doc/ru/api-requests/update-polling
Для получения новых сообщений нужно отправить GET- или POST-запрос на https://botapi.messenger.yandex.net/bot/v1/messages/getUpdates/
Возможные параметры запроса — это limit
и offset
. Параметр limit
ограничивает количество получаемых ботом сообщений, параметр offset указывает на ID первого запрашиваемого обновления.
В начале работы бота обычно отправляем запрос с offset
, равным 0: такой запрос вернёт в ответе массив самых первых из доступных боту обновлений. Количество таких сообщений будет равно значению limit
. Чтобы запросить следующие обновления после обработки ответа, необходимо задать offset, равный максимальному значению update_id + 1
, из массива обновлений, полученных на предыдущем шаге.
Запрос getUpdates
стирает все предыдущие обновления со значением update_id
меньше, чем offset
, делая их недоступными для получения этим ботом.
Бот получает все сообщения из чатов, где он участник или администратор. Если бот покидает чат, он может получить обновления, которые были сделаны до его выхода.
Ниже будет пример, в котором как раз рассмотрим, как получить сообщения этим методом.
Пример бота
Рассмотрим простой пример бота на Python, который получает новые сообщения и отвечает тем же текстом обратно.
Дисклеймер: я не разработчик на Python и не претендую на безупречность кода. Пример нужен, чтобы показать, как можно использовать API бот-платформы Мессенджера.
from time import sleep
from requests import post
UPDATES_URL = "https://botapi.messenger.yandex.net/bot/v1/messages/getUpdates" # URL для получения обновлений
SEND_TEXT_URL = "https://botapi.messenger.yandex.net/bot/v1/messages/sendText/" # URL для отправки текста
# В заголовке указываем токен бота
HEADERS = {
"Authorization": "OAuth y0_AgAAA*******",
"ContentType": "application/json"
}
# Функция, которая периодически запрашивает наличие новых сообщений для бота. В качестве аргумента передаём функцию
# которая будет вызвана при получении новых сообщений
def start_pooling(bot_fn):
# Первичный запрос для получения ID последнего сообщения. Чтобы не обрабатывать все сообщения чата, пока бот
# выключен. В реальном использовании возможно предусмотреть другое поведение и обрабатывать все сообщения
last_update_id = -1
request_body = {'limit': 100, 'offset': 0}
response = post(UPDATES_URL, json=request_body, headers=HEADERS)
updates = response.json()['updates']
if len(updates) > 0:
updates = response.json()['updates']
last_update_id = int(updates[len(updates) - 1]['update_id']) # Получаем ID последнего сообщения
# Запускаем цикл постоянных запросов на новые сообщения
while True:
# Запрашиваем только новые сообщения. Будут получены сообщения только с ID на 1 больше последнего полученного
# сообщения
request_body = {'limit': 100, 'offset': last_update_id + 1}
response = post(UPDATES_URL, json=request_body, headers=HEADERS)
updates = response.json()['updates'] # из ответа получаем массив новых сообщений
if len(updates) > 0:
# Для последующих запросов цикла сохраняем ID последнего сообщения
last_update_id = int(updates[len(updates) - 1]['update_id'])
# Для каждого сообщения вызываем функцию, которая будет обрабатывать это сообщение
for update in updates:
bot_fn(update)
sleep(1) # Ждём 1 секунду, прежде чем повторить цикл
# Функция бота, которая вызывается каждый раз при получении новых обновлений
def bot(update):
send_text(update) # В нашем примере мы отправляем текст при новых обновлениях
# Функция, которая будет отправлять сообщения от имени бота
def send_text(update):
request_body = {'text': update['text']} # тело запроса для отправки сообщения добавляем исходный текст сообщения
if update['chat']['type'] == 'group': # Если исходное сообщение отправлено в групповой чат, то отвечаем в него
request_body.update({'chat_id': update['chat']['id']})
elif update['chat']['type'] == 'private': # Если сообщение отправлено персонально боту, то отвечаем лично
request_body.update({'login': update['from']['login']})
post(SEND_TEXT_URL, json=request_body, headers=HEADERS) # отправляем сообщение
# Стартуем бота
if __name__ == '__main__':
start_pooling(bot)
Запустим скрипт и отправим сообщение персонально боту и получим в ответ тот же текст:
{
"ok": true,
"updates": [
{
"chat": {
"type": "private"
},
"from": {
"display_name": "Anton Bugrin",
"id": "22ef5004-fff1-****-****-************",
"login": "user@organization.ru",
"robot": false
},
"message_id": 1723104930258026,
"text": "И снова привет",
"timestamp": 1723104930,
"update_id": 705447835
}
]
}
Если отправить сообщение в группу, то бот тоже ответит в групповой чат
Что в итоге
Итак, мы с вами разобрали базовые возможности работы с Яндекс Мессенджером и сделали простейшего бота, который отвечает на сообщения.
Если у вас есть задачи, которые требуют автоматизации взаимодействия с пользователями в чатах, если вам нужно обрабатывать информацию от пользователей или из других систем, теперь вы знаете, с чего начать.
В будущем планирую рассказать, как обрабатывать нажатия кнопок пользователями и работу с файлами и изображениями. А если у вас возникнут вопросы по ботам, я с радостью отвечу в комментариях.