Kuandika boti ya telegramu katika R (sehemu ya 4): Kuunda mazungumzo thabiti na yenye mantiki na roboti

Ikiwa tayari umesoma yaliyotangulia makala tatu kutoka kwa safu hii, basi tayari unajua jinsi ya kuandika roboti kamili za telegraph na kibodi.

Katika makala hii, tutajifunza jinsi ya kuandika bot ambayo itadumisha mazungumzo thabiti. Wale. Boti itakuuliza maswali na kukusubiri uweke habari fulani. Kulingana na data unayoingiza, bot itafanya vitendo kadhaa.

Pia katika makala hii tutajifunza jinsi ya kutumia hifadhidata chini ya kofia ya bot, kwa mfano wetu itakuwa SQLite, lakini unaweza kutumia DBMS nyingine yoyote. Niliandika kwa undani zaidi juu ya kuingiliana na hifadhidata katika lugha ya R in Makala hii.

Kuandika boti ya telegramu katika R (sehemu ya 4): Kuunda mazungumzo thabiti na yenye mantiki na roboti

Nakala zote kutoka kwa safu "Kuandika bot ya telegraph katika R"

  1. Tunaunda roboti na kuitumia kutuma ujumbe kwa telegramu
  2. Ongeza msaada wa amri na vichungi vya ujumbe kwenye roboti
  3. Jinsi ya kuongeza msaada wa kibodi kwenye roboti
  4. Kuunda mazungumzo thabiti, yenye mantiki na roboti

yaliyomo

Ikiwa una nia ya uchambuzi wa data, unaweza kupendezwa na yangu telegram и youtube njia. Maudhui mengi yamejitolea kwa lugha ya R.

  1. Utangulizi
  2. Mchakato wa kujenga bot
  3. Muundo wa mradi wa bot
  4. Usanidi wa kijibu
  5. Unda mabadiliko ya mazingira
  6. Kuunda hifadhidata
  7. Kazi za kuandika ili kufanya kazi na hifadhidata
  8. Mbinu za kijibu
  9. Vichujio vya ujumbe
  10. Washughulikiaji
  11. Msimbo wa uzinduzi wa bot
  12. Hitimisho

Utangulizi

Ili bot iombe data kutoka kwako na ikungojee kuingiza habari yoyote, utahitaji kurekodi hali ya sasa ya mazungumzo. Njia bora ya kufanya hivyo ni kutumia aina fulani ya hifadhidata iliyopachikwa, kama vile SQLite.

Wale. Mantiki itakuwa kama ifuatavyo. Tunaita njia ya bot, na bot huomba kwa mtiririko habari fulani kutoka kwetu, na kwa kila hatua inasubiri habari hii kuingizwa na inaweza kuiangalia.

Tutaandika bot rahisi zaidi, kwanza itauliza jina lako, kisha umri wako, na itahifadhi data iliyopokelewa kwenye hifadhidata. Wakati wa kuuliza umri, itaangalia kuwa data iliyoingia ni nambari na sio maandishi.

Mazungumzo rahisi kama haya yatakuwa na majimbo matatu tu:

  1. kuanza ni hali ya kawaida ya bot, ambayo haitarajii taarifa yoyote kutoka kwako
  2. wait_name - hali ambayo bot inasubiri jina kuingizwa
  3. wait_age ni hali ambayo kijibu hungoja umri wako uingizwe, idadi ya miaka kamili.

Mchakato wa kujenga bot

Wakati wa kifungu, tutaunda kijibu hatua kwa hatua; mchakato mzima unaweza kuonyeshwa kimkakati kama ifuatavyo:
Kuandika boti ya telegramu katika R (sehemu ya 4): Kuunda mazungumzo thabiti na yenye mantiki na roboti

  1. Tunaunda usanidi wa bot ambao tutahifadhi mipangilio fulani. Kwa upande wetu, ishara ya bot, na njia ya faili ya hifadhidata.
  2. Tunaunda mabadiliko ya mazingira ambayo njia ya mradi na bot itahifadhiwa.
  3. Tunaunda hifadhidata yenyewe, na idadi ya kazi ili bot inaweza kuingiliana nayo.
  4. Tunaandika njia za bot, i.e. kazi itafanya.
  5. Kuongeza vichujio vya ujumbe. Kwa msaada ambao bot itafikia njia muhimu, kulingana na hali ya sasa ya mazungumzo.
  6. Tunaongeza vidhibiti ambavyo vitaunganisha amri na ujumbe na mbinu muhimu za bot.
  7. Wacha tuzindue kijibu.

