このシリーズの前の3つの記事をすでに読んでいる場合は、キーボードを使用して本格的なテレグラムボットを作成する方法をすでに知っています。
この記事では、一貫した対話を維持するボットを作成する方法を学習します。それら。ボットはあなたに質問をし、あなたが情報を入力するのを待ちます。入力したデータに応じて、ボットはいくつかのアクションを実行します。
また、この記事では、ボットの内部でデータベースを使用する方法を学習します。この例ではSQLiteになりますが、他の任意のDBMSを使用できます。この記事では、R言語でのデータベースの操作について詳しく説明しました。
シリーズ「R言語で電報ボットを書く」のすべての記事
- ボットを作成し、それを使用してテレグラムにメッセージを送信します
- コマンドサポートとメッセージフィルターをボットに追加します
- ボットにキーボードサポートを追加する方法
- ボットとの一貫した論理的な対話の構築
- ボットのユーザー権利管理
コンテンツ
データ分析に興味があるなら、私の電報とyoutubeチャンネルに興味があるかもしれません。その内容のほとんどはR言語に捧げられています。
, , - . , , SQLite.
.. . , - , , .
, , , . , , .
:
- start — ,
- wait_name — ,
- wait_age — , , .
, :
- , . , .
- , .
- , , .
- , .. .
- . , .
- , .
- .
, .
- bot.R —
- db_bot_function.R —
- bot_methods.R —
- message_filters.R —
- handlers.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
.
, — .Renviron.
, file.edit(path.expand(file.path("~", ".Renviron")))
. :
TG_BOT_PATH=C:////
.Renviron 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 :
- start —
- state —
- reset —
- enter_name —
- enter_age —
start
, wait_name, .. .
, enter_name
, , , wait_age.
. , , - : ,
, . , , , , , .. 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_name
, wait_age wait_age
.
handlers.R, :
# ###########################################################
# 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
, , .
, 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()
, :
/state
, /reset
.
, .
この場合、最も原始的な例を検討しました。そのようなボットを構築するというアイデアを理解しやすくするために、実際には、はるかに複雑なダイアログを構築できます。
このシリーズの次の記事では、さまざまな方法を使用するボットユーザーの権利を制限する方法を学習します。