Scrivite un telegramma bot in R (parte 4): Custruì un dialogu coherente è logicu cù u bot

Sè avete digià lettu u precedente trè articuli da sta serie, allora sapete digià cumu scrive bots di telegramma cumpletu cù un teclatu.

In questu articulu, ampararemu à scrive un bot chì mantene un dialogu coherente. Quelli. U bot vi farà dumande è aspittà per voi per entre qualchì infurmazione. Sicondu i dati chì inserite, u bot farà alcune azzioni.

Ancu in questu articulu avemu da amparà cumu utilizà una basa di dati sottu u cappucciu di u bot, in u nostru esempiu serà SQLite, ma pudete aduprà qualsiasi altru DBMS. Aghju scrittu in più dettagliu nantu à l'interazzione cù e basa di dati in a lingua R in stu articulu.

Scrivite un telegramma bot in R (parte 4): Custruì un dialogu coherente è logicu cù u bot

Tutti l'articuli di a serie "Scrivu un telegram bot in R"

  1. Creemu un bot è l'utilizanu per mandà missaghji in telegramma
  2. Aghjunghjite u supportu di cumandamentu è i filtri di messagi à u bot
  3. Cumu aghjunghje un supportu di tastiera à un bot
  4. Custruì un dialogu coherente è logicu cù u bot

Cuntenuti

Sè vo site interessatu in l'analisi di dati, pudete esse interessatu in u mo telegram и fratii canali. A maiò parte di u cuntenutu hè dedicatu à a lingua R.

  1. Introduzione
  2. U prucessu di custruzione di u bot
  3. Struttura di u prugettu Bot
  4. Bot cunfigurazione
  5. Crea una variabile d'ambiente
  6. Crià una basa di dati
  7. Funzioni di scrittura per travaglià cù a basa di dati
  8. I metudi di bot
  9. Filtri di messagi
  10. Manipulatori
  11. Bot codice di lanciamentu
  12. cunchiusioni

Introduzione

In ordine per u bot à dumandà dati da voi è aspittà per voi à entre ogni infurmazione, vi tuccherà à registrà u statu attuale di u dialogu. U megliu modu per fà questu hè di utilizà un tipu di basa di dati integrata, cum'è SQLite.

Quelli. A logica serà a siguenti. Chjamemu u metudu di u bot, è u bot sequentially dumanda qualchì infurmazione da noi, è à ogni passu aspetta chì sta informazione sia inserita è pò verificà.

Scriveremu u bot più simplice pussibule, prima dumandarà u vostru nome, dopu a vostra età, è salverà e dati ricevuti in a basa di dati. Quandu dumandate l'età, verificarà chì i dati inseriti sò un numeru è micca un testu.

Un tali dialogu simplice averà solu trè stati:

  1. iniziu hè u statu normale di u bot, in quale ùn aspetta micca infurmazione da voi
  2. wait_name - statu in quale u bot aspetta chì un nome sia inseritu
  3. wait_age hè u statu in quale u bot aspetta chì a vostra età sia inserita, u numeru di anni sanu.

U prucessu di custruzione di u bot

Duranti l'articulu, custruiremu un bot passu à passu, tuttu u prucessu pò esse schematicamente illustratu cum'è:
Scrivite un telegramma bot in R (parte 4): Custruì un dialogu coherente è logicu cù u bot

  1. Creemu una cunfigurazione di bot in quale guardemu alcune paràmetri. In u nostru casu, u bot token, è u percorsu à u schedariu di basa di dati.
  2. Creemu una variabile d'ambiente in quale u percorsu à u prugettu cù u bot serà guardatu.
  3. Creemu a basa di dati stessu, è una quantità di funzioni per chì u bot pò interagisce cun ellu.
  4. Scrivemu i metudi di bot, i.e. e funzioni chì hà da esse realizatu.
  5. Aghjunghje i filtri di messagi. Cù l'aiutu di quale u bot accede à i metudi necessarii, secondu u statu attuale di u chat.
  6. Aghjunghjemu handlers chì cunnetteranu cumandamenti è missaghji cù i metudi di bot necessarii.
  7. Lanciamu u bot.