Muundo wa mradi wa bot

Kwa urahisi, tutagawanya msimbo wa bot yetu, na faili zingine zinazohusiana, katika muundo ufuatao.

  • bot.R - nambari kuu ya bot yetu
  • db_bot_function.R - kizuizi cha nambari iliyo na vitendaji vya kufanya kazi na hifadhidata
  • njia_za_bot.R - kanuni za mbinu za bot
  • vichujio_vya ujumbe.R - vichungi vya ujumbe
  • washikaji.R - washikaji
  • usanidi.cfg - usanidi wa bot
  • create_db_data.sql - Hati ya SQL ya kuunda jedwali na data ya gumzo kwenye hifadhidata
  • create_db_state.sql - Hati ya SQL ya kuunda jedwali la hali ya sasa ya gumzo kwenye hifadhidata
  • bot.db - hifadhidata ya bot

Unaweza kutazama mradi mzima wa bot, au download kutoka kwangu hazina kwenye GitHub.

Usanidi wa kijibu

Tutatumia ile ya kawaida kama usanidi ini faili, fomu ifuatayo:

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

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

Katika usanidi tunaandika ishara ya bot na njia ya hifadhidata, i.e. kwa faili ya bot.db; tutaunda faili yenyewe katika hatua inayofuata.

Kwa roboti changamano zaidi, unaweza kuunda usanidi changamano zaidi, zaidi ya hayo, si lazima kuandika usanidi wa ini, unaweza kutumia umbizo lingine lolote ikijumuisha JSON.

Unda mabadiliko ya mazingira

Kwenye kila PC, folda iliyo na mradi wa bot inaweza kupatikana katika saraka tofauti na kwenye anatoa tofauti, kwa hivyo katika msimbo njia ya folda ya mradi itawekwa kupitia utofauti wa mazingira. TG_BOT_PATH.

Kuna njia kadhaa za kuunda mabadiliko ya mazingira, rahisi zaidi ni kuandika kwenye faili .Renviron.

Unaweza kuunda au kuhariri faili hii kwa kutumia amri file.edit(path.expand(file.path("~", ".Renviron"))). Itekeleze na ongeza mstari mmoja kwenye faili:

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

Ifuatayo, hifadhi faili .Renviron na uanze tena RStudio.

Kuunda hifadhidata

Hatua inayofuata ni kuunda hifadhidata. Tutahitaji meza 2:

  • chat_data - data ambayo bot iliomba kutoka kwa mtumiaji
  • chat_state - hali ya sasa ya mazungumzo yote

Unaweza kuunda jedwali hizi kwa kutumia swali lifuatalo la 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
);

Ikiwa ulipakua mradi wa bot kutoka GitHub, kisha kuunda hifadhidata unaweza kutumia nambari ifuatayo katika 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'))

Kazi za kuandika ili kufanya kazi na hifadhidata

Tayari tunayo faili ya usanidi tayari na hifadhidata imeundwa. Sasa unahitaji kuandika vitendaji ili kusoma na kuandika data kwenye hifadhidata hii.

Ikiwa ulipakua mradi kutoka GitHub, basi unaweza kupata kazi katika faili db_bot_function.R.

Nambari ya kazi ya kufanya kazi na hifadhidata

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

}

Tumeunda kazi 4 rahisi:

  • get_state() - pata hali ya sasa ya mazungumzo kutoka kwa hifadhidata
  • set_state() - andika hali ya sasa ya gumzo kwenye hifadhidata
  • get_chat_data() - Pokea data iliyotumwa na mtumiaji
  • set_chat_data() - rekodi data iliyopokelewa kutoka kwa mtumiaji

Kazi zote ni rahisi sana, zinaweza kusoma data kutoka kwa hifadhidata kwa kutumia amri dbGetQuery(), au kujitolea UPSERT operesheni (kubadilisha data iliyopo au kuandika data mpya kwenye hifadhidata), kwa kutumia kazi dbExecute().

Sintaksia ya operesheni ya UPSERT ni kama ifuatavyo:

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

Wale. katika uwanja wetu wa meza kitambulisho_cha_chat ina kizuizi cha kipekee na ndio ufunguo wa msingi wa jedwali. Hapo awali, tunajaribu kuongeza habari kwenye jedwali, na tunapata hitilafu ikiwa data ya gumzo la sasa tayari iko, kwa hali ambayo tunasasisha tu maelezo ya gumzo hili.

Ifuatayo, tutatumia kazi hizi katika njia na vichungi vya bot.

