Русский
Русский
English
Статистика
Реклама

Как написать телеграм бота

Пишем telegram бота на языке R (часть 2) Добавляем боту поддержку команд и фильтры сообщений

25.08.2020 10:05:02 | Автор: admin

В предыдущей публикации мы разобрались как создать бота, инициализировали экземпляр класса Bot и ознакомились с методами отправки сообщений с его помощью.


В этой статье я продолжаю данную тему, поэтому приступать к чтению данной статьи я рекомендую только после прочтения первой части.


В этот раз мы разберёмся как оживить нашего бота и добавим ему поддержку команд, а также познакомимся с классом Updater.


В ходе статьи мы напишем нескольких простых ботов, последний будет по заданной дате и коду страны определять является ли день в данной стране выходным или рабочим согласно производственного календаря. Но, как и прежде цель статьи ознакомить вас с интерфейсом пакета telegram.bot для решения ваших собственных задач.



Все статьи из серии "Пишем telegram бота на языке R"


  1. Создаём бота, и отправляем с его помощью сообщения в telegram
  2. Добавляем боту поддержку команд и фильтры сообщений

Содержание


  1. Класс Updater
  2. Handlers обработчики
  3. Добавляем первую команду боту, обработчик команд
  4. Обработчик текстовых сообщений и фильтры
  5. Добавление команд с параметрами
  6. Запускаем бота в фоновом режиме
  7. Заключение

Класс Updater


Updater это класс, который упрощает вам разработку телеграм бота, и использует под капотом класс Dispetcher. Назначение класса Updater заключается в том, что бы получить обновления от бота (в предыдущей статье мы использовали для этой цели метод getUpdates()), и передать их далее в Dispetcher.


В свою очередь Dispetcher содержит в себе созданные вами обработчики, т.е. объекты класса Handler.


Handlers обработчики


С помощью обработчиков вы добавляете в Dispetcher реакции бота на различные события. На момент написания статьи в telegram.bot добавлены следующие типы обработчиков:


  • MessageHandler Обработчик сообщений
  • CommandHandler Обработчик команд
  • CallbackQueryHandler Обработчик данных отправляемых из Inline клавиатур
  • ErrorHandler Обработчик ошибок при запросе обновлений от бота

Добавляем первую команду боту, обработчик команд


Если вы никогда ранее не использовали ботов, и не в курсе, что такое команда, то команды боту необходимо отправлять с помощью прямого слеша / в качестве префикса.


Начнём мы с простых команд, т.е. научим нашего бота здороваться по команде /hi.


Код 1: Учим бота здороваться
library(telegram.bot)# создаём экземпляр класса Updaterupdater <- Updater('ТОКЕН ВАШЕГО БОТА')# Пишем метод для приветсвияsay_hello <- function(bot, update) {  # Имя пользователя с которым надо поздароваться  user_name <- update$message$from$first_name  # Отправка приветственного сообщения  bot$sendMessage(update$message$chat_id,                   text = paste0("Моё почтение, ", user_name, "!"),                   parse_mode = "Markdown")}# создаём обработчик hi_hendler <- CommandHandler('hi', say_hello)# добаляем обработчик в диспетчерupdater <- updater + hi_hendler# запускаем ботаupdater$start_polling()

Запустите приведённый выше пример кода, предварительно заменив 'ТОКЕН ВАШЕГО БОТА' на реальный токен, который вы получили при создании бота через BotFather (о создании бота я рассказывал в первой статье).

Метод start_polling() класса Updater, который используется в конце кода, запускает бесконечный цикл запроса и обработки обновлений от бота.


Теперь откроем телеграм, и напишем нашему боту первую команду /hi.



Теперь наш бот понимает команду /hi, и умеет с нами здороваться.


Схематически процесс построения такого простейшего бота можно изобразить следующим образом.



  1. Создаём экземпляр класса Updater;
  2. Создаём методы, т.е. функции которые будет выполнять наш бот. В примере кода это функция say_hello(). Функции, которые вами будут использоваться как методы бота должны иметь два обязательных аргумента bot и update, и один необязательный args. Аргумент bot, это и есть ваш бот, с его помощью вы можете отвечать на сообщения, отправлять сообщения, или использовать любые другие доступные боту методы. Аргумент update это то, что бот получил от пользователя, по сути, то что в первой статье мы получали методом getUpdates(). Аргумент args позволяет вам обрабатывать дополнительные данные отправленные пользователем вместе с командой, к этой теме мы ещё вернёмся немного позже;
  3. Создаём обработчики, т.е. связываем какие-то действия пользователя с созданными на прошлом шаге методами. По сути обработчик это триггер, событие которое вызывает какую-то функцию бота. В нашем примере таким триггером является отправка команды /hi, и реализуется командой hi_hendler <- CommandHandler('hi', say_hello). Первый аргумент функции CommandHandler() позволяет вам задать команду, в нашем случае hi, на которую будет реагировать бот. Второй аргумент позволяет указать метод бота, мы будем вызывать метод say_hello, который будет выполняться если пользователь вызвал указанную в первом аргументе команду;
  4. Далее добавляем созданный обработчик в диспетчер нашего экземпляра класса Updater. Добавлять обработчики можно несколькими способами, в примере выше я использовал простейший, с помощью знака +, т.е. updater <- updater + hi_hendler. То же самое можно сделать с помощью метода add_handler(), который относится к классу Dispatcher, найти этот метод можно так: updater$dispatcher$add_handler();
  5. Запускаем бота с помощью команды start_polling().

