Чатботы плотно вошли в нашу информационную жизнь, во всех уважающих себя соцсетях и мессенджерах есть поддержка ботов, для их разработки и использования онные предоставляют удобное API, всё для удобства пользователей и программистов. Теперь, чтобы создать бота в Телеграме даже не обязательно знать какой-либо язык программирования. Существуют сервисы, который позволяют сконструировать бота с помощью веб-интерфейса. И это действительно хорошо, но совсем недавно я столкнулся с проблемой и был удивлён, что на всей этой волне популярности чатботов, которые к тому же теперь являются не просто крутой фичёй, но и приносящим доход инструментом — ответа практически нет.
А вопрос такой: что если я хочу для одного сервиса создать более чем одного бота? Например, я знаю, что ЦА сидит в Вконтакте и Телеграме, как мне с приложением минимальных усилий написать ботов, работающих с людьми и там, и там? Если вдруг я (например, как владелец интернет-магазина) захочу также с помощью ботов работать с аудиторией уже на Facebook, неужели действительно надо будет разрабатывать нового бота с нуля и переписывать всю логику под него или пытаться вникнуть в новое API или библиотеку. А ответ я постарался найти под катом, прошу к столу.
На самом деле, решения есть, и их много, но все они сводятся к тому, что вы должны хостить своего бота у сервиса, который также предоставляет и платформу. То есть как-такового коробочного решения не получить. Возможно, я не прав и не до конца изучил, что на самом деле есть, но сам факт того, что первая ссылка в гугле не приводит к решению — уже настораживает. Есть ещё Botman. Это действительно мощная полноценная развивающаяся opensource-ная библиотека с кучей фишек и исчерпывающей документацией. И она написана на PHP. Я не имею ничего против PHP, во всяком случае не признаю этого публично, чтобы не разводить ненужный холивар, но вести разработку на нём совсем не хочется. Решил поискать что-то похожее на Python, к тому же для Python-а существует уйма библиотек, позволяющие работать с Telegram Bot API. И я не нашёл ничего, поэтому вскоре пришёл к выводу, что стоит писать самому. (Может быть, кто-нибудь знает подходящие решения для мультиплатформенных ботов с открытой системой, буду рад любой информации)
Тут, кстати назревает другая проблема. Я абсолютно не представляю, где ещё можно поделиться работой с аудиторией в виде статьи кроме как на Хабре. Буду очень рад помощи и в этом вопросе
Название Botovod пришло само собой.
В общем, приведу небольшой код и с использованием Botovod-а и объясню его вкратце.
Заголовок спойлера
from botovod import Botovod, Message, utils
@utils.convert_to_text
def handler_message(agent, chat, text):
message = Message()
message.text = "Я получил сообщение"
agent.send_message(chat, message)
@utils.convert_to_images
def handler_images(agent, chat, images):
message = Message()
message.text = "Я вижу фото"
agent.send_message(chat, message)
def handler_echo(agent, chat, message):
agent.send_message(chat, message)
settings = [
{
"name": "telegram",
"agent": "botovod.agents.telegram",
"settings": {"token": "462755273:AzBZBQ7AAnqFEXqZ_P8Z-qvCddmjqTVAYPI", "method": "polling"}
},
]
botovod = Botovod(settings)
botovod.add_handler(handler_message)
botovod.add_handler(handler_images)
botovod.add_handler(handler_echo)
botovod.start()
Здесь мы определяем 3 обработчика для входящих сообщений, каждый в ответ что-то отправляет. Первый: «Я получил сообщение», второй: «Я вижу фото», третий просто будет отсылать обратно то, что получил. Потом создаём менеджер ботов (Botovod) и передаём ему настройки для ботов, в данном для бота в Телеграме. Дальше последовательно добавляем обработчики сообщений. Если к боту придёт сообщение, то оно попадёт к первому обработчику, который согласится его принять. Например, если нам прислали аудио, то сначала его попытается принять первый обработчик, но откажется, так как это не текст. Потом примет второй, но также откажется, так как это не картинка, потом примет третий, у которого нет ограничений — таким образом перешлёт аудио орбратно. Ограничения накладываются как декораторы из модуль utils.
Теперь постараюсь в подробностях рассказать, что есть что:
Есть менеджер ботов — объект класса Botovod — ему в конструкторе передаются имя бота (у каждого своё уникальное), класс агента, который будет его обрабатывать и настройки для бота. Также в менеджер ботов добавляются по очереди обработчики. Если к боту придёт сообщение, то менеджер проверит их по очереди, пока не найдёт тот обработчик, который не выбросит исключение NotPassed. Первый добавленный обработчик проверяется первым, последний, соответственно, последним. Если вы собираетесь использовать вебхуки, то менеджер ботов можно подключить к веб-серверу. Для этого у менеджера ботов есть метод listen, который принимает имя бота, заголовки и тело запроса. Далее он передаёт эти данные парсеру агента, который возвращает сформированное сообщение, после это сообщение проталкивается по обработчикам. В ответ метод listen возвращает словарь {«status»: any_code, «headers»: dict(), «body»: «any_text»}, где в headers — заголовки ответа, а в body — тело ответа. Иногда мессенджер/соцсеть требует, чтобы сервер возвращал объект, поэтому я думаю, что такое поведение удобно.
Приведу пример для бота Вконтакте под именем «vk-bot», и Botovod будет подключаться к серверу Django
def view(request):
response = manager.listen("vk-bot", request.headers, request.text)
return HttpResponse(status = response["status"], headers = response["headers"], response["body"])
Сформированное сообщение — это объект класса Message. В него входят поля: text — текст сообщения; images — список с изображениями; audios — список со звуковыми файлами; videos — список с видео; documents — список с документами; locations — список с местами на карте; raw — необработанное тело сообщения или дополнительная информация к нему(словарь).
Также каждый список объекта Message (images, audios, videos, documents) содержит в себе специальные объекты, классы которых унаследованы от Attachment. Класс Attachment по умолчанию имеет в себе метод url и file_path, в которые парсеры агентов обычно и кладут информацию о полученном файле. Список locations содержит в себе объекты Location, в конструктор которому надо передать longitude и latitude (долгота и широта).
Ниже пример конструирования сообщений в обработчиках
def handler(agent, chat, message):
out = botovod.Message()
image = botovod.Image()
image.file_path = "/tmp/1.png"
location = botovod.Location()
out.images.append(image)
out.text = "Вот фото, что ты просил"
agent.send_message(chat, out)
Это пока всё, что в нём есть, но надеюсь, что кому-нибудь такое решение будет интересно и кто-нибудь захочет помочь советом, комментарием, идеей, а может и собственным участием в разработке. Всем спасибо за прочтение!
Ссылка на github