Mbinu za kijibu

Hatua inayofuata katika kujenga bot yetu ni kuunda mbinu. Ikiwa ulipakua mradi kutoka GitHub, basi njia zote ziko kwenye faili njia_za_bot.R.

Msimbo wa mbinu ya kijibu

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

}

Tumeunda njia 5:

  • anza - Anzisha mazungumzo
  • hali - Pata hali ya mazungumzo ya sasa
  • weka upya — Weka upya hali ya sasa ya gumzo
  • enter_name - Bot inauliza jina lako
  • enter_age - Boti inauliza umri wako

Mbinu start anauliza jina lako, na kubadilisha hali ya mazungumzo kuwa subiri_jina, i.e. kusubiri kwa ajili ya kuingiza jina lako.

Ifuatayo, unatuma jina na linachakatwa na mbinu enter_name, roboti inakusalimu, inaandika jina lililopokelewa kwenye hifadhidata, na kubadilisha soga hadi hali subiri_umri.

Katika hatua hii, roboti inatarajia uingie umri wako. Unatuma umri wako, roboti hukagua ujumbe, ikiwa umetuma maandishi badala ya nambari, itasema: Ты ввёл некорректные данные, введи число, na itakusubiri uweke tena data yako. Ikiwa ulituma nambari, bot itaripoti kwamba imekubali umri wako, kuandika data iliyopokelewa kwenye hifadhidata, ripoti data zote zilizopokelewa kutoka kwako na urejeshe hali ya mazungumzo kwenye nafasi yake ya awali, i.e. V start.

Kwa kupiga njia state unaweza kuomba hali ya sasa ya gumzo wakati wowote, na kwa kutumia reset rudisha gumzo katika hali yake ya asili.

Vichujio vya ujumbe

Kwa upande wetu, hii ni moja ya sehemu muhimu zaidi katika kujenga bot. Ni kwa usaidizi wa vichungi vya ujumbe ambapo roboti itaelewa ni taarifa gani inatarajia kutoka kwako na jinsi inavyopaswa kuchakatwa.

Katika mradi wa GitHub vichungi vimesajiliwa kwenye faili vichujio_vya ujumbe.R.

Msimbo wa kichujio cha ujumbe:

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

Katika vichungi tunatumia kazi iliyoandikwa hapo awali get_state(), ili kuomba hali ya sasa ya gumzo. Chaguo hili la kukokotoa linahitaji hoja 1 pekee, kitambulisho cha gumzo.

Kichujio kinachofuata subiri_jina huchakata ujumbe wakati soga iko katika hali wait_name, na ipasavyo chujio subiri_umri huchakata ujumbe wakati soga iko katika hali wait_age.

Washughulikiaji

Faili iliyo na washughulikiaji inaitwa washikaji.R, na ina nambari ifuatayo:

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

Kwanza tunaunda vidhibiti vya amri ambavyo vitakuruhusu kuendesha njia za kuanzisha mazungumzo, kuiweka upya, na kuuliza hali ya sasa.

Ifuatayo, tunaunda vidhibiti 2 vya ujumbe kwa kutumia vichujio vilivyoundwa katika hatua ya awali, na kuongeza kichujio kwao !MessageFilters$command, ili tuweze kutumia amri katika hali yoyote ya mazungumzo.

Msimbo wa uzinduzi wa bot

Sasa tuna kila kitu tayari kuzindua, msimbo kuu wa kuzindua bot iko kwenye faili 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()

Kama matokeo, tulipata bot hii:
Kuandika boti ya telegramu katika R (sehemu ya 4): Kuunda mazungumzo thabiti na yenye mantiki na roboti

Wakati wowote kwa kutumia amri /state tunaweza kuuliza hali ya sasa ya gumzo, na kwa kutumia amri /reset rudisha gumzo katika hali yake ya asili na uanze mazungumzo tena.

Hitimisho

Katika makala haya, tuligundua jinsi ya kutumia hifadhidata ndani ya roboti, na jinsi ya kuunda midahalo ya kimantiki kwa kurekodi hali ya gumzo.

Katika kesi hii, tuliangalia mfano wa zamani zaidi, ili iwe rahisi kwako kuelewa wazo la kuunda roboti kama hizo; kwa mazoezi, unaweza kuunda mazungumzo ngumu zaidi.

Katika makala inayofuata katika mfululizo huu, tutajifunza jinsi ya kuzuia haki za watumiaji wa roboti kutumia mbinu zake mbalimbali.

Chanzo: mapenzi.com

Kuongeza maoni