ProHoster > Blog > Administrácia > Písanie telegramového robota v R (časť 3): Ako pridať podporu klávesnice do robota
Písanie telegramového robota v R (časť 3): Ako pridať podporu klávesnice do robota
Toto je tretí článok zo série „Písanie telegramového robota v R“. V predchádzajúcich publikáciách sme sa naučili, ako vytvoriť telegramového robota, posielať cez neho správy, pridávať príkazy a filtre správ do robota. Preto skôr, ako začnete čítať tento článok, vrelo odporúčam prečítať si ho predchádzajúce, pretože Tu sa už nebudem zdržiavať skôr popísanými základmi stavby botov.
V tomto článku zlepšíme použiteľnosť nášho robota pridaním klávesnice, vďaka ktorej bude rozhranie robota intuitívne a ľahko použiteľné.
Všetky články zo série „Písanie telegramového robota v R“
V čase tohto písania telegram.bot umožňuje vytvoriť dva typy klávesníc:
Odpoveď – hlavná, bežná klávesnica, ktorá sa nachádza pod panelom na zadávanie textu správy. Takáto klávesnica jednoducho pošle textovú správu robotovi a ako text odošle text, ktorý je napísaný na samotnom tlačidle.
Inline – klávesnica spojená s konkrétnou správou robota. Táto klávesnica odosiela údaje robota spojené so stlačeným tlačidlom; tieto údaje sa môžu líšiť od textu napísaného na samotnom tlačidle. A takéto tlačidlá sú spracované cez CallbackQueryHandler.
Aby bot otvoril klávesnicu, je to potrebné pri odosielaní správy prostredníctvom metódy sendMessage(), odovzdajte predtým vytvorenú klávesnicu ako argument reply_markup.
Nižšie sa pozrieme na niekoľko príkladov.
Klávesnica odpovede
Ako som písal vyššie, toto je hlavná klávesnica na ovládanie botov.
Príklad vytvorenia Reply klávesnice z oficiálneho pomocníka
Vyššie uvedené je príklad z oficiálnej pomoci balíka telegram.bot. Ak chcete vytvoriť klávesnicu, použite funkciu ReplyKeyboardMarkup(), ktorý zase preberá zoznam zoznamov tlačidiel, ktoré sú vytvorené funkciou KeyboardButton().
Prečo v ReplyKeyboardMarkup() Potrebujete odovzdať nielen zoznam, ale aj zoznam zoznamov? Faktom je, že miniete hlavný zoznam a v ňom definujete každý riadok tlačidiel v samostatných zoznamoch, pretože Do jedného radu môžete umiestniť niekoľko tlačidiel.
argument resize_keyboard umožňuje automaticky vybrať optimálnu veľkosť tlačidiel klávesnice a argument one_time_keyboard umožňuje skryť klávesnicu po každom stlačení tlačidla.
Napíšme jednoduchého robota, ktorý bude mať 3 tlačidlá:
ID chatu - Vyžiadajte ID rozhovoru pre dialóg s robotom
Moje meno - Vyžiadajte si svoje meno
Moje prihlásenie - Vyžiadajte si svoje používateľské meno v telegrame
Kód 1: Jednoduchý robot s klávesnicou 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()
Spustite vyššie uvedený príklad kódu po nahradení 'Your BOT TOKEN' skutočným tokenom, ktorý ste dostali pri vytváraní robota cez Obaja Otec (Hovoril som o vytvorení robota v prvý článok).
Po spustení dajte robotovi príkaz /start, pretože To je presne to, čo sme definovali na spustenie klávesnice.
Ak je pre vás v súčasnosti ťažké analyzovať daný príklad kódu s vytvorením metód, filtrov a obslužných programov, mali by ste sa vrátiť k predchádzajúcemu článok, v ktorej som to všetko podrobne opísal.
Vytvorili sme 4 metódy:
štart — Spustenie klávesnice
chat_id — Vyžiadať ID chatu
my_name — Vyžiadajte si svoje meno
my_username — Vyžiadajte si prihlásenie
Namietať MessageFilters pridali 3 filtre správ na základe ich textu:
chat_id — správy s textom "Чат ID"
meno — Správy s textom "Моё имя"
užívateľské meno — správy s textom "Мой логин"
A vytvorili sme 4 handlery, ktoré na základe daných príkazov a filtrov budú vykonávať zadané metódy.
V našom prípade sme všetky tlačidlá umiestnili pod seba, ale môžeme ich usporiadať do jedného radu vykonaním zmien v zozname zoznamov tlačidiel. Pretože jeden riadok vnútri klávesnice je vytvorený prostredníctvom vnoreného zoznamu tlačidiel, potom, aby sme mohli zobraziť naše tlačidlá v jednom riadku, musíme prepísať časť kódu na zostavenie klávesnice takto:
Klávesnica sa odošle do chatu pomocou metódy sendMessage(), v argumente reply_markup.
bot$sendMessage(update$message$chat_id,
text = 'Выберите команду',
reply_markup = RKM)
Inline klávesnica
Ako som písal vyššie, Inline klávesnica je viazaná na konkrétnu správu. Práca s ňou je o niečo náročnejšia ako s hlavnou klávesnicou.
Spočiatku musíte do robota pridať metódu na volanie vloženej klávesnice.
Ak chcete reagovať na kliknutie na tlačidlo Inline, môžete použiť aj metódu robota answerCallbackQuery(), ktorý môže používateľovi, ktorý stlačí tlačidlo Inline, zobraziť upozornenie v rozhraní telegramu.
Údaje odoslané z tlačidla Inline nie sú textové, takže na ich spracovanie je potrebné vytvoriť špeciálny handler pomocou príkazu CallbackQueryHandler().
Kód na zostavenie klávesnice Inline, ktorý je uvedený v oficiálnej pomoci balíka telegram.bot.
Kód na zostavenie klávesnice Inline z oficiálnej pomoci
Pomocou príkazu musíte zostaviť vloženú klávesnicu InlineKeyboardMarkup(), na rovnakom princípe ako klávesnica Reply. IN InlineKeyboardMarkup() je potrebné odovzdať zoznam zoznamov Inline tlačidiel, pričom každé jednotlivé tlačidlo je vytvorené funkciou InlineKeyboardButton().
Vložené tlačidlo môže buď odovzdať niektoré údaje robotovi pomocou argumentu callback_dataalebo otvorte akúkoľvek stránku HTML určenú pomocou argumentu url.
Výsledkom bude zoznam, v ktorom je každý prvok zároveň zoznamom tlačidiel Inline, ktoré je potrebné spojiť do jedného riadku.
Ďalej sa pozrieme na niekoľko príkladov robotov s tlačidlami Inline.
Príklad jednoduchého bota s podporou tlačidiel InLine
Najprv napíšeme robota na expresné testovanie na COVID-19. Podľa príkazu /test, pošle vám klávesnicu s dvoma tlačidlami, v závislosti od stlačeného tlačidla vám pošle správu s výsledkami vášho testovania.
Kód 2: Najjednoduchší robot s vloženou klávesnicou
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()
Spustite vyššie uvedený príklad kódu po nahradení 'Your BOT TOKEN' skutočným tokenom, ktorý ste dostali pri vytváraní robota cez Obaja Otec (Hovoril som o vytvorení robota v prvý článok).
Výsledok:
Vytvorili sme dve metódy:
test — Na odoslanie do chatu Inline klávesnica
answer_cb — Na spracovanie údajov odoslaných z klávesnice.
Údaje, ktoré sa budú odosielať z každého tlačidla, sú špecifikované v argumente callback_data, pri vytváraní tlačidla. Údaje odoslané z tlačidla môžete prijímať pomocou konštruktu update$callback_query$data, vo vnútri metódy answer_cb.
Aby robot reagoval na vloženú klávesnicu, metóda answer_cb spracované špeciálnym manipulátorom: CallbackQueryHandler(answer_cb). Ktorý spustí zadanú metódu po kliknutí na tlačidlo Inline. Handler CallbackQueryHandler má dva argumenty:
callback — Metóda, ktorú treba spustiť
pattern — Filtrujte podľa údajov, ktoré sú viazané na tlačidlo pomocou argumentu callback_data.
V súlade s tým pomocou argumentu pattern Na stlačenie každého tlačidla môžeme napísať samostatnú metódu:
Kód 3: Samostatné metódy pre každé tlačidlo 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()
Spustite vyššie uvedený príklad kódu po nahradení 'Your BOT TOKEN' skutočným tokenom, ktorý ste dostali pri vytváraní robota cez Obaja Otec (Hovoril som o vytvorení robota v prvý článok).
Teraz sme napísali 2 samostatné metódy t.j. jeden spôsob, pre každé stlačenie tlačidla a použitý argument pattern, pri vytváraní ich handlerov:
Kód metódy končí answer_cb tímom bot$answerCallbackQuery(callback_query_id = update$callback_query$id), ktorý robotovi oznámi, že boli prijaté údaje z vloženej klávesnice.
Príklad robota, ktorý hlási aktuálne počasie pre vybrané mesto
Skúsme napísať robota, ktorý požaduje údaje o počasí.
Logika jeho práce bude nasledovná. Spočiatku tým /start voláte na hlavnú klávesnicu, ktorá má iba jedno tlačidlo „Počasie“. Kliknutím na toto tlačidlo dostanete pomocou klávesnice Inline správu na výber mesta, pre ktoré chcete zistiť aktuálne počasie. Vyberte jedno z miest a získajte aktuálne počasie.
V tomto príklade kódu použijeme niekoľko dodatočných balíkov:
httr — balík na prácu s požiadavkami HTTP, na základe ktorého je postavená práca s ľubovoľným API. V našom prípade použijeme bezplatné API openweathermap.org.
stringr — balík na prácu s textom, v našom prípade ho použijeme na vygenerovanie správy o počasí vo vybranom meste.
Kód 4: Robot, ktorý hlási aktuálne počasie pre vybrané mesto
Spustite vyššie uvedený príklad kódu po nahradení 'Your BOT TOKEN' skutočným tokenom, ktorý ste dostali pri vytváraní robota cez Obaja Otec (Hovoril som o vytvorení robota v prvý článok).
V dôsledku toho bude náš robot fungovať takto:
Schematicky môže byť tento robot znázornený takto:
V našom meteorologickom robote sme vytvorili 3 dostupné metódy:
Začať — Spustite hlavnú klávesnicu robota
počasie — Spustite inline klávesnicu a vyberte mesto
answer_cb — Hlavná metóda, ktorá si vyžiada počasie z API pre dané mesto a pošle ho do chatu.
metóda Začať spustíme ho príkazom /start, ktorú realizuje handler CommandHandler('start', start).
Ak chcete spustiť metódu počasie vytvorili sme filter s rovnakým názvom:
# создаём фильтры
## сообщения с текстом Погода
MessageFilters$weather <- BaseFilter(function(message) {
# проверяем текст сообщения
message$text == "Погода"
}
)
A túto metódu voláme s nasledujúcou obsluhou správ: MessageHandler(weather, filters = MessageFilters$weather).
A na záver naša hlavná metóda answer_cb reaguje na stlačenie tlačidiel Inline, čo je implementované špeciálnym handlerom: CallbackQueryHandler(answer_cb).
Vo vnútri metódy answer_cb, načítame dáta odoslané z klávesnice a zapíšeme ich do premennej city: city <- update$callback_query$data. Potom si vyžiadame údaje o počasí z API, vygenerujeme a odošleme správu a nakoniec použijeme metódu answerCallbackQuery s cieľom informovať robota, že sme spracovali kliknutie na tlačidlo Inline.
Príklad robota, ktorý zobrazuje zoznam najnovších článkov s odkazmi na zadaný Hub z hab.com.
Predstavujem tohto robota, aby som vám ukázal, ako zobraziť tlačidlá Inline, ktoré vedú na webové stránky.
Logika tohto robota je podobná predchádzajúcej, najprv spustíme hlavnú klávesnicu pomocou príkazu /start. Potom nám robot poskytne zoznam 6 centier, z ktorých si môžeme vybrať, vyberieme centrum, ktoré nás zaujíma, a dostaneme 5 najnovších publikácií z vybraného centra.
Ako ste pochopili, v tomto prípade musíme získať zoznam článkov a na tento účel použijeme špeciálny balík habR, ktorá vám umožňuje vyžiadať si články od Habra a niektoré štatistiky o nich v R.
Nainštalujte balík habR možné iba z githubu, ku ktorému budete potrebovať ďalší balík devtools. Na inštaláciu použite nižšie uvedený kód.
Teraz sa pozrime na kód na zostavenie robota opísaného vyššie:
Kód 5: Robot, ktorý zobrazuje zoznam najnovších článkov vo vybranom centre
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()
Spustite vyššie uvedený príklad kódu po nahradení 'Your BOT TOKEN' skutočným tokenom, ktorý ste dostali pri vytváraní robota cez Obaja Otec (Hovoril som o vytvorení robota v prvý článok).
V dôsledku toho dostaneme tento výsledok:
Napevno sme zakódovali zoznam Hubov dostupných na výber v metóde habs:
Príkazom dostaneme zoznam článkov zo zadaného Hubu habr_hub_posts(), z balíka habR. Zároveň upozorňujeme, že nepotrebujeme zoznam článkov na celý čas, ale iba prvú stranu, na ktorej sa nachádza 20 článkov. Z výslednej tabuľky pomocou príkazu head() Necháme len 5 najlepších, čo sú najnovšie články.
Logika je veľmi podobná predchádzajúcemu robotovi, ale v tomto prípade generujeme Inline klávesnicu so zoznamom článkov dynamicky pomocou funkcie lapply().
Do textu tlačidla vložíme názov článku posts$title[x], a v argumentácii url odkaz na článok: url = posts$link[x].
Ďalej vytvoríme filter, obslužné programy a spustíme nášho robota.
Záver
Teraz bude používanie robotov, ktoré napíšete, oveľa pohodlnejšie, pretože sa budú ovládať z klávesnice a nie zadávaním príkazov. Minimálne pri interakcii s botom cez smartfón klávesnica výrazne zjednoduší proces jej používania.
V ďalšom článku prídeme na to, ako vybudovať logický dialóg s botom a pracovať s databázami.