การเขียนบอทโทรเลขใน R (ตอนที่ 4): การสร้างบทสนทนาเชิงตรรกะที่สอดคล้องกับบอท

หากได้อ่านตอนที่แล้วแล้ว สามบทความ จากซีรีส์นี้คุณก็รู้วิธีเขียนบอทโทรเลขเต็มรูปแบบด้วยคีย์บอร์ดแล้ว

ในบทความนี้ เราจะได้เรียนรู้วิธีเขียนบอทที่จะรักษาบทสนทนาที่สอดคล้องกัน เหล่านั้น. บอทจะถามคำถามคุณและรอให้คุณป้อนข้อมูลบางอย่าง บอทจะดำเนินการบางอย่างขึ้นอยู่กับข้อมูลที่คุณป้อน

นอกจากนี้ในบทความนี้ เราจะได้เรียนรู้วิธีใช้ฐานข้อมูลภายใต้การทำงานของบอท ในตัวอย่างของเรา มันจะเป็น SQLite แต่คุณสามารถใช้ DBMS อื่น ๆ ได้ ฉันเขียนรายละเอียดเพิ่มเติมเกี่ยวกับการโต้ตอบกับฐานข้อมูลในภาษา R มา บทความนี้.

การเขียนบอทโทรเลขใน R (ตอนที่ 4): การสร้างบทสนทนาเชิงตรรกะที่สอดคล้องกับบอท

บทความทั้งหมดจากซีรีส์ “การเขียนบอทโทรเลขใน R”

  1. เราสร้างบอทและใช้เพื่อส่งข้อความทางโทรเลข
  2. เพิ่มการสนับสนุนคำสั่งและตัวกรองข้อความให้กับบอท
  3. วิธีเพิ่มการรองรับคีย์บอร์ดให้กับบอท
  4. สร้างบทสนทนาเชิงตรรกะที่สอดคล้องกับบอท

Содержание

หากคุณสนใจในการวิเคราะห์ข้อมูล คุณอาจสนใจใน my โทรเลข и YouTube ช่อง. เนื้อหาส่วนใหญ่เกี่ยวกับภาษา R

  1. การแนะนำ
  2. กระบวนการสร้างบอท
  3. โครงสร้างโครงการบอท
  4. การกำหนดค่าบอท
  5. สร้างตัวแปรสภาพแวดล้อม
  6. การสร้างฐานข้อมูล
  7. การเขียนฟังก์ชั่นการทำงานกับฐานข้อมูล
  8. วิธีการบอท
  9. ตัวกรองข้อความ
  10. ตัวจัดการ
  11. รหัสเปิดตัวบอท
  12. ข้อสรุป

การแนะนำ

เพื่อให้บอทขอข้อมูลจากคุณและรอให้คุณป้อนข้อมูลใดๆ คุณจะต้องบันทึกสถานะปัจจุบันของบทสนทนา วิธีที่ดีที่สุดในการทำเช่นนี้คือการใช้ฐานข้อมูลแบบฝังบางประเภท เช่น SQLite

เหล่านั้น. ตรรกะจะเป็นดังนี้ เราเรียกวิธีบอท และบอทจะขอข้อมูลบางอย่างจากเราตามลำดับ และในแต่ละขั้นตอนจะรอให้ป้อนข้อมูลนี้และสามารถตรวจสอบได้

เราจะเขียนบอทที่ง่ายที่สุดที่เป็นไปได้ ขั้นแรกมันจะถามชื่อของคุณ จากนั้นอายุของคุณ และจะบันทึกข้อมูลที่ได้รับลงในฐานข้อมูล เมื่อถามอายุจะตรวจสอบว่าข้อมูลที่กรอกเป็นตัวเลขไม่ใช่ข้อความ

บทสนทนาง่ายๆ ดังกล่าวจะมีเพียงสามสถานะเท่านั้น:

  1. start เป็นสถานะปกติของบอท โดยที่บอทจะไม่คาดหวังข้อมูลใดๆ จากคุณ
  2. wait_name - สถานะที่บอทรอให้ป้อนชื่อ
  3. wait_age คือสถานะที่บอทรอให้ป้อนอายุของคุณ ซึ่งเป็นจำนวนปีเต็ม

กระบวนการสร้างบอท

ในบทความนี้ เราจะสร้างบอททีละขั้นตอน โดยสามารถอธิบายกระบวนการทั้งหมดได้ดังนี้:
การเขียนบอทโทรเลขใน R (ตอนที่ 4): การสร้างบทสนทนาเชิงตรรกะที่สอดคล้องกับบอท

  1. เราสร้างการกำหนดค่าบอทซึ่งเราจะจัดเก็บการตั้งค่าบางอย่าง ในกรณีของเรา โทเค็นบอท และเส้นทางไปยังไฟล์ฐานข้อมูล
  2. เราสร้างตัวแปรสภาพแวดล้อมซึ่งเส้นทางไปยังโครงการที่มีบอทจะถูกจัดเก็บ
  3. เราสร้างฐานข้อมูลเองและฟังก์ชันจำนวนหนึ่งเพื่อให้บอทสามารถโต้ตอบกับฐานข้อมูลได้
  4. เราเขียนวิธีการบอทเช่น ฟังก์ชั่นที่มันจะดำเนินการ
  5. การเพิ่มตัวกรองข้อความ ด้วยความช่วยเหลือที่บอทจะเข้าถึงวิธีการที่จำเป็น ขึ้นอยู่กับสถานะปัจจุบันของการแชท
  6. เราเพิ่มตัวจัดการที่จะเชื่อมต่อคำสั่งและข้อความด้วยวิธีบอทที่จำเป็น
  7. มาเปิดตัวบอทกันเถอะ

โครงสร้างโครงการบอท

เพื่อความสะดวก เราจะแบ่งโค้ดของบอทของเราและไฟล์อื่นๆ ที่เกี่ยวข้องออกเป็นโครงสร้างดังต่อไปนี้

  • บอท.อาร์ — รหัสหลักของบอทของเรา
  • db_bot_function.R — บล็อกโค้ดพร้อมฟังก์ชันสำหรับการทำงานกับฐานข้อมูล
  • bot_methods.R — รหัสของวิธีการบอท
  • message_filters.R — ตัวกรองข้อความ
  • ตัวจัดการ.R - ตัวจัดการ
  • config.cfg - การตั้งค่าบอท
  • create_db_data.sql — สคริปต์ SQL สำหรับสร้างตารางพร้อมข้อมูลแชทในฐานข้อมูล
  • create_db_state.sql — สคริปต์ SQL สำหรับสร้างตารางสถานะการแชทปัจจุบันในฐานข้อมูล
  • บอท.ดีบี - ฐานข้อมูลบอท

คุณสามารถดูโครงการบอททั้งหมดหรือ ดาวน์โหลด จากของฉัน พื้นที่เก็บข้อมูลบน GitHub.

การกำหนดค่าบอท

เราจะใช้อันปกติเป็นการกำหนดค่า ไฟล์ .ini, แบบฟอร์มต่อไปนี้:

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

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

ในการกำหนดค่าเราเขียนโทเค็นบอทและเส้นทางไปยังฐานข้อมูล เช่น ไปยังไฟล์ bot.db เราจะสร้างไฟล์เองในขั้นตอนถัดไป

สำหรับบอทที่ซับซ้อนมากขึ้น คุณสามารถสร้างการกำหนดค่าที่ซับซ้อนมากขึ้นได้ นอกจากนี้ ไม่จำเป็นต้องเขียนการกำหนดค่า ini คุณสามารถใช้รูปแบบอื่นใดก็ได้ รวมถึง JSON

สร้างตัวแปรสภาพแวดล้อม

บนพีซีแต่ละเครื่อง โฟลเดอร์ที่มีโปรเจ็กต์บอทสามารถอยู่ในไดเร็กทอรีที่แตกต่างกันและบนไดรฟ์ที่แตกต่างกัน ดังนั้นในโค้ด เส้นทางไปยังโฟลเดอร์โปรเจ็กต์จะถูกตั้งค่าผ่านตัวแปรสภาพแวดล้อม TG_BOT_PATH.

มีหลายวิธีในการสร้างตัวแปรสภาพแวดล้อม วิธีที่ง่ายที่สุดคือการเขียนลงในไฟล์ .เรนวิรอน.

คุณสามารถสร้างหรือแก้ไขไฟล์นี้โดยใช้คำสั่ง file.edit(path.expand(file.path("~", ".Renviron"))). ดำเนินการและเพิ่มหนึ่งบรรทัดลงในไฟล์:

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

ต่อไปก็บันทึกไฟล์ .เรนวิรอน และรีสตาร์ท 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}';

เหล่านั้น. ในช่องตารางของเรา แชท_ไอดี มีข้อจำกัดด้านเอกลักษณ์และเป็นคีย์หลักของตาราง ในตอนแรก เราพยายามเพิ่มข้อมูลลงในตาราง และเราได้รับข้อผิดพลาดหากมีข้อมูลสำหรับการแชทปัจจุบันอยู่แล้ว ในกรณีนี้ เราเพียงอัปเดตข้อมูลสำหรับการแชทนี้

ต่อไป เราจะใช้ฟังก์ชันเหล่านี้ในวิธีการและตัวกรองของบอท

วิธีการบอท

ขั้นตอนต่อไปในการสร้างบอทของเราคือการสร้างวิธีการ หากคุณดาวน์โหลดโครงการจาก 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 วิธี:

  • เริ่มต้น — เริ่มกล่องโต้ตอบ
  • state — รับสถานะการแชทปัจจุบัน
  • รีเซ็ต — รีเซ็ตสถานะการแชทปัจจุบัน
  • enter_name — บอทจะถามชื่อของคุณ
  • enter_age - บอทถามอายุของคุณ

วิธี start ถามชื่อของคุณและเปลี่ยนสถานะการแชทเป็น wait_name, เช่น. เพื่อรอป้อนชื่อของคุณ

ต่อไปคุณส่งชื่อและประมวลผลโดยวิธี enter_nameบอทจะทักทายคุณ เขียนชื่อที่ได้รับลงในฐานข้อมูล และสลับการแชทเป็นสถานะ รอ_อายุ.

ในขั้นตอนนี้ บอทคาดหวังให้คุณเข้าสู่อายุของคุณ คุณส่งอายุของคุณ บอทจะตรวจสอบข้อความ หากคุณส่งข้อความแทนตัวเลข บอทจะแจ้งว่า: Ты ввёл некорректные данные, введи числоและจะรอให้คุณป้อนข้อมูลของคุณอีกครั้ง หากคุณส่งหมายเลข บอทจะรายงานว่ายอมรับอายุของคุณ เขียนข้อมูลที่ได้รับลงฐานข้อมูล รายงานข้อมูลทั้งหมดที่ได้รับจากคุณ และคืนสถานะการแชทกลับสู่ตำแหน่งเดิม เช่น วี 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 อาร์กิวเมนต์ รหัสแชท

ตัวกรองถัดไป wait_name ประมวลผลข้อความเมื่อการแชทอยู่ในสถานะ wait_nameและตามตัวกรอง รอ_อายุ ประมวลผลข้อความเมื่อการแชทอยู่ในสถานะ wait_age.

ตัวจัดการ

ไฟล์ที่มีตัวจัดการเรียกว่า ตัวจัดการ.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เพื่อให้เราสามารถใช้คำสั่งในสถานะแชทใดก็ได้

รหัสเปิดตัวบอท

ตอนนี้เรามีทุกอย่างพร้อมสำหรับการเปิดตัวแล้ว รหัสหลักสำหรับการเปิดตัวบอทอยู่ในไฟล์ บอท.อาร์.

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

เป็นผลให้เราได้รับบอทนี้:
การเขียนบอทโทรเลขใน R (ตอนที่ 4): การสร้างบทสนทนาเชิงตรรกะที่สอดคล้องกับบอท

ได้ตลอดเวลาโดยใช้คำสั่ง /state เราสามารถสอบถามสถานะการแชทปัจจุบันได้และใช้คำสั่ง /reset คืนการแชทกลับสู่สถานะดั้งเดิมและเริ่มการสนทนาอีกครั้ง

ข้อสรุป

ในบทความนี้ เราได้เรียนรู้วิธีใช้ฐานข้อมูลภายในบอท และวิธีสร้างบทสนทนาเชิงตรรกะตามลำดับโดยการบันทึกสถานะการแชท

ในกรณีนี้ เราได้ดูตัวอย่างดั้งเดิมที่สุด เพื่อให้คุณเข้าใจแนวคิดในการสร้างบอทได้ง่ายขึ้น ในทางปฏิบัติ คุณสามารถสร้างบทสนทนาที่ซับซ้อนมากขึ้นได้

ในบทความถัดไปในชุดนี้ เราจะได้เรียนรู้วิธีจำกัดสิทธิ์ของผู้ใช้บอทในการใช้วิธีการต่างๆ

ที่มา: will.com

เพิ่มความคิดเห็น