レッツ 第4次産業革命♪
Bot Frameworkでの開発で基本となる「Dialog」についてレッツモリモリ行きましょう。 公式のドキュメントのDialogの部分 http://docs.botframework.com/en-us/csharp/builder/sdkreference/forms.htmlDialogs | Bot Builder SDK C# Reference Library | Bot Framework あたりを参考にしてます。
Bot開発を初めてする場合は、VSの開発テンプレートとEmulatorに関する事前準備をします。 beachside.hatenablog.com
> Environment
検証した環境は以下です。
- Visual Studio 2015 (Enterprise update3)
- Microsoft.Bot.Builder 3.0.0
- Microsoft.Rest.ClientRuntime 1.8.2
> Overview
項番2で説明する機能に対して、項番4~項番6の異なる方法でBotを作ってみます。
1. 単純なEchoBot
2. このあと作るボットの機能概要
3. 共通部品をつくっておきます
4. Stateを持ったBot その1
5. Stateを持ったBot その2「CommandDialog」
6. Stateを持ったBot その3「Chain」
1. 単純なEchoBot
最初は、何か入力したらそれを返すBotを作ります。
VSで、新しいプロジェクト作成→右上の検索でbot
を入力してBotApprication
を選択します。プロジェクト名は、「DialogDemo」にしました。
ASP.NET WebAPIのプロジェクトができました。
(個人的な趣味で)お決まりのDialogs
というフォルダを追加しました。その中にSimpleEchoDialog
クラスを追加しました。
そしてコード。
SimpleEchoDIalog
クラスは、おきまりのSerializableAttribute
がついており(これ大事)、IDialog
インターフェースを実装し、メソッドをさらりと書きます。
次は、Botの呼び出し元となるWebAPIのコントローラーのコードを書いていきます。プロジェクトを作成すると、MessagesController
ができています。
ここのコードを以下のようにざっくり変更しましょう。
Botのメッセージのやりとりは、Activity
クラスが中心となります。Activity
クラスについては、本家ドキュメントに概要が書いてあります。
メッセージを受けとると、28行目でDoSomethingAsync
メソッドを呼んで、Botの処理をするようにしています。
Dialogを使うときの基本的な方法として、Conversation.SendAsyncメソッドで処理をします。詳しくは本家ドキュメントにて。
先ほどSimpleEchoDIalog
クラスはIDialog
が実装されているので、インスタンス化したところでStartAsync
メソッドが実行されます。
デバッグしてEmulatorから何か入力してみましょう。
ほい、想像通りな動作です。
2. このあと作るボットの機能概要
同じ動きをするボットをいくつかのパターンで実装します。その機能は以下です。
- [機能1] 文字を入力したら、エコーして文字数も教えてくれる
- [機能2] 会話した回数を数えてくれる
- [機能3] クライアントの入力された文字列が「reset」だったら、以下のリセット処理をする
- 「(
クラス名
)Are you sure you want to reset the count?」と確認メッセージを返す - 「はい」と返答がきたらカウンターを0に戻す
- 「いいえ」だったらカウンターはリセットしない
- 「(
3. 共通部品をつくっておきます
このあと、何かと同じコードを書くので、Utility的なクラスを書いておきます。
カウンターをインクリメント/リセットするメソッド、Botが返答するメッセージのメソッドを書いています。
4. Stateを持ったBot その1
機能は、前述したとおりです。ここでは、ソリューションエクスプローラーのDialogs
フォルダの下にStateEchoDialog
クラスを作り、以下コードを実装しました。
StateEchoDialog
クラスにはお決まりのSerializableAttribute
がついています。カウンターは、StateEchoDialog
クラスのprivateメンバー変数_count
で保持しています。
StartAsync
メソッドでカウンターを初期化(0にセット)し、MessageReceivedAsync
メソッドを実行します。MessageReceivedAsync
メソッドの中では、第2引数のargumentからクライアントのデータをとることができます。
25行目のif
で、クライアントが入力した文字列が「reset」かどうかを判定します。そして、[機能1]、[機能2]は、35行目で実装しています。
[機能3]のリセット処理は、27行目のPromptDialog.Confirm
からです。「reset」入力後にリセットを本当にするかの確認は、PromptDialog.Confirm
の機能で行います。はい/いいえの応答後、44行目のAfterResetAsync
メソッドでリセットするしないの処理を行います。
MessagesController
クラスのDoSomethingAsync
メソッドは、以下のように変更します。
これで実行すると、無事に動きます。
会話をしたカウントもちゃんと取れています。
ところで余談ですが、resetと入力したときに今回書いたクラスに変わらないことありますか?
コードを変更してデバッグしても、私の環境では古いコードを認識したままってのが頻繁におきます....。そんなときはEmulatorを再起動するか、古いコード(今回だとSimpleEchoDIalog
クラス)を全部コメントアウトすると、ちゃんと動きます。そう、このために、reset時にクラス名を表示してちゃんとどうさしているか確認していたわけでして....これなんなんでしょうね...
5. Stateを持ったBot その2「CommandDialog」
同様の機能をCommandDialogを使って実装してみます。
ソリューションエクスプローラーのDialogs
フォルダの下にEchoCommandDialog
クラスを追加し、以下のコードを書きます。
ここからは、会話回数のカウンターをWebService側で保持するのではなく、会話のコンテキスト側で保持するようにします。 本家ドキュメントのBot State Service | Bot Builder SDK C# Reference Library | Bot Frameworkの内容を参考にしています。
ここでは、UserData
のcount
というKeyのValueに会話の回数を保存しました。DialogSampleUtil
クラスのIncrementCount
メソッド(DialogSampleUtil.csの7行目)とResetCount
メソッド(DialogSampleUtil.csの15行目)がその処理になります。
UserData
以外にも
Bot State Service | Bot Builder SDK C# Reference Library | Bot Frameworkに記載があるようにStateを保持するプロパティとそのSet/Getメソッドが用意されています。用途に応じて使い方を検討するところですね。
[機能1][機能2]は、33行目からのOnDefault
で処理しています。35行目のDialogSampleUtil.IncrementCount
メソッドでUserData
に現在のカウントを取得して1つプラスし、37行目でメッセージを返答しています。
[機能3]は、15~32行目の処理です。
MessagesController
クラスのDoSomethingAsync
メソッドは、以下のように変更します。
これでデバッグ実行しても同じように動きます。resetした時にクラス名が更新されていることは注意してください。
6. Stateを持ったBot その3「Chain」
次は、本命(?)のChainを使ってみます。本家のドキュメントでは以下を参考にしました。
Dialog Chains
ソリューションエクスプローラーのDialogs
フォルダの下にEchoChainDialog
クラスを追加し、以下のコードを書きます。
Chainは、Switch
で入力されたメッセージに応じて処理を分岐させています。
[機能1][機能2]のエコーを返す処理は、36行目のDefaultCase
の辺りです。[機能3]のリセット処理は、12行目。主要な処理は上記の例同様DialogSampleUtil
クラスの処理を使っています。
34行目は、「help」と入力されたときの処理を冗談半分に作りました。
MessagesController
クラスのDoSomethingAsync
メソッドは、以下のように変更します。
デバッグで実装するとちゃんとうごきますね。
今日はここまでですね。