Пишемо telegram бота мовою R (частина 3): Як додати боту підтримку клавіатури

Це третя стаття із серії "Пишемо telegram бота мовою R". У попередніх публікаціях ми навчилися створювати телеграм бота, надсилати через нього повідомлення, додали боту команди та фільтри повідомлень. Тому перед тим як приступити до читання цієї статті я вкрай рекомендую ознайомитися з попередніми, т.к. тут я вже не зупинятиму на описаних раніше основах ботобудування.

У цій статті ми підвищимо юзабіліті нашого бот за рахунок додавання клавіатури, яка зробить інтерфейс бот інтуїтивно зрозумілим, і простим у використанні.

Пишемо telegram бота мовою R (частина 3): Як додати боту підтримку клавіатури

Всі статті із серії "Пишемо telegram бота мовою R"

  1. Створюємо бота і відправляємо за його допомогою повідомлення в telegram
  2. Додаємо боту підтримку команд та фільтри повідомлень
  3. Як додати боту підтримку клавіатури

Зміст

Якщо ви цікавитеся аналізом даних можливо вам будуть цікаві мої телеграма и 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 Keyboard
text <- "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 Keyboard
bot$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)

# создаём экземпляр класса Updater
updater <- 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")

}

# создаём фильтры
## сообщения с текстом Чат ID
MessageFilters$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, т.к. саме її ми визначили для запуску клавіатури.

Пишемо telegram бота мовою R (частина 3): Як додати боту підтримку клавіатури

Якщо на даний момент вам складно розібрати наведений приклад коду, зі створенням методів, фільтрів та обробників, слід повернутися до попередньої статті, В якій я докладно все це описав.

Ми створили 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
)

Пишемо telegram бота мовою R (частина 3): Як додати боту підтримку клавіатури

Відправляється клавіатура в чат методом 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 bot
bot <- Bot(token = "TOKEN")
chat_id <- "CHAT_ID"

# Create Inline Keyboard
text <- "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 Keyboard
bot$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)

# создаём экземпляр класса Updater
updater <- 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 (про створення бота я розповідав у першій статті).

Результат:
Пишемо telegram бота мовою R (частина 3): Як додати боту підтримку клавіатури

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

  • тест — Для надсилання в чат 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)

# создаём экземпляр класса Updater
updater <- 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)

# создаём экземпляр класса Updater
updater <- 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 (про створення бота я розповідав у першій статті).

В результаті наш бот працюватиме приблизно так:
Пишемо telegram бота мовою R (частина 3): Як додати боту підтримку клавіатури

Схематично цього робота можна вибрати так:
Пишемо telegram бота мовою R (частина 3): Як додати боту підтримку клавіатури

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

  • старт - Запуск основної клавіатури робота
  • погода — Запуск клавіатури Inline для вибору міста
  • answer_cb - Основний метод, який по заданому місту запитує в API погоду, і відправляє її в чат.

метод старт у нас запускається командою /start, що реалізовано обробником CommandHandler('start', start).

Для запуску методу погода ми створили однойменний фільтр:

# создаём фильтры
## сообщения с текстом Погода
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)

# создаём экземпляр класса Updater
updater <- 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 (про створення бота я розповідав у першій статті).

У результаті ми отримаємо такий результат:
Пишемо telegram бота мовою R (частина 3): Як додати боту підтримку клавіатури

Список доступних для вибору Хабов ми вбили хардкодом, у методі 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].

Далі, створюємо фільтр, обробники та запускаємо нашого бота.

Висновок

Тепер написані вами роботи будуть значно зручнішими в роботі, за рахунок того, що управління ними здійснюватиметься з клавіатури, а не введенням команд. Як мінімум, при взаємодії з ботом через смартфон клавіатура суттєво спростить процес його використання.

У наступній статті ми розберемося як будувати логічний діалог з ботом і працювати з базами даних.

Джерело: habr.com

Додати коментар або відгук