MS謹製のbot作成フレームワーク「Bot Builder」で遊んでみた！〜対話篇〜

([MS謹製のbot作成フレームワーク「botbuilder」で遊んでみた！ - Qiita](http://qiita.com/o0h/items/1a51cd0bbd9c38027388)の続き。)

前回の記事の発展として「対話」を行ってみたいと思います。
対話(Conversation)はbotkitでも用意されているのですが、初めて見た時は大感動したものの、ちょっと癖が強くない・・？という風に感じられました。
もしコレがBotbuilderで簡単になっているなら嬉しいな・・・

公式docの[Collecting Input](http://docs.botframework.com/builder/node/guides/core-concepts/#collecting-input)の内容をベースに書いてみました。

## 今回やること
簡単に会話(=連鎖的なやり取り、くらいの意味です)の内容を覚えてみよう〜ということでやってみます。
名前教えて→名字教えて→氏名を出力する、という非常に単純なものです。
実際に動かしてみたのが↓↓

![botbuilder-conv.gif](https://qiita-image-store.s3.amazonaws.com/0/941/264a888e-3dc9-3547-9f46-898684afd140.gif "botbuilder-conv.gif")

### Sessionで会話の管理
「会話を始める」「終了する」という状態を管理するために、sessionが用いられます。
[Session | Bot Builder SDK Reference Library | Bot Framework](http://docs.botframework.com/sdkreference/nodejs/classes/_botbuilder_d_.session.html)

また最初にコードを見てみましょう。

```js
var Botkit = require('botkit');
var builder = require('botbuilder');
var controller = Botkit.slackbot();
var bot = controller.spawn({
  token: process.env.token
});

var slackBot = new builder.SlackBot(controller, bot);
var dialog   = new builder.CommandDialog();

// 起動時のハンドリング
dialog.matches('名前おしえるね', function (session) {
  if (! session.userData.firstName) {
    session.beginDialog('/profile/first');
  } else if(! session.userData.lastName) {
    session.beginDialog('/profile/last');
  } else {
    session.send(session.userData.lastName + session.userData.firstName + '・・・');
    session.send('覚えたぞ！！！');
  }
});

// ファーストネームを聞く処理
slackBot.add('/profile/first', [
	function (session) {
  		builder.Prompts.text(session, 'ファーストネーム教えて！！！');
	},
	function (session, results) {
  		session.userData.firstName = results.response;
  		session.endDialog();
	}
]);

// ラストネームを聞く処理
slackBot.add('/profile/last', [
  	function (session) {
  		builder.Prompts.text(session, 'ラストネーム教えて！！！');
	},
	function (session, results) {
  		session.userData.lastName = results.response;
  		session.endDialog();
	}
]);

slackBot.add('/', dialog);

slackBot.listen(['direct_mention']);
bot.startRTM(function(err,bot,payload) {
  if (err) {
    throw new Error('Could not connect to Slack');
  }
});

```

`dialog.matches('名前おしえるね', function (session){});` となっていますが、これを受けて会話シーケンスを起動します。
その中で、`session.userData`の値をチェックして実行するdialogを制御しているのですね。
お察しの通り、この`session.userData`こそがユーザーとの会話を記録していく場所になります。
doc→ [session.userData](http://docs.botframework.com/sdkreference/nodejs/classes/_botbuilder_d_.session.html#userdata)

もう1つの要が[session.beginDialog](http://docs.botframework.com/sdkreference/nodejs/classes/_botbuilder_d_.session.html#begindialog)であり、これによって「いまどんなdialogが走っているか」が制御できるわけです。
第1引数に「どのdialogを実行するか」を渡しており、またそのdialog中で`session.endDialog()`をコールすることで会話の終了を管理するという流れです。

子dialogの方を見てみると、第2引数がリストで指定されていることが特徴です。
これによって、順番に逐次実行を行うことが可能です([Waterfall](http://docs.botframework.com/builder/node/dialogs/overview/#waterfall))。
まず最初に `builder.Prompts.text()`で質問文を投げかけ、その後に実行される処理で入力値の受け取り→ストレージへの格納→dialogの終了処理を行っています。


この辺りは割と公式docが分かりやすかったので、目を通してみることをおすすめします。
[Core Concepts | Documentation | Bot Framework](http://docs.botframework.com/builder/node/guides/core-concepts/#collecting-input)

### 返事の内容をチェック(バリデーション)することはできるの・・？
いまいち正解がわかっていないのですが・・
たとえば「名前は5文字以上での入力を必須にしたい」、といった場合。
`session.replaceDialog()`を用いて、「同じDialogに再度飛ばす」ことで実現できているように思いました。

![botbuilder-conv2.gif](https://qiita-image-store.s3.amazonaws.com/0/941/2c4e6687-b663-c6dd-b016-4c1fc7875e8e.gif "botbuilder-conv2.gif")

```js
// ファーストネームを聞く処理
slackBot.add('/profile/first', [
	function (session, results) {
		if (results.response.length < 5) {
		  session.send('名前5文字以上にしてね！！');
		  session.replaceDialog(this);
		  return;
		}
	  	session.userData.firstName = results.response;
		session.endDialog();
	},
	function (session, results) {
		session.userData.firstName = results.response;
  		session.endDialog();
	}
]);
```

## 感想
botkitの会話より楽だと良いな・・とは冒頭で書きましたが、実際に触ってみるとこちらの方がシンプルな感じがしました！(ちょろっと触った程度ですが、回答内容のバリデーションをして引っかかったら再質問を・・という処理に難儀した記憶があります。)
また、今回は触れていませんが、Promptsには他にも`confirm()`・`choice()`・`time()`といったメソッドも用意されていて、自然なインターフェイスを作りやすいのではないか？という印象でした。
知見を深めたいですね・・！