Telegrammas robota rakstīšana programmā R (4. daļa): konsekventa, loģiska dialoga veidošana ar robotu

Ja jau esi izlasījis iepriekšējo trīs raksti no šīs sērijas, tad jūs jau zināt, kā rakstīt pilnvērtīgus telegrammu botus ar tastatūru.

Šajā rakstā mēs uzzināsim, kā uzrakstīt robotu, kas uzturēs konsekventu dialogu. Tie. Bots uzdos jums jautājumus un gaidīs, kamēr ievadīsit kādu informāciju. Atkarībā no ievadītajiem datiem robots veiks dažas darbības.

Arī šajā rakstā mēs uzzināsim, kā izmantot datubāzi zem robota pārsega, mūsu piemērā tas būs SQLite, bet jūs varat izmantot jebkuru citu DBVS. Es rakstīju sīkāk par mijiedarbību ar datu bāzēm R valodā Šis raksts.

Telegrammas robota rakstīšana programmā R (4. daļa): konsekventa, loģiska dialoga veidošana ar robotu

Visi raksti no sērijas “Telegrammas robota rakstīšana R”

  1. Mēs izveidojam robotu un izmantojam to ziņojumu sūtīšanai telegrammā
  2. Pievienojiet robotam komandu atbalstu un ziņojumu filtrus
  3. Kā robotam pievienot tastatūras atbalstu
  4. Konsekventa, loģiska dialoga veidošana ar robotprogrammatūru

saturs

Ja jūs interesē datu analīze, jūs varētu interesēt mana telegramma и youtube kanāliem. Lielākā daļa satura ir veltīta R valodai.

  1. Ievads
  2. Botu veidošanas process
  3. Botu projekta struktūra
  4. Bota konfigurācija
  5. Izveidojiet vides mainīgo
  6. Datu bāzes izveide
  7. Rakstīšanas funkcijas darbam ar datu bāzi
  8. Botu metodes
  9. Ziņojumu filtri
  10. Apdarinātāji
  11. Bota palaišanas kods
  12. Secinājums

Ievads

Lai robots varētu pieprasīt no jums datus un gaidīt, kamēr jūs ievadīsit jebkādu informāciju, jums būs jāreģistrē pašreizējais dialoga stāvoklis. Labākais veids, kā to izdarīt, ir izmantot kādu iegultu datubāzi, piemēram, SQLite.

Tie. Loģika būs šāda. Mēs izsaucam robota metodi, un robots secīgi pieprasa no mums kādu informāciju un katrā solī gaida, līdz šī informācija tiks ievadīta, un var to pārbaudīt.

Mēs uzrakstīsim pēc iespējas vienkāršāku botu, vispirms tas prasīs jūsu vārdu, pēc tam vecumu, un saņemtos datus saglabās datu bāzē. Pieprasot vecumu, tā pārbaudīs, vai ievadītie dati ir cipars, nevis teksts.

Šādam vienkāršam dialogam būs tikai trīs stāvokļi:

  1. start ir parastais robota stāvoklis, kurā tas negaida no jums nekādu informāciju
  2. gaidīt_nosaukums — stāvoklis, kurā robots gaida vārda ievadīšanu
  3. gaid_vecums ir stāvoklis, kurā robotprogrammatūra gaida, kad tiks ievadīts jūsu vecums, pilno gadu skaits.

Botu veidošanas process

Raksta laikā mēs soli pa solim izveidosim botu, visu procesu var shematiski attēlot šādi:
Telegrammas robota rakstīšana programmā R (4. daļa): konsekventa, loģiska dialoga veidošana ar robotu

  1. Mēs izveidojam robota konfigurāciju, kurā saglabāsim dažus iestatījumus. Mūsu gadījumā robota marķieris un ceļš uz datu bāzes failu.
  2. Mēs izveidojam vides mainīgo, kurā tiks saglabāts ceļš uz projektu ar robotprogrammatūru.
  3. Mēs izveidojam pašu datu bāzi un vairākas funkcijas, lai robots varētu ar to mijiedarboties.
  4. Mēs rakstām botu metodes, t.i. funkcijas, kuras tas veiks.
  5. Ziņojumu filtru pievienošana. Ar kuru palīdzību robots piekļūs nepieciešamajām metodēm atkarībā no pašreizējā tērzēšanas stāvokļa.
  6. Mēs pievienojam apstrādātājus, kas savienos komandas un ziņojumus ar nepieciešamajām robotu metodēm.
  7. Palaidīsim botu.

