Að skrifa símskeyti botni í R (hluti 4): Byggja upp samkvæma, rökrétta samræður við botninn

Ef þú hefur þegar lesið fyrri þrjár greinar úr þessari seríu, þá veistu nú þegar hvernig á að skrifa fullgilda símskeyti vélmenni með lyklaborði.

Í þessari grein munum við læra hvernig á að skrifa vélmenni sem mun viðhalda stöðugri umræðu. Þeir. Botninn mun spyrja þig spurninga og bíða eftir að þú slærð inn einhverjar upplýsingar. Það fer eftir gögnunum sem þú slærð inn, botninn mun framkvæma nokkrar aðgerðir.

Einnig í þessari grein munum við læra hvernig á að nota gagnagrunn undir hettunni á botni, í okkar dæmi mun það vera SQLite, en þú getur notað hvaða önnur DBMS sem er. Ég skrifaði nánar um samskipti við gagnagrunna á R tungumálinu í Þessi grein.

Að skrifa símskeyti botni í R (hluti 4): Byggja upp samkvæma, rökrétta samræður við botninn

Allar greinar úr seríunni „Að skrifa símskeyti láni í R“

  1. Við búum til bot og notum það til að senda skilaboð í símskeyti
  2. Bættu stjórnunarstuðningi og skilaboðasíum við botninn
  3. Hvernig á að bæta lyklaborðsstuðningi við vélmenni
  4. Byggja upp samkvæma, rökrétta samræður við botninn

efni

Ef þú hefur áhuga á gagnagreiningu gætirðu haft áhuga á mínum símskeyti и YouTube rásir. Mest af efninu er tileinkað R tungumálinu.

  1. Inngangur
  2. Bot byggingarferli
  3. Bot verkefni uppbygging
  4. Bot config
  5. Búðu til umhverfisbreytu
  6. Að búa til gagnagrunn
  7. Ritunaraðgerðir til að vinna með gagnagrunninn
  8. Bot aðferðir
  9. Skilaboðasíur
  10. Handhafar
  11. Bot ræsingarkóði
  12. Ályktun

Inngangur

Til þess að botninn geti beðið um gögn frá þér og bíð eftir að þú slærð inn einhverjar upplýsingar þarftu að skrá núverandi stöðu samræðunnar. Besta leiðin til að gera þetta er að nota einhvers konar innbyggðan gagnagrunn, eins og SQLite.

Þeir. Rökfræðin verður sem hér segir. Við köllum botnaaðferðina og botninn biður í röð um einhverjar upplýsingar frá okkur og í hverju skrefi bíður hann eftir að þessar upplýsingar séu færðar inn og getur athugað þær.

Við munum skrifa einfaldasta mögulega vélmenni, fyrst mun það biðja um nafnið þitt, síðan aldur þinn, og mun vista móttekin gögn í gagnagrunninum. Þegar spurt er um aldur mun það athuga hvort innslögðu gögnin séu númer en ekki texti.

Slík einföld samræða mun aðeins hafa þrjú ríki:

  1. byrjun er eðlilegt ástand vélmennisins, þar sem það býst ekki við neinum upplýsingum frá þér
  2. wait_name - ástand þar sem botni bíður eftir að nafn sé slegið inn
  3. wait_age er ástandið þar sem botninn bíður eftir að aldur þinn sé færður inn, fjöldi heilra ára.

Bot byggingarferli

Meðan á greininni stendur munum við búa til vélmenni skref fyrir skref; allt ferlið er hægt að sýna með skýringarmynd sem hér segir:
Að skrifa símskeyti botni í R (hluti 4): Byggja upp samkvæma, rökrétta samræður við botninn

  1. Við búum til bot config þar sem við munum geyma nokkrar stillingar. Í okkar tilviki, botn táknið og slóðin að gagnagrunnsskránni.
  2. Við búum til umhverfisbreytu þar sem leiðin að verkefninu með botni verður geymd.
  3. Við búum til gagnagrunninn sjálfan og fjölda aðgerða svo að botninn geti haft samskipti við hann.
  4. Við skrifum bot aðferðir, þ.e. aðgerðir sem það mun framkvæma.
  5. Bætir við skilaboðasíum. Með hjálp sem lánmaðurinn mun fá aðgang að nauðsynlegum aðferðum, allt eftir núverandi stöðu spjallsins.
  6. Við bætum við meðhöndlum sem munu tengja skipanir og skilaboð með nauðsynlegum botnaaðferðum.
  7. Við skulum ræsa botann.

