bot開発日記3(ダイアログを改造してみる)
簡単な受け答え
ボットを作るぞというと、何をしたいですか? こんな例をしてみたいですか?
ユーザ: こんにちは
Bot: こんにちは
Bot: 今、〇〇にいるのですね。暑いですか?
ユーザ: 暑い〜
Bot: 今日は気温が30度を超えるので水分補給を忘れないようにしてください。
GPSの座標を駆使したボットの会話で自然な流れですね。 でも、これ単純に開発するのは結構難しいのです。
なぜ???
理由は色々あるのですが、この会話だけしかできないボットは難しくないですが この会話の中に柔軟な受け答えができるボットを作りたいという意図が含まれていることが多いです。 そのような汎用性のあるボットは非常に難しいのです。
じゃあ何なら簡単?
一概に言えませんがまずはQ&A形式のが良いです。
ユーザ:電話番号
Bot: 電話番号問い合わせを行います
Bot: どなたの電話番号が知りたいですか?
ユーザ: 〇〇さん
Bot: すいませんよくわかりません。敬称をつけていた場合は外して再度入れてください。
ユーザ: 〇〇
Bot: 〇〇の電話番号は0x0-xxxx-xxxxです。
Bot: お問い合わせを終了します。
これは、どうですか?非常に機械的なシナリオに見えます。 相手が機械であることがわかる感じの内容です。 まずはこれを作ってみましょう
シナリオの流れ
参考資料
簡易解説
- 要件
- 「電話番号」と問い合わせが来ると電話番号検索のシナリオ(Dialog)を開始
- 電話番号が検索出来ない場合は、再登録用のメッセージを記述
- 検索結果が一致すると電話番号を表示しシナリオ(Dialog)を終了する
- 制限制約事項
- 途中で別のシナリオ(Dialog)を割り込み出来ない <= 今後この部分に関して記事化予定
- 途中でシナリオを中断できない
解説
bots/dialogBot.js
メインの大元処理部分となります。 Dialogの受け渡し、ステータスの大元を管理しているクラスになります.
処理自体は、メッセージの受け取りと、ダイアログの処理の2つで残りはデフォルトの処理です.
dialogs/mainDialog.js
ダイアログの直接的な処理と制御を行います。
constructor各種初期化で重要なのはthis.addDialog
の部分です。
ここでは3つのデータをinputします。
1つ目は、addDialog(new TextPrompt(COMMAND_TEXT, this.validateInputCheck))
この部分
この部分で、データを取得するための型宣言と入力時のバリデータを入れます。
2つ目は、.addDialog(new TelDialog(TEL_DIALOG))
この部分
現在のmainDialogを親として、子供ダイアログTelDialogを設定します。
この記述はのちのbeginDialogの部分に必要な手続きです。
3つ目は、.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG,
この部分
WaterfallDialogがこのmainDialogの主の処理になります。Waterfall <=> ウォーターフォール
開発プロセスにもあるように次に流れるようなステップです。
今回は3つの関数を定義しています。
introStepメソッド
async introStep(stepContext) {
// 会話情報の取得.
// 2回目以降ならstepContext.resultに値が代入されるが、初回は代入されないためcontextから取得.
const value = (stepContext.result) ? stepContext.result : stepContext.context.activity.text;
if (await this.validateInputCheck(value)) {
// データの入力をスキップして次のステップに移動.
return await stepContext.next(value);
// return await stepContext.beginDialog(TEL_DIALOG); <= この記述だと、TEL_DIALOGが終わるとinputStepが実行されるためエラーとなる.
}
// 問い合わせ内容をメッセージ
return await stepContext.prompt(COMMAND_TEXT, {
prompt: 'お問い合わせしたい内容を入れてください。',
retryPrompt: 'ご入力された内容には対応していません。 入力例:電話番号' });
}
return await stepContext.next(value);
こう言った記述があります。
これは、次のステップに飛ばすという意味になります。valueを引数にすることで次の結果で取得が可能です。
通常各stepは1ステップ実行したらユーザに問い合わせが行われることになるのですがnextを使うと即時実行が可能です。
// return await stepContext.beginDialog(TEL_DIALOG);
参考に記述したのですが
各サンプルをみていると上記のような実行を行うとtelDialogが実行されるとtelDialog終了時に次のステップが残っているため
次のステップでエラーになります。 実際にコメントアウトを外して実行してもらえるとわかりやすいです。
dialogs/telDialog.js
基本的に先ほどのmainDialogと似ています。 この2つのファイルを見てですが、役割を細分化してダイアログ化して行くことが 重要ではないかと思われます。
エラー処理
{% asset_img bot_other.png エラー処理 %} ちなみに、エラー(例外)処理に対しては上記のような結果になります。 例外処理を考慮してボットを作成するのが個人的には一番難しくキモの部分と思います。
まとめ
簡単な検索だけでも結構大掛かりな事になる。 Q&Aを拡張させていくと、このシナリオ(Dialog)が非常に多くなってしまう。 今後、割り込み処理・中断処理の部分の考え方が非常に重要になってくる。