今回は、SlackのBotと会話する方法を解説する。
以前の記事で、SlackのBotは簡単に作れることを解説したけれど、あれはごくごく簡単なものだった。今回は、もう少し込み入ったロジックで使える、BotkitのConversationという仕組みを解説する。
Botkit Conversation
Conversationを使えば、ユーザーとBotがやりとりすることができる。ユーザーの発言に応じてBotのアクションを切り替え、会話のようなことが出来る。
会話といえば、reply() でだってBotを喋らせることができる。それなのにどうしてConversationを使うんだろう?確かに、ユーザーの問いかけに対して一回応答するだけならreply()で充分だ。しかしこの後見ていくように、Conversationを使えばユーザーの問いかけに対して何度も応答したり、逆にBotから質問できたりする。
Conversationを使うには、hears()やon()などのハンドラーの中でbot.startConversation()を呼び出し、一連の処理を実行させる。具体的にはこうだ。
1 2 3 4 5 6 7 8 9 10 |
controller.hears( ['conversation'], ['direct_mention'], function(bot, message) { bot.startConversation( message, function(err, convo) { // Conversationの処理を記述する }); }); |
startConversationのハンドラーの引数で貰っている convo を使って、ユーザーとのインタラクティブな動作を実現する。それでは、そのための関数を見ていこう。
say
Conversationの中で、Botに喋らせる時に使う。
1 2 3 4 5 6 7 8 9 10 11 |
controller.hears( ['conversation'], ['direct_mention'], function(bot, message) { bot.startConversation( message, function(err, convo) { convo.say('Hello!'); convo.say('Start conversation!'); }); }); |
この例では、単純に”Hello!”と”Start conversation!”という二言を喋らせている。実際の動作はこんな感じ。
このsay()だけなら、Conversationでなくともreply()を使う方がいい。ネストが浅くなって可読性も上がる。ただ、Conversationの真骨頂は次に解説するask()だろう。say()もask()と組み合わせて使うケースが大半なはずだ。
ask
askという名前のとおり、ユーザーに『問いかけ』、その返事を受けて動作を続ける。
例えば、ユーザーの今日の気分を聞き、その返事をオウム返しするBotを作ってみるとこうなる。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
bot.startConversation( message, function(err, convo) { convo.say('Hello!'); convo.say('Start conversation!'); convo.ask( 'How are you?', function(response, convo) { convo.say('You said:' + response.text); convo.next(); }); }); |
こいつを動かしてみるとこうなる。
ちなみに next() はConversationを続けるために使われる。これを呼びださなければ、Conversationがハングし、メモリーリークを引き起こすなんて怖いことが公式レファレンスには書かれている。忘れずに呼び出しておこう。
ask 高度な使い方
ask()にはもう一つの使い方がある。それは、ユーザーの応答によって処理を変えるという使い方だ。
ユーザーが「YES」と言ったらこれを、「NO」ならこっちをみたいな動作を実装できる。
試しに、SF好きなBotを作ってみよう。ユーザーにSFが好きかどうか尋ね、「YES」ならオススメを教え、「NO」なら質問をやめる。そしてそれ以外なら質問しなおすといったロジックだ。
ask()の第二引数にコールバック関数の配列を渡し、それぞれの関数のpatternで、ユーザーのどんな応答に対応しているかを決めている。
期待していた応答ではない=「YES」「NO」ではない場合の処理は、三つ目の関数が担っている。defaultプロパティをtrueに設定した関数がそれで、質問を繰り返すよう実装してある。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
bot.startConversation( message, function(err, convo) { convo.ask( 'Do you like SF? Say YES or NO.', [ { pattern: bot.utterances.yes, callback: function(response, convo) { convo.say('The Martian is awesome SF novel!'); convo.next(); } }, { pattern: bot.utterances.no, callback: function(response, convo) { convo.say('Bye x<'); convo.next(); } }, { default: true, callback: function(response, convo) { convo.say('Please say YES or NO :)'); convo.repeat(); convo.next(); } } ]); |
patternに使われているbot.utterances.yesとbot.utterances.noは、それぞれユーザーの「YES」と「NO」に対応しているが、同じような意味の言葉もカバーしている。「non」や「yup」などだ。
これを実際に動かしてみるとこうなる。
「YES」の場合
「NO」の場合
「YES」「NO」以外の場合
「YES」「NO」以外の場合で使った repeat() は質問を繰り返すときに使うもので、ドラクエで何度も同じ質問をしてくるのはこれを使っているとか、いないとか……
その他の使い方
Conversationの大枠は以上だけれど、解説したもの以外の関数も用意されている。ユーザー毎に応答を溜めておいて後で取り出したり、direct messageチャンネル内でconversationをしたりと、色々なものが用意されているから、必要なら公式レファレンスを見てみてほしい。
Multi-message Replies to Incoming Messages – Botkit
ECMAScript 2015 (ES6) 時代に備えるには今しかない。ES6のキャッチアップはこちら。
関連記事