Telegram bot bat idaztea R-n (4. zatia): botarekin elkarrizketa koherente eta logikoa eraikitzea

Aurrekoa irakurri baduzu dagoeneko hiru artikulu serie honetatik, badakizu dagoeneko teklatu batekin telegram bot osoak idazten.

Artikulu honetan, elkarrizketa koherentea mantenduko duen bot bat idazten ikasiko dugu. Horiek. Botak galderak egingo dizkizu eta informazio batzuk sartu arte itxarongo dizu. Sartzen dituzun datuen arabera, bot-ak ekintza batzuk egingo ditu.

Artikulu honetan ere bot-aren kaputxa azpian datu-base bat nola erabili ikasiko dugu, gure adibidean SQLite izango da, baina beste edozein DBMS erabil dezakezu. R hizkuntzan datu-baseekin elkarreragineari buruz zehatzago idatzi nuen Artikulu honetan.

Telegram bot bat idaztea R-n (4. zatia): botarekin elkarrizketa koherente eta logikoa eraikitzea

"Telegram bot bat R-n idazten" serieko artikulu guztiak

  1. Bot bat sortzen dugu eta telegram-en mezuak bidaltzeko erabiltzen dugu
  2. Gehitu komando-laguntza eta mezu-iragazkiak bot-ari
  3. Nola gehitu teklatuaren euskarria bot bati
  4. Botarekin elkarrizketa koherente eta logikoa eraikitzea

Edukia

Datuen analisia interesatzen bazaizu, baliteke nirea interesatzea telegrama и youtube kanalak. Eduki gehienak R hizkuntzari eskainitakoak dira.

  1. Sarrera
  2. Bot eraikuntza prozesua
  3. Bot proiektuaren egitura
  4. Bot konfigurazioa
  5. Sortu ingurune-aldagai bat
  6. Datu-base bat sortzea
  7. Datu-basearekin lan egiteko funtzioak idaztea
  8. Bot metodoak
  9. Mezu-iragazkiak
  10. Kudeatzaileak
  11. Bot abiarazteko kodea
  12. Ondorioa

Sarrera

Botak zuri datuak eskatzeko eta edozein informazio sartu arte itxaron ahal izateko, elkarrizketaren uneko egoera grabatu beharko duzu. Horretarako modurik onena kapsulatutako datu-baseren bat erabiltzea da, adibidez SQLite.

Horiek. Logika hau izango da. Bot metodoari deitzen diogu, eta bot-ak sekuentzialki informazio batzuk eskatzen dizkigu, eta urrats bakoitzean informazio hori sartu arte itxaroten du eta egiaztatu ahal izango du.

Ahalik eta bot errazena idatziko dugu, lehenik zure izena eskatuko du, gero zure adina, eta jasotako datuak datu-basean gordeko ditu. Adina galdetzean, sartutako datuak zenbaki bat direla eta ez testua egiaztatuko du.

Elkarrizketa sinple horrek hiru egoera baino ez ditu izango:

  1. start bot-aren egoera normala da, eta bertan ez du zuregandik inolako informaziorik espero
  2. wait_name - bot-ak izen bat sartu arte itxaroten duen egoera
  3. wait_age bot-ak zure adina sartu arte itxaroten duen egoera da, urte osoen kopurua.

Bot eraikuntza prozesua

Artikuluan zehar, bot bat eraikiko dugu urratsez urrats; prozesu osoa eskematikoki honela irudikatu daiteke:
Telegram bot bat idaztea R-n (4. zatia): botarekin elkarrizketa koherente eta logikoa eraikitzea

  1. Bot konfigurazio bat sortzen dugu eta bertan ezarpen batzuk gordeko ditugu. Gure kasuan, bot tokena eta datu-basearen fitxategirako bidea.
  2. Ingurune-aldagai bat sortzen dugu eta bertan botarekin proiekturako bidea gordeko da.
  3. Datu-basea bera sortzen dugu, eta hainbat funtzio, bot-ak harekin elkarreragin dezan.
  4. Bot metodoak idazten ditugu, hau da. beteko dituen funtzioak.
  5. Mezu-iragazkiak gehitzea. Horren laguntzaz bot-ak beharrezko metodoetara sartuko du, txataren uneko egoeraren arabera.
  6. Komandoak eta mezuak beharrezko bot metodoekin konektatuko dituzten kudeatzaileak gehitzen ditugu.
  7. Abiarazi dezagun bot-a.

