Telegram bot описание — Урок 7. Встраиваемые боты (Inline)

Урок 7. Встраиваемые боты (Inline)

Важно

: код, приведённый здесь, актуален для первой версии Bot API. Пожалуйста, откройте урок 8, чтобы узнать о важных изменениях.

4 января 2016 года разработчики Telegram выпустили большое дополнение к существующему BotAPI, заключающееся в появлении встраиваемых ботов.К сожалению, не все до конца понимают, в чем их особенность. А вот в чем: если раньше для того, чтобы получить какую-либо информацию от бота и перекинуть её собеседнику нужно было открывать диалог с ботом, писать всякие команды, а потом пересылать ответ в нужный чат, то теперь всё стало быстрее и проще (для некоторых ситуаций): просто открываете нужный чат, вызываете бота, введя его ник в поле ввода сообщения, ставите пробел и пишете свой запрос. Бот отвечает на эти запросы в виде всплывающих подсказок, число и содержание которых зависит от того, что вы написали боту и от заложенного в него алгоритма. Если одна из подсказок удовлетворяет вашему запросу, нажимаете на неё и некоторое сообщение отправляется в тот чат, в котором вы находитесь.Например, если вы хотите отправить своему собеседнику ссылку на статью о Telegram из русскоязычной Википедии, то достаточно ввести в поле ввода @wiki ru Telegram и подождать пару секунд. Результат представлен на рисунке:

рис. 1. Как выглядят результаты запросов от встраиваемых ботов

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

Помимо ссылок, при помощи Inline API можно отправлять фотографии, GIF-анимации, видеоанимации в формате Mpeg-4 и ссылки на видеозаписи, которые можно будет смотреть прямо в приложении.

Прежде, чем мы начнём писать своего встраиваемого бота, несколько слов о том, для чего НЕ надо их использовать и какие есть ограничения. Во-первых, такие боты нужны именно для подсказок, когда вы хотите чем-то поделиться, но вам нужна помощь бота. Вы же не помните все ссылки на те самые видео с котиками? А бот быстренько поможет его найти, чтобы вы поделились им в чатике. Во-вторых, существуют недокументированные ограничения по объемам отправляемой информации. Скажем, для текстов и ссылок нельзя отправлять элементы длиннее 300-400 символов (на самом деле, получается без проблем около двухсот, больше — с оговорками). На мой взгляд, это самый неприятный момент в API. Я давеча пытался прикрутить поиск цитат с сайта Bash.im из своей базы для одного из моих ботов. Увы, всё, чего удалось добиться, это отправка коротких цитат (примерно с твит размером) непосредственно текстом, длинных — через отправку ссылок на сам Баш.

Ну а теперь приступим к созданию нашего первого встраиваемого бота. Вообще говоря, никто не мешает добавить существующему Inline-возможности, но дабы не усложнять код, напишем отдельного.

Что же он будет уметь? Пусть на вход боту будут подаваться 2 числа, а он в подсказках будет предлагать основные математические действия: сложение, вычитание, умножение и деление. Да, пример надуманный, но как нельзя лучше показывает особенности Inline API.

В начале, зарегистрируем бота у @BotFather (или воспользуемся имеющимся) для него вызовем команду /setinline.Внимание: после ввода этой команды и выбора бота нужно ввести подсказку, появляющуюся в поле ввода при вызове нашего бота в дальнейшем, иначе фокус не удастся.

Создадим файл исходного кода и добавим туда необходимые импорты и объект самого бота:

Мы условились, что на вход будут подаваться 2 числа, поэтому нам нужно построить регулярное выражение, которое будет реагировать на корректный ввод. Оно очень простое: digits_pattern = re.compile(r'^[0-9]+ [0-9]+$', re.MULTILINE).

А теперь самое главное — логика. Пока юзер пишет, Телеграм никак себя не проявляет, но как только он делает паузу, приложение считает, что это законченный ввод и отправляет его боту. Юзер дописал ещё пару символов и остановился? Окей, снова кидаем это боту. Соответственно, может сложиться ситуация, когда пользователь ввёл одно число и задумался. Наш парсер, попробовав сопоставить текст на наличие регулярного выражение, ругнётся и сотворит всякие нехорошие вещи, например, остановит весь скрипт (мы же помним, что Python — интерпретируемый язык, да?). Значит, надо ставить ловлю исключений:

