[Из песочницы] Telegram чат-бот на Python в 30 строчек кода с ИИ

Habrahabr 2

image

Сегодня мне в голову пришла мысль: «А почему бы не написать Telegram чат-бота с ИИ, которого потом можно будет обучать?»

Сейчас сделать это совсем легко, поэтому, недолго думая, я принялся к написанию кода. Языком я выбрал Python, т.к. на нём легче всего работать с подобного рода приложениями.

Итак, для создания Telegram чат-бота с ИИ нам потребуется:

1. API Telegram. В качестве обёртки я взял проверенную библиотеку python-telegram-bot

2. API ИИ. Выбрал я продукт от Google, а именно Dialogflow. Он предоставляет довольно-таки неплохое бесплатное API. Обёртка Dialogflow для Python

Шаг 1. Создаём бота в Telegram

Придумываем имя нашему боту и пишем @botfather. После создания бота нам придёт API токен, который желательно бы где-то сохранить, т.к. в дальнейшем он нам понадобится.

image

Шаг 2. Пишем основу бота

Создаём папку Bot, в которой потом создаём файл bot.py. Здесь будет код нашего бота. Открываем консоль и переходим в директорию с файлом, устанавливаем python-telegram-bot.
pip install python-telegram-bot --upgrade
После установки мы уже можем написать «основу», которая пока что будет просто отвечать однотипными сообщениями. Импортируем необходимые модули и прописываем наш токен API:
Код настроек и импорта
# Настройки
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
updater = Updater(token='ВАШ API КЛЮЧ') # Токен API к Telegram
dispatcher = updater.dispatcher

Далее напишем 2 обработчика команд. Это callback-функции, которые будут вызываться тогда, когда будет получено обновление. Напишем две таких функции для команды /start и для обычного любого текстового сообщения. В качестве аргументов туда передаются два параметра: bot и update. Bot содержит необходимые методы для взаимодействия с API, а update содержит данные о пришедшем сообщении.
Код callback'ов
# Обработка команд
def startCommand(bot, update):
    bot.send_message(chat_id=update.message.chat_id, text='Привет, давай пообщаемся?')
def textMessage(bot, update):
    response = 'Получил Ваше сообщение: ' + update.message.text
    bot.send_message(chat_id=update.message.chat_id, text=response)

Теперь осталось лишь присвоить уведомлениям эти обработчики и начать поиск обновлений. Делается это очень просто:
Код хендлеров
# Хендлеры
start_command_handler = CommandHandler('start', startCommand)
text_message_handler = MessageHandler(Filters.text, textMessage)
# Добавляем хендлеры в диспетчер
dispatcher.add_handler(start_command_handler)
dispatcher.add_handler(text_message_handler)
# Начинаем поиск обновлений
updater.start_polling(clean=True)
# Останавливаем бота, если были нажаты Ctrl + C
updater.idle()
Итого, полная основа скрипта выглядит вот так:
Код полной основы бота
# Настройки
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
updater = Updater(token='ВАШ API ТОКЕН') # Токен API к Telegram
dispatcher = updater.dispatcher
# Обработка команд
def startCommand(bot, update):
    bot.send_message(chat_id=update.message.chat_id, text='Привет, давай пообщаемся?')
def textMessage(bot, update):
    response = 'Получил Ваше сообщение: ' + update.message.text
    bot.send_message(chat_id=update.message.chat_id, text=response)
# Хендлеры
start_command_handler = CommandHandler('start', startCommand)
text_message_handler = MessageHandler(Filters.text, textMessage)
# Добавляем хендлеры в диспетчер
dispatcher.add_handler(start_command_handler)
dispatcher.add_handler(text_message_handler)
# Начинаем поиск обновлений
updater.start_polling(clean=True)
# Останавливаем бота, если были нажаты Ctrl + C
updater.idle()
Теперь мы можем проверить работоспособность нашего нового бота. Вставляем на 2 строке наш API токен, сохраняем изменения, переносимся в консоль и запускаем бота:
python bot.py
После запуска пишем ему. Если всё настроено правильно, то Вы увидите вот это:

image

Основа бота написана, приступаем к следующему шагу! P.s. не забывайте выключить бота, для этого вернитесь в консоль и нажмите Ctrl + C, подождите пару секунд и бот успешно завершит работу.

Шаг 3. Настройка ИИ

В первую очередь, идём и регистрируемся на Dialogflow (просто входим с помощью своего Google аккаунта). Сразу после авторизации мы попадаем в панель управления.

image

Жмём на кнопку Create agent и заполняем поля по усмотрению (это никакой роли не сыграет, это нужно лишь для следующего действия).

image

Жмём на Create и видим следующую картину:

image

Расскажу, почему созданный нами ранее «Агент» никакой роли не играет. Во вкладке Intents есть «команды», по которым работает бот. Сейчас он умеет лишь отвечать на фразы типа «Привет», и если не понимает, то отвечает «Я вас не понял». Не сильно впечатляет. После создания нашего пустого агента, у нас появилась куча других вкладок. Нам нужно нажать на Prebuilt Agents (это уже специально обученные агенты, которые имеют множество команд) и из всего представленного списка выбрать Small Talk.

image

