Telegram bot írása R nyelven (4. rész): Sorozatos, logikus párbeszéd kialakítása a bottal

Ha már megismerkedett a korábbi három cikkel ebben a sorozatban, akkor már tud írni teljes értékű telegram botokat billentyűzettel.

Ebben a cikkben megtanuljuk, hogyan kell írni egy botot, amely támogatja a sorozatos párbeszédet. Tehát a bot kérdéseket fog feltenni, és várni fogja az információk bevitelét. Az Ön által megadott adatoktól függően a bot bizonyos műveleteket fog végrehajtani.

Ezenkívül megtanuljuk, hogyan használjunk adatbázisokat a bot mögött. Például a példánkban SQLite-ot fogunk használni, de bármilyen más adatbázis-kezelőt is használhat. cikkben.

Telegram bot írása R nyelven (4. rész): Sorozatos, logikus párbeszéd kialakítása a bottal

Minden cikk a "Telegram bot írása R nyelven" sorozatból

  1. Bot létrehozása és üzenetek küldése a telegramon keresztül
  2. Bot parancsok támogatásának és üzenetszűrők hozzáadása
  3. Hogyan lehet billentyűzet támogatást adni a bothoz
  4. Sorozatos, logikus párbeszéd kialakítása a bottal

Tartalom

Ha érdeklik az adatelemzés, talán érdekesek lesznek a telegram és youtube csatornák. A tartalom nagyobb része R nyelvvel foglalkozik.

  1. Bevezetés
  2. A bot felépítési folyamata
  3. A bot projekt struktúrája
  4. A bot konfigurációja
  5. Környezeti változó létrehozása
  6. Adatbázis létrehozása
  7. Funkciók írása az adatbázissal való munkához
  8. A bot módszerei
  9. Üzenetszűrők
  10. Kezelők
  11. A bot indító kódja
  12. Zárás

Bevezetés

Ahhoz, hogy a bot adatokat tudjon kérni tőled és várjon az információk bevitelére, rögzíteni kell a párbeszéd aktuális állapotát. A legjobb módja ennek, ha valamilyen beágyazott adatbázist használunk, például SQLite-ot.

Tehát a logika a következő lesz. Meghívjuk a bot módszerét, és a bot sorozatosan kérdezi tőlünk az információt, miközben minden lépésben várja az információk bevitelét, és ellenőrizheti azt.

Egy nagyon egyszerű botot fogunk írni, először meg fogja kérdezni a nevét, majd az életkorát, a megkapott adatokat az adatbázisba menti. Életkor kérdésekor ellenőrzi, hogy a megadott adat szám-e, nem szöveg.

Ez a egyszerű párbeszéd összesen három állapotot fog tartalmazni:

  1. start — a bot normál állapota, amelyben nem vár semmilyen információt tőled
  2. wait_name — állapot, amikor a bot azt várja, hogy a nevedet beírd
  3. wait_age — állapot, amikor a bot azt várja, hogy megadd az életkorodat, a teljes évek számát.

A bot felépítési folyamata

A cikk során lépésről lépésre létrehozzuk a botot, a folyamatot az alábbiak szerint lehet sémásan ábrázolni:
Telegram bot írása R nyelven (4. rész): Sorozatos, logikus párbeszéd kialakítása a bottal

  1. Létrehozzuk a bot konfigurációját, amelyben tárolni fogjuk bizonyos beállításokat. A mi esetünkben a bot tokenjét és az adatbázis fájl elérési útját.
  2. Létrehozunk egy környezeti változót, amelyben a bot projektjének elérési útja lesz tárolva.
  3. Létrehozzuk magát az adatbázist, és egy sor funkciót, amelyek lehetővé teszik a bot számára, hogy interakcióba lépjen vele.
  4. Megírjuk a bot módszereit, azaz a funkciókat, amelyeket végrehajtani fog.
  5. Hozzáadjuk az üzenetszűrőket. Ezek segítségével a bot a megfelelő módszerekhez lép el, a chat aktuális állapota alapján.
  6. Hozzáadjuk az eseménykezelőket, amelyek összekapcsolják a parancsokat és üzeneteket a bot szükséges módszereivel.
  7. Elindítjuk a botot.

A bot projekt struktúrája

