كتابة روبوت برقية بلغة R (الجزء 4): بناء حوار منطقي متسق مع الروبوت

إذا كنت قد قرأت بالفعل المقالات الثلاثة السابقة في هذه السلسلة ، فأنت تعرف بالفعل كيفية كتابة روبوتات برقية كاملة باستخدام لوحة المفاتيح.



في هذه المقالة ، سوف نتعلم كيفية كتابة روبوت يحافظ على حوار متسق. أولئك. سيطرح عليك الروبوت أسئلة وينتظر منك إدخال أي معلومات. بناءً على البيانات التي أدخلتها ، سيقوم الروبوت ببعض الإجراءات.



في هذه المقالة أيضًا ، سنتعلم كيفية استخدام قاعدة بيانات تحت غطاء الروبوت ، في مثالنا ستكون SQLite ، ولكن يمكنك استخدام أي نظام DBMS آخر. لقد كتبت بمزيد من التفاصيل حول التفاعل مع قواعد البيانات بلغة R في هذه المقالة .





جميع المقالات من سلسلة "كتابة روبوت برقية بلغة R"



  1. نقوم بإنشاء روبوت وإرسال رسائل إلى Telegram باستخدامه
  2. أضف دعم الأوامر وعوامل تصفية الرسائل إلى الروبوت
  3. كيفية إضافة دعم لوحة المفاتيح إلى الروبوت الخاص بك
  4. بناء حوار منطقي متسق مع الروبوت
  5. إدارة حقوق مستخدم الروبوت


المحتوى



إذا كنت مهتمًا بتحليل البيانات ، فقد تكون مهتمًا بقنواتي البرقية و youtube . معظم محتواها مخصص للغة R.



  1. المقدمة
  2. عملية بناء الروبوت
  3. هيكل مشروع البوت
  4. تكوين البوت




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


, :

صورة



/state , /reset .





, .



في هذه الحالة ، قمنا بفحص المثال الأكثر بدائية ، من أجل تسهيل فهم فكرة بناء مثل هذه الروبوتات ، من الناحية العملية يمكنك بناء حوارات أكثر تعقيدًا.



في المقالة التالية في هذه السلسلة ، سوف نتعلم كيفية تقييد حقوق مستخدمي الروبوتات في استخدام أساليب مختلفة.




All Articles