Bot verkefni uppbygging

Til hægðarauka munum við skipta kóðanum á botni okkar, og öðrum tengdum skrám, í eftirfarandi uppbyggingu.

  • bot.R - aðalkóði láni okkar
  • db_bot_function.R — kóðablokk með aðgerðum til að vinna með gagnagrunn
  • bot_methods.R — kóða lánaaðferða
  • skilaboðasíur.R — skilaboðasíur
  • umsjónarmenn.R - umsjónarmenn
  • config.cfg - bot config
  • búa til_db_gögn.sql — SQL forskrift til að búa til töflu með spjallgögnum í gagnagrunninum
  • búa til_db_state.sql — SQL forskrift til að búa til töflu yfir núverandi spjallástand í gagnagrunninum
  • bot.db - Bot gagnagrunnur

Þú getur skoðað allt botaverkefnið, eða sækja frá mínum geymsla á GitHub.

Bot config

Við munum nota venjulega sem stillingu ini skrá, eftirfarandi form:

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

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

Í stillingunni skrifum við bot token og slóðina að gagnagrunninum, þ.e. í bot.db skrána; við munum búa til skrána sjálfa í næsta skrefi.

Fyrir flóknari vélmenni geturðu búið til flóknari stillingar, auk þess er ekki nauðsynlegt að skrifa ini stillingar, þú getur notað hvaða annað snið sem er, þar á meðal JSON.

Búðu til umhverfisbreytu

Á hverri tölvu getur möppan með bot-verkefninu verið staðsett í mismunandi möppum og á mismunandi drifum, þannig að í kóðanum verður slóðin að verkefnamöppunni stillt með umhverfisbreytu TG_BOT_PATH.

Það eru nokkrar leiðir til að búa til umhverfisbreytu, einfaldast er að skrifa hana í skrá .Environ.

Þú getur búið til eða breytt þessari skrá með skipuninni file.edit(path.expand(file.path("~", ".Renviron"))). Keyrðu það og bættu einni línu við skrána:

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

Næst skaltu vista skrána .Environ og endurræstu RStudio.

Að búa til gagnagrunn

Næsta skref er að búa til gagnagrunn. Við þurfum 2 borð:

  • chat_data — gögn sem botninn bað um frá notandanum
  • chat_state — núverandi ástand allra spjalla

Þú getur búið til þessar töflur með því að nota eftirfarandi SQL fyrirspurn:

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

Ef þú halaðir niður botaverkefninu frá GitHub, til að búa til gagnagrunninn geturðu notað eftirfarandi kóða í 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'))

Ritunaraðgerðir til að vinna með gagnagrunninn

Við erum nú þegar með stillingarskrá tilbúin og gagnagrunn búinn til. Nú þarftu að skrifa aðgerðir til að lesa og skrifa gögn í þennan gagnagrunn.

Ef þú hefur hlaðið niður verkefninu frá GitHub, þá geturðu fundið aðgerðirnar í skránni db_bot_function.R.

Aðgerðarkóði til að vinna með gagnagrunninn

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

}

Við bjuggum til 4 einfaldar aðgerðir:

  • get_state() — fáðu núverandi spjallstöðu úr gagnagrunninum
  • set_state() — skrifaðu núverandi spjallástand í gagnagrunninn
  • get_chat_data() — taka á móti gögnum sem notandinn sendir
  • set_chat_data() — skrá gögn sem berast frá notanda

Allar aðgerðir eru frekar einfaldar, þær lesa ýmist gögn úr gagnagrunninum með skipuninni dbGetQuery(), eða skuldbinda sig UPSERT aðgerð (að breyta fyrirliggjandi gögnum eða skrifa ný gögn í gagnagrunninn), með því að nota aðgerðina dbExecute().

Setningafræði fyrir UPSERT aðgerðina er sem hér segir:

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

Þeir. í töflureitnum okkar spjall_id hefur sérstöðuþvingun og er aðallykill töflur. Upphaflega reynum við að bæta upplýsingum við töfluna og við fáum villu ef gögn fyrir núverandi spjall eru þegar til staðar, í því tilviki uppfærum við einfaldlega upplýsingarnar fyrir þetta spjall.

