आर में टेलीग्राम बॉट लिखना (भाग 4): बॉट के साथ एक सुसंगत, तार्किक संवाद बनाना

यदि आप पिछला पढ़ चुके हैं तीन लेख इस श्रृंखला से, तो आप पहले से ही जानते हैं कि कीबोर्ड के साथ पूर्ण टेलीग्राम बॉट कैसे लिखें।

इस लेख में, हम सीखेंगे कि एक बॉट कैसे लिखें जो लगातार संवाद बनाए रखेगा। वे। बॉट आपसे प्रश्न पूछेगा और आपके द्वारा कुछ जानकारी दर्ज करने की प्रतीक्षा करेगा। आपके द्वारा दर्ज किए गए डेटा के आधार पर, बॉट कुछ क्रियाएं करेगा।

साथ ही इस लेख में हम सीखेंगे कि बॉट के हुड के तहत डेटाबेस का उपयोग कैसे करें, हमारे उदाहरण में यह SQLite होगा, लेकिन आप किसी अन्य DBMS का उपयोग कर सकते हैं। मैंने आर भाषा में डेटाबेस के साथ इंटरैक्ट करने के बारे में अधिक विस्तार से लिखा है यह लेख.

आर में टेलीग्राम बॉट लिखना (भाग 4): बॉट के साथ एक सुसंगत, तार्किक संवाद बनाना

श्रृंखला के सभी लेख "आर में टेलीग्राम बॉट लिखना"

  1. हम एक बॉट बनाते हैं और टेलीग्राम में संदेश भेजने के लिए इसका उपयोग करते हैं
  2. बॉट में कमांड समर्थन और संदेश फ़िल्टर जोड़ें
  3. बॉट में कीबोर्ड सपोर्ट कैसे जोड़ें
  4. बॉट के साथ सुसंगत, तार्किक संवाद बनाना

सामग्री

यदि आप डेटा विश्लेषण में रुचि रखते हैं, तो आपको मेरी रुचि भी हो सकती है तार и यूट्यूब चैनल. अधिकांश सामग्री आर भाषा को समर्पित है।

  1. परिचय
  2. बॉट निर्माण प्रक्रिया
  3. बॉट परियोजना संरचना
  4. बॉट कॉन्फिग
  5. एक पर्यावरण चर बनाएँ
  6. एक डेटाबेस बनाना
  7. डेटाबेस के साथ काम करने के लिए लेखन कार्य
  8. बॉट तरीके
  9. संदेश फ़िल्टर
  10. संचालकों
  11. बॉट लॉन्च कोड
  12. निष्कर्ष

परिचय

बॉट द्वारा आपसे डेटा का अनुरोध करने और आपके द्वारा कोई जानकारी दर्ज करने की प्रतीक्षा करने के लिए, आपको संवाद की वर्तमान स्थिति को रिकॉर्ड करना होगा। ऐसा करने का सबसे अच्छा तरीका SQLite जैसे किसी प्रकार के एम्बेडेड डेटाबेस का उपयोग करना है।

वे। तर्क इस प्रकार होगा. हम बॉट विधि को कॉल करते हैं, और बॉट क्रमिक रूप से हमसे कुछ जानकारी का अनुरोध करता है, और प्रत्येक चरण पर यह इस जानकारी के दर्ज होने की प्रतीक्षा करता है और इसकी जांच कर सकता है।

हम सबसे सरल संभव बॉट लिखेंगे, पहले यह आपका नाम पूछेगा, फिर आपकी उम्र, और प्राप्त डेटा को डेटाबेस में सहेजेगा। उम्र पूछते समय, यह जाँच करेगा कि दर्ज किया गया डेटा एक संख्या है, न कि टेक्स्ट।

इस तरह के एक सरल संवाद में केवल तीन अवस्थाएँ होंगी:

  1. प्रारंभ बॉट की सामान्य स्थिति है, जिसमें वह आपसे किसी भी जानकारी की अपेक्षा नहीं करता है
  2. wait_name - वह स्थिति जिसमें बॉट किसी नाम के दर्ज होने की प्रतीक्षा करता है
  3. wait_age वह स्थिति है जिसमें बॉट आपकी आयु, पूरे वर्षों की संख्या दर्ज होने की प्रतीक्षा करता है।

बॉट निर्माण प्रक्रिया

लेख के दौरान, हम चरण दर चरण एक बॉट बनाएंगे; पूरी प्रक्रिया को योजनाबद्ध रूप से निम्नानुसार चित्रित किया जा सकता है:
आर में टेलीग्राम बॉट लिखना (भाग 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 स्क्रिप्ट
  • बॉट.डीबी - बॉट डेटाबेस

आप संपूर्ण बॉट प्रोजेक्ट देख सकते हैं, या डाउनलोड से मेरी 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 टेबल की आवश्यकता होगी:

  • चैट_डेटा - वह डेटा जो बॉट ने उपयोगकर्ता से अनुरोध किया था
  • चैट_स्टेट - सभी चैट की वर्तमान स्थिति

आप निम्न 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, तो डेटाबेस बनाने के लिए आप आर में निम्नलिखित कोड का उपयोग कर सकते हैं।

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

वे। हमारे टेबल फ़ील्ड में चैट_आईडी इसमें एक विशिष्टता बाधा है और यह तालिकाओं की प्राथमिक कुंजी है। प्रारंभ में, हम तालिका में जानकारी जोड़ने का प्रयास करते हैं, और यदि वर्तमान चैट के लिए डेटा पहले से मौजूद है तो हमें एक त्रुटि मिलती है, ऐसी स्थिति में हम बस इस चैट के लिए जानकारी को अपडेट करते हैं।

इसके बाद, हम इन फ़ंक्शंस का उपयोग बॉट के तरीकों और फ़िल्टर में करेंगे।

बॉट तरीके

हमारे बॉट के निर्माण में अगला कदम तरीके बनाना है। यदि आपने प्रोजेक्ट डाउनलोड किया है 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 तर्क, चैट आईडी की आवश्यकता है।

अगला फ़िल्टर प्रतीक्षा_नाम जब चैट किसी स्थिति में हो तो संदेशों को संसाधित करता है 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()

परिणामस्वरूप, हमें यह बॉट मिला:
आर में टेलीग्राम बॉट लिखना (भाग 4): बॉट के साथ एक सुसंगत, तार्किक संवाद बनाना

किसी भी समय कमांड का उपयोग करना /state हम वर्तमान चैट स्थिति और कमांड का उपयोग करके क्वेरी कर सकते हैं /reset चैट को उसकी मूल स्थिति में लौटाएँ और संवाद फिर से शुरू करें।

निष्कर्ष

इस लेख में, हमने पता लगाया कि बॉट के अंदर डेटाबेस का उपयोग कैसे करें, और चैट स्थिति को रिकॉर्ड करके अनुक्रमिक तार्किक संवाद कैसे बनाएं।

इस मामले में, हमने सबसे आदिम उदाहरण को देखा, ताकि आपके लिए ऐसे बॉट बनाने के विचार को समझना आसान हो जाए; व्यवहार में, आप बहुत अधिक जटिल संवाद बना सकते हैं।

इस श्रृंखला के अगले लेख में, हम सीखेंगे कि बॉट उपयोगकर्ताओं के इसके विभिन्न तरीकों का उपयोग करने के अधिकारों को कैसे प्रतिबंधित किया जाए।

स्रोत: www.habr.com

एक टिप्पणी जोड़ें