Ysgrifennu bot telegram yn R (rhan 4): Adeiladu deialog gyson, rhesymegol gyda'r bot

Os ydych chi eisoes wedi darllen yr un blaenorol tair erthygl o'r gyfres hon, yna rydych chi eisoes yn gwybod sut i ysgrifennu bots telegram llawn gyda bysellfwrdd.

Yn yr erthygl hon, byddwn yn dysgu sut i ysgrifennu bot a fydd yn cynnal deialog gyson. Y rhai. Bydd y bot yn gofyn cwestiynau i chi ac yn aros i chi nodi rhywfaint o wybodaeth. Yn dibynnu ar y data rydych chi'n ei nodi, bydd y bot yn perfformio rhai gweithredoedd.

Hefyd yn yr erthygl hon byddwn yn dysgu sut i ddefnyddio cronfa ddata o dan gwfl y bot, yn ein hesiampl ni fydd SQLite, ond gallwch chi ddefnyddio unrhyw DBMS arall. Ysgrifennais yn fanylach am ryngweithio â chronfeydd data yn yr iaith R yn Mae'r erthygl hon yn.

Ysgrifennu bot telegram yn R (rhan 4): Adeiladu deialog gyson, rhesymegol gyda'r bot

Pob erthygl o'r gyfres “Ysgrifennu bot telegram yn R”

  1. Rydyn ni'n creu bot ac yn ei ddefnyddio i anfon negeseuon mewn telegram
  2. Ychwanegu cefnogaeth gorchymyn a hidlwyr neges i'r bot
  3. Sut i ychwanegu cefnogaeth bysellfwrdd at bot
  4. Adeiladu deialog gyson, rhesymegol gyda'r bot

Cynnwys

Os oes gennych ddiddordeb mewn dadansoddi data, efallai y bydd gennych ddiddordeb yn fy telegram и youtube sianeli. Mae'r rhan fwyaf o'r cynnwys wedi'i neilltuo i'r iaith R.

  1. Cyflwyniad
  2. Proses adeiladu bot
  3. Strwythur prosiect bot
  4. Cyfluniad bot
  5. Creu newidyn amgylchedd
  6. Creu cronfa ddata
  7. Swyddogaethau ysgrifennu i weithio gyda'r gronfa ddata
  8. Dulliau bot
  9. Hidlyddion neges
  10. Trinwyr
  11. Cod lansio bot
  12. Casgliad

Cyflwyniad

Er mwyn i'r bot ofyn am ddata gennych chi ac aros i chi nodi unrhyw wybodaeth, bydd angen i chi gofnodi cyflwr presennol y ddeialog. Y ffordd orau o wneud hyn yw defnyddio rhyw fath o gronfa ddata wedi'i hymgorffori, fel SQLite.

Y rhai. Bydd y rhesymeg fel a ganlyn. Rydyn ni'n galw'r dull bot, ac mae'r bot yn gofyn am rywfaint o wybodaeth gennym ni yn olynol, ac ar bob cam mae'n aros i'r wybodaeth hon gael ei nodi a gall ei gwirio.

Byddwn yn ysgrifennu'r bot symlaf posibl, yn gyntaf bydd yn gofyn am eich enw, yna eich oedran, a bydd yn cadw'r data a dderbyniwyd i'r gronfa ddata. Wrth ofyn am oedran, bydd yn gwirio mai rhif yw'r data a gofnodwyd ac nid testun.

Dim ond tri chyflwr fydd i ddeialog mor syml:

  1. cychwyn yw cyflwr arferol y bot, lle nad yw'n disgwyl unrhyw wybodaeth gennych chi
  2. wait_name - cyflwr lle mae'r bot yn aros i enw gael ei nodi
  3. wait_age yw'r cyflwr y mae'r bot yn aros i'ch oedran gael ei nodi, nifer y blynyddoedd llawn.

Proses adeiladu bot

Yn ystod yr erthygl, byddwn yn adeiladu bot gam wrth gam; gellir darlunio'r broses gyfan yn sgematig fel a ganlyn:
Ysgrifennu bot telegram yn R (rhan 4): Adeiladu deialog gyson, rhesymegol gyda'r bot

  1. Rydym yn creu cyfluniad bot lle byddwn yn storio rhai gosodiadau. Yn ein hachos ni, y tocyn bot, a'r llwybr i'r ffeil cronfa ddata.
  2. Rydym yn creu newidyn amgylchedd lle bydd y llwybr i'r prosiect gyda'r bot yn cael ei storio.
  3. Rydyn ni'n creu'r gronfa ddata ei hun, a nifer o swyddogaethau fel y gall y bot ryngweithio ag ef.
  4. Rydym yn ysgrifennu dulliau bot, h.y. y swyddogaethau y bydd yn eu cyflawni.
  5. Ychwanegu hidlwyr neges. Gyda chymorth y bydd y bot yn cyrchu'r dulliau angenrheidiol, yn dibynnu ar gyflwr presennol y sgwrs.
  6. Rydym yn ychwanegu trinwyr a fydd yn cysylltu gorchmynion a negeseuon gyda'r dulliau bot angenrheidiol.
  7. Gadewch i ni lansio'r bot.