Bot proiektuaren egitura

Erosotasunerako, gure botaren kodea eta erlazionatutako beste fitxategi batzuk hurrengo egituran banatuko ditugu.

  • bot.R - gure bot-aren kode nagusia
  • db_bot_function.R — datu-basearekin lan egiteko funtzioak dituen kode bloke bat
  • bot_metodoak.R — bot metodoen kodea
  • mezu_iragazkiak.R — mezuen iragazkiak
  • kudeatzaileak.R - kudeatzaileak
  • konfig.cfg - bot konfigurazioa
  • create_db_data.sql — Datu-basean txat-datuekin taula bat sortzeko SQL scripta
  • create_db_state.sql — Datu-basean uneko txat egoeraren taula bat sortzeko SQL scripta
  • bot.db - bot datu-basea

Bot proiektu osoa ikus dezakezu edo deskargatu niregandik GitHub-en biltegia.

Bot konfigurazioa

Ohikoa dena erabiliko dugu konfigurazio gisa ini fitxategia, forma hau:

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

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

Konfigurazioan bot tokena eta datu-baserako bidea idazten ditugu, hau da. bot.db fitxategira; fitxategia bera sortuko dugu hurrengo urratsean.

Bot konplexuagoetarako, konfigurazio konplexuagoak sor ditzakezu, gainera, ez da beharrezkoa ini konfigurazioa idaztea, beste edozein formatu erabil dezakezu JSON barne.

Sortu ingurune-aldagai bat

PC bakoitzean, bot proiektua duen karpeta direktorio ezberdinetan eta disko ezberdinetan egon daiteke, beraz, kodean proiektuaren karpetarako bidea ingurune-aldagai baten bidez ezarriko da. TG_BOT_PATH.

Ingurune aldagai bat sortzeko hainbat modu daude, errazena fitxategi batean idaztea da .Inguruan.

Komandoa erabiliz fitxategi hau sortu edo edita dezakezu file.edit(path.expand(file.path("~", ".Renviron"))). Exekutatu eta gehitu lerro bat fitxategiari:

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

Ondoren, gorde fitxategia .Inguruan eta berrabiarazi RStudio.

Datu-base bat sortzea

Hurrengo urratsa datu-base bat sortzea da. 2 taula beharko ditugu:

  • chat_data - bot-ak erabiltzaileari eskatutako datuak
  • chat_state — txat guztien egungo egoera

Taula hauek sor ditzakezu SQL kontsulta hau erabiliz:

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

Bot proiektua deskargatu baduzu GitHub, ondoren datu-basea sortzeko hurrengo kodea erabil dezakezu R-n.

# Скрипт создания базы данных
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'))

Datu-basearekin lan egiteko funtzioak idaztea

Dagoeneko prest daukagu ​​konfigurazio fitxategi bat eta datu-base bat sortua. Orain datu-base honetan datuak irakurtzeko eta idazteko funtzioak idatzi behar dituzu.

Proiektua hemendik deskargatu baduzu GitHub, orduan funtzioak fitxategian aurki ditzakezu db_bot_function.R.

Datu-basearekin lan egiteko funtzio-kodea

# ###########################################################
# 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 funtzio sinple sortu ditugu:

  • get_state() — eskuratu uneko txat-egoera datu-basetik
  • set_state() — idatzi uneko txat-egoera datu-basean
  • get_chat_data() — Erabiltzaileak bidalitako datuak jaso
  • set_chat_data() — erabiltzailearengandik jasotako datuak erregistratzea

Funtzio guztiak nahiko sinpleak dira, komandoa erabiliz datu-baseko datuak irakurtzen dituzte dbGetQuery(), edo konpromisoa hartu UPSERT eragiketa (dauden datuak aldatzea edo datu-basean datu berriak idaztea), funtzioa erabiliz dbExecute().

UPSERT eragiketaren sintaxia honako hau da:

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

Horiek. gure taulen eremuan txat_id berezitasun-murriztapena du eta taulen gako nagusia da. Hasieran, taulan informazioa gehitzen saiatzen gara, eta errore bat jasoko dugu uneko txataren datuak dagoeneko badaude, eta kasu horretan, berriketa honen informazioa eguneratzen dugu.

Ondoren, funtzio hauek bot-en metodo eta iragazkietan erabiliko ditugu.

Bot metodoak

