ProHoster > Blog > administração > Escrevendo um bot de telegrama em R (parte 3): como adicionar suporte de teclado a um bot
Escrevendo um bot de telegrama em R (parte 3): como adicionar suporte de teclado a um bot
Este é o terceiro artigo da série “Escrevendo um bot de telegrama em R”. Nas publicações anteriores, aprendemos como criar um bot de telegrama, enviar mensagens por meio dele, adicionar comandos e filtros de mensagens ao bot. Portanto, antes de começar a ler este artigo, recomendo fortemente que você leia anterior, porque Aqui não vou mais me alongar nos fundamentos da construção de bots descritos anteriormente.
Neste artigo, melhoraremos a usabilidade do nosso bot adicionando um teclado, o que tornará a interface do bot intuitiva e fácil de usar.
Todos os artigos da série “Escrevendo um bot de telegrama em R”
Se você estiver interessado em análise de dados, talvez esteja interessado em meu telegrama и Youtube canais. A maior parte do conteúdo é dedicada à linguagem R.
No momento em que este livro foi escrito telegram.bot permite criar dois tipos de teclados:
Responder - O teclado principal normal, localizado sob o painel de entrada de texto da mensagem. Esse teclado simplesmente envia uma mensagem de texto para o bot e, como texto, enviará o texto que está escrito no próprio botão.
Inline – Teclado associado a uma mensagem específica do bot. Este teclado envia os dados do bot associados ao botão pressionado; esses dados podem diferir do texto escrito no próprio botão. E esses botões são processados através CallbackQueryHandler.
Para que o bot abra o teclado é necessário ao enviar uma mensagem através do método sendMessage(), passe o teclado criado anteriormente como argumento reply_markup.
Abaixo veremos vários exemplos.
Responder teclado
Como escrevi acima, este é o teclado principal de controle do bot.
Um exemplo de criação de um teclado de resposta na ajuda oficial
O acima é um exemplo da ajuda oficial do pacote telegram.bot. Para criar um teclado, use a função ReplyKeyboardMarkup(), que por sua vez pega uma lista de listas de botões criadas pela função KeyboardButton().
Por que em ReplyKeyboardMarkup() Você precisa passar não apenas uma lista, mas uma lista de listas? A questão é que você passa a lista principal, e nela você define cada linha de botões em listas separadas, pois Você pode colocar vários botões em uma linha.
Argumento resize_keyboard permite que você selecione automaticamente o tamanho ideal dos botões do teclado e o argumento one_time_keyboard permite ocultar o teclado após cada pressionamento de botão.
Vamos escrever um bot simples que terá 3 botões:
ID de bate-papo - Solicita ID de bate-papo do diálogo com o bot
Meu nome - Solicite seu nome
Meu login - Solicite seu nome de usuário no Telegram
Código 1: bot simples com teclado de resposta
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()
Execute o exemplo de código acima, após substituir 'YOUR BOT TOKEN' pelo token real que você recebeu ao criar o bot via BotPai (Falei sobre a criação de um bot em primeiro artigo).
Após o lançamento, dê um comando ao bot /start, porque Isso é exatamente o que definimos para iniciar o teclado.
Se no momento você tem dificuldade em analisar o exemplo de código fornecido, com a criação de métodos, filtros e manipuladores, então você deve retornar ao anterior статье, no qual descrevi tudo isso em detalhes.
Criamos 4 métodos:
iniciar – Inicie o teclado
chat_id — Solicita ID de bate-papo
meu_nome — Solicite seu nome
my_username — Solicite seu login
Para objetar Filtros de mensagens adicionou 3 filtros de mensagens com base no texto:
chat_id — Mensagens com texto "Чат ID"
nome – Mensagens com texto "Моё имя"
nome de usuário – Mensagens com texto "Мой логин"
E criamos 4 manipuladores que, com base em determinados comandos e filtros, executarão os métodos especificados.
No nosso caso, colocamos todos os botões uns abaixo dos outros, mas podemos organizá-los em uma linha fazendo alterações na lista de listas de botões. Porque uma linha dentro do teclado é criada através de uma lista aninhada de botões, então, para exibir nossos botões em uma linha, precisamos reescrever parte do código para construir o teclado assim:
O teclado é enviado para o chat usando o método sendMessage(), no argumento reply_markup.
bot$sendMessage(update$message$chat_id,
text = 'Выберите команду',
reply_markup = RKM)
Teclado embutido
Como escrevi acima, o teclado Inline está vinculado a uma mensagem específica. É um pouco mais difícil de trabalhar do que o teclado principal.
Inicialmente, você precisa adicionar um método ao bot para chamar o teclado Inline.
Para responder a um clique de botão Inline, você também pode usar o método bot answerCallbackQuery(), que pode exibir uma notificação na interface do telegrama para o usuário que pressiona o botão Inline.
Os dados enviados do botão Inline não são texto, portanto, para processá-los, você precisa criar um manipulador especial usando o comando CallbackQueryHandler().
O código para construir um teclado Inline que é fornecido na ajuda oficial do pacote telegram.bot.
Código para construir um teclado Inline da ajuda oficial
Você precisa construir um teclado Inline usando o comando InlineKeyboardMarkup(), no mesmo princípio do teclado Responder. EM InlineKeyboardMarkup() é necessário passar uma lista de listas de botões Inline, cada botão individual é criado pela função InlineKeyboardButton().
Um botão embutido pode passar alguns dados para o bot usando um argumento callback_dataou abra qualquer página HTML especificada usando o argumento url.
O resultado será uma lista em que cada elemento também é uma lista de botões Inline que precisam ser combinados em uma linha.
A seguir veremos vários exemplos de bots com botões Inline.
Um exemplo de bot simples com suporte para botões InLine
Primeiro, escreveremos um bot para testes expressos para covid-19. Por comando /test, ele lhe enviará um teclado com dois botões, dependendo do botão pressionado ele lhe enviará uma mensagem com o resultado do seu teste.
Código 2: O bot mais simples com teclado 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()
Execute o exemplo de código acima, após substituir 'YOUR BOT TOKEN' pelo token real que você recebeu ao criar o bot via BotPai (Falei sobre a criação de um bot em primeiro artigo).
Resultado:
Criamos dois métodos:
teste — Para enviar para bate-papo Teclado embutido
resposta_cb — Para processar dados enviados do teclado.
Os dados que serão enviados de cada botão são especificados no argumento callback_data, ao criar um botão. Você pode receber os dados enviados do botão usando a construção update$callback_query$data, dentro do método resposta_cb.
Para o bot reagir ao teclado Inline, método resposta_cb processado por um manipulador especial: CallbackQueryHandler(answer_cb). Que executa o método especificado quando o botão Inline é clicado. Manipulador CallbackQueryHandler leva dois argumentos:
callback — O método que precisa ser executado
pattern — Filtrar por dados vinculados ao botão usando um argumento callback_data.
Assim, usando o argumento pattern Podemos escrever um método separado para pressionar cada botão:
Código 3: Métodos separados para cada botão 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()
Execute o exemplo de código acima, após substituir 'YOUR BOT TOKEN' pelo token real que você recebeu ao criar o bot via BotPai (Falei sobre a criação de um bot em primeiro artigo).
Agora escrevemos 2 métodos separados, ou seja, um método, cada botão pressionado e usou o argumento pattern, ao criar seus manipuladores:
O código do método termina resposta_cb a equipe bot$answerCallbackQuery(callback_query_id = update$callback_query$id), que informa ao bot que os dados do teclado embutido foram recebidos.
Um exemplo de bot que informa o clima atual de uma cidade selecionada
Vamos tentar escrever um bot que solicite dados meteorológicos.
A lógica do seu trabalho será a seguinte. Inicialmente pela equipe /start você liga para o teclado principal, que possui apenas um botão “Tempo”. Ao clicar neste botão você receberá uma mensagem com o teclado Inline para selecionar a cidade para a qual deseja saber o clima atual. Selecione uma das cidades e obtenha o clima atual.
Neste exemplo de código usaremos vários pacotes adicionais:
httr — um pacote para trabalhar com solicitações HTTP, com base no qual é construído o trabalho com qualquer API. No nosso caso usaremos a API gratuita openweathermap.org.
stringr — um pacote para trabalhar com texto, no nosso caso iremos utilizá-lo para gerar uma mensagem sobre o clima da cidade selecionada.
Código 4: Um bot que informa o clima atual da cidade selecionada
Execute o exemplo de código acima, após substituir 'YOUR BOT TOKEN' pelo token real que você recebeu ao criar o bot via BotPai (Falei sobre a criação de um bot em primeiro artigo).
Como resultado, nosso bot funcionará mais ou menos assim:
Esquematicamente, este bot pode ser representado assim:
Criamos 3 métodos disponíveis em nosso bot meteorológico:
começo — Inicie o teclado bot principal
clima — Inicie o teclado Inline para selecionar uma cidade
resposta_cb — Principal método que solicita a previsão do tempo da API de uma determinada cidade e envia para o chat.
método começo nós o lançamos com o comando /start, que é implementado pelo manipulador CommandHandler('start', start).
Para executar um método clima criamos um filtro com o mesmo nome:
# создаём фильтры
## сообщения с текстом Погода
MessageFilters$weather <- BaseFilter(function(message) {
# проверяем текст сообщения
message$text == "Погода"
}
)
E chamamos esse método com o seguinte manipulador de mensagens: MessageHandler(weather, filters = MessageFilters$weather).
E no final, nosso método principal resposta_cb reage ao pressionar botões Inline, que é implementado por um manipulador especial: CallbackQueryHandler(answer_cb).
Dentro de um método resposta_cb, lemos os dados enviados do teclado e os escrevemos em uma variável city: city <- update$callback_query$data. Em seguida, solicitamos dados meteorológicos da API, geramos e enviamos uma mensagem e, por fim, usamos o método answerCallbackQuery para informar ao bot que processamos o clique do botão Inline.
Um exemplo de bot que exibe uma lista dos artigos mais recentes com links para o Hub especificado de habr.com.
Apresento este bot para mostrar como exibir botões Inline que levam a páginas da web.
A lógica deste bot é semelhante à anterior; inicialmente lançamos o teclado principal com o comando /start. A seguir, o bot nos dá uma lista de 6 hubs para escolher, selecionamos o hub que nos interessa e recebemos as 5 publicações mais recentes do Hub selecionado.
Como você entende, neste caso precisamos obter uma lista de artigos, e para isso utilizaremos um pacote especial habR, que permite solicitar artigos do Habra e algumas estatísticas sobre eles no R.
Instalar pacote habR só é possível no github, para o qual você precisará de um pacote adicional devtools. Para instalar, use o código abaixo.
Agora vamos dar uma olhada no código para construir o bot descrito acima:
Código 5: Um bot que exibe uma lista dos artigos mais recentes no Hub selecionado
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()
Execute o exemplo de código acima, após substituir 'YOUR BOT TOKEN' pelo token real que você recebeu ao criar o bot via BotPai (Falei sobre a criação de um bot em primeiro artigo).
Como resultado, obteremos este resultado:
Codificamos a lista de Hubs disponíveis para seleção no método habs:
Obtemos uma lista de artigos do Hub especificado com o comando habr_hub_posts(), do pacote habR. Ao mesmo tempo, ressaltamos que não precisamos de uma lista de artigos para todo o tempo, mas apenas da primeira página onde estão localizados 20 artigos. Da tabela resultante usando o comando head() Deixamos apenas o top 5, que são os artigos mais recentes.
Inserimos o título do artigo no texto do botão posts$title[x], e no argumento url link para o artigo: url = posts$link[x].
A seguir, criamos um filtro, manipuladores e lançamos nosso bot.
Conclusão
Agora os bots que você escreve serão muito mais convenientes de usar, pois serão controlados pelo teclado, e não pela digitação de comandos. No mínimo, ao interagir com um bot por meio de um smartphone, o teclado simplificará significativamente o processo de uso.
No próximo artigo descobriremos como construir um diálogo lógico com um bot e trabalhar com bancos de dados.