Kényelmi okokból a bot kódját és a vele kapcsolatos fájlokat a következő struktúrába rendezzük.

  • bot.R — a bot fő kódja
  • db_bot_function.R — adatbázis kezeléséhez szükséges funkciók kódja
  • bot_methods.R — a bot módszereinek kódja
  • message_filters.R — üzenetszűrők
  • handlers.R — eseménykezelők
  • config.cfg — a bot konfigurációja
  • create_db_data.sql — SQL script a chat adatainak táblájának létrehozásához az adatbázisban
  • create_db_state.sql — SQL script a chat aktuális állapotának táblájának létrehozásához az adatbázisban
  • bot.db — a bot adatbázisa

Az egész bot projektjét megtekintheti, vagy letölteni az én GitHub tárolóból.

A bot konfigurációja

A konfigurációhoz egy egyszerű ini fájlt, a következő formában fogunk használni:

[bot_settings]
bot_token=AZ_ÖN_BOT_TOKENJE

[db_settings]
db_path=C:/AZ_ÚT/A_PROJEKT_MAPPÁJÁHOZ/bot.db

A konfigurációba felvesszük a bot tokenjét és az adatbázis elérési útját, azaz a bot.db fájl elérési útját, amelyet a következő lépésben hozunk létre.

Bonyolultabb botok esetén bonyolultabb konfigurációs fájlokat is létrehozhat, ráadásul nem szükséges, hogy kifejezetten ini formátumot használjon, bármilyen más formátumot, beleértve a JSON-t is, használhat.

Környezeti változó létrehozása

Minden PC-n a bot projekt mappája különböző könyvtárakban és különböző meghajtókon található, ezért a kódban a projekt mappájának elérési útját környezeti változóval kell megadni. TG_BOT_PATH.

A környezeti változót többféleképpen létrehozhatja, a legegyszerűbb módja, ha beírja a következő fájlba: .Renviron.

A fájlt létrehozni vagy szerkeszteni a következő parancs segítségével lehet: file.edit(path.expand(file.path("~", ".Renviron"))). Hajtsa végre ezt, és adjon hozzá a fájlhoz egy sort:

TG_BOT_PATH=C:/AZ_ÚT/A_PROJEKTJÉHEZ

Ezután mentse el a fájlt, .Renviron és indítsa újra az RStudio-t.

Adatbázis létrehozása

A következő lépés az adatbázis létrehozása. Két táblázatra lesz szükségünk:

  • chat_data — az adat, amelyet a bot a felhasználótól kért
  • chat_state — az összes chat aktuális állapota

Ezek a táblák a következő SQL lekérdezéssel hozhatók létre:

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

Ha letöltötte a bot projektjét a GitHub, a következő R nyelvű kódot használhatja az adatbázis létrehozásához.

# Скрипт создания базы данных
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'))

Funkciók írása az adatbázissal való munkához

Már van egy konfigurációs fájlunk és egy létrehozott adatbázisunk. Most funkciókat kell írnunk az adatok olvasására és írására ebbe az adatbázisba.

Ha letöltötte a projektet a GitHub, a funkciókat a db_bot_function.R.

adatbázissal való munka funkcióinak kódja

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

}

Négy egyszerű funkciót hoztunk létre:

  • get_state() — a chat aktuális állapotának lekérése az adatbázisból
  • set_state() — a chat aktuális állapotának rögzítése az adatbázisban
  • get_chat_data() — a felhasználó által küldött adatok lekérése
  • set_chat_data() — a felhasználótól kapott adatok rögzítése

Minden funkció elég egyszerű, hogy vagy adatokat olvas az adatbázisból a dbGetQuery(), vagy végrehajt egy UPSERT műveletet (meglevő adatok módosítása vagy új adatok rögzítése az adatbázisban) a dbExecute().

funkció segítségével.

Az UPSERT művelet szintaxisa a következőképpen néz ki:

INSERT INTO chat_data (chat_id, ${field}) VALUES(${chat_id}, '${value}') ON CONFLICT(chat_id) DO UPDATE SET ${field}='${value}'; chat_id mezőnk egyedi korlátozással rendelkezik, és a táblák elsődleges kulcsát képezi. Először megpróbáljuk hozzáadni az információt a táblához, és hibát kapunk, ha az aktuális chat adatai már léteznek; ilyen esetben egyszerűen frissítjük az információkat.

Ezeket a funkciókat a bot módszereiben és szűrőiben fogjuk használni.

A bot módszerei

A következő lépés a botunk felépítésében a módszerek létrehozása. Ha letöltöd a projektet a GitHub, akkor minden módszer a bot_methods.R.

a bot módszereinek kódja

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

}

