Kui olete juba tutvunud kolme varasema artikliga, Selles artiklis õpime, kuidas kirjutada robotit, mis toetab järjestikust dialooge. S.t. robot esitab teile küsimusi ja ootab teiepoolset teabe sisestamist. Sõltuvalt sisestatud andmetest teostab robot teatud toiminguid.
Samuti õpime selles artiklis kasutama robotite taga andmebaasi; meie näites on see SQLite, kuid võite kasutada ka muud tüüpi andmebaasi. Rohkem teavet andmebaasidega suhtlemise kohta R keeles olen juba kirjutanud
Järjestikuse, loogilise dialooge robotiga loomine .

Kõik artiklid seeriast "Kirjutame telegrammi boti R keeles"
Sisukord
Kui teid huvitab andmeanalüüs, võivad teid huvitada minu ja kanalid, millel on suur osa sisu R keelele.
Sissejuhatus
S.t. loogika on järgmine. Kutsume üles roboti meetodi ja robot küsib meie käest järjestikku mingit teavet, samal ajal ootab ta iga sammu juures selle teabe sisestamist ja võib seda kontrollida.
Kirjutame täiesti lihtsa roboti, esmalt küsib ta teie nime, seejärel vanust, saadud andmed salvestab ta andmebaasi. Vanuse küsimisel kontrollib ta, et sisestatud andmed oleks number, mitte tekst.
Sellisel lihtsal dialooge on vaid kolm olekut:
start — tavapärane roboti olek, kus ta ei oota teilt mingeid andmeid
- wait_name — olek, kus robot ootab nime sisestamist
- wait_age — olek, kus robot ootab teie vanuse sisestamist, täisealiste aastate arvu.
- Artikli käigus loome teiega samm-sammult roboti; kogu protsessi saab visuaalselt kujundada järgmiselt:
Roboti projektistruktuur
Loome roboti konfiguratsiooni, kus hoiame mõned seaded. Meie puhul roboti token ja tee andmebaasifailini.

