ProHoster > blog > Utawala > Kuandika boti ya telegramu katika R (sehemu ya 4): Kuunda mazungumzo thabiti na yenye mantiki na roboti
Kuandika boti ya telegramu katika R (sehemu ya 4): Kuunda mazungumzo thabiti na yenye mantiki na roboti
Ikiwa tayari umesoma yaliyotangulia makala tatu kutoka kwa safu hii, basi tayari unajua jinsi ya kuandika roboti kamili za telegraph na kibodi.
Katika makala hii, tutajifunza jinsi ya kuandika bot ambayo itadumisha mazungumzo thabiti. Wale. Boti itakuuliza maswali na kukusubiri uweke habari fulani. Kulingana na data unayoingiza, bot itafanya vitendo kadhaa.
Pia katika makala hii tutajifunza jinsi ya kutumia hifadhidata chini ya kofia ya bot, kwa mfano wetu itakuwa SQLite, lakini unaweza kutumia DBMS nyingine yoyote. Niliandika kwa undani zaidi juu ya kuingiliana na hifadhidata katika lugha ya R in Makala hii.
Nakala zote kutoka kwa safu "Kuandika bot ya telegraph katika R"
Ili bot iombe data kutoka kwako na ikungojee kuingiza habari yoyote, utahitaji kurekodi hali ya sasa ya mazungumzo. Njia bora ya kufanya hivyo ni kutumia aina fulani ya hifadhidata iliyopachikwa, kama vile SQLite.
Wale. Mantiki itakuwa kama ifuatavyo. Tunaita njia ya bot, na bot huomba kwa mtiririko habari fulani kutoka kwetu, na kwa kila hatua inasubiri habari hii kuingizwa na inaweza kuiangalia.
Tutaandika bot rahisi zaidi, kwanza itauliza jina lako, kisha umri wako, na itahifadhi data iliyopokelewa kwenye hifadhidata. Wakati wa kuuliza umri, itaangalia kuwa data iliyoingia ni nambari na sio maandishi.
Mazungumzo rahisi kama haya yatakuwa na majimbo matatu tu:
kuanza ni hali ya kawaida ya bot, ambayo haitarajii taarifa yoyote kutoka kwako
wait_name - hali ambayo bot inasubiri jina kuingizwa
wait_age ni hali ambayo kijibu hungoja umri wako uingizwe, idadi ya miaka kamili.
Mchakato wa kujenga bot
Wakati wa kifungu, tutaunda kijibu hatua kwa hatua; mchakato mzima unaweza kuonyeshwa kimkakati kama ifuatavyo:
Tunaunda usanidi wa bot ambao tutahifadhi mipangilio fulani. Kwa upande wetu, ishara ya bot, na njia ya faili ya hifadhidata.
Tunaunda mabadiliko ya mazingira ambayo njia ya mradi na bot itahifadhiwa.
Tunaunda hifadhidata yenyewe, na idadi ya kazi ili bot inaweza kuingiliana nayo.
Tunaandika njia za bot, i.e. kazi itafanya.
Kuongeza vichujio vya ujumbe. Kwa msaada ambao bot itafikia njia muhimu, kulingana na hali ya sasa ya mazungumzo.
Tunaongeza vidhibiti ambavyo vitaunganisha amri na ujumbe na mbinu muhimu za bot.
Wacha tuzindue kijibu.
Muundo wa mradi wa bot
Kwa urahisi, tutagawanya msimbo wa bot yetu, na faili zingine zinazohusiana, katika muundo ufuatao.
bot.R - nambari kuu ya bot yetu
db_bot_function.R - kizuizi cha nambari iliyo na vitendaji vya kufanya kazi na hifadhidata
njia_za_bot.R - kanuni za mbinu za bot
vichujio_vya ujumbe.R - vichungi vya ujumbe
washikaji.R - washikaji
usanidi.cfg - usanidi wa bot
create_db_data.sql - Hati ya SQL ya kuunda jedwali na data ya gumzo kwenye hifadhidata
create_db_state.sql - Hati ya SQL ya kuunda jedwali la hali ya sasa ya gumzo kwenye hifadhidata
Katika usanidi tunaandika ishara ya bot na njia ya hifadhidata, i.e. kwa faili ya bot.db; tutaunda faili yenyewe katika hatua inayofuata.
Kwa roboti changamano zaidi, unaweza kuunda usanidi changamano zaidi, zaidi ya hayo, si lazima kuandika usanidi wa ini, unaweza kutumia umbizo lingine lolote ikijumuisha JSON.
Unda mabadiliko ya mazingira
Kwenye kila PC, folda iliyo na mradi wa bot inaweza kupatikana katika saraka tofauti na kwenye anatoa tofauti, kwa hivyo katika msimbo njia ya folda ya mradi itawekwa kupitia utofauti wa mazingira. TG_BOT_PATH.
Kuna njia kadhaa za kuunda mabadiliko ya mazingira, rahisi zaidi ni kuandika kwenye faili .Renviron.
Unaweza kuunda au kuhariri faili hii kwa kutumia amri file.edit(path.expand(file.path("~", ".Renviron"))). Itekeleze na ongeza mstari mmoja kwenye faili:
TG_BOT_PATH=C:/ПУТЬ/К/ВАШЕМУ/ПРОЕКТУ
Ifuatayo, hifadhi faili .Renviron na uanze tena RStudio.
Kuunda hifadhidata
Hatua inayofuata ni kuunda hifadhidata. Tutahitaji meza 2:
chat_data - data ambayo bot iliomba kutoka kwa mtumiaji
chat_state - hali ya sasa ya mazungumzo yote
Unaweza kuunda jedwali hizi kwa kutumia swali lifuatalo la 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
);
Ikiwa ulipakua mradi wa bot kutoka GitHub, kisha kuunda hifadhidata unaweza kutumia nambari ifuatayo katika 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'))
Kazi za kuandika ili kufanya kazi na hifadhidata
Tayari tunayo faili ya usanidi tayari na hifadhidata imeundwa. Sasa unahitaji kuandika vitendaji ili kusoma na kuandika data kwenye hifadhidata hii.
Ikiwa ulipakua mradi kutoka GitHub, basi unaweza kupata kazi katika faili db_bot_function.R.
Nambari ya kazi ya kufanya kazi na hifadhidata
# ###########################################################
# 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]])
}
Tumeunda kazi 4 rahisi:
get_state() - pata hali ya sasa ya mazungumzo kutoka kwa hifadhidata
set_state() - andika hali ya sasa ya gumzo kwenye hifadhidata
get_chat_data() - Pokea data iliyotumwa na mtumiaji
set_chat_data() - rekodi data iliyopokelewa kutoka kwa mtumiaji
Kazi zote ni rahisi sana, zinaweza kusoma data kutoka kwa hifadhidata kwa kutumia amri dbGetQuery(), au kujitolea UPSERT operesheni (kubadilisha data iliyopo au kuandika data mpya kwenye hifadhidata), kwa kutumia kazi dbExecute().
Sintaksia ya operesheni ya UPSERT ni kama ifuatavyo:
INSERT INTO chat_data (chat_id, ${field})
VALUES(${chat_id}, '${value}')
ON CONFLICT(chat_id)
DO UPDATE SET ${field}='${value}';
Wale. katika uwanja wetu wa meza kitambulisho_cha_chat ina kizuizi cha kipekee na ndio ufunguo wa msingi wa jedwali. Hapo awali, tunajaribu kuongeza habari kwenye jedwali, na tunapata hitilafu ikiwa data ya gumzo la sasa tayari iko, kwa hali ambayo tunasasisha tu maelezo ya gumzo hili.
Ifuatayo, tutatumia kazi hizi katika njia na vichungi vya bot.
Mbinu za kijibu
Hatua inayofuata katika kujenga bot yetu ni kuunda mbinu. Ikiwa ulipakua mradi kutoka GitHub, basi njia zote ziko kwenye faili njia_za_bot.R.
Msimbo wa mbinu ya kijibu
# ###########################################################
# 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')
}
}
Tumeunda njia 5:
anza - Anzisha mazungumzo
hali - Pata hali ya mazungumzo ya sasa
weka upya — Weka upya hali ya sasa ya gumzo
enter_name - Bot inauliza jina lako
enter_age - Boti inauliza umri wako
Mbinu start anauliza jina lako, na kubadilisha hali ya mazungumzo kuwa subiri_jina, i.e. kusubiri kwa ajili ya kuingiza jina lako.
Ifuatayo, unatuma jina na linachakatwa na mbinu enter_name, roboti inakusalimu, inaandika jina lililopokelewa kwenye hifadhidata, na kubadilisha soga hadi hali subiri_umri.
Katika hatua hii, roboti inatarajia uingie umri wako. Unatuma umri wako, roboti hukagua ujumbe, ikiwa umetuma maandishi badala ya nambari, itasema: Ты ввёл некорректные данные, введи число, na itakusubiri uweke tena data yako. Ikiwa ulituma nambari, bot itaripoti kwamba imekubali umri wako, kuandika data iliyopokelewa kwenye hifadhidata, ripoti data zote zilizopokelewa kutoka kwako na urejeshe hali ya mazungumzo kwenye nafasi yake ya awali, i.e. V start.
Kwa kupiga njia state unaweza kuomba hali ya sasa ya gumzo wakati wowote, na kwa kutumia reset rudisha gumzo katika hali yake ya asili.
Vichujio vya ujumbe
Kwa upande wetu, hii ni moja ya sehemu muhimu zaidi katika kujenga bot. Ni kwa usaidizi wa vichungi vya ujumbe ambapo roboti itaelewa ni taarifa gani inatarajia kutoka kwako na jinsi inavyopaswa kuchakatwa.
Katika mradi wa GitHub vichungi vimesajiliwa kwenye faili vichujio_vya ujumbe.R.
Msimbo wa kichujio cha ujumbe:
# ###########################################################
# 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"
}
)
Katika vichungi tunatumia kazi iliyoandikwa hapo awali get_state(), ili kuomba hali ya sasa ya gumzo. Chaguo hili la kukokotoa linahitaji hoja 1 pekee, kitambulisho cha gumzo.
Kichujio kinachofuata subiri_jina huchakata ujumbe wakati soga iko katika hali wait_name, na ipasavyo chujio subiri_umri huchakata ujumbe wakati soga iko katika hali wait_age.
Washughulikiaji
Faili iliyo na washughulikiaji inaitwa washikaji.R, na ina nambari ifuatayo:
# ###########################################################
# 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)
Kwanza tunaunda vidhibiti vya amri ambavyo vitakuruhusu kuendesha njia za kuanzisha mazungumzo, kuiweka upya, na kuuliza hali ya sasa.
Ifuatayo, tunaunda vidhibiti 2 vya ujumbe kwa kutumia vichujio vilivyoundwa katika hatua ya awali, na kuongeza kichujio kwao !MessageFilters$command, ili tuweze kutumia amri katika hali yoyote ya mazungumzo.
Msimbo wa uzinduzi wa bot
Sasa tuna kila kitu tayari kuzindua, msimbo kuu wa kuzindua bot iko kwenye faili 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()
Kama matokeo, tulipata bot hii:
Wakati wowote kwa kutumia amri /state tunaweza kuuliza hali ya sasa ya gumzo, na kwa kutumia amri /reset rudisha gumzo katika hali yake ya asili na uanze mazungumzo tena.
Hitimisho
Katika makala haya, tuligundua jinsi ya kutumia hifadhidata ndani ya roboti, na jinsi ya kuunda midahalo ya kimantiki kwa kurekodi hali ya gumzo.
Katika kesi hii, tuliangalia mfano wa zamani zaidi, ili iwe rahisi kwako kuelewa wazo la kuunda roboti kama hizo; kwa mazoezi, unaweza kuunda mazungumzo ngumu zaidi.
Katika makala inayofuata katika mfululizo huu, tutajifunza jinsi ya kuzuia haki za watumiaji wa roboti kutumia mbinu zake mbalimbali.