R тілінде телеграмма ботын жазу (4-бөлім): Ботпен дәйекті, логикалық диалог құру

Егер сіз алдыңғысын оқып қойған болсаңыз үш мақала осы сериядан, содан кейін сіз пернетақтамен толыққанды телеграмма боттарын қалай жазу керектігін білесіз.

Бұл мақалада біз тұрақты диалогты сақтайтын ботты қалай жазу керектігін үйренеміз. Анау. Бот сізге сұрақтар қояды және кейбір ақпаратты енгізуіңізді күтеді. Сіз енгізген деректерге байланысты бот кейбір әрекеттерді орындайды.

Сондай-ақ, осы мақалада біз боттың астындағы дерекқорды қалай пайдалану керектігін үйренеміз, біздің мысалда ол SQLite болады, бірақ сіз кез келген басқа ДҚБЖ пайдалана аласыз. Мен R тіліндегі дерекқорлармен әрекеттесу туралы толығырақ жаздым Бұл мақала.

R тілінде телеграмма ботын жазу (4-бөлім): Ботпен дәйекті, логикалық диалог құру

«R тілінде телеграмма ботын жазу» сериясының барлық мақалалары

  1. Біз бот жасаймыз және оны телеграмда хабарламалар жіберу үшін пайдаланамыз
  2. Ботқа пәрменді қолдау және хабар сүзгілерін қосу
  3. Ботқа пернетақта қолдауын қалай қосуға болады
  4. Ботпен жүйелі, логикалық диалог құру

Мазмұны

Егер сіз деректерді талдауға қызығушылық танытсаңыз, сізді мені қызықтыруы мүмкін жеделхат и YouTube арналар. Мазмұнның көп бөлігі R тіліне арналған.

  1. Кіріспе
  2. Бот құру процесі
  3. Бот жобасының құрылымы
  4. Бот конфигурациясы
  5. Айнымалы ортаны жасаңыз
  6. Мәліметтер қорын құру
  7. Мәліметтер қорымен жұмыс істеу функцияларын жазу
  8. Бот әдістері
  9. Хабар сүзгілері
  10. Өңдеушілер
  11. Ботты іске қосу коды
  12. қорытынды

Кіріспе

Бот сізден деректерді сұрауы және кез келген ақпаратты енгізуіңізді күтуі үшін диалогтың ағымдағы күйін жазуыңыз қажет. Мұны істеудің ең жақсы жолы - SQLite сияқты ендірілген дерекқорды пайдалану.

Анау. Логика келесідей болады. Біз бот әдісін шақырамыз және бот бізден кейбір ақпаратты ретімен сұрайды және әр қадамда ол осы ақпараттың енгізілуін күтеді және оны тексере алады.

Біз ең қарапайым ботты жазамыз, ол алдымен сіздің атыңызды, содан кейін жасыңызды сұрайды және алынған деректерді дерекқорға сақтайды. Жасты сұраған кезде ол енгізілген деректер мәтін емес, сан екенін тексереді.

Мұндай қарапайым диалог тек үш күйге ие болады:

  1. бастау - боттың қалыпты күйі, онда ол сізден ешқандай ақпарат күтпейді
  2. күту_аты - бот атауды енгізуді күтетін күй
  3. wait_age — бот сіздің жасыңызды енгізуді күтетін күй, толық жылдар саны.

Бот құру процесі

Мақалада біз ботты кезең-кезеңімен жасаймыз, бүкіл процесті схемалық түрде келесідей бейнелеуге болады:
R тілінде телеграмма ботын жазу (4-бөлім): Ботпен дәйекті, логикалық диалог құру

  1. Біз кейбір параметрлерді сақтайтын бот конфигурациясын жасаймыз. Біздің жағдайда, бот белгісі және дерекқор файлына жол.
  2. Біз ботпен жобаға жол сақталатын ортаның айнымалы мәнін жасаймыз.
  3. Біз дерекқордың өзін және бот онымен әрекеттесуі үшін бірқатар функцияларды жасаймыз.
  4. Біз бот әдістерін жазамыз, яғни. атқаратын функциялары.
  5. Хабарлама сүзгілерін қосу. Оның көмегімен бот чаттың ағымдағы күйіне байланысты қажетті әдістерге қол жеткізеді.
  6. Біз пәрмендер мен хабарларды қажетті бот әдістерімен байланыстыратын өңдеушілерді қосамыз.
  7. Ботты іске қосайық.

Бот жобасының құрылымы