Strwythur prosiect bot

Er hwylustod, byddwn yn rhannu cod ein bot, a ffeiliau cysylltiedig eraill, i'r strwythur canlynol.

  • bot.R — prif god ein bot
  • db_bot_function.R — bloc o god gyda swyddogaethau ar gyfer gweithio gyda'r gronfa ddata
  • bot_methods.R — cod dulliau bot
  • neges_hidlyddion.R - hidlyddion neges
  • trinwyr.R - trinwyr
  • config.cfg - cyfluniad bot
  • creu_db_data.sql — Sgript SQL ar gyfer creu tabl gyda data sgwrsio yn y gronfa ddata
  • creu_db_state.sql — Sgript SQL ar gyfer creu tabl o'r cyflwr sgwrsio cyfredol yn y gronfa ddata
  • bot.db - cronfa ddata bot

Gallwch weld y prosiect bot cyfan, neu скачать oddi wrth fy ystorfa ar GitHub.

Cyfluniad bot

Byddwn yn defnyddio'r un arferol fel ffurfwedd ffeil ini, y ffurflen ganlynol:

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

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

Yn y ffurfweddiad rydyn ni'n ysgrifennu'r tocyn bot a'r llwybr i'r gronfa ddata, h.y. i'r ffeil bot.db; byddwn yn creu'r ffeil ei hun yn y cam nesaf.

Ar gyfer bots mwy cymhleth, gallwch greu cyfluniadau mwy cymhleth, ar wahân, nid oes angen ysgrifennu ini config, gallwch ddefnyddio unrhyw fformat arall gan gynnwys JSON.

Creu newidyn amgylchedd

Ar bob cyfrifiadur personol, gellir lleoli'r ffolder gyda'r prosiect bot mewn gwahanol gyfeiriaduron ac ar wahanol yriannau, felly yn y cod bydd y llwybr i ffolder y prosiect yn cael ei osod trwy newidyn amgylchedd TG_BOT_PATH.

Mae sawl ffordd o greu newidyn amgylchedd, y symlaf yw ei ysgrifennu mewn ffeil .Renviron.

Gallwch greu neu olygu'r ffeil hon gan ddefnyddio'r gorchymyn file.edit(path.expand(file.path("~", ".Renviron"))). Gweithredwch ef ac ychwanegwch un llinell at y ffeil:

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

Nesaf arbedwch y ffeil .Renviron ac ailgychwyn RStudio.

Creu cronfa ddata

Y cam nesaf yw creu cronfa ddata. Bydd angen 2 dabl arnom:

  • chat_data — data y gofynnodd y bot amdano gan y defnyddiwr
  • chat_state — cyflwr presennol pob sgwrs

Gallwch greu'r tablau hyn gan ddefnyddio'r ymholiad SQL canlynol:

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

Os gwnaethoch chi lawrlwytho'r prosiect bot o GitHub, yna i greu'r gronfa ddata gallwch ddefnyddio'r cod canlynol yn 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'))

Swyddogaethau ysgrifennu i weithio gyda'r gronfa ddata

Mae gennym ffeil ffurfweddu yn barod a chronfa ddata wedi'i chreu. Nawr mae angen i chi ysgrifennu swyddogaethau i ddarllen ac ysgrifennu data i'r gronfa ddata hon.

Os gwnaethoch chi lawrlwytho'r prosiect o GitHub, yna gallwch ddod o hyd i'r swyddogaethau yn y ffeil db_bot_function.R.

Cod swyddogaeth ar gyfer gweithio gyda'r gronfa ddata

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

}

Rydym wedi creu 4 swyddogaeth syml:

  • get_state() — cael y cyflwr sgwrsio cyfredol o'r gronfa ddata
  • set_state() — ysgrifennu'r cyflwr sgwrsio cyfredol i'r gronfa ddata
  • get_chat_data() — derbyn data a anfonwyd gan y defnyddiwr
  • set_chat_data() — cofnodi data a dderbyniwyd gan y defnyddiwr

Mae'r holl swyddogaethau yn eithaf syml, maent naill ai'n darllen data o'r gronfa ddata gan ddefnyddio'r gorchymyn dbGetQuery(), neu ymrwymo UPSERT gweithredu (newid data presennol neu ysgrifennu data newydd i'r gronfa ddata), gan ddefnyddio'r swyddogaeth dbExecute().

Mae'r gystrawen ar gyfer gweithrediad UPSERT fel a ganlyn:

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

Y rhai. yn ein maes byrddau sgwrs_id Mae ganddo gyfyngiad unigryw a dyma brif allwedd tablau. I ddechrau, rydym yn ceisio ychwanegu gwybodaeth at y tabl, ac rydym yn cael gwall os yw data ar gyfer y sgwrs gyfredol eisoes yn bresennol, ac os felly rydym yn syml yn diweddaru'r wybodaeth ar gyfer y sgwrs hon.

Nesaf, byddwn yn defnyddio'r swyddogaethau hyn yn nulliau a hidlwyr y bot.

Dulliau bot

Y cam nesaf wrth adeiladu ein bot yw creu dulliau. Os gwnaethoch chi lawrlwytho'r prosiect o GitHub, yna mae pob dull yn y ffeil bot_methods.R.

Cod dull 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')
  }

}

Rydym wedi creu 5 dull:

  • cychwyn — Cychwyn deialog
  • cyflwr - Sicrhewch y cyflwr sgwrsio cyfredol
  • ailosod - Ailosod y cyflwr sgwrsio cyfredol
  • enter_name - Mae'r bot yn gofyn am eich enw
  • enter_age — Mae'r bot yn gofyn am eich oedran

Dull start yn gofyn am eich enw, ac yn newid cyflwr y sgwrs i enw_aros, h.y. i wrth gefn ar gyfer rhoi eich enw.

Nesaf, byddwch yn anfon yr enw ac mae'n cael ei brosesu gan y dull enter_name, mae'r bot yn eich cyfarch, yn ysgrifennu'r enw a dderbyniwyd i'r gronfa ddata, ac yn newid y sgwrs i'r wladwriaeth aros_oed.

Ar y cam hwn, mae'r bot yn disgwyl ichi nodi'ch oedran. Rydych chi'n anfon eich oedran, mae'r bot yn gwirio'r neges, os anfonoch chi destun yn lle rhif, bydd yn dweud: Ты ввёл некорректные данные, введи число, a bydd yn aros i chi ail-gofnodi'ch data. Os anfonoch rif, bydd y bot yn adrodd ei fod wedi derbyn eich oedran, yn ysgrifennu'r data a dderbyniwyd i'r gronfa ddata, yn adrodd ar yr holl ddata a dderbyniwyd gennych ac yn dychwelyd y cyflwr sgwrsio i'w safle gwreiddiol, h.y. V start.

Trwy alw y dull state gallwch ofyn am y statws sgwrsio cyfredol ar unrhyw adeg, a defnyddio'r reset dychwelyd y sgwrs i'w chyflwr gwreiddiol.

Hidlyddion neges

Yn ein hachos ni, dyma un o'r rhannau pwysicaf wrth adeiladu bot. Gyda chymorth hidlwyr negeseuon y bydd y bot yn deall pa wybodaeth y mae'n ei ddisgwyl gennych chi a sut y dylid ei phrosesu.

Yn y prosiect ar GitHub mae hidlwyr wedi'u cofrestru yn y ffeil neges_hidlyddion.R.

Cod hidlydd neges:

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

Mewn hidlwyr rydym yn defnyddio'r ffwythiant a ysgrifennwyd yn flaenorol get_state(), er mwyn gofyn am gyflwr presennol y sgwrs. Dim ond 1 arg sydd ei angen ar y swyddogaeth hon, ID sgwrs.

Hidlydd nesaf enw_aros yn prosesu negeseuon pan fo'r sgwrs mewn cyflwr wait_name, ac yn unol â hynny yr hidlydd aros_oed yn prosesu negeseuon pan fo'r sgwrs mewn cyflwr wait_age.

Trinwyr

Gelwir y ffeil gyda thrinwyr trinwyr.R, ac mae ganddo'r cod canlynol:

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

Yn gyntaf rydym yn creu trinwyr gorchymyn a fydd yn caniatáu ichi redeg dulliau i gychwyn deialog, ei ailosod, a holi am y cyflwr presennol.

Nesaf, rydym yn creu 2 driniwr negeseuon gan ddefnyddio'r hidlwyr a grëwyd yn y cam blaenorol, ac yn ychwanegu hidlydd atynt !MessageFilters$command, fel y gallwn ddefnyddio gorchmynion mewn unrhyw gyflwr sgwrsio.

Cod lansio bot

Nawr bod gennym ni bopeth yn barod i'w lansio, mae'r prif god ar gyfer lansio'r bot yn y ffeil 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()

O ganlyniad, cawsom y bot hwn:
Ysgrifennu bot telegram yn R (rhan 4): Adeiladu deialog gyson, rhesymegol gyda'r bot

Ar unrhyw adeg gan ddefnyddio'r gorchymyn /state gallwn gwestiynu'r cyflwr sgwrsio cyfredol, a defnyddio'r gorchymyn /reset dychwelwch y sgwrs i'w chyflwr gwreiddiol a chychwyn y ddeialog eto.

Casgliad

Yn yr erthygl hon, fe wnaethom ddarganfod sut i ddefnyddio cronfa ddata y tu mewn i bot, a sut i adeiladu deialogau rhesymegol dilyniannol trwy gofnodi'r cyflwr sgwrsio.

Yn yr achos hwn, fe wnaethom edrych ar yr enghraifft fwyaf cyntefig, fel y byddai'n haws i chi ddeall y syniad o adeiladu bots o'r fath; yn ymarferol, gallwch chi adeiladu deialogau llawer mwy cymhleth.

Yn yr erthygl nesaf yn y gyfres hon, byddwn yn dysgu sut i gyfyngu ar hawliau defnyddwyr bot i ddefnyddio amrywiol ei ddulliau.

Ffynhonnell: hab.com

Ychwanegu sylw