Наводим на него и жмём Import. Далее ничего не меняя, жмём Ok. Агент импортировался и теперь мы можем его настроить. Для этого в левом верхнем углу жмём на шестерёнку возле Small-Talk и попадаем на страницу настроек. Теперь мы можем изменить имя агента, как захотим (я оставляю как было). Меняем часовой пояс и во вкладке Languages проверяем, чтобы был установлен русский язык (если не установлен, то ставим).

image

image

Возвращаемся на вкладку General, спускаемся немного вниз и копируем Client access token

image

Теперь наш ИИ полностью настроен, можно возвращаться к боту.

Шаг 4. Собираем всё вместе

ИИ готов, основа бота готова, что дальше? Дальше нам нужно скачать обёртку API от Dialogflow для питона.
pip install apiai
Установили? Возвращаемся к нашему боту. Добавляем в нашу секцию «Настройки» импорт модулей apiai и json (нужно, чтобы в будущем разбирать json ответы от dialogflow). Теперь это выглядит вот так:
Код обновлённых настроек
# Настройки
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
import apiai, json
updater = Updater(token='ВАШ API КЛЮЧ') # Токен API к Telegram
dispatcher = updater.dispatcher
Переходим к функции textMessage (которая отвечает за получение любого текстового сообщения) и посылаем полученные сообщения на сервера Dialogflow:
Код отправления сообщений на Dialogflow
def textMessage(bot, update):
    request = apiai.ApiAI('ВАШ API ТОКЕН').text_request() # Токен API к Dialogflow
    request.lang = 'ru' # На каком языке будет послан запрос
    request.session_id = 'BatlabAIBot' # ID Сессии диалога (нужно, чтобы потом учить бота)
    request.query = update.message.text # Посылаем запрос к ИИ с сообщением от юзера
Этот код будет посылать запрос к Dialogflow, но нам нужно также извлечь ответ. Дописываем парочку строк, итого textMessage выглядит вот так:
Полный код функции textMessage
def textMessage(bot, update):
    request = apiai.ApiAI('ВАШ API ТОКЕН').text_request() # Токен API к Dialogflow
    request.lang = 'ru' # На каком языке будет послан запрос
    request.session_id = 'BatlabAIBot' # ID Сессии диалога (нужно, чтобы потом учить бота)
    request.query = update.message.text # Посылаем запрос к ИИ с сообщением от юзера
    responseJson = json.loads(request.getresponse().read().decode('utf-8'))
    response = responseJson['result']['fulfillment']['speech'] # Разбираем JSON и вытаскиваем ответ
    # Если есть ответ от бота - присылаем юзеру, если нет - бот его не понял
    if response:
        bot.send_message(chat_id=update.message.chat_id, text=response)
    else:
        bot.send_message(chat_id=update.message.chat_id, text='Я Вас не совсем понял!')
Немного пояснений. С помощью
request.getresponse().read()
получается ответ от сервера, закодированный в байтах. Чтобы декодировать его, просто применяем метод
decode('utf-8')
и после этого «заворачиваем» всё в
json.loads()
чтобы распарсить json ответ.

Если ответа нет (точнее, json приходит всегда, но не всегда есть сам массив с ответом ИИ), то это означает, что Small-Talk не понял пользователя (обучением можно будет заняться позже). Поэтому если «ответа» нет, то пишем пользователю «Я Вас не совсем понял!». Итого, полный код бота с ИИ будет выглядеть вот так:

Полный код бота с ИИ
# Настройки
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
import apiai, json
updater = Updater(token='ВАШ API ТОКЕН') # Токен API к Telegram
dispatcher = updater.dispatcher
# Обработка команд
def startCommand(bot, update):
    bot.send_message(chat_id=update.message.chat_id, text='Привет, давай пообщаемся?')
def textMessage(bot, update):
    request = apiai.ApiAI('ВАШ API ТОКЕН').text_request() # Токен API к Dialogflow
    request.lang = 'ru' # На каком языке будет послан запрос
    request.session_id = 'BatlabAIBot' # ID Сессии диалога (нужно, чтобы потом учить бота)
    request.query = update.message.text # Посылаем запрос к ИИ с сообщением от юзера
    responseJson = json.loads(request.getresponse().read().decode('utf-8'))
    response = responseJson['result']['fulfillment']['speech'] # Разбираем JSON и вытаскиваем ответ
    # Если есть ответ от бота - присылаем юзеру, если нет - бот его не понял
    if response:
        bot.send_message(chat_id=update.message.chat_id, text=response)
    else:
        bot.send_message(chat_id=update.message.chat_id, text='Я Вас не совсем понял!')
# Хендлеры
start_command_handler = CommandHandler('start', startCommand)
text_message_handler = MessageHandler(Filters.text, textMessage)
# Добавляем хендлеры в диспетчер
dispatcher.add_handler(start_command_handler)
dispatcher.add_handler(text_message_handler)
# Начинаем поиск обновлений
updater.start_polling(clean=True)
# Останавливаем бота, если были нажаты Ctrl + C
updater.idle()
Сохраняем изменения, запускаем бота и идём проверять:

image

Вот и всё! Бот в 30 строк с ИИ написан!

Шаг 5. Заключительная часть

Думаю, Вы убедились, что написать бота с ИИ – дело 10 минут. Осталось лишь теперь его учить и учить. Делать это, кстати, можно во вкладке Training. Там можно посмотреть все сообщения, которые писались и что на них ответил бот (или не ответил). Там же его можно и обучать, говоря боту где он ответил правильно, а где нет.

image

Надеюсь, статья была Вам полезна, удачи в обучении!