Обработчик текстовых сообщений и фильтры


Как отправлять боту команды мы разобрались, но иногда нам требуется, что бы бот реагировал не только на команды, но и на какие-то обычные, текстовые сообщения. Для этого необходимо использовать обработчики сообщений MessageHandler.


Обычный MessageHandler будет реагировать на абсолютно все входящие сообщения. Поэтому зачастую обработчики сообщений используются вместе с фильтрами. Давайте научим бота здороваться не только по команде /hi, но и всегда, когда в сообщении отправленном боту встречается одно из следующих слов: привет, здравствуй, салют, хай, бонжур.


Пока мы не будем писать какие-то новые методы, т.к. у нас уже есть метод с помощью которого бот с нами здоровается. От нас требуется только создать нужный фильтр и обработчик сообщений.


Код 2: Добавляем обработчик текстовых сообщений и фильтр
library(telegram.bot)# создаём экземпляр класса Updaterupdater <- Updater('ТОКЕН ВАШЕГО БОТА')# Пишем метод для приветсвия## команда приветвияsay_hello <- function(bot, update) {  # Имя пользователя с которым надо поздароваться  user_name <- update$message$from$first_name  # Отправляем приветсвенное сообщение  bot$sendMessage(update$message$chat_id,                   text = paste0("Моё почтение, ", user_name, "!"),                  parse_mode = "Markdown",                  reply_to_message_id = update$message$message_id)}# создаём фильтрыMessageFilters$hi <- BaseFilter(function(message) {  # проверяем, встречается ли в тексте сообщения слова: привет, здравствуй, салют, хай, бонжур  grepl(x           = message$text,         pattern     = 'привет|здравствуй|салют|хай|бонжур',        ignore.case = TRUE)  })# создаём обработчик hi_hendler <- CommandHandler('hi', say_hello) # обработчик команды hihi_txt_hnd <- MessageHandler(say_hello, filters = MessageFilters$hi)# добаляем обработчики в диспетчерupdater <- updater +              hi_hendler +             hi_txt_hnd# запускаем ботаupdater$start_polling()

Запустите приведённый выше пример кода, предварительно заменив 'ТОКЕН ВАШЕГО БОТА' на реальный токен, который вы получили при создании бота через BotFather (о создании бота я рассказывал в первой статье).

Теперь попробуем отправить боту несколько сообщений, в которых будут встречаться перечисленные ранее слова приветствия:


Итак, в первую очередь мы научили бота не просто здороваться, а отвечать на приветствие. Сделали мы это с помощью аргумента reply_to_message_id, который доступен в методе sendMessage(), в который необходимо передать id сообщения на которое требуется ответить. Получить id сообщения можно вот так: update$message$message_id.


Но главное, что мы сделали добавили боту фильтр с помощью функции BaseFilter():


# создаём фильтрыMessageFilters$hi <- BaseFilter(   # анонимная фильтрующая функция  function(message) {    # проверяем, встречается ли в тексте сообщения слова приветствия    grepl(x           = message$text,           pattern     = 'привет|здравствуй|салют|хай|бонжур',          ignore.case = TRUE)  })

Как вы могли заметить, фильтры необходимо добавлять в объект MessageFilters, в котором изначально уже есть небольшой набор готовых фильтров. В нашем примере в объект MessageFilters мы добавили элемент hi, это новый фильтр.


В функцию BaseFilter() вам необходимо передать фильтрующую функцию. По сути, фильтр это просто функция, которая получает экземпляр сообщения и возвращает TRUE или FALSE. В нашем примере, мы написали простейшую функцию, которая с помощью базовой функции grepl() проверяет текст сообщения, и если он соответствует регулярному выражению привет|здравствуй|салют|хай|бонжур возвращает TRUE.


Далее мы создаём обработчик сообщений hi_txt_hnd <- MessageHandler(say_hello, filters = MessageFilters$hi). Первый аргумент функции MessageHandler() метод, который будет вызывать обработчик, а второй аргумент это фильтр по которому он будет вызываться. В нашем случае это созданный нами фильтр MessageFilters$hi.


Ну и в итоге, мы добавляем в диспетчер созданный только, что обработчик hi_txt_hnd.


updater <- updater +              hi_hendler +             hi_txt_hnd

Как я уже писал выше, в пакете telegram.bot и объекте MessageFilters уже есть набор встроенных фильтров, которые вы можете использовать:


  • all Все сообщения
  • text Текстовые сообщения
  • command Команды, т.е. сообщения которые начинаются на /
  • reply Сообщения, которые являются ответом на другое сообщение
  • audio Сообщения в которых содержится аудио файл
  • document Сообщения с отправленным документом
  • photo Сообщения с отправленными изображениями
  • sticker Сообщения с отправленным стикером
  • video Сообщения с видео
  • voice Голосовые сообщения
  • contact Сообщения в которых содержится контант телеграм пользователя
  • location Сообщения с геолокацией
  • venue Пересылаемые сообщения
  • game Игры

Если вы хотите совместить некоторые фильтры в одном обработчике просто используйте знак | в качестве логического ИЛИ, и знак & в качестве логического И. Например, если вы хотите что бы бот вызывал один и тот же метод когда он получает видео, изображение или документ используйте следующий пример создания обработчика сообщений:


handler <- MessageHandler(callback,   MessageFilters$video | MessageFilters$photo | MessageFilters$document)

Добавление команд с параметрами