Næst munum við nota þessar aðgerðir í aðferðum og síum vélmennisins.

Bot aðferðir

Næsta skref í að byggja upp vélmenni okkar er að búa til aðferðir. Ef þú hefur hlaðið niður verkefninu frá GitHub, þá eru allar aðferðir í skránni bot_methods.R.

Bot aðferð kóði

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

}

Við bjuggum til 5 aðferðir:

  • byrja — Byrjaðu glugga
  • ástand — Fáðu núverandi spjallstöðu
  • endurstilla — Núllstilla núverandi spjallástand
  • enter_name — Botninn biður um nafnið þitt
  • enter_age — Botninn spyr um aldur þinn

Aðferð start biður um nafnið þitt og breytir spjallstöðu í bið_nafn, þ.e. í biðstöðu til að slá inn nafnið þitt.

Næst sendir þú nafnið og það er unnið með aðferðinni enter_name, botninn heilsar þér, skrifar móttekið nafn inn í gagnagrunninn og skiptir spjallinu yfir í ástandið bið_aldur.

Á þessu stigi býst vélmaðurinn við að þú slærð inn aldur þinn. Þú sendir aldur þinn, botninn athugar skilaboðin, ef þú sendir smá texta í stað númers mun hann segja: Ты ввёл некорректные данные, введи число, og mun bíða eftir að þú slærð inn gögnin þín aftur. Ef þú sendir númer mun botninn tilkynna að hann hafi samþykkt aldur þinn, skrifa móttekin gögn í gagnagrunninn, tilkynna öll gögn sem berast frá þér og skila spjallástandi í upprunalega stöðu, þ.e. V start.

Með því að kalla aðferðina state þú getur beðið um núverandi spjallstöðu hvenær sem er og með því að nota reset koma spjallinu í upprunalegt horf.

Skilaboðasíur

Í okkar tilviki er þetta einn mikilvægasti hlutinn við að byggja upp vélmenni. Það er með hjálp skilaboðasíur sem botninn mun skilja hvaða upplýsingar hann býst við frá þér og hvernig ætti að vinna úr þeim.

Í verkefninu á GitHub síur eru skráðar í skrána skilaboðasíur.R.

Skilaboðasíukóði:

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

Í síum notum við áður skrifaða aðgerðina get_state(), til að biðja um núverandi stöðu spjallsins. Þessi aðgerð krefst aðeins 1 rök, spjallauðkenni.

Næsta sía bið_nafn vinnur úr skilaboðum þegar spjallið er í ástandi wait_name, og í samræmi við síuna bið_aldur vinnur úr skilaboðum þegar spjallið er í ástandi wait_age.

Handhafar

Skráin með meðhöndlum er kölluð umsjónarmenn.R, og hefur eftirfarandi kóða:

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

Fyrst búum við til skipanameðhöndlun sem gerir þér kleift að keyra aðferðir til að hefja svarglugga, endurstilla hann og spyrjast fyrir um núverandi ástand.

Næst búum við til 2 skilaboðastjóra með því að nota síurnar sem voru búnar til í fyrra skrefi og bætum síu við þá !MessageFilters$command, svo að við getum notað skipanir í hvaða spjalli sem er.

Bot ræsingarkóði

Nú höfum við allt tilbúið til að ræsa, aðalkóði til að ræsa botni er í skránni 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()

Fyrir vikið fengum við þennan bot:
Að skrifa símskeyti botni í R (hluti 4): Byggja upp samkvæma, rökrétta samræður við botninn

Hvenær sem er með því að nota skipunina /state við getum spurt um núverandi spjallstöðu og notað skipunina /reset koma spjallinu aftur í upprunalegt horf og hefja samtalið aftur.

Ályktun

Í þessari grein komumst við að því hvernig á að nota gagnagrunn inni í vélmenni og hvernig á að byggja upp röð rökréttar samræður með því að skrá spjallástandið.

Í þessu tilviki skoðuðum við frumstæðasta dæmið, svo að það væri auðveldara fyrir þig að skilja hugmyndina um að smíða slíka vélmenni; í reynd geturðu byggt upp miklu flóknari samræður.

Í næstu grein í þessari röð munum við læra hvernig á að takmarka réttindi botnotenda til að nota ýmsar aðferðir þess.

Heimild: www.habr.com

Bæta við athugasemd