ProHoster > Блог > Pagdumala > Pagsulat og telegram bot sa R (bahin 4): Paghimo og makanunayon, lohikal nga dialogue sa bot
Pagsulat og telegram bot sa R (bahin 4): Paghimo og makanunayon, lohikal nga dialogue sa bot
Kung nabasa na nimo ang miaging tulo ka artikulo gikan sa kini nga serye, nan nahibal-an na nimo kung giunsa pagsulat ang mga bug-os nga telegram bot nga adunay keyboard.
Niini nga artikulo, mahibal-an naton kung giunsa pagsulat ang usa ka bot nga magpadayon sa usa ka makanunayon nga dayalogo. Mga. Ang bot mangutana kanimo og mga pangutana ug maghulat kanimo sa pagsulod sa pipila ka impormasyon. Depende sa datos nga imong gisulod, ang bot mohimo sa pipila ka mga aksyon.
Usab niini nga artikulo makakat-on kita kon sa unsang paagi sa paggamit sa usa ka database sa ilalum sa hood sa bot, sa atong panig-ingnan kini mao ang SQLite, apan kamo makahimo sa paggamit sa bisan unsa nga lain nga DBMS. Gisulat ko ang dugang nga detalye bahin sa pagpakig-uban sa mga database sa R nga pinulongan sa kini nga artikulo.
Ang tanan nga mga artikulo gikan sa serye nga "Pagsulat sa usa ka telegrama bot sa R"
Kung interesado ka sa pagtuki sa datos, mahimong interesado ka sa akong telegram и youtube mga kanal. Kadaghanan sa sulod niini gipahinungod sa R nga pinulongan.
Aron ang bot makahangyo ug datos gikan kanimo ug maghulat kanimo sa pagsulod sa bisan unsang impormasyon, kinahanglan nimo nga irekord ang kasamtangan nga kahimtang sa dayalogo. Ang labing maayo nga paagi sa pagbuhat niini mao ang paggamit sa usa ka matang sa naka-embed nga database, sama sa SQLite.
Mga. Ang lohika mahimong ingon sa mosunod. Gitawag namon ang pamaagi sa bot, ug ang bot nagsunud-sunod nga nangayo og pipila ka kasayuran gikan kanamo, ug sa matag lakang naghulat kini nga masulod kini nga kasayuran ug masusi kini.
Isulat namon ang pinakasimple nga posible nga bot, una kini mangutana sa imong ngalan, dayon ang imong edad, ug i-save ang nadawat nga datos sa database. Kung mangutana alang sa edad, susihon kung ang gisulod nga datos usa ka numero ug dili teksto.
Ang ingon nga yano nga dayalogo adunay tulo ra ka estado:
Ang pagsugod mao ang normal nga kahimtang sa bot, diin wala kini magdahom nga bisan unsang kasayuran gikan kanimo
wait_name - estado diin ang bot naghulat alang sa usa ka ngalan nga ipasulod
wait_age mao ang estado diin ang bot naghulat sa imong edad nga masulod, ang gidaghanon sa tibuok tuig.
Proseso sa pagtukod sa bot
Atol sa artikulo, maghimo kami usa ka bot nga lakang sa lakang; ang tibuuk nga proseso mahimong gihulagway nga eskematiko sama sa mosunod:
Naghimo kami usa ka bot config diin kami magtipig pipila ka mga setting. Sa among kaso, ang bot token, ug ang agianan sa database file.
Naghimo kami usa ka variable sa palibot diin ang agianan sa proyekto nga adunay bot itago.
Gihimo namo ang database mismo, ug daghang mga gimbuhaton aron ang bot maka-interact niini.
Gisulat namon ang mga pamaagi sa bot, i.e. ang mga gimbuhaton nga himuon niini.
Pagdugang mga filter sa mensahe. Uban sa tabang nga ang bot maka-access sa gikinahanglan nga mga pamaagi, depende sa kasamtangan nga kahimtang sa chat.
Nagdugang kami og mga tigdumala nga magkonektar sa mga sugo ug mga mensahe sa gikinahanglan nga mga pamaagi sa bot.
Atong ilunsad ang bot.
Ang istruktura sa proyekto sa bot
Alang sa kasayon, among bahinon ang code sa among bot, ug uban pang may kalabutan nga mga file, sa mosunod nga istruktura.
bot.R — ang nag-unang code sa among bot
db_bot_function.R - usa ka bloke sa code nga adunay mga gimbuhaton alang sa pagtrabaho sa usa ka database
bot_methods.R - code sa mga pamaagi sa bot
message_filters.R - mga filter sa mensahe
mga tigdumala.R - mga tigdumala
config.cfg - bot config
create_db_data.sql — SQL script alang sa paghimo sa usa ka lamesa nga adunay data sa chat sa database
create_db_state.sql — SQL script alang sa paghimo sa usa ka lamesa sa karon nga kahimtang sa chat sa database
Sa config atong gisulat ang bot token ug ang dalan sa database, i.e. ngadto sa bot.db file, atong himoon ang file mismo sa sunod nga lakang.
Para sa mas komplikado nga mga bot, makahimo ka og mas komplikadong mga config, gawas pa, dili na kinahanglan nga magsulat og ini config, mahimo nimong gamiton ang bisan unsang format lakip ang JSON.
Paghimo usa ka variable sa palibot
Sa matag PC, ang folder nga adunay proyekto sa bot mahimong makit-an sa lainlaing mga direktoryo ug sa lainlaing mga drive, mao nga sa code ang agianan sa folder sa proyekto itakda pinaagi sa usa ka variable sa palibot. TG_BOT_PATH.
Adunay daghang mga paagi sa paghimo sa usa ka variable sa palibot, ang pinakasimple mao ang pagsulat niini sa usa ka file .Renviron.
Mahimo nimo o usbon kini nga file gamit ang command file.edit(path.expand(file.path("~", ".Renviron"))). Ipatuman kini ug idugang ang usa ka linya sa file:
TG_BOT_PATH=C:/ПУТЬ/К/ВАШЕМУ/ПРОЕКТУ
Sunod i-save ang file .Renviron ug i-restart ang RStudio.
Paghimo og database
Ang sunod nga lakang mao ang paghimo og database. Kinahanglan namon ang 2 ka lamesa:
chat_data — data nga gipangayo sa bot gikan sa user
chat_state — kasamtangan nga kahimtang sa tanang chat
Mahimo nimo kini nga mga lamesa gamit ang mosunod nga pangutana sa SQL:
CREATE TABLE chat_data (
chat_id BIGINT PRIMARY KEY
UNIQUE,
name TEXT,
age INTEGER
);
CREATE TABLE chat_state (
chat_id BIGINT PRIMARY KEY
UNIQUE,
state TEXT
);
Kung gi-download nimo ang proyekto sa bot gikan sa GitHub, unya sa paghimo sa database mahimo nimong gamiton ang mosunod nga code sa R.
# Скрипт создания базы данных
library(DBI) # интерфейс для работы с СУБД
library(configr) # чтение конфига
library(readr) # чтение текстовых SQL файлов
library(RSQLite) # драйвер для подключения к SQLite
# директория проекта
setwd(Sys.getenv('TG_BOT_PATH'))
# чтение конфига
cfg <- read.config('config.cfg')
# подключение к SQLite
con <- dbConnect(SQLite(), cfg$db_settings$db_path)
# Создание таблиц в базе
dbExecute(con, statement = read_file('create_db_data.sql'))
dbExecute(con, statement = read_file('create_db_state.sql'))
Mga gimbuhaton sa pagsulat aron magtrabaho kauban ang database
Nakaandam na kami og configuration file ug usa ka database nga gihimo. Karon kinahanglan nimo nga isulat ang mga gimbuhaton aron mabasa ug isulat ang datos sa kini nga database.
Kung imong gi-download ang proyekto gikan sa GitHub, unya makit-an nimo ang mga gimbuhaton sa file db_bot_function.R.
Function code alang sa pagtrabaho uban sa database
# ###########################################################
# Function for work bot with database
# получить текущее состояние чата
get_state <- function(chat_id) {
con <- dbConnect(SQLite(), cfg$db_settings$db_path)
chat_state <- dbGetQuery(con, str_interp("SELECT state FROM chat_state WHERE chat_id == ${chat_id}"))$state
return(unlist(chat_state))
dbDisconnect(con)
}
# установить текущее состояние чата
set_state <- function(chat_id, state) {
con <- dbConnect(SQLite(), cfg$db_settings$db_path)
# upsert состояние чата
dbExecute(con,
str_interp("
INSERT INTO chat_state (chat_id, state)
VALUES(${chat_id}, '${state}')
ON CONFLICT(chat_id)
DO UPDATE SET state='${state}';
")
)
dbDisconnect(con)
}
# запись полученных данных в базу
set_chat_data <- function(chat_id, field, value) {
con <- dbConnect(SQLite(), cfg$db_settings$db_path)
# upsert состояние чата
dbExecute(con,
str_interp("
INSERT INTO chat_data (chat_id, ${field})
VALUES(${chat_id}, '${value}')
ON CONFLICT(chat_id)
DO UPDATE SET ${field}='${value}';
")
)
dbDisconnect(con)
}
# read chat data
get_chat_data <- function(chat_id, field) {
con <- dbConnect(SQLite(), cfg$db_settings$db_path)
# upsert состояние чата
data <- dbGetQuery(con,
str_interp("
SELECT ${field}
FROM chat_data
WHERE chat_id = ${chat_id};
")
)
dbDisconnect(con)
return(data[[field]])
}
Naghimo kami og 4 ka yano nga mga gimbuhaton:
get_state() — pagkuha sa kasamtangan nga kahimtang sa chat gikan sa database
set_state() — isulat ang kasamtangan nga kahimtang sa chat sa database
get_chat_data() - makadawat data nga gipadala sa user
set_chat_data() - Pagrekord sa datos nga nadawat gikan sa tiggamit
Ang tanan nga mga gimbuhaton yano ra, sila nagbasa sa datos gikan sa database gamit ang mando dbGetQuery(), o pasalig UPSERT operasyon (pag-usab sa kasamtangan nga datos o pagsulat sa bag-ong datos ngadto sa database), gamit ang function dbExecute().
Ang syntax alang sa UPSERT nga operasyon mao ang mosunod:
INSERT INTO chat_data (chat_id, ${field})
VALUES(${chat_id}, '${value}')
ON CONFLICT(chat_id)
DO UPDATE SET ${field}='${value}';
Mga. sa among mga lamesa natad chat_id adunay usa ka talagsaon nga pagpugong ug mao ang nag-unang yawe sa mga lamesa. Sa sinugdan, gisulayan namon nga idugang ang kasayuran sa lamesa, ug nakakuha kami usa ka sayup kung ang datos alang sa karon nga chat naa na, kung diin among gi-update ang kasayuran alang sa kini nga chat.
Sunod, gamiton namon kini nga mga gimbuhaton sa mga pamaagi ug mga filter sa bot.
Mga pamaagi sa bot
Ang sunod nga lakang sa paghimo sa among bot mao ang paghimo og mga pamaagi. Kung imong gi-download ang proyekto gikan sa GitHub, unya ang tanan nga mga pamaagi naa sa file bot_methods.R.
Code sa pamaagi sa bot
# ###########################################################
# bot methods
# start dialog
start <- function(bot, update) {
#
# Send query
bot$sendMessage(update$message$chat_id,
text = "Введи своё имя")
# переключаем состояние диалога в режим ожидания ввода имени
set_state(chat_id = update$message$chat_id, state = 'wait_name')
}
# get current chat state
state <- function(bot, update) {
chat_state <- get_state(update$message$chat_id)
# Send state
bot$sendMessage(update$message$chat_id,
text = unlist(chat_state))
}
# reset dialog state
reset <- function(bot, update) {
set_state(chat_id = update$message$chat_id, state = 'start')
}
# enter username
enter_name <- function(bot, update) {
uname <- update$message$text
# Send message with name
bot$sendMessage(update$message$chat_id,
text = paste0(uname, ", приятно познакомится, я бот!"))
# Записываем имя в глобальную переменную
#username <<- uname
set_chat_data(update$message$chat_id, 'name', uname)
# Справшиваем возраст
bot$sendMessage(update$message$chat_id,
text = "Сколько тебе лет?")
# Меняем состояние на ожидание ввода имени
set_state(chat_id = update$message$chat_id, state = 'wait_age')
}
# enter user age
enter_age <- function(bot, update) {
uage <- as.numeric(update$message$text)
# проверяем было введено число или нет
if ( is.na(uage) ) {
# если введено не число то переспрашиваем возраст
bot$sendMessage(update$message$chat_id,
text = "Ты ввёл некорректные данные, введи число")
} else {
# если введено число сообщаем что возраст принят
bot$sendMessage(update$message$chat_id,
text = "ОК, возраст принят")
# записываем глобальную переменную с возрастом
#userage <<- uage
set_chat_data(update$message$chat_id, 'age', uage)
# сообщаем какие данные были собраны
username <- get_chat_data(update$message$chat_id, 'name')
userage <- get_chat_data(update$message$chat_id, 'age')
bot$sendMessage(update$message$chat_id,
text = paste0("Тебя зовут ", username, " и тебе ", userage, " лет. Будем знакомы"))
# возвращаем диалог в исходное состояние
set_state(chat_id = update$message$chat_id, state = 'start')
}
}
Naghimo kami og 5 nga mga pamaagi:
pagsugod - Pagsugod sa usa ka dialog
estado — Kuhaa ang kasamtangan nga kahimtang sa chat
reset — I-reset ang kasamtangan nga kahimtang sa chat
enter_name — Gipangutana sa bot ang imong ngalan
enter_age — Gipangutana sa bot ang imong edad
Paagi start nangayo sa imong ngalan, ug giusab ang kahimtang sa chat ngadto sa wait_name, i.e. sa standby para sa pagsulod sa imong ngalan.
Sunod, ipadala nimo ang ngalan ug giproseso kini sa pamaagi enter_name, ang bot nangumusta kanimo, gisulat ang nadawat nga ngalan sa database, ug gibalhin ang chat sa estado paghulat_edad.
Niini nga yugto, ang bot nagpaabot kanimo nga mosulod sa imong edad. Gipadala nimo ang imong edad, gisusi sa bot ang mensahe, kung nagpadala ka usa ka teksto imbes usa ka numero, kini moingon: Ты ввёл некорректные данные, введи число, ug maghulat alang kanimo sa pagsulod pag-usab sa imong data. Kung nagpadala ka usa ka numero, ang bot magreport nga gidawat ang imong edad, isulat ang nadawat nga datos sa database, ireport ang tanan nga datos nga nadawat gikan kanimo ug ibalik ang estado sa chat sa orihinal nga posisyon niini, i.e. V start.
Pinaagi sa pagtawag sa pamaagi state mahimo nimong hangyoon ang kasamtangan nga status sa chat bisan unsang orasa, ug gamit ang reset ibalik ang chat sa orihinal nga kahimtang niini.
Mga filter sa mensahe
Sa among kaso, kini usa sa labing hinungdanon nga bahin sa paghimo og bot. Uban kini sa tabang sa mga filter sa mensahe nga masabtan sa bot kung unsa nga kasayuran ang gipaabut niini gikan kanimo ug kung giunsa kini pagproseso.
Sa proyekto sa GitHub ang mga filter narehistro sa file message_filters.R.
Filter code sa mensahe:
# ###########################################################
# message state filters
# фильтр сообщений в состоянии ожидания имени
MessageFilters$wait_name <- BaseFilter(function(message) {
get_state( message$chat_id ) == "wait_name"
}
)
# фильтр сообщений в состоянии ожидания возраста
MessageFilters$wait_age <- BaseFilter(function(message) {
get_state( message$chat_id ) == "wait_age"
}
)
Sa mga filter gigamit namon ang nauna nga gisulat nga function get_state(), aron makapangayo sa kasamtangan nga kahimtang sa chat. Kini nga function nagkinahanglan lamang og 1 argumento, chat id.
Sunod nga filter wait_name nagproseso sa mga mensahe kung ang chat naa sa estado wait_name, ug sumala niana ang filter paghulat_edad nagproseso sa mga mensahe kung ang chat naa sa estado wait_age.
Mga tigdumala
Ang file nga adunay mga handler gitawag mga tigdumala.R, ug adunay mosunod nga code:
# ###########################################################
# handlers
# command handlers
start_h <- CommandHandler('start', start)
state_h <- CommandHandler('state', state)
reset_h <- CommandHandler('reset', reset)
# message handlers
## !MessageFilters$command - означает что команды данные обработчики не обрабатывают,
## только текстовые сообщения
wait_age_h <- MessageHandler(enter_age, MessageFilters$wait_age & !MessageFilters$command)
wait_name_h <- MessageHandler(enter_name, MessageFilters$wait_name & !MessageFilters$command)
Una naghimo kami og mga command handler nga magtugot kanimo sa pagpadagan sa mga pamaagi sa pagsugod sa usa ka dialog, pag-reset niini, ug pagpangutana sa kasamtangan nga kahimtang.
Sunod, naghimo kami og 2 nga tigdumala sa mensahe gamit ang mga filter nga gihimo sa miaging lakang, ug gidugangan sila og filter !MessageFilters$command, aron magamit namo ang mga sugo sa bisan unsang kahimtang sa chat.
Bot launch code
Karon naa na namo ang tanan nga andam sa paglansad, ang nag-unang code sa paglansad sa bot naa sa file bot.R.
library(telegram.bot)
library(tidyverse)
library(RSQLite)
library(DBI)
library(configr)
# переходим в папку проекта
setwd(Sys.getenv('TG_BOT_PATH'))
# читаем конфиг
cfg <- read.config('config.cfg')
# создаём экземпляр бота
updater <- Updater(cfg$bot_settings$bot_token)
# Загрузка компонентов бота
source('db_bot_function.R') # функции для работы с БД
source('bot_methods.R') # методы бота
source('message_filters.R') # фильтры сообщений
source('handlers.R') # обработчики сообщений
# Добавляем обработчики в диспетчер
updater <- updater +
start_h +
wait_age_h +
wait_name_h +
state_h +
reset_h
# Запускаем бота
updater$start_polling()
Ingon usa ka sangputanan, nakuha namon kini nga bot:
Sa bisan unsang oras gamit ang mando /state kita makapangutana sa kasamtangan nga kahimtang sa chat, ug sa paggamit sa sugo /reset ibalik ang chat sa orihinal nga kahimtang niini ug sugdi pag-usab ang dayalogo.
konklusyon
Sa kini nga artikulo, nahibal-an namon kung giunsa ang paggamit sa usa ka database sa sulod sa usa ka bot, ug kung giunsa paghimo ang sunud-sunod nga lohikal nga mga diyalogo pinaagi sa pagrekord sa kahimtang sa chat.
Sa kini nga kaso, among gitan-aw ang labing karaan nga panig-ingnan, aron mas sayon alang kanimo nga masabtan ang ideya sa paghimo sa ingon nga mga bot; sa praktis, makahimo ka og mas komplikado nga mga diyalogo.
Sa sunod nga artikulo sa kini nga serye, mahibal-an naton kung giunsa ang pagpugong sa mga katungod sa mga tiggamit sa bot sa paggamit sa lainlaing mga pamaagi niini.