Мы уже знаем, что такое команды, как их создавать и как заставить бота выполнить нужную команду. Но в некоторых случаях помимо названия команды, нам необходимо передать некоторые данные для её выполнения.


Ниже пример бота, который по заданной дате и стране возвращает вам тип дня из производственного календаря.


Приведённый ниже бот использует API производственного календаря isdayoff.ru.


Код 3: Бот, который сообщает по дате и стране
library(telegram.bot)# создаём экземпляр класса Updaterupdater <- Updater('1165649194:AAFkDqIzQ6Wq5GV0YU7PmEZcv1gmWIFIB_8')# Пишем метод для приветсвия## команда приветвияcheck_date <- function(bot, update, args) {  # входящие данные  day     <- args[1]  # дата  country <- args[2]  # страна  # проверка введённых параметров  if ( !grepl('\\d{4}-\\d{2}-\\d{2}', day) ) {    # Send Custom Keyboard    bot$sendMessage(update$message$chat_id,                     text = paste0(day, " - некорреткная дата, введите дату в формате ГГГГ-ММ-ДД"),                    parse_mode = "Markdown")  } else {    day <- as.Date(day)    # переводим в формат POSIXtl    y <- format(day, "%Y")    m <- format(day, "%m")    d <- format(day, "%d")  }  # страна для проверки  ## проверяем задана ли страна  ## если не задана устанавливаем ru  if ( ! country %in% c('ru', 'ua', 'by', 'kz', 'us') ) {    # Send Custom Keyboard    bot$sendMessage(update$message$chat_id,                     text = paste0(country, " - некорретктный код страны, возможнные значения: ru, by, kz, ua, us. Запрошены данные по России."),                    parse_mode = "Markdown")    country <- 'ru'  }  # запрос данных из API  # компоновка HTTP запроса  url <- paste0("https://isdayoff.ru/api/getdata?",                "year=",  y, "&",                "month=", m, "&",                "day=",   d, "&",                "cc=",    country, "&",                "pre=1&",                "covid=1")  # получаем ответ  res <- readLines(url)  # интрепретация ответа  out <- switch(res,                 "0"   = "Рабочий день",                "1"   = "Нерабочий день",                "2"   = "Сокращённый рабочий день",                "4"   = "covid-19",                "100" = "Ошибка в дате",                "101" = "Данные не найдены",                "199" = "Ошибка сервиса")  # отправляем сообщение  bot$sendMessage(update$message$chat_id,                   text = paste0(day, " - ", out),                  parse_mode = "Markdown")}# создаём обработчик date_hendler <- CommandHandler('check_date', check_date, pass_args = TRUE)# добаляем обработчик в диспетчерupdater <- updater + date_hendler# запускаем ботаupdater$start_polling()

Запустите приведённый выше пример кода, предварительно заменив 'ТОКЕН ВАШЕГО БОТА' на реальный токен, который вы получили при создании бота через BotFather (о создании бота я рассказывал в первой статье).

Мы создали бота, который в арсенале имеет всего один метод check_date, данный метод вызывается одноимённой командой.


Но, помимо имени команды, данный метод ждёт от вас введения двух параметров, код страны и дату. Далее бот проверяется, является ли заданный день в указанной стране выходным, сокращённым или рабочим согласно официального производственного календаря.


Что бы создаваемый нами метод принимал дополнительные параметры вместе с командой, используйте аргумент pass_args = TRUE в функции CommandHandler(), и при создании метода, помимо обязательных аргументов bot, update создайте опциональный args. Созданный таким образом метод будет принимать параметры, которые вы передаёте боту после названия команды. Параметры необходимо между собой разделять пробелом, в метод они поступят в виде текстового вектора.


Давайте запустим, и протестируем нашего бота.



Запускаем бота в фоновом режиме


Последний шаг который нам осталось выполнить запустить бота в фоновом режиме.


Для этого следуйте по описанному ниже алгоритму:


  1. Сохраните код бота в файл с расширением R. При работе в RStudio это делается через меню File, командой Save As....
  2. Добавьте путь к папке bin, которая в свою очередь находится в папке в которую вы установили язык R в переменную Path, инструкция тут.
  3. Создайте обычный текстовый файл, в котором пропишите 1 строку: R CMD BATCH C:\Users\Alsey\Documents\my_bot.R. Вместо C:\Users\Alsey\Documents\my_bot.R пропишите путь к своему скрипту бота. При этом важно, что бы в пути не встречалась кириллица и пробелы, т.к. это может вызвать проблемы при запуске бота. Сохраните его, и замените его расширение с txt на bat.
  4. Откройте планировщик заданий Windows, есть множество способов это сделать, например откройте любую папку и в адресс введите %windir%\system32\taskschd.msc /s. Другие способы запуска можно найти тут.
  5. В верхнем правом меню планировщика нажмите "Создать задачу...".
  6. На вкладке "Общие" задайте произвольное имя вашей задаче, и переключатель перевидите в состояние "Выполнять для всех пользователей".
  7. Перейдите на вкладку "Действия", нажмите "Создать". В поле "Программа или сценарий" нажмите "Обзор", найдите созданный на втором шаге bat файл, и нажмите ОК.
  8. Жмём ОК, при необходимости вводим пароль от вашей учётной записи операционной системы.
  9. Находим в планировщике созданную задачу, выделяем и в нижнем правом углу жмём кнопку "Выполнить".

Наш бот запущен в фоновом режиме, и будет работать до тех пор, пока вы не остановите задачу, или не выключите ваш ПК или сервер на котором его запустили.


Заключение


В этой статье мы разобрались как написать полноценного бота, который не только умеет отправлять сообщения, но и реагировать на входящие сообщения и команды. Полученных знананий уже достаточно для решения большинства ваших задач.


В следующей статье речь пойдёт о том, как добавить боту клавиатуру, для более удобной работы.

Подробнее..

Пишем telegram бота на языке R (часть 3) Как добавить боту поддержку клавиатуры

08.09.2020 10:16:23 | Автор: admin

Это третья статья из серии "Пишем telegram бота на языке R". В предыдущих публикациях мы научились создавать телеграм бота, отправлять через него сообщения, добавили боту команды и фильтры сообщений. Поэтому перед тем как приступить к чтению данной статьи я крайне рекомендую ознакомиться с предыдущими, т.к. тут я уже не буду останавливать на описанных ранее основах ботостроения.


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



Все статьи из серии "Пишем telegram бота на языке R"


  1. Создаём бота, и отправляем с его помощью сообщения в telegram
  2. Добавляем боту поддержку команд и фильтры сообщений
  3. Как добавить боту поддержку клавиатуры

Содержание


Если вы интересуетесь анализом данных возможно вам будут интересны мои telegram и youtube каналы. Большая часть контента которых посвящены языку R.


  1. Какие типы клавиатур поддерживает телеграм бот
  2. Reply клавиатура
  3. Inline клавиатура
    3.1. Пример простейшего бота с поддержкой InLine кнопок
    3.2. Пример бота, который сообщает текущую погоду по выбранному городу
    3.3. Пример бота, который выводит список самых свежих статей со ссылками по-указанному Хабу из habr.com
  4. Заключение

Какие типы клавиатур поддерживает телеграм бот


На момент написания статьи telegram.bot позволяет вам создать клавиатуры двух типов:


  • Reply Основная, обычная клавиатура, которая находится под панелью ввода текста сообщения. Такая клавиатура просто отправляет боту текстовое сообщение, и в качестве текста отправит тот текст, который написан на самой кнопке.
  • Inline Клавиатура привязанная к конкретному сообщению бота. Данная клавиатура отправляет боту данные, привязанные к нажатой кнопке, эти данные могут отличаться от текста, написанного на самой кнопке. И обрабатываются такие кнопки через CallbackQueryHandler.

Для того, что бы бот открыл клавиатуру необходимо при отправке сообщения через метод sendMessage(), передать созданную ранее клавиатуру в аргумент reply_markup.


Ниже мы разберём несколько примеров.


Reply клавиатура


Как я уже писал выше, это основная клавиатура управления ботом.


Пример создания Reply клавиатуры из официальной справки
bot <- Bot(token = "TOKEN")chat_id <- "CHAT_ID"# Create Custom Keyboardtext <- "Aren't those custom keyboards cool?"RKM <- ReplyKeyboardMarkup(  keyboard = list(    list(KeyboardButton("Yes, they certainly are!")),    list(KeyboardButton("I'm not quite sure")),    list(KeyboardButton("No..."))  ),  resize_keyboard = FALSE,  one_time_keyboard = TRUE)# Send Custom Keyboardbot$sendMessage(chat_id, text, reply_markup = RKM)

Выше приведён пример из официальной справки пакета telegram.bot. Для создания клавиатуры используется функция ReplyKeyboardMarkup(), которая в свою очередь принимает список списков кнопок, которые создаются функцией KeyboardButton().


Почему в ReplyKeyboardMarkup() необходимо передавать не просто список, а список списков? Дело в том, что вы передаёте основной список, и в нём отдельными списками вы задаёте каждый ряд кнопок, т.к. в один ряд можно расположить несколько кнопок.


Аргумент resize_keyboard позволяет автоматически подбирать оптимальный размер кнопок клавиатуры, а аргумент one_time_keyboard позволяет скрывать клавиатуру после каждого нажатия на кнопку.


Давайте напишем простейшего бота, у которого будет 3 кнопки:


  • Чат ID Запросить чат ID диалога с ботом
  • Моё имя Запросить своё имя
  • Мой логин Запросить своё имя пользователя в телеграм

Код 1: Простой бот с Reply клавиатурой
library(telegram.bot)# создаём экземпляр класса Updaterupdater <- Updater('ТОКЕН ВАШЕГО БОТА')# создаём методы## метод для запуска клавиатурыstart <- function(bot, update) {  # создаём клавиатуру  RKM <- ReplyKeyboardMarkup(    keyboard = list(      list(KeyboardButton("Чат ID")),      list(KeyboardButton("Моё имя")),      list(KeyboardButton("Мой логин"))    ),    resize_keyboard = FALSE,    one_time_keyboard = TRUE  )  # отправляем клавиатуру  bot$sendMessage(update$message$chat_id,                  text = 'Выберите команду',                   reply_markup = RKM)}## метод возвразающий id чатаchat_id <- function(bot, update) {  bot$sendMessage(update$message$chat_id,                   text = paste0("Чат id этого диалога: ", update$message$chat_id),                  parse_mode = "Markdown")}## метод возвращающий имяmy_name <- function(bot, update) {  bot$sendMessage(update$message$chat_id,                   text = paste0("Вас зовут ", update$message$from$first_name),                  parse_mode = "Markdown")}## метод возвращающий логинmy_username <- function(bot, update) {  bot$sendMessage(update$message$chat_id,                   text = paste0("Ваш логин ", update$message$from$username),                  parse_mode = "Markdown")}# создаём фильтры## сообщения с текстом Чат IDMessageFilters$chat_id <- BaseFilter(function(message) {  # проверяем текст сообщения  message$text == "Чат ID"})## сообщения с текстом Моё имяMessageFilters$name <- BaseFilter(function(message) {  # проверяем текст сообщения  message$text == "Моё имя"})## сообщения с текстом Мой логинMessageFilters$username <- BaseFilter(function(message) {  # проверяем текст сообщения  message$text == "Мой логин")# создаём обработчикиh_start    <- CommandHandler('start', start)h_chat_id  <- MessageHandler(chat_id, filters = MessageFilters$chat_id)h_name     <- MessageHandler(my_name, filters = MessageFilters$name)h_username <- MessageHandler(my_username, filters = MessageFilters$username)# добавляем обработчики в диспетчерupdater <- updater +             h_start +            h_chat_id +            h_name +            h_username# запускаем бота updater$start_polling()

Запустите приведённый выше пример кода, предварительно заменив 'ТОКЕН ВАШЕГО БОТА' на реальный токен, который вы получили при создании бота через BotFather (о создании бота я рассказывал в первой статье).

После запуска задайте боту команду /start, т.к. именно её мы определили для запуска клавиатуры.



Если на данный момент вам сложно разобрать приведённый пример кода, с созданием методов, фильтров и обработчиков, то следует вернуться к предыдущей статье, в которой я подробно всё это описал.


Мы создали 4 метода:


  • start Запуск клавиатуры
  • chat_id Запрос идентификатора чата
  • my_name Запрос своего имени
  • my_username Запрос своего логина

В объект MessageFilters добавили 3 фильтра сообщений, по их тексту:


  • chat_id Сообщения с текстом "Чат ID"
  • name Сообщения с текстом "Моё имя"
  • username Сообщения с текстом "Мой логин"

И создали 4 обработчика, которые по заданным командам и фильтрам будут выполнять указанные методы.


# создаём обработчикиh_start    <- CommandHandler('start', start)h_chat_id  <- MessageHandler(chat_id, filters = MessageFilters$chat_id)h_name     <- MessageHandler(my_name, filters = MessageFilters$name)h_username <- MessageHandler(my_username, filters = MessageFilters$username)

Сама клавиатура создаётся внутри метода start() командой ReplyKeyboardMarkup().


RKM <- ReplyKeyboardMarkup(    keyboard = list(      list(KeyboardButton("Чат ID")),      list(KeyboardButton("Моё имя")),      list(KeyboardButton("Мой логин"))    ),    resize_keyboard = FALSE,    one_time_keyboard = TRUE)

В нашем случае все кнопки мы расположили друг под другом, но мы можем расположить их в один ряд, внеся изменения в список списков кнопок. Т.к. один ряд внутри клавиатуры создаётся через вложенный список кнопок, то для того, что бы вывести наши кнопки в один ряд надо переписать часть кода по построению клавиатуры вот так:


RKM <- ReplyKeyboardMarkup(    keyboard = list(      list(          KeyboardButton("Чат ID"),          KeyboardButton("Моё имя"),          KeyboardButton("Мой логин")     )    ),    resize_keyboard = FALSE,    one_time_keyboard = TRUE)


Отправляется клавиатура в чат методом sendMessage(), в аргументе reply_markup.


  bot$sendMessage(update$message$chat_id,                  text = 'Выберите команду',                   reply_markup = RKM)

Inline клавиатура


Как я уже писал выше, Inline клавиатура привязана к конкретному сообщению. С ней работать несколько сложнее чем с основной клавиатурой.


Изначально вам необходимо добавить боту метод, для вызова Inline клавиатуры.


Для ответа на нажатие Inline кнопки также можно использовать метод бота answerCallbackQuery(), который может вывести уведомление в интерфейсе telegram, пользователю нажавшему Inline кнопку.


Данные отправленные с Inline кнопки не являются текстом, поэтому для их обработки необходимо создать специальный обработчик с помощью команды CallbackQueryHandler().


Код построения Inline клавиатуры который приводится в официальной справке пакета telegram.bot.


Код построения Inline клавиатуры из официальной справки
# Initialize botbot <- Bot(token = "TOKEN")chat_id <- "CHAT_ID"# Create Inline Keyboardtext <- "Could you type their phone number, please?"IKM <- InlineKeyboardMarkup(  inline_keyboard = list(    list(      InlineKeyboardButton(1),      InlineKeyboardButton(2),      InlineKeyboardButton(3)    ),    list(      InlineKeyboardButton(4),      InlineKeyboardButton(5),      InlineKeyboardButton(6)    ),    list(      InlineKeyboardButton(7),      InlineKeyboardButton(8),      InlineKeyboardButton(9)    ),    list(      InlineKeyboardButton("*"),      InlineKeyboardButton(0),      InlineKeyboardButton("#")    )  ))# Send Inline Keyboardbot$sendMessage(chat_id, text, reply_markup = IKM)

Строить Inline клавиатуру необходимо с помощью команды InlineKeyboardMarkup(), по такому же принципу, как и Reply клавиатуру. В InlineKeyboardMarkup() необходимо передать список, списков Inline кнопок, каждая отдельная кнопка создаётся функцией InlineKeyboardButton().


Inline кнопка может либо передавать боту какие-то данные с помощью аргумента callback_data, либо открывать какую-либо HTML страницу, заданную с помощью аргумента url.


В результате будет список, в котором каждый элемент так же является списком Inline кнопок, которые необходимо объединить в один ряд.


