Escribir un bot de telegrama en lenguaje R (parte 4): construir un diálogo lógico y consistente con un bot

Si ya ha leído los tres artículos anteriores de esta serie, entonces ya sabe cómo escribir bots de telegramas completos con un teclado.



En este artículo, aprenderemos cómo escribir un bot que mantendrá un diálogo constante. Aquellos. el bot le hará preguntas y esperará a que ingrese cualquier información. Dependiendo de los datos que ingresó, el bot realizará algunas acciones.



También en este artículo aprenderemos cómo usar una base de datos bajo el capó de un bot, en nuestro ejemplo será SQLite, pero puede usar cualquier otro DBMS. Escribí con más detalle sobre la interacción con bases de datos en el lenguaje R en este artículo .





Todos los artículos de la serie "Escribir un bot de telegrama en lenguaje R"



  1. Creamos un bot y enviamos mensajes a telegram con él
  2. Agregue soporte de comando y filtros de mensajes al bot
  3. Cómo agregar soporte de teclado a su bot
  4. Construyendo un diálogo lógico y consistente con el bot
  5. Gestión de derechos de usuario de bot


Contenido



telegram youtube . R.







, , - . , , SQLite.



.. . , - , , .



, , , . , , .



:



  1. start — ,
  2. wait_name — ,
  3. wait_age — , , .




, :



  1. , . , .
  2. , .
  3. , , .
  4. , .. .
  5. . , .
  6. , .
  7. .




, .



  • bot.R
  • db_bot_function.R
  • bot_methods.R
  • message_filters.R
  • handlers.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.



, — .Renviron.



, file.edit(path.expand(file.path("~", ".Renviron"))). :



TG_BOT_PATH=C:////


.Renviron 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 :



  • start —
  • state —
  • reset —
  • enter_name —
  • enter_age —


start , wait_name, .. .



, enter_name, , , wait_age.



. , , - : , , . , , , , , .. 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 , id .



wait_name wait_name, wait_age wait_age.





handlers.R, :



# ###########################################################
# 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, , .





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


, :

imagen



/state , /reset .





, .



En este caso, examinamos el ejemplo más primitivo, para que le sea más fácil comprender la idea de construir tales bots, en la práctica puede construir diálogos mucho más complejos.



En el próximo artículo de esta serie, aprenderemos cómo restringir los derechos de los usuarios de bots para usar varios métodos.




All Articles