Ыңғайлы болу үшін біз боттың кодын және басқа да қатысты файлдарды келесі құрылымға бөлеміз.

  • бот.Р — біздің боттың негізгі коды
  • db_bot_function.R — мәліметтер қорымен жұмыс істеу функциялары бар код блогы
  • bot_methods.R — бот әдістерінің коды
  • message_filters.R — хабарлама сүзгілері
  • өңдеушілер.Р - өңдеушілер
  • config.cfg - бот конфигурациясы
  • create_db_data.sql — Мәліметтер базасында чат деректерімен кесте құруға арналған SQL сценарийі
  • create_db_state.sql — Деректер базасында ағымдағы чат күйінің кестесін құруға арналған SQL сценарийі
  • bot.db - бот деректері

Сіз бүкіл бот жобасын көре аласыз немесе скачать менің GitHub репозиторийі.

Бот конфигурациясы

Біз конфигурация ретінде әдеттегіні қолданамыз ini файлы, келесі пішін:

[bot_settings]
bot_token=ТОКЕН_ВАШЕГО_БОТА

[db_settings]
db_path=C:/ПУТЬ/К/ПАПКЕ/ПРОЕКТА/bot.db

Конфигурацияда біз бот белгісін және дерекқорға жолды жазамыз, яғни. bot.db файлына, келесі қадамда файлдың өзін жасаймыз.

Неғұрлым күрделі боттар үшін күрделірек конфигурацияларды жасауға болады, сонымен қатар ini конфигурациясын жазудың қажеті жоқ, JSON сияқты кез келген басқа пішімді пайдалануға болады.

Айнымалы ортаны жасаңыз

Әрбір компьютерде бот жобасы бар қалта әртүрлі каталогтарда және әртүрлі дискілерде орналасуы мүмкін, сондықтан кодта жоба қалтасына жол орта айнымалысы арқылы орнатылады. TG_BOT_PATH.

Айнымалы ортаны құрудың бірнеше жолы бар, ең қарапайымы оны файлға жазу .Ренвирон.

Бұл файлды пәрмен арқылы жасауға немесе өңдеуге болады file.edit(path.expand(file.path("~", ".Renviron"))). Оны орындап, файлға бір жолды қосыңыз:

TG_BOT_PATH=C:/ПУТЬ/К/ВАШЕМУ/ПРОЕКТУ

Содан кейін файлды сақтаңыз .Ренвирон және RStudio қайта іске қосыңыз.

Мәліметтер қорын құру

Келесі қадам мәліметтер базасын құру болып табылады. Бізге 2 кесте қажет:

  • chat_data — бот пайдаланушыдан сұраған деректер
  • chat_state — барлық чаттардың ағымдағы күйі

Бұл кестелерді келесі 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
);

Егер сіз бот жобасын жүктеп алсаңыз GitHub, содан кейін дерекқорды жасау үшін 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'))

Мәліметтер қорымен жұмыс істеу функцияларын жазу

Бізде дайын конфигурация файлы және жасалған дерекқор бар. Енді осы дерекқорға деректерді оқу және жазу функцияларын жазу керек.

Егер сіз жобаны мына жерден жүктеп алсаңыз GitHub, содан кейін файлдағы функцияларды таба аласыз db_bot_function.R.

Мәліметтер қорымен жұмыс істеуге арналған функция коды

# ###########################################################
# 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 қарапайым функцияны жасадық:

  • get_state() — дерекқордан ағымдағы чат күйін алу
  • set_state() — дерекқорға ағымдағы чат күйін жазу
  • get_chat_data() — пайдаланушы жіберген деректерді алу
  • set_chat_data() — пайдаланушыдан алынған деректерді жазу

Барлық функциялар өте қарапайым, олар пәрмен арқылы дерекқордан деректерді оқиды dbGetQuery(), немесе міндеттеңіз UPSERT операция (бар деректерді өзгерту немесе дерекқорға жаңа деректерді жазу), функцияны пайдалану dbExecute().

UPSERT операциясының синтаксисі келесідей:

INSERT INTO chat_data (chat_id, ${field})
VALUES(${chat_id}, '${value}') 
ON CONFLICT(chat_id) 
DO UPDATE SET ${field}='${value}';

Анау. біздің кестелер өрісінде chat_id бірегейлік шектеуі бар және кестелердің негізгі кілті болып табылады. Бастапқыда біз кестеге ақпаратты қосуға тырысамыз және ағымдағы чатқа арналған деректер бұрыннан бар болса, қатені аламыз, бұл жағдайда біз осы чатқа арналған ақпаратты жай ғана жаңартамыз.

Әрі қарай, біз бұл функцияларды бот әдістері мен сүзгілерінде қолданамыз.