- Loome keskkonnamuutuja, kus salvestame tee robotiga projekti juurde.
- Loome keskkonnamuutuja, kuhu salvestatakse tee botiga projekti.
- Loodame andmebaasi ja hulga funktsioone, et bot saaks sellega suhelda.
- Kirjutame boti meetodid, st. funktsioonid, mida ta täidab.
- Lisame sõnumifiltrid, mille kaudu bot suunab vajalikke meetodeid vastavalt vestluse praegusele seisundile.
- Lisame töötlejad, mis seovad käsud ja sõnumid boti vajalike meetoditega.
- Käivitame boti.
Roboti konfigureerimine
Mugavuse huvides jagame boti koodi ja sellega seotud faile järgnevasse struktuuri.
- bot.R — boti põhikood
- db_bot_function.R — andmebaasiga töötamise funktsioonide koodiblokk
- bot_methods.R — boti meetodite kood
- message_filters.R — sõnumifiltrid
- handlers.R — töötlejad
- config.cfg — boti konfiguratsioon
- create_db_data.sql — SQL skript andmete tabeli loomiseks vestluse andmebaasis
- create_db_state.sql — SQL skript vestluse praeguse seisundi tabeli loomiseks andmebaasis
- bot.db — boti andmebaas
Kogu boti projektiga saab tutvuda või minu .
Loome keskkonnamuutuja
Konfiguratsioonina kasutame tavalist , järgmise kujuga:
[bot_settings]
bot_token=TEIE_BOTI_TOKEN
[db_settings]
db_path=C:/TEE/P/NDAFAILE/bot.dbKonfiguratsioonis kirjutame boti tokeni ja tee andmebaasi, st. faili bot.db, mille loome järgmises etapis.
Karmimate boti jaoks saab luua ka keerukamaid konfiguratsioone, lisaks ei pea kindlasti kasutama just ini konfiguratsiooni, võite kasutada mistahes muud formaati, sealhulgas JSON.
Loome andmebaasi
Igal PC-l võib boti projekti kaust asuda erinevates kataloogides ja erinevatel ketastel, seetõttu on koodis projekti kausta tee määratud keskkonnamuutuja kaudu. TG_BOT_PATH.
Keskkonnamuutujat saab luua mitmel viisil, kõige lihtsam on see määrata failis: .Renviron.
Seda faili saab luua või redigeerida käsu kaudu: file.edit(path.expand(file.path("~", ".Renviron"))). Käitage seda ja lisage faili üks rida:
TG_BOT_PATH=C:/TEE/K/TEIE/PROJEKTISSeejärel salvestage fail .Renviron ja taaskäivitage RStudio.
Kirjutame andmebaasi töötamise funktsioonid
Järgmine samm on andmebaasi loomine. Vajalikke on 2 tabelit:
- chat_data — andmed, mida bot küsis kasutajalt
- chat_state — kõigi vestluste praegune seisund
Need tabelid saab luua järgmise SQL päringu abil:
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
);
Kui olete boti projekti alla laadinud , et andmete baasi loomiseks võite kasutada järgmisi R keeles kirjutatud koodi.
# Скрипт создания базы данных
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'))
Roboti meetodid
Meil on juba valmis konfiguratsioonifail ja andmebaas. Nüüd peame kirjutama funktsioonid andmete lugemiseks ja salvestamiseks sellesse andmebaasi.
Kui olete projekti alla laadinud , leiate funktsioonid failist db_bot_function.R.
Andmebaasiga töötamiseks mõeldud funktsioonide kood
# ###########################################################
# 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]])
}Oleme loonud 4 lihtsat funktsiooni:
get_state()— saadud vestluse praegune olek andmebaasistset_state()— salvestada vestluse praegune olek andmebaasiget_chat_data()— saada kasutaja saadetud andmedset_chat_data()— salvestada kasutajalt saadud andmed
Kõik funktsioonid on enam-vähem lihtsad, need kas loevad andmeid andmebaasist kasutades käsku dbGetQuery(), või teevad UPSERT tegevuste (olemasolevate andmete muutmine või uute andmete salvestamine andmebaasi) jaoks kasutades funktsiooni dbExecute().
UPSERT tegevuse süntaks näeb välja järgmine:
INSERT INTO chat_data (chat_id, ${field})
VALUES(${chat_id}, '${value}')
ON CONFLICT(chat_id)
DO UPDATE SET ${field}='${value}';St, meie tabelites on väli chat_id omab unikaalsuse piirangut ja on tabelite põhivõti. Alguses proovime teavet tabelisse lisada, ja kui andmed praeguse vestluse kohta juba eksisteerivad, saame vea, mille korral uuendame lihtsalt selle vestluse teavet.
Edasi kasutame neid funktsioone roboti meetodites ja filtrites.
Sõnumifiltrid
Järgmine samm meie roboti koostamisel on meetodite loomine. Kui olete projekti alla laadinud , on kõik meetodid failis bot_methods.R.
Roboti meetodite kood
# ###########################################################
# 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')
}
}Oleme loonud 5 meetodit:
- start — Vestluse alustamine
- state — Saada praegune vestluse olek
- reset — Vestluse praeguse oleku lähtestamine
- enter_name — Robot küsib teie nime
- enter_age — Robot küsib teie vanust
Meetod start küsib teie nime ja viib vestluse oleku wait_name, st ooterežiimi, et sisestaksite oma nime.
Edasi saadate nime ja see töödeldakse meetodi enter_name, robot tervitab teid, salvestab saadud nime andmebaasi ja viib vestluse oleku wait_age.
Selles etapis ootab robot teilt teie vanuse sisestamist. Te saadate oma vanuse, robot kontrollib sõnumit, kui te saite saadud teksti asemel mingeid tekstilisi väärtusi, ütleb ta: Sa sisestasid vale andmed, palun sisesta number, ja ootab teilt andmete uuesti sisestamist. Kui olete saatnud numbri, teavitab bot teid, et ta on teie vanuse vastu võtnud, salvestab saadud andmed, teatab kõikidest teie edastatud andmetest ja viib vestluse oleku tagasi algsesse seisu, st start.
Kutsudes välja meetodi state võite igal hetkel küsida vestluse praegust olekut, ja meetodiga ülestartimine viia vestlus algsesse olekusse.
Töötlejad
Meie puhul on see üks kõige olulisemaid osi boti loomisel. Just sõnumifiltrite abil mõistab bot, millist teavet ta teilt ootab ja kuidas seda töödelda.
Projektis on filtrid määratletud failis message_filters.R.
Sõnumifiltrite kood:
# ###########################################################
# 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"
}
)Filtrites kasutame varem kirjutatud funktsiooni get_state(), et küsida vestluse praegust olekut. See funktsioon nõuab vaid 1 argumenti, vestluse id-d.
Seejärel töötleb filter wait_name sõnumeid, kui vestlus on olekus wait_name, ja vastavalt töötleb filter wait_age sõnumeid, kui vestlus on olekus wait_age.
Roboti käivituskood
Fail käsitlejatega kannab nime handlers.R, ja sisaldab järgmine koodi:
# ###########################################################
# 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)Esmalt loome käskude käsitlejad, mis võimaldavad teil käivitada meetodeid, et alustada dialooge, selle lähtestamist ja küsida praegust olekut.
Peale selle loome 2 sõnumite käsitlejat, kasutades eelmisel sammul loodud filtreid, ja lisame neile filtri !MessageFilters$command, et igas vestluse olekus saaksime kasutada käske.
Selleks, et robot saaks teilt andmeid küsida ja oodata teabe sisestamist, peate fikseerima praeguse dialooge oleku. Parim viis selleks on kasutada mingit sisseehitatud andmebaasi, näiteks SQLite.
Nüüd on meil kõik käivitamiseks valmis, boti põhikood asub failis bot.R.
library(telegram.bot)
library(tidyverse)
library(RSQLite)
library(DBI)
library(configr)
# läheme projekti kausta
setwd(Sys.getenv('TG_BOT_PATH'))
# loeme konfi
cfg <- read.config('config.cfg')
# loome boti eksemplari
updater <- Updater(cfg$bot_settings$bot_token)
# Boti komponentide laadimine
source('db_bot_function.R') # funktsioonid andmebaasiga töötamiseks
source('bot_methods.R') # boti meetodid
source('message_filters.R') # sõnumifiltrid
source('handlers.R') # sõnumite käsitlejad
# Lisame käsitlejad seirerisse
updater <- updater +
start_h +
wait_age_h +
wait_name_h +
state_h +
reset_h
# Käivitame boti
updater$start_polling()Tulemuseks saime sellise boti:

Igal hetkel saame käsu /state abil küsida vestluse praegust olekut, ja käsu abil /reset viia vestlus algsesse olekusse ja alustada dialooge uuesti.
Kokkuvõte
Selles artiklis uurisime, kuidas kasutada botis andmebaase ja kuidas luua loogilisi dialooge vestluse olekut fikseerides.
Antud juhul vaatleme kõige primitiivsemat näidet, et lihtsustada teie arusaamist selliste botide loomise ideest; praktikas saate luua palju keerulisemaid dialooge.
Selles seerias järgmises artiklis õpime piirama botikasutajate õigusi kasutada erinevaid selle meetodeid.
Allikas: habr.com