Gure bot eraikitzeko hurrengo urratsa metodoak sortzea da. Proiektua hemendik deskargatu baduzu GitHub, orduan metodo guztiak fitxategian daude bot_metodoak.R.

Bot metodoaren kodea

# ###########################################################
# 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 metodo sortu ditugu:

  • start — Hasi elkarrizketa-koadroa
  • egoera — Lortu uneko txat egoera
  • berrezarri — Berrezarri uneko txat-egoera
  • enter_name — Botak zure izena eskatzen dizu
  • enter_age — Botak zure adina eskatzen dizu

Метод start zure izena eskatzen du, eta txat-egoera aldatzen du itxaron_izena, hau da. zure izena idazteko egonean egoteko.

Ondoren, izena bidaltzen duzu eta metodoaren bidez prozesatzen da enter_name, bot-ak agurtzen zaitu, jasotako izena datu-basean idazten du eta txata egoerara aldatzen du itxaron_adina.

Fase honetan, bot-ak zure adina sartzea espero du. Zure adina bidaltzen duzu, bot-ak mezua egiaztatzen du, zenbaki baten ordez testuren bat bidali baduzu, esango du: Ты ввёл некорректные данные, введи число, eta zure datuak berriro sartu arte itxarongo du. Zenbaki bat bidali baduzu, bot-ak zure adina onartu duela jakinaraziko du, jasotako datuak datu-basean idatziko ditu, zuregandik jasotako datu guztien berri emango du eta txat-egoera jatorrizko posiziora itzuliko du, hau da. V start.

Metodoari deituz state uneko txataren egoera edozein unetan eska dezakezu eta hau erabiliz reset itzuli txata jatorrizko egoerara.

Mezu-iragazkiak

Gure kasuan, hau da bot bat eraikitzeko zati garrantzitsuenetako bat. Mezu-iragazkien laguntzaz ulertuko du bot-ak zuregandik zer informazio espero duen eta nola prozesatu behar den.

On proiektuan GitHub iragazkiak fitxategian erregistratzen dira mezu_iragazkiak.R.

Mezuen iragazkien kodea:

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

Iragazkietan aurretik idatzitako funtzioa erabiltzen dugu get_state(), txataren egungo egoera eskatzeko. Funtzio honek argumentu bakarra behar du, txataren IDa.

Hurrengo iragazkia itxaron_izena mezuak prozesatzen ditu txata egoera batean dagoenean wait_name, eta horren arabera iragazkia itxaron_adina mezuak prozesatzen ditu txata egoera batean dagoenean wait_age.

Kudeatzaileak

Kudeatzaileak dituen fitxategiari deitzen zaio kudeatzaileak.R, eta kode hau dauka:

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

Lehenik eta behin, komando-kudeatzaileak sortuko ditugu, elkarrizketa-koadro bat hasteko, berrezartzeko eta uneko egoera kontsultatzeko metodoak exekutatzeko aukera emango dizutenak.

Jarraian, 2 mezu-kudeatzaile sortzen ditugu aurreko urratsean sortutako iragazkiak erabiliz, eta iragazki bat gehitzen diegu !MessageFilters$command, komandoak edozein txat egoeratan erabili ahal izateko.

Bot abiarazteko kodea

Orain dena prest dugu abiarazteko, bot-a abiarazteko kode nagusia fitxategian dago 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()

Ondorioz, bot hau lortu dugu:
Telegram bot bat idaztea R-n (4. zatia): botarekin elkarrizketa koherente eta logikoa eraikitzea

Edozein unetan komandoa erabiliz /state uneko txat-egoera kontsultatu dezakegu, eta komandoa erabiliz /reset itzuli txata jatorrizko egoerara eta hasi elkarrizketa berriro.

Ondorioa

Artikulu honetan, bot baten barruan datu-base bat nola erabili eta elkarrizketa logiko sekuentzialak nola eraiki txat-egoera grabatuz asmatu dugu.

Kasu honetan, adibiderik primitiboena aztertu dugu, horrela errazagoa izango zaizu ulertzea horrelako bot-ak eraikitzeko ideia; praktikan, askoz elkarrizketa konplexuagoak eraiki ditzakezu.

Serie honetako hurrengo artikuluan, bot erabiltzaileek bere metodo desberdinak erabiltzeko eskubideak nola mugatu ikasiko dugu.

Iturria: www.habr.com

Gehitu iruzkin berria