ProHoster > Blog > administracja > Pisanie telegramowego bota w R (część 3): Jak dodać obsługę klawiatury do bota
Pisanie telegramowego bota w R (część 3): Jak dodać obsługę klawiatury do bota
To już trzeci artykuł z serii „Pisanie bota telegramowego w R”. W poprzednich publikacjach dowiedzieliśmy się jak stworzyć bota telegramowego, wysyłać za jego pośrednictwem wiadomości, dodawać do bota polecenia i filtry wiadomości. Dlatego zanim zaczniesz czytać ten artykuł, gorąco polecam go przeczytać poprzedni, ponieważ Nie będę już rozwodzić się nad wcześniej opisanymi podstawami budowania botów.
W tym artykule poprawimy użyteczność naszego bota, dodając klawiaturę, dzięki której interfejs bota będzie intuicyjny i łatwy w użyciu.
Wszystkie artykuły z serii „Pisanie bota telegramowego w R”
W momencie pisania tego tekstu telegram.bot umożliwia utworzenie dwóch typów klawiatur:
Odpowiedź - główna, zwykła klawiatura, która znajduje się pod panelem wprowadzania tekstu wiadomości. Taka klawiatura po prostu wysyła do bota wiadomość tekstową, a jako tekst wyśle tekst, który jest zapisany na samym przycisku.
Inline — klawiatura powiązana z konkretną wiadomością od bota. Ta klawiatura wysyła do bota dane powiązane z naciśniętym przyciskiem; dane te mogą różnić się od tekstu zapisanego na samym przycisku. I takie przyciski są przetwarzane Funkcja obsługi zapytań zwrotnych.
Aby bot otworzył klawiaturę, jest to konieczne podczas wysyłania wiadomości tą metodą sendMessage(), podaj wcześniej utworzoną klawiaturę jako argument reply_markup.
Poniżej przyjrzymy się kilku przykładom.
Klawiatura odpowiedzi
Jak pisałem powyżej jest to główna klawiatura sterująca botem.
Przykład tworzenia klawiatury odpowiedzi z oficjalnej pomocy
Powyższy przykład pochodzi z oficjalnej pomocy pakietu telegram.bot. Aby utworzyć klawiaturę, użyj funkcji ReplyKeyboardMarkup(), co z kolei pobiera listę list przycisków tworzonych przez funkcję KeyboardButton().
Dlaczego w ReplyKeyboardMarkup() Czy musisz przekazać nie tylko listę, ale listę list? Faktem jest, że przekazujesz listę główną, a na niej definiujesz każdy rząd przycisków na osobnych listach, ponieważ Możesz umieścić kilka przycisków w jednym rzędzie.
argument resize_keyboard pozwala automatycznie wybrać optymalny rozmiar przycisków klawiatury i argumentu one_time_keyboard pozwala ukryć klawiaturę po każdym naciśnięciu przycisku.
Napiszmy prostego bota, który będzie miał 3 przyciski:
Identyfikator czatu — żądanie identyfikatora czatu dialogu z botem
Moje imię — poproś o podanie imienia
Mój login — poproś o nazwę użytkownika w telegramie
Kod 1: Prosty bot z klawiaturą odpowiedzi
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()
Uruchom powyższy przykładowy kod, po zastąpieniu „TWOJEGO ŻETONA BOTA” prawdziwym tokenem, który otrzymałeś podczas tworzenia bota poprzez Ojciec Bota (Mówiłem o stworzeniu bota w Pierwszy artykuł).
Po uruchomieniu wydaj botowi polecenie /start, ponieważ Dokładnie to zdefiniowaliśmy, aby uruchomić klawiaturę.
Jeśli w tej chwili trudno Ci przeanalizować podany przykładowy kod, wraz z utworzeniem metod, filtrów i handlerów, to powinieneś wrócić do poprzedniego Artykuł, w którym wszystko to szczegółowo opisałem.
Stworzyliśmy 4 metody:
start — Uruchom klawiaturę
chat_id — Poproś o identyfikator czatu
my_name — Poproś o podanie imienia
my_username — Poproś o login
Sprzeciwiać się Filtry wiadomości dodano 3 filtry wiadomości na podstawie ich tekstu:
chat_id — Wiadomości z tekstem "Чат ID"
nazwa — Wiadomości z tekstem "Моё имя"
nazwa użytkownika — Wiadomości z tekstem "Мой логин"
Stworzyliśmy 4 procedury obsługi, które na podstawie podanych poleceń i filtrów wykonają określone metody.
W naszym przypadku wszystkie przyciski umieściliśmy pod sobą, ale możemy je ułożyć w jednym rzędzie dokonując zmian na liście list przycisków. Ponieważ jeden wiersz wewnątrz klawiatury tworzony jest poprzez zagnieżdżoną listę przycisków, wówczas aby wyświetlić nasze przyciski w jednym rzędzie musimy przepisać część kodu budującego klawiaturę w następujący sposób:
Klawiatura jest wysyłana do czatu za pomocą metody sendMessage(), w argumentacji reply_markup.
bot$sendMessage(update$message$chat_id,
text = 'Выберите команду',
reply_markup = RKM)
Klawiatura wbudowana
Jak pisałem powyżej, klawiatura Inline jest powiązana z konkretnym komunikatem. Praca z nią jest nieco trudniejsza niż z klawiaturą główną.
Początkowo musisz dodać do bota metodę wywoływania klawiatury Inline.
Aby odpowiedzieć na kliknięcie przycisku Inline, możesz także skorzystać z metody bota answerCallbackQuery(), który może wyświetlić powiadomienie w interfejsie telegramu użytkownikowi, który naciśnie przycisk Inline.
Dane wysyłane z przycisku Inline nie są tekstem, dlatego aby je przetworzyć należy za pomocą polecenia utworzyć specjalny moduł obsługi CallbackQueryHandler().
Kod do zbudowania klawiatury Inline podany w oficjalnej pomocy pakietu telegram.bot.
Kod do zbudowania klawiatury Inline z oficjalnej pomocy
Musisz zbudować klawiaturę Inline za pomocą polecenia InlineKeyboardMarkup(), na tej samej zasadzie co klawiatura Odpowiedz. W InlineKeyboardMarkup() konieczne jest przekazanie listy list przycisków Inline, każdy indywidualny przycisk jest tworzony przez funkcję InlineKeyboardButton().
Przycisk wbudowany może przekazać botowi pewne dane za pomocą argumentu callback_datalub otwórz dowolną stronę HTML określoną za pomocą argumentu url.
Rezultatem będzie lista, w której każdy element jest jednocześnie listą przycisków Inline, które należy połączyć w jeden wiersz.
Następnie przyjrzymy się kilku przykładom botów z przyciskami Inline.
Przykład prostego bota z obsługą przycisków InLine
Na początek napiszemy bota do ekspresowych testów na covid-19. Na polecenie /test, wyśle Ci klawiaturę z dwoma przyciskami, w zależności od naciśniętego przycisku wyśle Ci wiadomość z wynikami testu.
Kod 2: Najprostszy bot z klawiaturą 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()
Uruchom powyższy przykładowy kod, po zastąpieniu „TWOJEGO ŻETONA BOTA” prawdziwym tokenem, który otrzymałeś podczas tworzenia bota poprzez Ojciec Bota (Mówiłem o stworzeniu bota w Pierwszy artykuł).
Wynik:
Stworzyliśmy dwie metody:
test — Aby wysłać do czatu Klawiatura wbudowana
odpowiedź_cb — Aby przetwarzać dane przesyłane z klawiatury.
Dane, które zostaną wysłane z każdego przycisku, są określone w argumencie callback_data, podczas tworzenia przycisku. Dane wysyłane z przycisku możesz odbierać za pomocą konstrukcji update$callback_query$data, wewnątrz metody odpowiedź_cb.
Aby bot reagował na klawiaturę Inline, metoda odpowiedź_cb przetwarzane przez specjalnego handlera: CallbackQueryHandler(answer_cb). Który uruchamia określoną metodę po kliknięciu przycisku Inline. Treser Funkcja obsługi zapytań zwrotnych przyjmuje dwa argumenty:
callback — Metoda, która ma zostać uruchomiona
pattern — Filtruj według danych powiązanych z przyciskiem za pomocą argumentu callback_data.
W związku z tym, używając argumentu pattern Możemy napisać osobną metodę naciskania każdego przycisku:
Kod 3: Oddzielne metody dla każdego przycisku 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()
Uruchom powyższy przykładowy kod, po zastąpieniu „TWOJEGO ŻETONA BOTA” prawdziwym tokenem, który otrzymałeś podczas tworzenia bota poprzez Ojciec Bota (Mówiłem o stworzeniu bota w Pierwszy artykuł).
Teraz napisaliśmy 2 oddzielne metody, tj. jedną metodę na każde naciśnięcie przycisku i użył argumentu pattern, podczas tworzenia ich procedur obsługi:
Kod metody kończy się odpowiedź_cb według zespołu bot$answerCallbackQuery(callback_query_id = update$callback_query$id), który informuje bota, że odebrane zostały dane z wbudowanej klawiatury.
Przykład bota raportującego aktualną pogodę dla wybranego miasta
Spróbujmy napisać bota żądającego danych o pogodzie.
Logika jego działania będzie następująca. Początkowo przez zespół /start wywołujesz klawiaturę główną, która ma tylko jeden przycisk „Pogoda”. Kliknięcie tego przycisku spowoduje wyświetlenie komunikatu z klawiaturą Inline w celu wybrania miasta, dla którego chcesz sprawdzić aktualną pogodę. Wybierz jedno z miast i poznaj aktualną pogodę.
W tym przykładzie kodu użyjemy kilku dodatkowych pakietów:
httr — pakiet do pracy z żądaniami HTTP, na podstawie którego budowana jest praca z dowolnym API. W naszym przypadku skorzystamy z darmowego API openweathermap.org.
stringr — pakiet do pracy z tekstem, w naszym przypadku wykorzystamy go do wygenerowania komunikatu o pogodzie w wybranym mieście.
Kod 4: Bot raportujący aktualną pogodę dla wybranego miasta
Uruchom powyższy przykładowy kod, po zastąpieniu „TWOJEGO ŻETONA BOTA” prawdziwym tokenem, który otrzymałeś podczas tworzenia bota poprzez Ojciec Bota (Mówiłem o stworzeniu bota w Pierwszy artykuł).
W rezultacie nasz bot będzie działał mniej więcej tak:
Schematycznie tego bota można przedstawić w następujący sposób:
Stworzyliśmy 3 metody dostępne w naszym bocie pogodowym:
początek — Uruchom główną klawiaturę bota
pogoda — Uruchom klawiaturę Inline, aby wybrać miasto
odpowiedź_cb — Główna metoda, która żąda pogody z API dla danego miasta i wysyła ją na czat.
metoda początek uruchamiamy go za pomocą polecenia /start, który jest implementowany przez procedurę obsługi CommandHandler('start', start).
Aby uruchomić metodę pogoda stworzyliśmy filtr o tej samej nazwie:
# создаём фильтры
## сообщения с текстом Погода
MessageFilters$weather <- BaseFilter(function(message) {
# проверяем текст сообщения
message$text == "Погода"
}
)
I wywołujemy tę metodę z następującą procedurą obsługi komunikatów: MessageHandler(weather, filters = MessageFilters$weather).
I na koniec nasza główna metoda odpowiedź_cb reaguje na wciśnięcie przycisków Inline, co jest realizowane przez specjalny handler: CallbackQueryHandler(answer_cb).
Wewnątrz metody odpowiedź_cb, odczytujemy dane przesłane z klawiatury i zapisujemy je do zmiennej city: city <- update$callback_query$data. Następnie żądamy danych pogodowych z API, generujemy i wysyłamy wiadomość, a na koniec korzystamy z metody answerCallbackQuery w celu poinformowania bota, że przetworzyliśmy kliknięcie przycisku Inline.
Przykład bota wyświetlającego listę najnowszych artykułów z linkami do określonego Huba www.habr.com.
Prezentuję tego bota, aby pokazać Ci, jak wyświetlić przyciski Inline prowadzące do stron internetowych.
Logika tego bota jest podobna do poprzedniego, początkowo uruchamiamy klawiaturę główną za pomocą polecenia /start. Następnie bot podaje nam listę 6 hubów do wyboru, wybieramy hub, który nas interesuje i odbieramy 5 najnowszych publikacji z wybranego Huba.
Jak rozumiesz, w tym przypadku musimy uzyskać listę artykułów i do tego użyjemy specjalnego pakietu habR, który umożliwia żądanie artykułów z Habra i niektórych statystyk na ich temat w R.
Zainstaluj pakiet habR możliwe tylko z githuba, do którego będziesz potrzebować dodatkowego pakietu devtools. Aby zainstalować użyj poniższego kodu.
Przyjrzyjmy się teraz kodowi budowy bota opisanego powyżej:
Kod 5: Bot wyświetlający listę najnowszych artykułów w wybranym Hubie
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()
Uruchom powyższy przykładowy kod, po zastąpieniu „TWOJEGO ŻETONA BOTA” prawdziwym tokenem, który otrzymałeś podczas tworzenia bota poprzez Ojciec Bota (Mówiłem o stworzeniu bota w Pierwszy artykuł).
W rezultacie otrzymamy taki wynik:
Zakodowaliśmy na stałe listę koncentratorów dostępnych do wyboru w metodzie habs:
Za pomocą polecenia otrzymujemy listę artykułów z określonego Huba habr_hub_posts(), z pakietu habR. Jednocześnie zwracamy uwagę, że nie potrzebujemy spisu artykułów na cały czas, a jedynie pierwszą stronę, na której znajduje się 20 artykułów. Z wynikowej tabeli za pomocą polecenia head() Zostawiamy tylko 5 najlepszych, czyli najnowsze artykuły.
Logika jest bardzo podobna do poprzedniego bota, jednak w tym przypadku klawiaturę Inline z listą artykułów generujemy dynamicznie za pomocą funkcji lapply().
Wstawiamy tytuł artykułu do tekstu przycisku posts$title[x]i w argumentacji url link do artykułu: url = posts$link[x].
Następnie tworzymy filtr, handlery i uruchamiamy naszego bota.
wniosek
Teraz obsługa botów, które napiszesz, będzie dużo wygodniejsza, bo sterować nimi będziesz z klawiatury, a nie poprzez wpisywanie poleceń. Przynajmniej podczas interakcji z botem za pośrednictwem smartfona klawiatura znacznie uprości proces jej obsługi.
W kolejnym artykule dowiemy się jak zbudować logiczny dialog z botem i pracować z bazami danych.