ProHoster > Блог > administratio > Scribens telegraphum autocinetum in R (parte 4): Aedificium constans, dialogus logicus cum autocineto
Scribens telegraphum autocinetum in R (parte 4): Aedificium constans, dialogus logicus cum autocineto
Si iam lege prior tria vasa ex hac serie, tunc iam scis telegraphum telegraphum claviaturae plenae scribere cum automata sua.
In hoc articulo discemus quomodo scribere autocinetum qui constantem dialogum servabit. Illae. Bot e te rogabit et te exspectabo ut aliquas notitias ineas. Prout notitias quas intras, actus aliquas bot aget.
Etiam in hoc articulo discemus quomodo uti database sub cucullo automati, in exemplo nostro erit SQLite, sed alia DBMS uti potes. Scripsi planius de mutuo cum databases in R lingua in hoc articulum.
Articuli omnes ex serie "Scribere telegraphum bot in R"
Ut automataria data a te petant et exspectent te ut aliqua indicia ineas, necesse est hodiernum dialogi statum referre. Optime ad hoc faciendum est utendum qualicumque datorum infixo, ut SQLite.
Illae. Ratio talis erit. Methodum bot vocamus, et successiue bot notitias aliquas a nobis petit, et in unoquoque gradu hanc informationem ineundam exspectat et eam coercere potest.
Simplicissima automata scribemus, primum nomen tuum rogabit, deinde aetas tua, et data accepta datorum servabis. Cum aetatem petens, notitias inscriptas reprehendo numerum et non textum esse.
Talis dialogus simplex tantum tres status habebit;
initium est normale status automati, in quo nulla a te exspectata notitia
wait_name - state in qua nomen automati exspectatur ingressus
wait_age est status in quo moratur aetas tua ineundo, numerus plenus annorum.
Bot aedificium processus
Per articulum gradatim aedificabimus autocinetum, totum processum schematically depingi potest hoc modo:
Nos creare automati config in quo aliquas occasus congregemus. In casu nostro, signum automati et via ad fasciculi datorum.
Ambitum variabile creamus in quo via ad consilium cum autocineto reponenda erit.
Ipsum database creamus et nonnulla munera ita ut autocinetus cum eo correspondere possit.
bot modos scribimus, i.e. quae tibi munera praestabunt.
Filtra nuntium addit. Cuius ope autocinetus accessurus methodos necessarios, secundum praesentem statum chat.
Tractatores addimus qui mandata ac mandata connectunt cum methodis autocineticis necessariis.
Lorem bot.
Bot project structure
Pro commodo, codicem nostrorum autocinetorum et aliorum imaginum cognatorum in structuram sequentem dividemus.
bot.R - pelagus codice nostrae bot
db_bot_function.R - truncum codicem munera ad operandum cum database
bot_methods.R - codice modi bot
message_filters.R - nuntius Filtra
handlers.R* - tracto
config.cfg - bot config
create_db_data.sql - SQL scriptum est ad partum mensam cum chat notitia in database
create_db_state.sql - SQL scriptum pro creando mensam hodiernae chat status in database
In aboutconfig scribimus bot signum et iter datorum, i.e. ad bot.db fasciculum: ipsam tabellam in proximo gradu creabimus.
Automata pro magis implicata, magis implicatas configas creare potes, praeterea, non est necesse scribere ini config, alia forma cum JSON uti potes.
Create an environment variabilis
In unaquaque PC, folder cum autocineto incepto collocari potest in diversis directoriis et in diversis agitationibus, sic in codice via ad folder consilium ponetur per ambitum variabile. TG_BOT_PATH.
Plures modi ambitum variabilem creandi, simplicissimus eam in tabella scribere est .Renviron.
Potes creare vel creare hunc fasciculum utens imperio file.edit(path.expand(file.path("~", ".Renviron"))). Hoc age, et unam tabellam adde:
TG_BOT_PATH=C:/ПУТЬ/К/ВАШЕМУ/ПРОЕКТУ
Next file servare .Renviron et sileo RStudio.
Creando database
Proximus gradus database creare est. Non opus est nobis 2 tabulis;
chat_data - notitia ut automati postulavit a user
chat_state - current status omnium chats
Has tabulas creare potes utentes interrogatione sequenti 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
);
Si downloaded bot project a GitHubtum creare datorum sequenti codice uti potes in 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'))
Scribere munera cum database laborare
Configurationis lima paratam et database creatum iam habemus. Nunc opus est tibi munera scribere ut notitias legere et scribere huic datorum.
Si downloaded project a GitHub, functiones in tabella invenire potes db_bot_function.R.
Function code for working with the 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]])
}
4 munera simplicia creavimus;
get_state() - adepto hodiernam chat status a database
set_state() - scribe hodiernam chat publica ad database
get_chat_data() - accipere notitia a user
set_chat_data() - recordum notitia accepi a user
Munera omnia admodum simplicia sunt, vel data a database lege utentes imperio dbGetQuery()Aut committere UPSERT operatio (mutatione existentium notitia vel scribens nova notitia ad database), utens ad munus dbExecute().
Syntaxis in opere UPSERT sic est:
INSERT INTO chat_data (chat_id, ${field})
VALUES(${chat_id}, '${value}')
ON CONFLICT(chat_id)
DO UPDATE SET ${field}='${value}';
Illae. in tabulis nostris agri chat_id unicitatem coactionem habet ac primarium clavem tabularum. Initio conamur informationes addere tabulae et errorem consequimur si notitia chat praesentis iam praesens est, quo in casu tantum informationes huius chat renovamus.
Deinde his muneribus utemur in methodis et percolationibus bot.
Bot modi
Proximus gradus nostrae aedificationis autocineti est methodos creare. Si downloaded project a GitHubergo omnes modi sunt in tabella bot_methods.R.
Bot modum codice
# ###########################################################
# 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')
}
}
V modos creavimus;
satus - Satus a alternis
status - Adepto hodiernam chat publica
Reset - Reset hodiernam chat publica
enter_name - Bot quaerit pro nomine tuo
enter_age - Bot quaerit propter aetatem
modum start petit nomen tuum, et mutat statum chat wait_name, i.e. ad standby intrantes nomen tuum.
Deinde nomen mittis et per modum processit enter_nameautomati te salutat, nomen receptum datorum et permutat chat ad rem publicam wait_age.
Hac scaena, expectat bot te ad tuam aetatem ingredi. Aetatem tuam mittis, autocinetum nuntium compescit, si textum aliquem loco numero misisti, dicet: Ты ввёл некорректные данные, введи числоet te exspectabo ut notitias tuas reintraham. Si plures misisti, automati nuntiabit receptam aetatem tuam, datam datorum scribe, omnia indicia a te accepta refer et chat statum suum in statum pristinum redde, i.e. V start.
Per modum vocant state postulare potes statum chat currentem quovis tempore, ac utens reset chat ad statum pristinum revertetur.
Nuntius filters
In nobis, haec est una ex maximis partibus in automati aedificando. Auxilio nuntiis eliquarum in eo intelleget automati quid indicio a te expectet et quomodo procedendum sit.
In project on GitHub Filtra sunt in tabella message_filters.R.
Nuntius codice filter:
# ###########################################################
# 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"
}
)
In odio utimur functione antea scripta get_state()ad petendam statum hodiernum chat. Munus hoc solum 1 argumentum requirit, Curabitur id.
Colloquium proximum wait_name processus nuntiis cum chat in civitate wait_nameac proinde colum wait_age processus nuntiis cum chat in civitate wait_age.
Tracto
Tabella tracto dicitur handlers.R*et sequenti codice habet;
# ###########################################################
# 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)
Primum tractatores iubemus creamus qui methodos currere permittet ut dialogum incipias, illud reset et praesentem quaestionem statuas.
Deinceps tractatores nuntium 2 creamus columellas in priore gradu creatos utentes, eis filtrum addimus !MessageFilters$commandut in quacumque re publica uti possimus.
Bot Lorem codice
Nunc omnia parata habemus ad deducendum, signum principale ad quod autocinetum in tabella deducendum est 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()
Quam ob rem hoc bot venimus:
Quando utens imperio /state statum hodiernam chat percontari et imperio uti possumus /reset chat in statum pristinum revertere et dialogum denuo committitur.
conclusio,
In hoc articulo figurati sumus quomodo utendi database in autocineto, et quomodo in dialogis logicis congruentibus aedificetur status chat memoria.
In hoc casu exemplum primitivum inspeximus, ut facilius esset ideam aedificandi huiusmodi automata perspicere, in praxi multo magis implicatas dialogos aedificare potes.
In sequenti articulo in hac serie, discemus restringere iura usorum autocinetorum variis modis uti.