ProHoster > Blog > Ma'muriyat > R-da telegramma botini yozish (4-qism): Bot bilan izchil, mantiqiy dialog qurish
R-da telegramma botini yozish (4-qism): Bot bilan izchil, mantiqiy dialog qurish
Agar siz avvalgisini o'qigan bo'lsangiz uchta maqola ushbu seriyadan, keyin siz klaviatura bilan to'liq huquqli telegram botlarini qanday yozishni allaqachon bilasiz.
Ushbu maqolada biz izchil dialogni davom ettiradigan botni qanday yozishni o'rganamiz. Bular. Bot sizga savollar beradi va ba'zi ma'lumotlarni kiritishingizni kutadi. Siz kiritgan ma'lumotlarga qarab, bot ba'zi amallarni bajaradi.
Shuningdek, ushbu maqolada biz bot qopqog'i ostidagi ma'lumotlar bazasidan qanday foydalanishni o'rganamiz, bizning misolimizda u SQLite bo'ladi, lekin siz boshqa har qanday DBMS dan foydalanishingiz mumkin. Men R tilida ma'lumotlar bazalari bilan ishlash haqida batafsilroq yozdim Ushbu maqola.
“Telegram botini R-da yozish” turkumidagi barcha maqolalar
Agar siz ma'lumotlarni tahlil qilish bilan qiziqsangiz, meni qiziqtirishi mumkin telegramma и youtube kanallar. Kontentning katta qismi R tiliga bag'ishlangan.
Bot sizdan ma'lumot so'rashi va istalgan ma'lumotni kiritishingizni kutishi uchun siz dialogning joriy holatini yozib olishingiz kerak bo'ladi. Buning eng yaxshi usuli SQLite kabi o'rnatilgan ma'lumotlar bazasidan foydalanishdir.
Bular. Mantiq quyidagicha bo'ladi. Biz bot usulini chaqiramiz va bot bizdan ketma-ket ba'zi ma'lumotlarni so'raydi va har bir qadamda bu ma'lumot kiritilishini kutadi va uni tekshirishi mumkin.
Biz eng oddiy botni yozamiz, avval u sizning ismingizni, keyin yoshingizni so'raydi va olingan ma'lumotlarni ma'lumotlar bazasiga saqlaydi. Yoshni so'raganda, kiritilgan ma'lumotlar matn emas, raqam ekanligini tekshiradi.
Bunday oddiy dialog faqat uchta holatga ega bo'ladi:
start - bu botning oddiy holati bo'lib, unda u sizdan hech qanday ma'lumot kutmaydi
wait_name - bot ism kiritilishini kutayotgan holat
wait_age - bot sizning yoshingiz kiritilishini kutadigan holat, to'liq yillar soni.
Bot yaratish jarayoni
Maqola davomida biz bosqichma-bosqich bot quramiz, butun jarayonni sxematik tarzda quyidagicha tasvirlash mumkin:
Biz ba'zi sozlamalarni saqlaydigan bot konfiguratsiyasini yaratamiz. Bizning holatda, bot tokeni va ma'lumotlar bazasi fayliga yo'l.
Biz atrof-muhit o'zgaruvchisini yaratamiz, unda bot bilan loyihaga yo'l saqlanadi.
Biz ma'lumotlar bazasini o'zi va bot u bilan o'zaro aloqada bo'lishi uchun bir qator funktsiyalarni yaratamiz.
Biz bot usullarini yozamiz, ya'ni. bajaradigan funktsiyalari.
Xabar filtrlarini qo'shish. Uning yordami bilan bot suhbatning hozirgi holatiga qarab kerakli usullarga kirishi mumkin.
Biz buyruqlar va xabarlarni kerakli bot usullari bilan bog'laydigan ishlov beruvchilarni qo'shamiz.
Keling, botni ishga tushiramiz.
Bot loyihasi tuzilishi
Qulaylik uchun biz botimiz kodini va boshqa tegishli fayllarni quyidagi tuzilishga ajratamiz.
bot.R — botimizning asosiy kodi
db_bot_function.R — maʼlumotlar bazasi bilan ishlash funksiyalariga ega kod bloki
bot_methods.R — bot usullari kodi
message_filters.R — xabar filtrlari
ishlovchilar.R - ishlovchilar
config.cfg - bot konfiguratsiyasi
create_db_data.sql — Maʼlumotlar bazasida suhbat maʼlumotlari bilan jadval yaratish uchun SQL skripti
create_db_state.sql — Maʼlumotlar bazasida joriy suhbat holati jadvalini yaratish uchun SQL skripti
Konfiguratsiyada biz bot tokenini va ma'lumotlar bazasiga yo'lni yozamiz, ya'ni. bot.db fayliga; keyingi bosqichda faylning o'zini yaratamiz.
Murakkab botlar uchun siz murakkabroq konfiguratsiyalarni yaratishingiz mumkin, bundan tashqari, ini konfiguratsiyasini yozish shart emas, siz boshqa har qanday formatdan, shu jumladan JSONdan ham foydalanishingiz mumkin.
Atrof-muhit o'zgaruvchisini yarating
Har bir shaxsiy kompyuterda bot loyihasi bo'lgan papka turli kataloglarda va turli disklarda joylashgan bo'lishi mumkin, shuning uchun kodda loyiha papkasiga yo'l muhit o'zgaruvchisi orqali o'rnatiladi. TG_BOT_PATH.
Muhit o'zgaruvchisini yaratishning bir necha usullari mavjud, eng oddiyi uni faylga yozishdir .Renviron.
Buyruq yordamida ushbu faylni yaratishingiz yoki tahrirlashingiz mumkin file.edit(path.expand(file.path("~", ".Renviron"))). Uni bajaring va faylga bitta qator qo'shing:
TG_BOT_PATH=C:/ПУТЬ/К/ВАШЕМУ/ПРОЕКТУ
Keyin faylni saqlang .Renviron va RStudio-ni qayta ishga tushiring.
Ma'lumotlar bazasini yaratish
Keyingi qadam ma'lumotlar bazasini yaratishdir. Bizga 2 ta jadval kerak bo'ladi:
chat_data - bot foydalanuvchidan so'ragan ma'lumotlar
chat_state — barcha chatlarning joriy holati
Ushbu jadvallarni quyidagi SQL so'rovi yordamida yaratishingiz mumkin:
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
);
Agar siz bot loyihasini yuklab olgan bo'lsangiz GitHub, keyin ma'lumotlar bazasini yaratish uchun R da quyidagi koddan foydalanishingiz mumkin.
# Скрипт создания базы данных
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'))
Ma'lumotlar bazasi bilan ishlash funksiyalarini yozish
Bizda allaqachon konfiguratsiya fayli va yaratilgan ma'lumotlar bazasi mavjud. Endi siz ushbu ma'lumotlar bazasiga ma'lumotlarni o'qish va yozish uchun funktsiyalarni yozishingiz kerak.
Agar siz loyihani yuklab olgan bo'lsangiz GitHub, keyin fayldagi funktsiyalarni topishingiz mumkin db_bot_function.R.
Ma'lumotlar bazasi bilan ishlash uchun funktsiya kodi
# ###########################################################
# 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]])
}
Biz 4 ta oddiy funktsiyani yaratdik:
get_state() — maʼlumotlar bazasidan joriy suhbat holatini oling
set_state() — maʼlumotlar bazasiga joriy suhbat holatini yozish
get_chat_data() — foydalanuvchi tomonidan yuborilgan maʼlumotlarni qabul qilish
set_chat_data() — foydalanuvchidan olingan maʼlumotlarni yozib olish
Barcha funktsiyalar juda oddiy, ular buyruq yordamida ma'lumotlar bazasidan ma'lumotlarni o'qiydilar dbGetQuery(), yoki topshiring UPSERT operatsiya (mavjud ma'lumotlarni o'zgartirish yoki ma'lumotlar bazasiga yangi ma'lumotlarni yozish), funktsiyadan foydalanish dbExecute().
UPSERT operatsiyasining sintaksisi quyidagicha:
INSERT INTO chat_data (chat_id, ${field})
VALUES(${chat_id}, '${value}')
ON CONFLICT(chat_id)
DO UPDATE SET ${field}='${value}';
Bular. bizning jadvallar maydonida chat_id noyoblik chekloviga ega va jadvallarning asosiy kalitidir. Dastlab, biz jadvalga ma'lumot qo'shishga harakat qilamiz va agar joriy chat uchun ma'lumotlar allaqachon mavjud bo'lsa, biz xatoga yo'l qo'yamiz, bu holda biz ushbu suhbat uchun ma'lumotni yangilaymiz.
Keyinchalik, biz ushbu funktsiyalardan botning usullari va filtrlarida foydalanamiz.
Bot usullari
Botimizni yaratishning keyingi bosqichi usullarni yaratishdir. Agar siz loyihani yuklab olgan bo'lsangiz GitHub, keyin barcha usullar faylda bot_methods.R.
Bot usuli kodi
# ###########################################################
# 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')
}
}
Biz 5 ta usulni yaratdik:
start — Muloqot oynasini boshlash
davlat — joriy suhbat holatini oling
reset — Joriy suhbat holatini qayta o'rnatish
enter_name - bot sizning ismingizni so'raydi
enter_age - bot sizning yoshingizni so'raydi
usul start ismingizni so'raydi va suhbat holatini o'zgartiradi kutish_nomi, ya'ni. ismingizni kiritish uchun kutish uchun.
Keyinchalik, siz nomni yuborasiz va u usul bilan qayta ishlanadi enter_name, bot sizni kutib oladi, olingan nomni ma'lumotlar bazasiga yozadi va chatni holatga o'tkazadi kutish_yoshi.
Ushbu bosqichda bot sizning yoshingizga kirishingizni kutadi. Siz yoshingizni yuborasiz, bot xabarni tekshiradi, agar siz raqam o'rniga matn yuborsangiz, u shunday deydi: Ты ввёл некорректные данные, введи число, va ma'lumotlaringizni qayta kiritishingizni kutadi. Agar siz raqam yuborgan bo'lsangiz, bot sizning yoshingizni qabul qilganligi haqida xabar beradi, olingan ma'lumotlarni ma'lumotlar bazasiga yozadi, sizdan olingan barcha ma'lumotlar haqida xabar beradi va suhbat holatini asl holatiga qaytaradi, ya'ni. V start.
Usulni chaqirish orqali state Siz istalgan vaqtda joriy chat holatini so'rashingiz mumkin reset suhbatni asl holatiga qaytaring.
Xabar filtrlari
Bizning holatlarimizda bu botni yaratishning eng muhim qismlaridan biridir. Xabar filtrlari yordamida bot sizdan qanday ma'lumot kutayotganini va uni qanday qayta ishlash kerakligini tushunadi.
Loyihada GitHub Filtrlar faylda qayd etilgan message_filters.R.
Xabar filtri kodi:
# ###########################################################
# 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"
}
)
Filtrlarda biz avval yozilgan funksiyadan foydalanamiz get_state(), chatning joriy holatini so'rash uchun. Bu funksiya faqat 1 ta argument, chat identifikatorini talab qiladi.
Keyingi filtr kutish_nomi chat holatida bo'lganda xabarlarni qayta ishlaydi wait_name, va shunga mos ravishda filtr kutish_yoshi chat holatida bo'lganda xabarlarni qayta ishlaydi wait_age.
Ishlovchilar
Ishlovchilarga ega fayl chaqiriladi ishlovchilar.R, va quyidagi kodga ega:
# ###########################################################
# 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)
Avval biz dialogni boshlash, uni qayta o'rnatish va joriy holatni so'rash usullarini ishga tushirish imkonini beruvchi buyruqlar ishlovchilarini yaratamiz.
Keyinchalik, oldingi bosqichda yaratilgan filtrlar yordamida 2 ta xabar ishlov beruvchisini yaratamiz va ularga filtr qo'shamiz !MessageFilters$command, shuning uchun biz har qanday chat holatida buyruqlardan foydalanishimiz mumkin.
Botni ishga tushirish kodi
Endi bizda ishga tushirish uchun hamma narsa tayyor, botni ishga tushirish uchun asosiy kod faylda 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()
Natijada biz ushbu botni oldik:
Istalgan vaqtda buyruq yordamida /state biz joriy chat holatini so'rashimiz mumkin va buyruq yordamida /reset suhbatni asl holatiga qaytaring va dialogni qaytadan boshlang.
xulosa
Ushbu maqolada biz bot ichidagi ma'lumotlar bazasidan qanday foydalanishni va suhbat holatini yozib olish orqali ketma-ket mantiqiy dialoglarni qanday qurishni aniqladik.
Bunday holda, biz eng ibtidoiy misolni ko'rib chiqdik, shunda siz bunday botlarni yaratish g'oyasini tushunishingiz osonroq bo'ladi; amalda siz ancha murakkab dialoglarni qurishingiz mumkin.
Ushbu turkumning keyingi maqolasida biz bot foydalanuvchilarining uning turli usullaridan foydalanish huquqlarini qanday cheklashni bilib olamiz.