Pagsulat og telegram bot sa R ​​(bahin 4): Paghimo og makanunayon, lohikal nga dialogue sa bot

Kung nabasa na nimo ang miaging tulo ka artikulo gikan sa kini nga serye, nan nahibal-an na nimo kung giunsa pagsulat ang mga bug-os nga telegram bot nga adunay keyboard.

Niini nga artikulo, mahibal-an naton kung giunsa pagsulat ang usa ka bot nga magpadayon sa usa ka makanunayon nga dayalogo. Mga. Ang bot mangutana kanimo og mga pangutana ug maghulat kanimo sa pagsulod sa pipila ka impormasyon. Depende sa datos nga imong gisulod, ang bot mohimo sa pipila ka mga aksyon.

Usab niini nga artikulo makakat-on kita kon sa unsang paagi sa paggamit sa usa ka database sa ilalum sa hood sa bot, sa atong panig-ingnan kini mao ang SQLite, apan kamo makahimo sa paggamit sa bisan unsa nga lain nga DBMS. Gisulat ko ang dugang nga detalye bahin sa pagpakig-uban sa mga database sa R ​​nga pinulongan sa kini nga artikulo.

Pagsulat og telegram bot sa R ​​(bahin 4): Paghimo og makanunayon, lohikal nga dialogue sa bot

Ang tanan nga mga artikulo gikan sa serye nga "Pagsulat sa usa ka telegrama bot sa R"

  1. Paghimo usa ka bot ug gamita kini aron magpadala mga mensahe sa telegrama
  2. Idugang ang suporta sa command ug mga filter sa mensahe sa bot
  3. Giunsa pagdugang ang suporta sa keyboard sa usa ka bot
  4. Paghimo usa ka makanunayon, lohikal nga dayalogo sa bot

Mga sulod

Kung interesado ka sa pagtuki sa datos, mahimong interesado ka sa akong telegram и youtube mga kanal. Kadaghanan sa sulod niini gipahinungod sa R ​​nga pinulongan.

  1. Pasiuna
  2. Proseso sa pagtukod sa bot
  3. Ang istruktura sa proyekto sa bot
  4. Bot config
  5. Paghimo usa ka variable sa palibot
  6. Paghimo og database
  7. Mga gimbuhaton sa pagsulat aron magtrabaho kauban ang database
  8. Mga pamaagi sa bot
  9. Mga filter sa mensahe
  10. Mga tigdumala
  11. Bot launch code
  12. konklusyon

Pasiuna

Aron ang bot makahangyo ug datos gikan kanimo ug maghulat kanimo sa pagsulod sa bisan unsang impormasyon, kinahanglan nimo nga irekord ang kasamtangan nga kahimtang sa dayalogo. Ang labing maayo nga paagi sa pagbuhat niini mao ang paggamit sa usa ka matang sa naka-embed nga database, sama sa SQLite.

Mga. Ang lohika mahimong ingon sa mosunod. Gitawag namon ang pamaagi sa bot, ug ang bot nagsunud-sunod nga nangayo og pipila ka kasayuran gikan kanamo, ug sa matag lakang naghulat kini nga masulod kini nga kasayuran ug masusi kini.

Isulat namon ang pinakasimple nga posible nga bot, una kini mangutana sa imong ngalan, dayon ang imong edad, ug i-save ang nadawat nga datos sa database. Kung mangutana alang sa edad, susihon kung ang gisulod nga datos usa ka numero ug dili teksto.

Ang ingon nga yano nga dayalogo adunay tulo ra ka estado:

  1. Ang pagsugod mao ang normal nga kahimtang sa bot, diin wala kini magdahom nga bisan unsang kasayuran gikan kanimo
  2. wait_name - estado diin ang bot naghulat alang sa usa ka ngalan nga ipasulod
  3. wait_age mao ang estado diin ang bot naghulat sa imong edad nga masulod, ang gidaghanon sa tibuok tuig.

Proseso sa pagtukod sa bot

Atol sa artikulo, maghimo kami usa ka bot nga lakang sa lakang; ang tibuuk nga proseso mahimong gihulagway nga eskematiko sama sa mosunod:
Pagsulat og telegram bot sa R ​​(bahin 4): Paghimo og makanunayon, lohikal nga dialogue sa bot

  1. Naghimo kami usa ka bot config diin kami magtipig pipila ka mga setting. Sa among kaso, ang bot token, ug ang agianan sa database file.
  2. Naghimo kami usa ka variable sa palibot diin ang agianan sa proyekto nga adunay bot itago.
  3. Gihimo namo ang database mismo, ug daghang mga gimbuhaton aron ang bot maka-interact niini.
  4. Gisulat namon ang mga pamaagi sa bot, i.e. ang mga gimbuhaton nga himuon niini.
  5. Pagdugang mga filter sa mensahe. Uban sa tabang nga ang bot maka-access sa gikinahanglan nga mga pamaagi, depende sa kasamtangan nga kahimtang sa chat.
  6. Nagdugang kami og mga tigdumala nga magkonektar sa mga sugo ug mga mensahe sa gikinahanglan nga mga pamaagi sa bot.
  7. Atong ilunsad ang bot.

Ang istruktura sa proyekto sa bot

Alang sa kasayon, among bahinon ang code sa among bot, ug uban pang may kalabutan nga mga file, sa mosunod nga istruktura.

  • bot.R — ang nag-unang code sa among bot
  • db_bot_function.R - usa ka bloke sa code nga adunay mga gimbuhaton alang sa pagtrabaho sa usa ka database
  • bot_methods.R - code sa mga pamaagi sa bot
  • message_filters.R - mga filter sa mensahe
  • mga tigdumala.R - mga tigdumala
  • config.cfg - bot config
  • create_db_data.sql — SQL script alang sa paghimo sa usa ka lamesa nga adunay data sa chat sa database
  • create_db_state.sql — SQL script alang sa paghimo sa usa ka lamesa sa karon nga kahimtang sa chat sa database
  • bot.db - database sa bot

Mahimo nimong tan-awon ang tibuuk nga proyekto sa bot, o скачать gikan sa akong repository sa GitHub.

Bot config

Gamiton namo ang naandan isip config ini nga file, ang mosunod nga porma:

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

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

Sa config atong gisulat ang bot token ug ang dalan sa database, i.e. ngadto sa bot.db file, atong himoon ang file mismo sa sunod nga lakang.

Para sa mas komplikado nga mga bot, makahimo ka og mas komplikadong mga config, gawas pa, dili na kinahanglan nga magsulat og ini config, mahimo nimong gamiton ang bisan unsang format lakip ang JSON.

Paghimo usa ka variable sa palibot

Sa matag PC, ang folder nga adunay proyekto sa bot mahimong makit-an sa lainlaing mga direktoryo ug sa lainlaing mga drive, mao nga sa code ang agianan sa folder sa proyekto itakda pinaagi sa usa ka variable sa palibot. TG_BOT_PATH.

Adunay daghang mga paagi sa paghimo sa usa ka variable sa palibot, ang pinakasimple mao ang pagsulat niini sa usa ka file .Renviron.

Mahimo nimo o usbon kini nga file gamit ang command file.edit(path.expand(file.path("~", ".Renviron"))). Ipatuman kini ug idugang ang usa ka linya sa file:

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

Sunod i-save ang file .Renviron ug i-restart ang RStudio.

Paghimo og database

Ang sunod nga lakang mao ang paghimo og database. Kinahanglan namon ang 2 ka lamesa:

  • chat_data — data nga gipangayo sa bot gikan sa user
  • chat_state — kasamtangan nga kahimtang sa tanang chat

Mahimo nimo kini nga mga lamesa gamit ang mosunod nga pangutana sa 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
);

Kung gi-download nimo ang proyekto sa bot gikan sa GitHub, unya sa paghimo sa database mahimo nimong gamiton ang mosunod nga code sa 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'))

Mga gimbuhaton sa pagsulat aron magtrabaho kauban ang database

Nakaandam na kami og configuration file ug usa ka database nga gihimo. Karon kinahanglan nimo nga isulat ang mga gimbuhaton aron mabasa ug isulat ang datos sa kini nga database.

Kung imong gi-download ang proyekto gikan sa GitHub, unya makit-an nimo ang mga gimbuhaton sa file db_bot_function.R.

Function code alang sa pagtrabaho uban sa database

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

}

Naghimo kami og 4 ka yano nga mga gimbuhaton:

  • get_state() — pagkuha sa kasamtangan nga kahimtang sa chat gikan sa database
  • set_state() — isulat ang kasamtangan nga kahimtang sa chat sa database
  • get_chat_data() - makadawat data nga gipadala sa user
  • set_chat_data() - Pagrekord sa datos nga nadawat gikan sa tiggamit

Ang tanan nga mga gimbuhaton yano ra, sila nagbasa sa datos gikan sa database gamit ang mando dbGetQuery(), o pasalig UPSERT operasyon (pag-usab sa kasamtangan nga datos o pagsulat sa bag-ong datos ngadto sa database), gamit ang function dbExecute().

Ang syntax alang sa UPSERT nga operasyon mao ang mosunod:

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

Mga. sa among mga lamesa natad chat_id adunay usa ka talagsaon nga pagpugong ug mao ang nag-unang yawe sa mga lamesa. Sa sinugdan, gisulayan namon nga idugang ang kasayuran sa lamesa, ug nakakuha kami usa ka sayup kung ang datos alang sa karon nga chat naa na, kung diin among gi-update ang kasayuran alang sa kini nga chat.

Sunod, gamiton namon kini nga mga gimbuhaton sa mga pamaagi ug mga filter sa bot.

Mga pamaagi sa bot