Если условие выше отработало без ошибок, значит, мы получили два искомых числа. Теперь начинаются особенности Inline API. Каждая подсказка, присылаемая ботом, это объект с набором некоторых характеристик. Мы будем использовать объект типа «Статья«.Согласно документации, обязательных параметров у такого объекта четыре: тип, уникальный идентификатор, заголовок и текст, который будет отправлен. По поводу типа можно не беспокоиться: используемая мной уже больше полугода библиотека pyTelegramBotAPI подставит нужное значение сама. Уникальный идентификатор придется ставить самим и тут есть подвох: при использовании подгрузки (об этом в конце урока) идентификаторы должны быть уникальными у всех значений в одном большом запросе (т.е. у исходных результатов и всех подгружаемых в пределах одного запроса). Учтите это. Заголовок — очевидно. Отправляемый текст — то, что будет отправлено в текущий чат при нажатии на данную подсказку.Есть ещё необязательный параметр «описание» (description). Так вот, описание != отправляемый текст. В подсказке может быть написано «Наполеон — это торт», а в отправляемом тексте могут содержаться коды запуска ядерный ракет. Шутка, но смысл понятен.

Вооружившись этими знаниями и имея на руках два присланных пользователем числа, давайте создадим 4 объекта, каждый из которых отвечает за свою математическую операцию (на самом деле 5, т.к. учтем деление на ноль):

Полагаю, тут ничего сверхсложного нет. Вызывает интерес только последняя строка, а именно метод answer_inline_query. У него обязательных параметров два: уникальный идентификатор запроса (его получает хэндлер, так что про него забываем) и массив ответов. Загоняем теперь предыдущие два куска кода в одну функцию, обернутую хэндлером:

И можно запускать! Введём в любом чате, кроме секретного, ник нашего бота и два числа. Смотрим на подсказку:

Рис. 2. Результат работы бота

В принципе, правильно, но как-то не наглядно. Да и не очень понятно для нового пользователя, как, что и зачем.А давайте учтем ситуацию, когда пользователь ввёл только ник бота, и покажем ему подсказку:

Уже лучше, но всё равно не очень наглядно. А давайте добавим превью для каждой подсказки, чтобы слева была иконка соответствующей операции, и, заодно, сделаем превью при делении на ноль кликабельным, отправляя пользователя на эту страницу Википедии.Во-первых, закачаем на какой-нибудь бесплатный хостинг иконки с нашими математическими операциями (сгенерировал в Metro Studio, размер каждой 48×48 px):

Во-вторых, отредактируем функцию query_text, добавив к каждому объекту типа «Статья» иконку, а для деления на ноль — свою иконку и ссылку:

Обратите снова внимание на функцию answer_inline_query, в ней я добавил аргумент cache_time. Значит он именно то, что первым приходит в голову — устанавливает время, на которое результат будет закэширован, чтобы лишний раз не дергать бота. Сейчас на моей стороне тот факт, что математика — фундаментальная наука, и за те 68 с копейками лет, что указаны у меня в аргументе cache_time, результат операций не изменится. Но! Выше на рис. 2 у меня слева от подсказок нет ничего, никаких картинок. И да, в течение 68 с лишним лет конкретно для данного запроса так и будет. Поэтому трижды подумайте, прежде чем установите большое время кэширования. Для каких-то динамических результатов, например, для подсказки при нулевом запросе, вполне достаточно времени 86400 (1 сутки). По умолчанию, кстати, вообще всего 300 секунд, т.е. 5 минут.

Теперь наши результаты выглядят куда симпатичнее:

Рис. 3. Результат с картинками
Рис. 4. Деление на ноль

Прекрасно! Мы написали своего первого встраиваемого бота! Но…Но есть ещё такая штука, как offset. Вообще говоря, это нужно для постепенной подгрузки новых результатов. Например, пользователь запрашивает видео с котиками, бот возвращает пять штук. Как только юзер долистывает до конца, бот запрашивает у своего источника ещё пять, а Telegram дописывает их к уже имеющимся. В итоге, уже 10 вариантов и так далее. В одном из своих ботов я сделал так: запрашиваю из БД 5 записей с offset равным нулю. При отправке их пользователю, я устанавливаю в функции answer_inline_query параметр next_offset в значение 5 (строковый параметр, если что). Если юзер долистал до конца, то боту придет запрос с этим же текстом, но с значением offset как раз 5, поэтому в следующий раз я из БД запрошу уже следующие пять записей, прибавлю ещё пятерку к текущему значению, получая 10 и снова верну пользователю значения. Как только у меня закончились соответствующие запросу данные в базе, отправляю пустую строку в качестве аргумента next_offset. В общем, всё выглядит примерно так (бОльшая часть кода вырезана для упрощения понимания):

Поделиться:
Нет комментариев

Добавить комментарий

Ваш e-mail не будет опубликован. Все поля обязательны для заполнения.

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