robot.hear/respondなどのマッチ条件を動的に定義する
仕組み?
DBにマッチ条件の文字を登録->スクリプト内で読み込み->ループ処理
やあ、やぁ、こんにちは、おはよう的なサムシングに対して、こんにちは!ぼくはぼっと!と返す処理を作ります。
そして最終的にいい感じにします。
ファイル構成
scripts(Hubotのscriptsディレクトリ) ├ index.js ├ register_api.js └db ├ files │ └ definition.db ├ nedb_wrapper.js ├ file_db_controller.js └ mem_db_controller.js
多分こうなります。気持ちいらないものもありますがご愛嬌ってことで。。。
HowTo
NeDBを利用してデータ操作を行うので、こちらの記事でNeDBの実装をしておきます。
Hubotと上記のNeDBを前提にしています。
データの準備
ひとまずJson形式で反応するキーワードリストを作りましょう。
const json_data = { key: "keywords", value: ["やあ","やぁ","こんにちは","おはよう"] }
これをDBにinsertします。今回はファイル、メモリどちらでもOKですが、登録内容の確認にも便利なので最初はファイルDBとして初期化することをオススメします。
ログ出力やエラー処理は省略。
const db = require('./db/file_db_controller'); db.insertQuery(json_data, db.GetConnection);
データの準備ができました。scriptフォルダ以下に早速待受処理を書いていきます。
valueを正規表現にして判定に利用する
現状は1レコードのみなので、適当にDBからレコードを抽出、Valueの配列をfor文で回します。
const query = { key: "keywords" } db.findAllQuery(query, db.GetConnection) .then(param => { for(let word of param.value){ let regexp = new RegExp(word, 'i'); robot.hear(regexp, (res) => { res.send("こんにちは!ぼくはぼっと!"); }); } })
はい、できました。
挨拶は大事ですが、これでは応答が固定で、ひたすら挨拶する残念な子になってしまいますね。
応答メッセージもセットにする
せっかくJSON形式を使うので応答メッセージもおなじレコードに入れ込みましょう。
json_dataに要素を追加します。
const json_data = { key: "keywords", value: ["やあ","やぁ","こんにちは","おはよう"], response: "こんにちは!ぼくはぼっと!" // responseとして回答テキストを追加 }
読み込み~応答部分も変更しましょう。
const query = { key: "keywords" } db.findAllQuery(query, db.GetConnection) //.then(param => { .then(params => { for(let param of params){ for(let word of param.value){ let regexp = new RegExp(word, 'i'); robot.hear(regexp, (res) => { //res.send("こんにちは!ぼくはぼっと!"); res.send(param.response); }); } } })
複数のレコードがあってもいいようにfindクエリの結果をfor文で回すように変更しました。
あとはres.send部分が変数化されたくらいです。
API経由でJsonパラメータを受け取ってみる
最後にレコードの取り込み用のAPIを追加しましょう。
ServerURL/api/v1/registerへJson形式でPOSTすることにします。
Json形式のデータを受け付けるので、BodyParserを使います。
※送るデータは{value:["よいではないか"], response:"あーれぇー"}
のような形にします。valueは配列にするのを忘れずに。
// register_api.js const db = require('./db/file_db_controller'); const path = require('path'); const bodyParser = require('body-parser'); module.exports = (robot) => { robot.router.use(bodyParser.urlencoded({ extended: true })); robot.router.use(bodyParser.json()); robot.router.post('/api/v1/register', async (req, res) => { if (!req.body) return; const json_data = { key: "keywords", value: req.body.value, response: req.body.response } await db.insertQuery(json_data, db.GetConnection); robot.loadFile(path.resolve(__dirname, "./"), 'index.js'); res.send(200); }) }
DBへ受け付けたレコードを流し込んだら、robot.loadFileコマンドでjsファイルを再読み込み、先程追加したレコードを有効化します。
すべて終わったら、レスポンスコード200でも返しておきましょう。
ついでに最終的なindex.jsはこんな感じ。
// index.js const db = require('./db/file_db_controller'); module.exports = (robot) => { const query = { key: "keywords" } db.findAllQuery(query, db.GetConnection) .then(params => { for(let param of params){ for(let word of param.value){ let regexp = new RegExp(word, 'i'); console.log("set hearing word: " + word); robot.hear(regexp, (res) => { res.send(param.response); }); } } }) }
ということで完成です。
やあ、というキーワードで、ややあんとにお とかでも反応するのが嫌な場合は、wordの部分を、"^" + word にするなど、先頭一致等の条件をいい具合煮付けてください。
あとは煮るなり焼くなり、認証つけるなり入力フォーム作るなりご自由にドウゾ。