Struttura di u prugettu Bot

Per comodità, divideremu u codice di u nostru bot, è altri schedarii cunnessi, in a struttura seguente.

  • bot.R - u codice principale di u nostru bot
  • db_bot_function.R - un bloccu di codice cù funzioni per travaglià cù a basa di dati
  • bot_methods.R - codice di i metudi di bot
  • message_filters.R - filtri di messagi
  • i maniscalchi.R - gestori
  • config.cfg - bot config
  • create_db_data.sql - Script SQL per creà una tabella cù dati di chat in a basa di dati
  • create_db_state.sql - Script SQL per creà una tabella di u statu di chat attuale in a basa di dati
  • bot.db - basa di dati di bot

Pudete vede tuttu u prughjettu di u bot, o скачать da u mo repository in GitHub.

Bot cunfigurazione

Avemu aduprà u solitu cum'è cunfigurazione file ini, a forma seguente:

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

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

In a cunfigurazione scrivemu u token di bot è u percorsu à a basa di dati, i.e. à u schedariu bot.db avemu da creà u schedariu stessu in u prossimu passu.

Per i bots più cumplessi, pudete creà cunfigurazioni più cumplessi, in più, ùn hè micca necessariu di scrive un ini config, pudete aduprà qualsiasi altru formatu cumpresu JSON.

Crea una variabile d'ambiente

In ogni PC, u cartulare cù u prughjettu di u bot pò esse situatu in diversi cartulari è in diverse unità, cusì in u codice u percorsu à u cartulare di u prughjettu serà stabilitu via una variabile di l'ambiente. TG_BOT_PATH.

Ci hè parechje manere di creà una variabile d'ambiente, u più simplice hè di scrive in un schedariu .Renvironment.

Pudete creà o edità stu schedariu cù u cumandimu file.edit(path.expand(file.path("~", ".Renviron"))). Eseguite è aghjunghje una linea à u schedariu:

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

Dopu salvà u schedariu .Renvironment è riavvia RStudio.

Crià una basa di dati

U prossimu passu hè di creà una basa di dati. Avemu bisognu di 2 tavule:

  • chat_data - dati chì u bot hà dumandatu da l'utilizatore
  • chat_state - u statu attuale di tutti i chats

Pudete creà sti tavule cù a seguente query 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
);

Se avete scaricatu u prughjettu di u bot da GitHub, dopu per creà a basa di dati pudete aduprà u codice seguente 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'))

Funzioni di scrittura per travaglià cù a basa di dati

Avemu digià un schedariu di cunfigurazione pronta è una basa di dati creata. Avà avete bisognu di scrive funzioni per leghje è scrive dati à sta basa di dati.

Sè avete scaricatu u prugettu da GitHub, allura pudete truvà e funzioni in u schedariu db_bot_function.R.

Codice di funzione per travaglià cù a basa di dati

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

}

Avemu creatu 4 funzioni simplici:

  • get_state() - uttene u statu di chat attuale da a basa di dati
  • set_state() - scrivite u statu di chat attuale à a basa di dati
  • get_chat_data() - riceve dati mandati da l'utilizatore
  • set_chat_data() - arregistrà i dati ricevuti da l'utilizatore

Tutte e funzioni sò abbastanza sèmplice, o leghjenu dati da a basa di dati cù u cumandimu dbGetQuery(), o impegnà UPSERT operazione (cambià dati esistenti o scrivite novi dati à a basa di dati), utilizendu a funzione dbExecute().

A sintassi per l'operazione UPSERT hè a siguenti:

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

Quelli. in u nostru campu di tavule chat_id hà una limitazione di unicità è hè a chjave primaria di e tavule. In principiu, pruvemu à aghjunghje infurmazione à a tavula, è avemu un errore se i dati per u chat attuale sò digià presente, in quale casu avemu solu aghjurnà l'infurmazioni per questa chat.