Бот әдістері

Біздің роботты құрудың келесі қадамы - әдістерді жасау. Егер сіз жобаны мына жерден жүктеп алсаңыз GitHub, содан кейін барлық әдістер файлда болады bot_methods.R.

Бот әдісінің коды

# ###########################################################
# 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')
  }

}

Біз 5 әдісті жасадық:

  • бастау — диалогты бастау
  • күй — ағымдағы сөйлесу күйін алыңыз
  • ысыру — Ағымдағы сөйлесу күйін қалпына келтіріңіз
  • enter_name — Бот атыңызды сұрайды
  • enter_age — Бот сіздің жасыңызды сұрайды

Әдіс start атыңызды сұрайды және чат күйін өзгертеді күту_аты, яғни. атыңызды енгізу үшін күту режиміне қойыңыз.

Содан кейін сіз атауды жібересіз және ол әдіс арқылы өңделеді enter_name, бот амандасады, алынған атауды дерекқорға жазады және чатты күйге ауыстырады күту_жасы.

Бұл кезеңде бот сіздің жасыңызды енгізуді күтеді. Сіз жасыңызды жібересіз, бот хабарламаны тексереді, егер сіз санның орнына мәтін жіберсеңіз, ол былай дейді: Ты ввёл некорректные данные, введи число, және сіздің деректеріңізді қайта енгізуіңізді күтеді. Нөмірді жіберген болсаңыз, бот сіздің жасыңызды қабылдағаны туралы хабарлайды, алынған деректерді дерекқорға жазады, сізден алынған барлық деректерді хабарлайды және чат күйін бастапқы орнына қайтарады, яғни. В start.

Әдісті шақыру арқылы state көмегімен ағымдағы чат күйін кез келген уақытта сұрауға болады reset чатты бастапқы күйіне қайтарыңыз.

Хабар сүзгілері

Біздің жағдайда бұл бот құрудағы ең маңызды бөліктердің бірі. Хабарлама сүзгілерінің көмегімен бот сізден қандай ақпаратты күтетінін және оны қалай өңдеу керектігін түсінеді.

Жобада GitHub сүзгілер файлда тіркелген message_filters.R.

Хабарлама сүзгі коды:

# ###########################################################
# 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"
}
)

Сүзгілерде біз бұрын жазылған функцияны қолданамыз get_state(), чаттың ағымдағы күйін сұрау үшін. Бұл функция тек 1 аргумент, чат идентификаторын қажет етеді.

Келесі сүзгі күту_аты чат күйде болғанда хабарларды өңдейді wait_name, және сәйкесінше сүзгі күту_жасы чат күйде болғанда хабарларды өңдейді wait_age.

Өңдеушілер

Өңдеушілері бар файл шақырылады өңдеушілер.Р, және келесі код бар:

# ###########################################################
# 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)

Алдымен диалогты бастау, оны қалпына келтіру және ағымдағы күйді сұрау әдістерін іске қосуға мүмкіндік беретін пәрмен өңдегіштерін жасаймыз.

Әрі қарай, біз алдыңғы қадамда жасалған сүзгілерді пайдаланып 2 хабар өңдегішін жасаймыз және оларға сүзгі қосамыз !MessageFilters$command, сондықтан біз кез келген сөйлесу күйінде пәрмендерді пайдалана аламыз.

Ботты іске қосу коды

Енді бізде іске қосу үшін барлығы дайын, ботты іске қосудың негізгі коды файлда бот.Р.

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()

Нәтижесінде біз мына ботты алдық:
R тілінде телеграмма ботын жазу (4-бөлім): Ботпен дәйекті, логикалық диалог құру

Кез келген уақытта пәрменді пайдалану /state біз ағымдағы чат күйін сұрай аламыз және пәрменді пайдалана аламыз /reset чатты бастапқы күйіне қайтарып, диалогты қайта бастаңыз.

қорытынды

Бұл мақалада біз бот ішінде дерекқорды қалай пайдалану керектігін және чат күйін жазу арқылы жүйелі логикалық диалогтарды қалай құру керектігін түсіндік.

Бұл жағдайда мұндай боттарды құру идеясын түсіну оңай болуы үшін біз ең қарапайым мысалды қарастырдық; іс жүзінде сіз әлдеқайда күрделі диалогтар құра аласыз.

Осы сериядағы келесі мақалада біз бот пайдаланушыларының оның әртүрлі әдістерін пайдалану құқықтарын қалай шектеу керектігін үйренеміз.

Ақпарат көзі: www.habr.com

пікір қалдыру