Öt módszert hoztunk létre:

  • start — A párbeszéd elindítása
  • state — A chat aktuális állapotának lekérése
  • reset — A chat aktuális állapotának visszaállítása
  • enter_name — A bot megkérdezi a neved
  • enter_age — A bot megkérdezi az életkorodat

Módszer start megkérdezi a neved, és a chat állapotát wait_name, azaz a neved megadására várakozó módba állítja.

Ezután te elküldöd a neved, ami a enter_namemódszerrel kerül feldolgozásra, a bot üdvözöl, rögzíti a kapott nevet az adatbázisban, és a chat állapotát wait_age.

Ebben a szakaszban a bot várja, hogy beírja az életkorát. Ön elküldi az életkorát, a bot ellenőrzi az üzenetet, ha ön valamilyen szöveget küldött szám helyett, ezt fogja mondani: Hibás adatokat adott meg, kérjük, adjon meg egy számot, és várja az újabb adatbevitelt. Ha számot küldött, a bot értesíti, hogy elfogadta az életkorát, rögzíti az adatokat az adatbázisban, tájékoztatja az összes kapott adatáról, és visszaállítja a chat állapotát az alaphelyzetbe, azaz start.

A metódus meghívásával state bármikor kérheti a chat aktuális állapotát, és a reset metódussal alapállapotba hozhatja a chatet.

Üzenetszűrők

Ebben az esetben ez az egyik legfontosabb rész a bot felépítésében. Pontosan az üzenetszűrők segítségével a bot megérti, hogy milyen információt vár tőled, és hogyan kell azt feldolgoznia.

A projektben a GitHub szűrők a következő fájlban találhatók: message_filters.R.

Az üzenetszűrők kódja:

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

A szűrőkben a korábban megírt funkciót használjuk get_state(), hogy lekérdezzük a chat aktuális állapotát. Ez a funkció mindössze egy argumentumot igényel, a chat azonosítóját.

Ezután a szűrő wait_name feldolgozza az üzeneteket, amikor a chat állapota wait_name, és ennek megfelelően a szűrő wait_age feldolgozza az üzeneteket, amikor a chat állapota wait_age.

Kezelők

A feldolgozók fájlja a handlers.R, és a következő kódot tartalmazza:

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

Először létrehozzuk a parancsok feldolgozóit, amelyek lehetővé teszik, hogy elindítsa a dialógust, visszaállítsa azt, és lekérje az aktuális állapotot.

Ezután létrehozunk 2 üzenetfeldolgozót a korábban létrehozott szűrők felhasználásával, és hozzáadunk egy szűrőt !MessageFilters$command, hogy bármilyen állapotban felhasználhassuk a parancsokat.

A bot indító kódja

Most mindent előkészítettünk az indításhoz, a bot fő indító kódja a következő fájlban található: bot.R.

library(telegram.bot)
library(tidyverse)
library(RSQLite)
library(DBI)
library(configr)

# átlépünk a projekt mappájába
setwd(Sys.getenv('TG_BOT_PATH'))

# olvassuk be a konfigurációs fájlt
cfg <- read.config('config.cfg')

# létrehozzuk a bot példányát
updater <- Updater(cfg$bot_settings$bot_token)

# A bot összetevőinek betöltése
source('db_bot_function.R') # adatbázis-kezelő funkciók
source('bot_methods.R')     # bot metódusok
source('message_filters.R') # üzenetszűrők
source('handlers.R') # üzenetfeldolgozók

# Feldolgozók hozzáadása a kezelőhöz
updater <- updater +
  start_h +
  wait_age_h +
  wait_name_h +
  state_h +
  reset_h

# A bot indítása
updater$start_polling()

Ennek eredményeként egy ilyen botunk lett:
Telegram bot írása R nyelven (4. rész): Sorozatos, logikus párbeszéd kialakítása a bottal

Bármikor a következő parancs segítségével /state lekérhetjük a chat aktuális állapotát, a parancs segítségével /reset A chat visszaállítása az alapértelmezett állapotba és a párbeszéd újrakezdése.

Zárás

Ebben a cikkben megvizsgáltuk, hogyan használhatunk adatbázisokat a boton belül, és hogyan építhetjük fel a logikus párbeszédeket a chat állapotának rögzítése révén.

Ebben az esetben a legprimitívebb példát vizsgáltuk, hogy egyszerűbb legyen megérteni a hasonló botok építésének ötletét, a gyakorlatban sokkal bonyolultabb párbeszédeket is létrehozhat.

A sorozat következő cikkében megtanuljuk korlátozni a bot használóinak jogait a különböző módszerek használatára.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster