Bot API v2: Кнопки и редактирование сообщений
В начале апреля 2016 года вышло первое по-настоящему крупное обновление API для ботов. Изменений довольно много, поэтому материал я разобью на несколько частей. Сегодня поговорим об inline-кнопках и редактировании сообщений, а затем обсудим новые инлайн-режимы вместе со специальными кнопками для отправки геолокации и номера телефона.
Новые возможности
Начнём с двух важных изменений:
- Каждая кнопка, будь то обычная или инлайн, это теперь самостоятельный объект KeyboardButton или InlineKeyboardButton , не забудьте обновить своих ботов!
- В Inline-режиме все текстовые поля теперь представлены отдельными объектами InputMessageContent , которые, в свою очередь могут быть аж 4-х типов (подробности тут).
URL-кнопки
Итак, инлайн-кнопки. Что это такое? Это специальные объекты, которые “цепляются” к конкретным сообщениям и распространяют своё действие, в общем случае, только на них. Делятся такие кнопки на три типа: URL-кнопки, Callback-кнопки и Switch-кнопки. Самыми простыми являются кнопки-ссылки (URL). Как видно из названия, их цель — просто перекидывать пользователей по определенным веб-адресам. Давайте сразу напишем обработчик, который будет на любое сообщение отвечать каким-либо текстом и предложением перейти, например, на Яндекс.
Инлайн-клавиатура представляет собой объект InlineKeyboardMarkup , а каждая инлайн-кнопка – это объект InlineKeyboardButton . Чтобы получилась URL-кнопка, нужно указать значения параметров text (текст на кнопке) и url (валидный веб-адрес). В результате бот пришлет нам такое сообщение (см. рис.). В целях обеспечения безопасности, перед переходом по URL-кнопкам появляется всплывающее окно, в котором видна ссылка целиком.
Callback-кнопки и редактирование сообщений
Прежде, чем мы перейдем к другим кнопкам, давайте познакомимся с функциями редактирования сообщений, коих тоже три: editMessageText (редактирование текста), editMessageCaption (редактирование подписи к медиа) и editMessageReplyMarkup (редактирование инлайн-клавиатуры). В рамках этого урока рассмотрим только первую функцию, остальные работают аналогично и предлагаются для самостоятельного изучения.
Чтобы отредактировать сообщение, нам надо знать, про какое именно идёт речь. В случае, если оно было отправлено самим ботом, идентификаторами служит связка chat_id + message_id . Но если сообщение было отправлено в инлайн-режиме, то ориентироваться надо по параметру inline_message_id .
И вот теперь вернемся к нашим баранам кнопкам. На очереди – Callback. Это, на мой взгляд, самая крутая фича нового обновления. Колбэк-кнопки позволяют выполнять произвольные действия по их нажатию. Всё зависит от того, какие параметры каждая кнопка в себе несёт. Соответственно, все нажатия будут приводить к отправке боту объекта CallbackQuery , содержащему поле data , в котором написана некоторая строка, заложенная в кнопку, а также либо объект Message , если сообщение отправлено ботом в обычном режиме, либо поле inline_message_id , если сообщение отправлено в инлайн-режиме.
Приведу пример, после которого все вопросы должны отпасть: пусть, например, если сообщение отправлено ботом в обычном режиме, то нажатие на кнопку заменит текст сообщения на “Пыщь”, если в инлайн – то “Бдыщь”. При этом в обоих случаях значение callback_data будет равно test . Что для этого нужно сделать: во-первых, написать простейший хэндлер для всех входящих сообщений, во-вторых, написать простейший хэндлер для инлайн-сообщений, в-третьих, написать простейший хэндлер для колбэка, который определит, из какого режима пришло сообщение.
Запускаем бота, отправляем инлайн-сообщение, которое, в свою очередь, вызовет обычное:
Нажмем на обе кнопки, результат правильный:
После проверки
Таким образом, callback-кнопки – это очень мощный инструмент для взаимодействия пользователей с ботом, а редактирование сообщений дополнительно помогает в этом. Более того, нажатие на колбэк-кнопку может дополнительно тригернуть либо уведомление в верхней части экрана, либо всплывающее окно. Покажу первый вариант. Пускай помимо изменения сообщения на “Пыщь”, аналогичное слово показывается уведомлением. Для этого перепишем первое if-условие в хендлере колбэков:
Результат – на скриншоте. Попробуйте, кстати, изменить аргумент show_alert на True и посмотрите, что получится.
Всплывающее уведомление
Switch-кнопки
Наконец, остался последний тип кнопок — Switch (переключатель). Они нужны, чаще всего, для обучения пользователей работе с ботом в инлайн-режиме. Чтобы активировать сделать кнопку такого типа, нужно указать аргумент switch_inline_query либо пустой, либо с каким-либо текстом. В последнем случае этот текст будет сразу подставлен в поле ввода, например, для показа демонстрации инлайна. Как вообще работает такая кнопка? При нажатии на неё Telegram предложит выбрать чат, после чего подставит в поле ввода ник вашего бота и (если есть), текст, указанный вами в аргументе switch_inline_query . Давайте попробуем так сделать. Добавим кнопку, которая будет перенаправлять пользователя в какой-либо чат и предлагать в инлайн-режиме запрос “Telegram”. Код всего хендлера выглядит вот так:
Теперь, если мы нажмем на кнопку и выберем чат, вот что получится:
Итак, в этом уроке мы познакомились с новыми кнопками в Telegram Bot API, научились переписывать историю редактировать сообщения и отправлять небольшие уведомления по нажатию. В следующий раз продолжим изучать новые возможности для ботов. А исходники к этому уроку можно найти в этом репозитории.
Кнопки в телеграм-ботах
Это статья из серии о телеграм-ботах. Я по частям расскажу о важных моментах в pytelegrambotapi. Сразу полезная информация: я начал учиться делать ботов по этой статье и всем ее рекомендую.
Кнопки в телеграм бывают двух видов — inline и обычные (reply).
Обычные вы видите вместо клавиатуры, все, что они делают, как правило, — отправляют текстовое сообщение боту.
Но, перед тем, как сделать кнопку, нужно создать клавиатуру. Для обычных кнопок она одна, для inline другая, вот обычная:
resize_keyboard: bool — необязательный | будет ли клавиатура растягиваться (по умолчанию: без значения)
one_time_keyboard: bool — необязательный \ разовая ли клавиатура (по умолчанию: без значения)
selective: bool — необязательный | кому показывать (по умолчанию: без значения)
row_width: int — обязательный | количество столбцов кнопок (по умолчанию: 3)
input_field_placeholder: str — необязательный | заменяет текст-заглушку в поле ввода (по умолчанию: без значения)
Создав клавиатуру, создадим к ней кнопку:
text: str — обязательный | текст кнопки. Если указан только он, то кнопка будет просто отправлять текст при нажатии.
request_contact: bool — необязательный | если указан как true то пользователь при нажатии отправит свой контакт. Доступен только в приватных чатах.
request_location: bool — необязательный | если указан как true, то пользователь при нажатии отправит свою локацию. Доступен только в приватных чатах.
request_poll: bool — необязательный | если указан как true, то пользователь при нажатии отправит свою локацию. Доступен только в приватных чатах.
web_app: WebAppInfo — необязательный | если указан как true, то при нажатии откроется страница указанного веб-приложения — про это есть отдельная статья. Доступен только в приватных чатах.
aiogram — разница между Inline & Reply Keyboard
Необходимы сложные действия по нажатию кнопок. Для inline кнопок понятно — есть callback и там получаем код нажатой кнопки и по кодам делаем произвольную обработку. Но — неудобно, поскольку клавиатура привязана к сообщению и уезжает вверх по мере нажатий кнопок. Клавиатура reply лучше в этом отношении — не уезжает, но непонятно — возможно ли на ее кнопки поставить сложное действие, или эта кнопка может выполнять только действия из стандартного набора? Например, вставить действие print(1234) в обработчик конкретной reply кнопки?
Вы можете выполнять все, что хотите через Inline и Reply это зависит от ваших фантазии и задачи в целом. Небольшой пример использования FSM и Reply Keyboard:
Ну в целом разница какая: при нажатии на реплай кнопку юзер как-бы пишет сообщение, а инлайн кнопку нужно обрабатывать колбек_хендлером.
Еще в инлайн кнопку можно вставить URL сайта чтобы при нажатии происходил переход на него. А еще через инлайн кнопки можно проводить платежи.
Инлайн кнопки как-бы красивее в плане том, что они не загрязняют историю сообщений всякой фигней.
Как фича реплай кнопки способны просить у пользователя его местоположение и номер телефона.
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.3.13.43307
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Пишем telegram бота на языке R (часть 3): Как добавить боту поддержку клавиатуры
Это третья статья из серии «Пишем telegram бота на языке R». В предыдущих публикациях мы научились создавать телеграм бота, отправлять через него сообщения, добавили боту команды и фильтры сообщений. Поэтому перед тем как приступить к чтению данной статьи я крайне рекомендую ознакомиться с предыдущими, т.к. тут я уже не буду останавливать на описанных ранее основах ботостроения.
В этой статье мы повысим юзабилити нашего бота за счёт добавления клавиатуры, которая сделает интерфейс бота интуитивно понятным, и простым в использовании.

Все статьи из серии «Пишем telegram бота на языке R»
Содержание
Если вы интересуетесь анализом данных возможно вам будут интересны мои telegram и youtube каналы. Большая часть контента которых посвящены языку R.
Какие типы клавиатур поддерживает телеграм бот
На момент написания статьи telegram.bot позволяет вам создать клавиатуры двух типов:
- Reply — Основная, обычная клавиатура, которая находится под панелью ввода текста сообщения. Такая клавиатура просто отправляет боту текстовое сообщение, и в качестве текста отправит тот текст, который написан на самой кнопке.
- Inline — Клавиатура привязанная к конкретному сообщению бота. Данная клавиатура отправляет боту данные, привязанные к нажатой кнопке, эти данные могут отличаться от текста, написанного на самой кнопке. И обрабатываются такие кнопки через CallbackQueryHandler.
Для того, что бы бот открыл клавиатуру необходимо при отправке сообщения через метод sendMessage() , передать созданную ранее клавиатуру в аргумент reply_markup .
Ниже мы разберём несколько примеров.
Reply клавиатура
Как я уже писал выше, это основная клавиатура управления ботом.
Выше приведён пример из официальной справки пакета telegram.bot . Для создания клавиатуры используется функция ReplyKeyboardMarkup() , которая в свою очередь принимает список списков кнопок, которые создаются функцией KeyboardButton() .
Почему в ReplyKeyboardMarkup() необходимо передавать не просто список, а список списков? Дело в том, что вы передаёте основной список, и в нём отдельными списками вы задаёте каждый ряд кнопок, т.к. в один ряд можно расположить несколько кнопок.
Аргумент resize_keyboard позволяет автоматически подбирать оптимальный размер кнопок клавиатуры, а аргумент one_time_keyboard позволяет скрывать клавиатуру после каждого нажатия на кнопку.
Давайте напишем простейшего бота, у которого будет 3 кнопки:
- Чат ID — Запросить чат ID диалога с ботом
- Моё имя — Запросить своё имя
- Мой логин — Запросить своё имя пользователя в телеграм
После запуска задайте боту команду /start , т.к. именно её мы определили для запуска клавиатуры.