Botu projekta struktūra

Ērtības labad mēs sadalīsim mūsu robotprogrammatūras kodu un citus saistītos failus šādā struktūrā.

  • bot.R — mūsu bota galvenais kods
  • db_bot_function.R — koda bloks ar funkcijām darbam ar datu bāzi
  • bot_methods.R — robotu metožu kods
  • ziņu_filtri.R — ziņojumu filtri
  • apdarinātāji.R - apdarinātāji
  • config.cfg - robotprogrammatūras konfigurācija
  • Create_db_data.sql — SQL skripts tabulas izveidei ar tērzēšanas datiem datu bāzē
  • Create_db_state.sql — SQL skripts pašreizējā tērzēšanas stāvokļa tabulas izveidei datu bāzē
  • bot.db - botu datu bāze

Varat apskatīt visu robotprogrammatūras projektu vai download no mana krātuve vietnē GitHub.

Bota konfigurācija

Kā konfigurāciju izmantosim parasto ini failu, šāda veidlapa:

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

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

Konfigurācijā ierakstām bota marķieri un ceļu uz datu bāzi, t.i. uz failu bot.db; nākamajā darbībā mēs izveidosim pašu failu.

Sarežģītākiem robotiem varat izveidot sarežģītākas konfigurācijas, turklāt nav nepieciešams rakstīt ini konfigurāciju, varat izmantot jebkuru citu formātu, ieskaitot JSON.

Izveidojiet vides mainīgo

Katrā datorā mape ar robotprojektu var atrasties dažādos direktorijos un dažādos diskos, tāpēc kodā ceļš uz projekta mapi tiks iestatīts, izmantojot vides mainīgo. TG_BOT_PATH.

Ir vairāki veidi, kā izveidot vides mainīgo, visvienkāršākais ir ierakstīt to failā .Renviron.

Varat izveidot vai rediģēt šo failu, izmantojot komandu file.edit(path.expand(file.path("~", ".Renviron"))). Izpildiet to un pievienojiet failam vienu rindiņu:

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

Tālāk saglabājiet failu .Renviron un restartējiet RStudio.

Datu bāzes izveide

Nākamais solis ir izveidot datubāzi. Mums būs nepieciešamas 2 tabulas:

  • chat_data — dati, ko robots pieprasīja lietotājam
  • chat_state — visu tērzēšanas sarunu pašreizējais stāvoklis

Šīs tabulas var izveidot, izmantojot šādu SQL vaicājumu:

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

Ja lejupielādējāt bota projektu no GitHub, pēc tam, lai izveidotu datu bāzi, varat izmantot šādu kodu 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'))

Rakstīšanas funkcijas darbam ar datu bāzi

Mums jau ir gatavs konfigurācijas fails un izveidota datu bāze. Tagad jums ir jāraksta funkcijas, lai lasītu un ierakstītu datus šajā datu bāzē.

Ja lejupielādējāt projektu no GitHub, tad varat atrast funkcijas failā db_bot_function.R.

Funkcijas kods darbam ar datu bāzi

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

}

Mēs izveidojām 4 vienkāršas funkcijas:

  • get_state() — iegūt pašreizējo tērzēšanas stāvokli no datu bāzes
  • set_state() — ierakstiet datu bāzē pašreizējo tērzēšanas stāvokli
  • get_chat_data() — saņemt lietotāja nosūtītos datus
  • set_chat_data() — ierakstīt datus, kas saņemti no lietotāja

Visas funkcijas ir diezgan vienkāršas, tās vai nu nolasa datus no datu bāzes, izmantojot komandu dbGetQuery(), vai apņemties UPSERT darbība (esošo datu maiņa vai jaunu datu ierakstīšana datu bāzē), izmantojot funkciju dbExecute().

UPSERT darbības sintakse ir šāda:

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

Tie. mūsu tabulu laukā tērzēšanas_id ir unikalitātes ierobežojums, un tā ir tabulu primārā atslēga. Sākotnēji mēs cenšamies pievienot informāciju tabulai, un mēs saņemam kļūdu, ja dati par pašreizējo tērzēšanu jau ir, un tādā gadījumā mēs vienkārši atjauninām informāciju par šo tērzēšanu.

Tālāk mēs izmantosim šīs funkcijas bota metodēs un filtros.

Botu metodes

Nākamais solis mūsu robotprogrammatūras veidošanā ir metožu izveide. Ja lejupielādējāt projektu no GitHub, tad visas metodes ir failā bot_methods.R.

Bota metodes kods

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

}

Mēs izveidojām 5 metodes:

  • start — lai sāktu dialogu
  • status — iegūstiet pašreizējo tērzēšanas stāvokli
  • atiestatīt — lai atiestatītu pašreizējo tērzēšanas stāvokli
  • enter_name — robots jautā jūsu vārdu
  • enter_age — robots jautā jūsu vecumu

Metode start jautā jūsu vārdu un maina tērzēšanas statusu uz gaidīt_nosaukums, t.i. gaidīšanas režīmā, lai ievadītu savu vārdu.

Pēc tam jūs nosūtāt vārdu, un tas tiek apstrādāts ar metodi enter_name, robots sveicina jūs, ieraksta saņemto vārdu datu bāzē un pārslēdz tērzēšanu uz stāvokli gaidīšanas_vecums.

Šajā posmā robots sagaida, ka ievadīsit savu vecumu. Jūs nosūtāt savu vecumu, robots pārbauda ziņojumu, ja numura vietā nosūtījāt tekstu, tas teiks: Ты ввёл некорректные данные, введи число, un gaidīs, kamēr atkārtoti ievadīsiet savus datus. Ja jūs nosūtījāt numuru, bots ziņos, ka ir pieņēmis jūsu vecumu, ierakstīs saņemtos datus datu bāzē, ziņos par visiem no jums saņemtajiem datiem un atgriezīs tērzēšanas stāvokli sākotnējā pozīcijā, t.i. V start.

Izsaucot metodi state jūs varat pieprasīt pašreizējo tērzēšanas statusu jebkurā laikā un izmantojot reset atgriezt tērzēšanu sākotnējā stāvoklī.

Ziņojumu filtri

Mūsu gadījumā šī ir viena no vissvarīgākajām robota izveides daļām. Tieši ar ziņojumu filtru palīdzību bots sapratīs, kādu informāciju tas no jums sagaida un kā tā jāapstrādā.

Projektā uz GitHub filtri ir reģistrēti failā ziņu_filtri.R.

Ziņojumu filtra kods:

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

Filtros mēs izmantojam iepriekš uzrakstīto funkciju get_state(), lai pieprasītu pašreizējo tērzēšanas stāvokli. Šai funkcijai ir nepieciešams tikai 1 arguments, tērzēšanas ID.

Nākamais filtrs gaidīt_nosaukums apstrādā ziņojumus, kad tērzēšana ir stāvoklī wait_name, un attiecīgi filtru gaidīšanas_vecums apstrādā ziņojumus, kad tērzēšana ir stāvoklī wait_age.

Apdarinātāji

Tiek izsaukts fails ar apstrādātājiem apdarinātāji.R, un tam ir šāds kods:

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

Vispirms mēs izveidojam komandu apdarinātājus, kas ļaus palaist metodes dialoga palaišanai, atiestatīšanai un pašreizējā stāvokļa vaicāšanai.

Pēc tam mēs izveidojam 2 ziņojumu apdarinātājus, izmantojot iepriekšējā darbībā izveidotos filtrus, un pievienojam tiem filtru !MessageFilters$command, lai mēs varētu izmantot komandas jebkurā tērzēšanas stāvoklī.

Bota palaišanas kods

Tagad mums viss ir gatavs palaišanai, galvenais kods bota palaišanai ir failā 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()

Rezultātā mēs saņēmām šo robotprogrammatūru:
Telegrammas robota rakstīšana programmā R (4. daļa): konsekventa, loģiska dialoga veidošana ar robotu

Jebkurā laikā, izmantojot komandu /state mēs varam jautāt par pašreizējo tērzēšanas stāvokli un izmantojot komandu /reset atgrieziet tērzēšanas sarunu sākotnējā stāvoklī un sāciet dialogu no jauna.

Secinājums

Šajā rakstā mēs noskaidrojām, kā izmantot datubāzi robotā un kā izveidot secīgus loģiskus dialogus, ierakstot tērzēšanas stāvokli.

Šajā gadījumā mēs apskatījām primitīvāko piemēru, lai jums būtu vieglāk saprast ideju par šādu robotprogrammatūru izveidi; praksē jūs varat veidot daudz sarežģītākus dialogus.

Nākamajā šīs sērijas rakstā uzzināsim, kā ierobežot botu lietotāju tiesības izmantot dažādas tā metodes.

Avots: www.habr.com

Pievieno komentāru