Далее мы рассмотрим несколько примеров ботов с Inline кнопками.


Пример простейшего бота с поддержкой InLine кнопок


Для начала мы напишем бота для экспресс тестирования на covid-19. По команде /test, он будет отправлять вам клавиатуру с двумя кнопками, в зависимости от нажатой кнопки он будет присылать вам сообщение с результатами вашего тестирования.


Код 2: Простейший бот с Inline клавиатурой
library(telegram.bot)# создаём экземпляр класса Updaterupdater <- Updater('ТОКЕН ВАШЕГО БОТА')# метод для отправки InLine клавиатурыtest <- function(bot, update) {  # создаём InLine клавиатуру  IKM <- InlineKeyboardMarkup(    inline_keyboard = list(      list(        InlineKeyboardButton("Да", callback_data = 'yes'),        InlineKeyboardButton("Нет", callback_data = 'no')      )    )  )  # Отправляем клавиатуру в чат  bot$sendMessage(update$message$chat_id,                   text = "Вы болете коронавирусом?",                   reply_markup = IKM)}# метод для обработки нажатия кнопкиanswer_cb <- function(bot, update) {  # полученные данные с кнопки  data <- update$callback_query$data  # получаем имя пользователя, нажавшего кнопку  uname <- update$effective_user()$first_name  # обработка результата  if ( data == 'no' ) {    msg <- paste0(uname, ", поздравляю, ваш тест на covid-19 отрицательный.")  } else {    msg <- paste0(uname, ", к сожалени ваш тест на covid-19 положительный.")  }  # Отправка сообщения  bot$sendMessage(chat_id = update$from_chat_id(),                  text = msg)  # сообщаем боту, что запрос с кнопки принят  bot$answerCallbackQuery(callback_query_id = update$callback_query$id) }# создаём обработчикиinline_h      <- CommandHandler('test', test)query_handler <- CallbackQueryHandler(answer_cb)# добавляем обработчики в диспетчерupdater <- updater + inline_h + query_handler# запускаем ботаupdater$start_polling()

Запустите приведённый выше пример кода, предварительно заменив 'ТОКЕН ВАШЕГО БОТА' на реальный токен, который вы получили при создании бота через BotFather (о создании бота я рассказывал в первой статье).

Результат:


Мы создали два метода:


  • 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 мы можем под нажатие каждой кнопки написать отдельный метод:


Код 3: Разделяем методы под каждую Inline кнопку
library(telegram.bot)# создаём экземпляр класса Updaterupdater <- Updater('ТОКЕН ВАШЕГО БОТА')# метод для отправки InLine клавиатурыtest <- function(bot, update) {    # создаём InLine клавиатуру  IKM <- InlineKeyboardMarkup(    inline_keyboard = list(      list(        InlineKeyboardButton("Да", callback_data = 'yes'),        InlineKeyboardButton("Нет", callback_data = 'no')      )    )  )  # Отправляем клавиатуру в чат  bot$sendMessage(update$message$chat_id,                   text = "Вы болете коронавирусом?",                   reply_markup = IKM)}# метод для обработки нажатия кнопки Даanswer_cb_yes <- function(bot, update) {  # получаем имя пользователя, нажавшего кнопку  uname <- update$effective_user()$first_name  # обработка результата  msg <- paste0(uname, ", к сожалени ваш текст на covid-19 положительный.")  # Отправка сообщения  bot$sendMessage(chat_id = update$from_chat_id(),                  text = msg)  # сообщаем боту, что запрос с кнопки принят  bot$answerCallbackQuery(callback_query_id = update$callback_query$id) }# метод для обработки нажатия кнопки Нетanswer_cb_no <- function(bot, update) {  # получаем имя пользователя, нажавшего кнопку  uname <- update$effective_user()$first_name  msg <- paste0(uname, ", поздравляю, ваш текст на covid-19 отрицательный.")  # Отправка сообщения  bot$sendMessage(chat_id = update$from_chat_id(),                  text = msg)  # сообщаем боту, что запрос с кнопки принят  bot$answerCallbackQuery(callback_query_id = update$callback_query$id) }# создаём обработчикиinline_h          <- CommandHandler('test', test)query_handler_yes <- CallbackQueryHandler(answer_cb_yes, pattern = 'yes')query_handler_no  <- CallbackQueryHandler(answer_cb_no, pattern = 'no')# добавляем обработчики в диспетчерupdater <- updater +             inline_h +             query_handler_yes +            query_handler_no# запускаем ботаupdater$start_polling()

Запустите приведённый выше пример кода, предварительно заменив 'ТОКЕН ВАШЕГО БОТА' на реальный токен, который вы получили при создании бота через BotFather (о создании бота я рассказывал в первой статье).

Теперь мы написали 2 отдельных метода, т.е. по одному методу, под нажатие каждой кнопки, и использовали аргумент pattern, при создании их обработчиков:


query_handler_yes <- CallbackQueryHandler(answer_cb_yes, pattern = 'yes')query_handler_no  <- CallbackQueryHandler(answer_cb_no, pattern = 'no')

Заканчивается код метода answer_cb командой bot$answerCallbackQuery(callback_query_id = update$callback_query$id), которая сообщает боту, что данные с inline клавиатуры получены.


Пример бота, который сообщает текущую погоду по выбранному городу


Давайте попробуем написать бота, который запрашивает данные о погоде.