Если на данный момент вам сложно разобрать приведённый пример кода, с созданием методов, фильтров и обработчиков, то следует вернуться к предыдущей статье, в которой я подробно всё это описал.
Мы создали 4 метода:
- start — Запуск клавиатуры
- chat_id — Запрос идентификатора чата
- my_name — Запрос своего имени
- my_username — Запрос своего логина
В объект MessageFilters добавили 3 фильтра сообщений, по их тексту:
- chat_id — Сообщения с текстом «Чат ID»
- name — Сообщения с текстом «Моё имя»
- username — Сообщения с текстом «Мой логин»
И создали 4 обработчика, которые по заданным командам и фильтрам будут выполнять указанные методы.
Сама клавиатура создаётся внутри метода start() командой ReplyKeyboardMarkup() .
В нашем случае все кнопки мы расположили друг под другом, но мы можем расположить их в один ряд, внеся изменения в список списков кнопок. Т.к. один ряд внутри клавиатуры создаётся через вложенный список кнопок, то для того, что бы вывести наши кнопки в один ряд надо переписать часть кода по построению клавиатуры вот так:

Отправляется клавиатура в чат методом sendMessage() , в аргументе reply_markup .
Inline клавиатура
Как я уже писал выше, Inline клавиатура привязана к конкретному сообщению. С ней работать несколько сложнее чем с основной клавиатурой.
Изначально вам необходимо добавить боту метод, для вызова Inline клавиатуры.
Для ответа на нажатие Inline кнопки также можно использовать метод бота answerCallbackQuery() , который может вывести уведомление в интерфейсе telegram, пользователю нажавшему Inline кнопку.
Данные отправленные с Inline кнопки не являются текстом, поэтому для их обработки необходимо создать специальный обработчик с помощью команды CallbackQueryHandler() .
Код построения Inline клавиатуры который приводится в официальной справке пакета telegram.bot .
Строить Inline клавиатуру необходимо с помощью команды InlineKeyboardMarkup() , по такому же принципу, как и Reply клавиатуру. В InlineKeyboardMarkup() необходимо передать список, списков Inline кнопок, каждая отдельная кнопка создаётся функцией InlineKeyboardButton() .
Inline кнопка может либо передавать боту какие-то данные с помощью аргумента callback_data , либо открывать какую-либо HTML страницу, заданную с помощью аргумента url .
В результате будет список, в котором каждый элемент так же является списком Inline кнопок, которые необходимо объединить в один ряд.
Далее мы рассмотрим несколько примеров ботов с Inline кнопками.
Пример простейшего бота с поддержкой InLine кнопок
Для начала мы напишем бота для экспресс тестирования на covid-19. По команде /test , он будет отправлять вам клавиатуру с двумя кнопками, в зависимости от нажатой кнопки он будет присылать вам сообщение с результатами вашего тестирования.
Результат: 
Мы создали два метода:
- test — Для отправки в чат Inline клавиатуры
- answer_cb — Для обработки отправленных с клавиатуры данных.
Данные, которые будут отправлены с каждой кнопки задаются в аргументе callback_data , при создании кнопки. Получить отправленные с кнопки данные можно с помощью конструкции update$callback_query$data , внутри метода answer_cb.
Что бы бот реагировал на Inline клавиатуру, метод answer_cb обрабатывается специальным обработчиком: CallbackQueryHandler(answer_cb) . Который запускает указанный метод по нажатию Inline кнопки. Обработчик CallbackQueryHandler принимает два аргумента:
- callback — Метод который необходимо запустить
- pattern — Фильтр по данным, которые привязаны к кнопке с помощью аргумента callback_data .
Соответвенно с помощью аргумента pattern мы можем под нажатие каждой кнопки написать отдельный метод:
Теперь мы написали 2 отдельных метода, т.е. по одному методу, под нажатие каждой кнопки, и использовали аргумент pattern , при создании их обработчиков:
Заканчивается код метода answer_cb командой bot$answerCallbackQuery(callback_query_id = update$callback_query$id) , которая сообщает боту, что данные с inline клавиатуры получены.
Пример бота, который сообщает текущую погоду по выбранному городу
Давайте попробуем написать бота, который запрашивает данные о погоде.
Логика его работы будет следующая. Изначально командой /start вы вызываете основную клавиатуру, в которой присутствует всего одна кнопка «Погода». Нажав на эту кнопку вы получаете сообщение с Inline клавиатурой, для выбора города, по которому требуется узнать текущую погоду. Выбираете один из городов, и получаете текущую погоду.
В этом примере кода мы будем использовать несколько дополнительных пакетов:
- httr — пакет для работы с HTTP запросами, на основе которых построена работа с любым API. В нашем случае мы будем использовать бесплатный API openweathermap.org.
- stringr — пакет для работы с текстом, в нашем случае мы будем его использовать для формирования сообщения о погоде в выбранном городе.
В результате наш бот будет работать примерно так: 
Схематически данного бота можно изобрать вот так: 
Мы создали 3 метода, доступные внутри нашего погодного бота:
- start — Запуск основной клавиатуры бота
- weather — Запуск Inline клавиатуры для выбора города
- answer_cb — Основной метод, который по заданному городу запрашивает в API погоду, и отправляет её в чат.
Метод start у нас запускается командой /start , что реализовано обработчиком CommandHandler(‘start’, start) .
Для запуска метода weather мы создали одноимённый фильтр:
И вызываем этот метод следующим обработчиком сообщений: MessageHandler(weather, filters = MessageFilters$weather) .
И в конце концов, основной наш метод answer_cb реагирует на нажатие Inline кнопок, что реализовано специальным обработчиком: CallbackQueryHandler(answer_cb) .
Внутри метода answer_cb, мы считываем отправленные с клавиатуры данные и записываем их в переменную city : city <- update$callback_query$data . После чего запрашиваем из API данные о погоде, формируем и отправляем сообщение, и в конце концов используем метод answerCallbackQuery для того, что бы сообщить боту, о том, что мы обработали нажатие Inline кнопки.
Пример бота, который выводит список самых свежих статей со ссылками по-указанному Хабу из habr.com.
Данного бота я привожу для того, что бы показать вам, как вывести Inline кнопки которые ведут на веб страницы.
Логика данного бота схожа с предыдущим, изначально мы запускаем основную клавиатуру командой /start . Далее бот даёт нам на выбор список из 6 хабов, мы выбираем интересующий нас хаб, и получаем 5 самых свежих публикаций из выбранного Хаба.
Как вы понимаете, в данном случае нам необходимо получить список статей, и для этого мы будем использовать специальный пакет habR , который позволяет запрашивать из хабры статьи и некоторую статистику по ним в R.
Установить пакет habR можно только из github, для чего вам понадобится дополнительный пакет devtools . Для установки воспользуйтесь приведённым ниже кодом.
Теперь рассмотрим код построения описанного выше бота:
В итоге мы получим вот такой результат: 
Список доступных для выбора Хабов мы вбили хардкодом, в методе habs :
Список статей из указанного Хаба мы получаем командой habr_hub_posts() , из пакета habR . При этом указываем, что нам не требуется список статей за всё время, а только первая страница на которой располагаются 20 статей. Из полученной таблицы с помощью команды head() оставляем только 5 самых верхних, которые и являются самыми свежими статьями.
Логика очень схожа с предыдущим ботом, но в данном случае Inline клавиатуру со списком статей мы генерируем динамически с помощью функции lapply() .
В текст кнопки мы подставляем название статьи posts$title[x] , а в аргумент url ссылку на статью: url = posts$link[x] .
Далее, создаём фильтр, обработчики и запускаем нашего бота.
Заключение
Теперь написанные вами боты будут значительно удобней в работе, за счёт того, что управление ими будет осуществляться с клавиатуры, а не вводом команд. Как минимум при взаимодействии с ботом через смартфон клавиатура ощутимо упростит процесс его использования.
В следующей статье мы разберёмся как строить логический диалог с ботом, и работать с базами данных.