Dopu, avemu aduprà sti funzioni in i metudi di u bot è filtri.

I metudi di bot

U prossimu passu à custruisce u nostru bot hè di creà metudi. Sè avete scaricatu u prugettu da GitHub, allura tutti i metudi sò in u schedariu bot_methods.R.

Codice di u metudu Bot

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

}

Avemu creatu 5 metudi:

  • start - Start un dialogu
  • state - Ottene u statu di chat attuale
  • reset - Resetta u statu di chat attuale
  • enter_name - U bot dumanda u vostru nome
  • enter_age - U bot dumanda a vostra età

Metu start dumanda u vostru nome, è cambia u statu di chat à wait_name, i.e. in standby per inserisce u vostru nome.

In seguitu, mandate u nome è hè trattatu da u metudu enter_name, u bot ti saluta, scrive u nome ricevutu in a basa di dati, è cambia u chat à u statu aspetta_età.

À questu stadiu, u bot aspetta chì entre in a vostra età. Mandate a vostra età, u bot cuntrolla u missaghju, se avete mandatu qualchì testu invece di un numeru, dicerà: Ты ввёл некорректные данные, введи число, è vi aspittà per voi à ritruvà i vostri dati. Se avete mandatu un numeru, u bot hà dettu chì hà accettatu a vostra età, scrivite i dati ricivuti à a basa di dati, rappurtate tutti i dati ricevuti da voi è torna u statu di chat à a so pusizioni originale, i.e. V start.

Chjamendu u metudu state pudete dumandà u statu di chat attuale in ogni mumentu, è utilizendu u reset torna u chat à u so statu originale.

Filtri di messagi

In u nostru casu, questu hè una di e parti più impurtanti in a custruzione di un bot. Hè cù l'aiutu di i filtri di missaghju chì u bot hà da capisce quale infurmazione aspetta da voi è cumu si deve esse trattatu.

In u prughjettu nantu GitHub i filtri sò registrati in u schedariu message_filters.R.

Codice di filtru di messagiu:

# ###########################################################
# 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 i filtri usemu a funzione scritta prima get_state(), per dumandà u statu attuale di u chat. Questa funzione richiede solu 1 argumentu, chat id.

Filtru prossimu wait_name processa missaghji quandu u chat hè in un statu wait_name, è dunque u filtru aspetta_età processa missaghji quandu u chat hè in un statu wait_age.

Manipulatori

U schedariu cù handlers hè chjamatu i maniscalchi.R, è hà u codice seguente:

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

Prima avemu criatu cumandanti di cumandamenti chì vi permettenu di eseguisce metudi per inizià un dialogu, resettallu, è dumandate u statu attuale.

In seguitu, creamu 2 gestori di missaghju cù i filtri creati in u passu precedente, è aghjunghje un filtru à elli !MessageFilters$command, cusì chì pudemu usà cumandamenti in ogni statu di chat.

Bot codice di lanciamentu

Avà avemu tuttu prontu per lancià, u codice principale per lancià u bot hè in u schedariu 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()

In u risultatu, avemu avutu stu bot:
Scrivite un telegramma bot in R (parte 4): Custruì un dialogu coherente è logicu cù u bot

In ogni mumentu usendu u cumandamentu /state pudemu interrogà u statu di chat attuale, è usendu u cumandamentu /reset torna u chat à u so statu uriginale è principià u dialogu novu.

cunchiusioni

In questu articulu, avemu capitu cumu utilizà una basa di dati in un bot, è cumu custruisce dialoghi lògichi sequenziali arregistrendu u statu di chat.

In questu casu, avemu vistu l'esempiu più primitivu, perchè esse più faciule per voi per capiscenu l'idea di custruisce tali bots in pratica, pudete custruisce dialoghi assai più cumplessi.

In u prossimu articulu in questa serie, avemu da amparà à limità i diritti di l'utilizatori di u bot per utilizà diversi di i so metudi.

Source: www.habr.com

Add a comment