Навиштани боти телеграмма дар R (қисми 4): Эҷоди муколамаи пайваста ва мантиқӣ бо бот

Агар шумо қаблан хонда бошед се мақола аз ин силсила, пас шумо аллакай медонед, ки чӣ гуна ботҳои пурраи телеграммаро бо клавиатура нависед.

Дар ин мақола, мо мефаҳмем, ки чӣ гуна бот нависед, ки муколамаи пайвастаро нигоҳ дорад. Онхое. Бот ба шумо саволҳо медиҳад ва интизор мешавад, ки шумо ягон маълумот ворид кунед. Вобаста аз маълумоте, ки шумо ворид мекунед, бот баъзе амалҳоро иҷро мекунад.

Инчунин дар ин мақола мо мефаҳмем, ки чӣ тавр истифода бурдани пойгоҳи додаҳо дар зери сарпӯши бот, дар мисоли мо он SQLite хоҳад буд, аммо шумо метавонед ҳама гуна DBMS-ро истифода баред. Ман муфассалтар дар бораи ҳамкорӣ бо пойгоҳи додаҳо дар забони R навиштам ин мақола.

Навиштани боти телеграмма дар R (қисми 4): Эҷоди муколамаи пайваста ва мантиқӣ бо бот

Ҳама мақолаҳо аз силсилаи "Навиштани боти телеграмма дар R"

  1. Мо бот эҷод мекунем ва онро барои фиристодани паёмҳо дар телеграмма истифода мебарем
  2. Ба бот дастгирии фармон ва филтрҳои паём илова кунед
  3. Чӣ тавр илова кардани дастгирии клавиатура ба бот
  4. Эҷоди муколамаи пайваста ва мантиқӣ бо бот

Мундариҷа

Агар шумо ба таҳлили маълумот таваҷҷӯҳ дошта бошед, шумо шояд ба ман таваҷҷӯҳ кунед телеграмма и YouTube каналхо. Аксари мундариҷа ба забони R бахшида шудаанд.

  1. Муқаддима
  2. Раванди сохтани бот
  3. Сохтори лоиҳаи бот
  4. Танзимоти бот
  5. Тағйирёбандаи муҳити зист эҷод кунед
  6. Эҷоди пойгоҳи додаҳо
  7. Навиштани функсияҳо барои кор бо пойгоҳи додаҳо
  8. Усулҳои бот
  9. Филтрҳои паёмҳо
  10. Корфармоён
  11. Рамзи оғози бот
  12. хулоса

Муқаддима

Барои он ки бот аз шумо маълумот талаб кунад ва интизор шавед, ки шумо ягон маълумот ворид кунед, шумо бояд ҳолати кунунии муколамаро сабт кунед. Роҳи беҳтарини ин кор ин истифодаи як намуди пойгоҳи додаҳо, ба монанди SQLite мебошад.

Онхое. Мантиқ чунин хоҳад буд. Мо усули ботро даъват мекунем ва бот пай дар пай баъзе маълумотро аз мо талаб мекунад ва дар ҳар қадам интизори ворид шудани ин маълумот аст ва метавонад онро тафтиш кунад.

Мо соддатарин боти имконпазирро менависем, аввал номи шумо, баъд синну солатонро мепурсад ва маълумоти гирифташударо дар базаи маълумот захира мекунад. Ҳангоми дархост кардани синну сол, он тафтиш мекунад, ки маълумоти воридшуда рақам аст, на матн.

Чунин муколамаи оддӣ танҳо се ҳолат дорад:

  1. оғоз ҳолати муқаррарии бот аст, ки дар он аз шумо ягон маълумот интизор нест
  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 — филтрҳои паёмҳо
  • идоракунандагон.Р - корбарон
  • 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.

Якчанд роҳҳои эҷоди тағирёбандаи муҳити зист вуҷуд доранд, соддатаринаш дар файл навиштани он аст .Ренвирон.

Шумо метавонед ин файлро бо истифода аз фармон эҷод ё таҳрир кунед 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}';

Онхое. дар майдони мизҳои мо 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 усулро таҳия кардем:

  • оғоз — Муколамаро оғоз кунед
  • давлат — Ҳолати ҷории чатро гиред
  • аз нав танзим кардан — Ҳолати ҷории сӯҳбатро аз нав танзим кунед
  • enter_name — Бот номи шуморо мепурсад
  • enter_age — Бот синну соли шуморо мепурсад

метод start номи шуморо мепурсад ва ҳолати чатро ба тағйир медиҳад интизор_ном, яъне. барои ворид кардани номи худ интизор шавед.

Баъдан, шумо номро мефиристед ва он бо усул коркард карда мешавад 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 аргументро талаб мекунад, чат ID.

Филтри навбатӣ интизор_ном ҳангоми дар ҳолати будани чат паёмҳоро коркард мекунад wait_name, ва мувофиқан филтр давраи интизорӣ ҳангоми дар ҳолати будани чат паёмҳоро коркард мекунад wait_age.

Корфармоён

Файл бо коркардкунандагон даъват карда мешавад идоракунандагон.Р, ва дорои рамзи зерин:

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

Илова Эзоҳ