Ang sunod nga lakang sa paghimo sa among bot mao ang paghimo og mga pamaagi. Kung imong gi-download ang proyekto gikan sa GitHub, unya ang tanan nga mga pamaagi naa sa file bot_methods.R.

Code sa pamaagi sa 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')
  }

}

Naghimo kami og 5 nga mga pamaagi:

  • pagsugod - Pagsugod sa usa ka dialog
  • estado — Kuhaa ang kasamtangan nga kahimtang sa chat
  • reset — I-reset ang kasamtangan nga kahimtang sa chat
  • enter_name — Gipangutana sa bot ang imong ngalan
  • enter_age — Gipangutana sa bot ang imong edad

Paagi start nangayo sa imong ngalan, ug giusab ang kahimtang sa chat ngadto sa wait_name, i.e. sa standby para sa pagsulod sa imong ngalan.

Sunod, ipadala nimo ang ngalan ug giproseso kini sa pamaagi enter_name, ang bot nangumusta kanimo, gisulat ang nadawat nga ngalan sa database, ug gibalhin ang chat sa estado paghulat_edad.

Niini nga yugto, ang bot nagpaabot kanimo nga mosulod sa imong edad. Gipadala nimo ang imong edad, gisusi sa bot ang mensahe, kung nagpadala ka usa ka teksto imbes usa ka numero, kini moingon: Ты ввёл некорректные данные, введи число, ug maghulat alang kanimo sa pagsulod pag-usab sa imong data. Kung nagpadala ka usa ka numero, ang bot magreport nga gidawat ang imong edad, isulat ang nadawat nga datos sa database, ireport ang tanan nga datos nga nadawat gikan kanimo ug ibalik ang estado sa chat sa orihinal nga posisyon niini, i.e. V start.

Pinaagi sa pagtawag sa pamaagi state mahimo nimong hangyoon ang kasamtangan nga status sa chat bisan unsang orasa, ug gamit ang reset ibalik ang chat sa orihinal nga kahimtang niini.

Mga filter sa mensahe

Sa among kaso, kini usa sa labing hinungdanon nga bahin sa paghimo og bot. Uban kini sa tabang sa mga filter sa mensahe nga masabtan sa bot kung unsa nga kasayuran ang gipaabut niini gikan kanimo ug kung giunsa kini pagproseso.

Sa proyekto sa GitHub ang mga filter narehistro sa file message_filters.R.

Filter code sa mensahe:

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

Sa mga filter gigamit namon ang nauna nga gisulat nga function get_state(), aron makapangayo sa kasamtangan nga kahimtang sa chat. Kini nga function nagkinahanglan lamang og 1 argumento, chat id.

Sunod nga filter wait_name nagproseso sa mga mensahe kung ang chat naa sa estado wait_name, ug sumala niana ang filter paghulat_edad nagproseso sa mga mensahe kung ang chat naa sa estado wait_age.

Mga tigdumala

Ang file nga adunay mga handler gitawag mga tigdumala.R, ug adunay mosunod nga code:

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

Una naghimo kami og mga command handler nga magtugot kanimo sa pagpadagan sa mga pamaagi sa pagsugod sa usa ka dialog, pag-reset niini, ug pagpangutana sa kasamtangan nga kahimtang.

Sunod, naghimo kami og 2 nga tigdumala sa mensahe gamit ang mga filter nga gihimo sa miaging lakang, ug gidugangan sila og filter !MessageFilters$command, aron magamit namo ang mga sugo sa bisan unsang kahimtang sa chat.

Bot launch code

Karon naa na namo ang tanan nga andam sa paglansad, ang nag-unang code sa paglansad sa bot naa sa file 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()

Ingon usa ka sangputanan, nakuha namon kini nga bot:
Pagsulat og telegram bot sa R ​​(bahin 4): Paghimo og makanunayon, lohikal nga dialogue sa bot

Sa bisan unsang oras gamit ang mando /state kita makapangutana sa kasamtangan nga kahimtang sa chat, ug sa paggamit sa sugo /reset ibalik ang chat sa orihinal nga kahimtang niini ug sugdi pag-usab ang dayalogo.

konklusyon

Sa kini nga artikulo, nahibal-an namon kung giunsa ang paggamit sa usa ka database sa sulod sa usa ka bot, ug kung giunsa paghimo ang sunud-sunod nga lohikal nga mga diyalogo pinaagi sa pagrekord sa kahimtang sa chat.

Sa kini nga kaso, among gitan-aw ang labing karaan nga panig-ingnan, aron mas sayon ​​​​alang kanimo nga masabtan ang ideya sa paghimo sa ingon nga mga bot; sa praktis, makahimo ka og mas komplikado nga mga diyalogo.

Sa sunod nga artikulo sa kini nga serye, mahibal-an naton kung giunsa ang pagpugong sa mga katungod sa mga tiggamit sa bot sa paggamit sa lainlaing mga pamaagi niini.

Source: www.habr.com

Idugang sa usa ka comment