Логика его работы будет следующая. Изначально командой /start вы вызываете основную клавиатуру, в которой присутствует всего одна кнопка "Погода". Нажав на эту кнопку вы получаете сообщение с Inline клавиатурой, для выбора города, по которому требуется узнать текущую погоду. Выбираете один из городов, и получаете текущую погоду.


В этом примере кода мы будем использовать несколько дополнительных пакетов:


  • httr пакет для работы с HTTP запросами, на основе которых построена работа с любым API. В нашем случае мы будем использовать бесплатный API openweathermap.org.
  • stringr пакет для работы с текстом, в нашем случае мы будем его использовать для формирования сообщения о погоде в выбранном городе.

Код 4: Бот, который сообщает текущую погоду по выбранному городу
library(telegram.bot)library(httr)library(stringr)# создаём экземпляр класса Updaterupdater <- Updater('ТОКЕН ВАШЕГО БОТА')# создаём методы## метод для запуска основной клавиатурыstart <- function(bot, update) {  # создаём клавиатуру  RKM <- ReplyKeyboardMarkup(    keyboard = list(      list(        KeyboardButton("Погода")      )    ),    resize_keyboard = TRUE,    one_time_keyboard = TRUE  )  # отправляем клавиатуру  bot$sendMessage(update$message$chat_id,                  text = 'Выберите команду',                   reply_markup = RKM)}## Метод вызова Inine клавиатурыweather <- function(bot, update) {  IKM <- InlineKeyboardMarkup(    inline_keyboard = list(      list(        InlineKeyboardButton(text = 'Москва', callback_data = 'New York,us'),        InlineKeyboardButton(text = 'Санкт-Петербург', callback_data = 'Saint Petersburg'),        InlineKeyboardButton(text = 'Нью-Йорк', callback_data = 'New York')      ),      list(        InlineKeyboardButton(text = 'Екатеринбург', callback_data = 'Yekaterinburg,ru'),        InlineKeyboardButton(text = 'Берлин', callback_data = 'Berlin,de'),        InlineKeyboardButton(text = 'Париж', callback_data = 'Paris,fr')      ),      list(        InlineKeyboardButton(text = 'Рим', callback_data = 'Rome,it'),        InlineKeyboardButton(text = 'Одесса', callback_data = 'Odessa,ua'),        InlineKeyboardButton(text = 'Киев', callback_data = 'Kyiv,fr')      ),      list(        InlineKeyboardButton(text = 'Токио', callback_data = 'Tokyo'),        InlineKeyboardButton(text = 'Амстердам', callback_data = 'Amsterdam,nl'),        InlineKeyboardButton(text = 'Вашингтон', callback_data = 'Washington,us')      )    )  )  # Send Inline Keyboard  bot$sendMessage(chat_id = update$message$chat_id,                   text = "Выберите город",                   reply_markup = IKM)}# метод для сообщения погодыanswer_cb <- function(bot, update) {  # получаем из сообщения город  city <- update$callback_query$data  # отправляем запрос  ans <- GET('https://api.openweathermap.org/data/2.5/weather',              query = list(q     = city,                          lang  = 'ru',                          units = 'metric',                          appid = '4776568ccea136ffe4cda9f1969af340'))   # парсим ответ  result <- content(ans)  # формируем сообщение  msg <- str_glue("{result$name} погода:\n",                  "Текущая температура: {result$main$temp}\n",                  "Скорость ветра: {result$wind$speed}\n",                  "Описание: {result$weather[[1]]$description}")  # отправляем информацию о погоде  bot$sendMessage(chat_id = update$from_chat_id(),                  text    = msg)  bot$answerCallbackQuery(callback_query_id = update$callback_query$id) }# создаём фильтры## сообщения с текстом ПогодаMessageFilters$weather <- BaseFilter(function(message) {  # проверяем текст сообщения  message$text == "Погода"})# создаём обработчикиh_start         <- CommandHandler('start', start)h_weather       <- MessageHandler(weather, filters = MessageFilters$weather)h_query_handler <- CallbackQueryHandler(answer_cb)# добавляем обработчики в диспетчерupdater <- updater +               h_start +              h_weather +              h_query_handler# запускаем ботаupdater$start_polling()

Запустите приведённый выше пример кода, предварительно заменив 'ТОКЕН ВАШЕГО БОТА' на реальный токен, который вы получили при создании бота через BotFather (о создании бота я рассказывал в первой статье).

В результате наш бот будет работать примерно так:


Схематически данного бота можно изобрать вот так:


Мы создали 3 метода, доступные внутри нашего погодного бота:


  • start Запуск основной клавиатуры бота
  • weather Запуск Inline клавиатуры для выбора города
  • answer_cb Основной метод, который по заданному городу запрашивает в API погоду, и отправляет её в чат.

Метод start у нас запускается командой /start, что реализовано обработчиком CommandHandler('start', start).


Для запуска метода weather мы создали одноимённый фильтр:


# создаём фильтры## сообщения с текстом ПогодаMessageFilters$weather <- BaseFilter(function(message) {  # проверяем текст сообщения  message$text == "Погода"})

И вызываем этот метод следующим обработчиком сообщений: 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. Для установки воспользуйтесь приведённым ниже кодом.


install.packages('devtools')devtools::install_github('selesnow/habR')

Теперь рассмотрим код построения описанного выше бота:


Код 5: Бот который выводит список наиболее свежих статей по выбранному Хабу
library(telegram.bot)library(habR)# создаём экземпляр класса Updaterupdater <- Updater('ТОКЕН ВАШЕГО БОТА')# создаём методы## метод для запуска основной клавиатурыstart <- function(bot, update) {  # создаём клавиатуру  RKM <- ReplyKeyboardMarkup(    keyboard = list(      list(        KeyboardButton("Список статей")      )    ),    resize_keyboard = TRUE,    one_time_keyboard = TRUE  )  # отправляем клавиатуру  bot$sendMessage(update$message$chat_id,                  text = 'Выберите команду',                   reply_markup = RKM)}## Метод вызова Inine клавиатурыhabs <- function(bot, update) {  IKM <- InlineKeyboardMarkup(    inline_keyboard = list(      list(        InlineKeyboardButton(text = 'R', callback_data = 'R'),        InlineKeyboardButton(text = 'Data Mining', callback_data = 'data_mining'),        InlineKeyboardButton(text = 'Data Engineering', callback_data = 'data_engineering')      ),      list(        InlineKeyboardButton(text = 'Big Data', callback_data = 'bigdata'),        InlineKeyboardButton(text = 'Python', callback_data = 'python'),        InlineKeyboardButton(text = 'Визуализация данных', callback_data = 'data_visualization')      )    )  )  # Send Inline Keyboard  bot$sendMessage(chat_id = update$message$chat_id,                   text = "Выберите Хаб",                   reply_markup = IKM)}# метод для сообщения погодыanswer_cb <- function(bot, update) {  # получаем из сообщения город  hub <- update$callback_query$data  # сообщение о том, что данные по кнопке получены  bot$answerCallbackQuery(callback_query_id = update$callback_query$id,                           text = 'Подождите несколько минут, запрос обрабатывается')   # сообщение о том, что надо подождать пока бот получит данные  mid <- bot$sendMessage(chat_id = update$from_chat_id(),                         text    = "Подождите несколько минут пока, я соберу данные по выбранному Хабу")  # парсим Хабр  posts <- head(habr_hub_posts(hub, 1), 5)  # удаляем сообщение о том, что надо подождать  bot$deleteMessage(update$from_chat_id(), mid$message_id)   # формируем список кнопок  keys <- lapply(1:5, function(x) list(InlineKeyboardButton(posts$title[x], url = posts$link[x])))  # формируем клавиатуру  IKM <- InlineKeyboardMarkup(    inline_keyboard =  keys     )  # отправляем информацию о погоде  bot$sendMessage(chat_id = update$from_chat_id(),                  text    = paste0("5 наиболее свежих статей из Хаба ", hub),                  reply_markup = IKM)}# создаём фильтры## сообщения с текстом ПогодаMessageFilters$hubs <- BaseFilter(function(message) {  # проверяем текст сообщения  message$text == "Список статей"})# создаём обработчикиh_start         <- CommandHandler('start', start)h_hubs          <- MessageHandler(habs, filters = MessageFilters$hubs)h_query_handler <- CallbackQueryHandler(answer_cb)# добавляем обработчики в диспетчерupdater <- updater +   h_start +  h_hubs  +  h_query_handler# запускаем ботаupdater$start_polling()

Запустите приведённый выше пример кода, предварительно заменив 'ТОКЕН ВАШЕГО БОТА' на реальный токен, который вы получили при создании бота через BotFather (о создании бота я рассказывал в первой статье).

В итоге мы получим вот такой результат:


Список доступных для выбора Хабов мы вбили хардкодом, в методе habs:


## Метод вызова Inine клавиатурыhabs <- function(bot, update) {  IKM <- InlineKeyboardMarkup(    inline_keyboard = list(      list(        InlineKeyboardButton(text = 'R', callback_data = 'r'),        InlineKeyboardButton(text = 'Data Mining', callback_data = 'data_mining'),        InlineKeyboardButton(text = 'Data Engineering', callback_data = 'data_engineering')      ),      list(        InlineKeyboardButton(text = 'Big Data', callback_data = 'bigdata'),        InlineKeyboardButton(text = 'Python', callback_data = 'python'),        InlineKeyboardButton(text = 'Визуализация данных', callback_data = 'data_visualization')      )    )  )  # Send Inline Keyboard  bot$sendMessage(chat_id = update$message$chat_id,                   text = "Выберите Хаб",                   reply_markup = IKM)}

Список статей из указанного Хаба мы получаем командой habr_hub_posts(), из пакета habR. При этом указываем, что нам не требуется список статей за всё время, а только первая страница на которой располагаются 20 статей. Из полученной таблицы с помощью команды head() оставляем только 5 самых верхних, которые и являются самыми свежими статьями.


  # парсим Хабр  posts <- head(habr_hub_posts(hub, 1), 5)

Логика очень схожа с предыдущим ботом, но в данном случае Inline клавиатуру со списком статей мы генерируем динамически с помощью функции lapply().


  # формируем список кнопок  keys <- lapply(1:5, function(x) list(InlineKeyboardButton(posts$title[x], url = posts$link[x])))  # формируем клавиатуру  IKM <- InlineKeyboardMarkup(    inline_keyboard =  keys     )

В текст кнопки мы подставляем название статьи posts$title[x], а в аргумент url ссылку на статью: url = posts$link[x].


Далее, создаём фильтр, обработчики и запускаем нашего бота.


Заключение


Теперь написанные вами боты будут значительно удобней в работе, за счёт того, что управление ими будет осуществляться с клавиатуры, а не вводом команд. Как минимум при взаимодействии с ботом через смартфон клавиатура ощутимо упростит процесс его использования.


В следующей статье мы разберёмся как строить логический диалог с ботом, и работать с базами данных.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru