LINE Bot を Bot Framework Composer でローコード開発する : その 3 より高度なトリガーと複雑なダイアログ

[前回](https://qiita.com/kenakamu/items/bd00bd5646f1d7e163c8) はローカルデバッグの構成を行った後、シンプルな挨拶ダイアログを作成しました。今回は挨拶ダイアログを改良していきます。

# 自然言語処理を使ったトリガー

正規表現は、メールアドレスのチェックや電話番号のフォーマット確認を行うには強力ですが、ユーザーが入力した文章が挨拶かを判定するにはあまり向きません。

そこで今回は Azure の自然言語処理機能である LUIS を使ってユーザーの意図(インテント)を判定し、ダイアログをトリガーする方法を説明します。

Bot Framework は LUIS と統合されているため、LUIS の使い方を知らなくとも問題ありません。

## トリガーの更新

1\. メインダイアログより「Recognizer Type」を「Regular Expression」から「LUIS」に変更。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/bd052f72-fe3c-09b6-643c-08603b8b6919.png)

2\. Hello トリガーを選択し「Expected responses」を挨拶を捉えてほしい例文を追加。応答の作成と同様、```- ``` (ハイフンと半角スペース) で始める。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/ce0e95a3-01de-f370-951a-3aca64d94422.png)

## Composer の設定の更新

1\. [Azure ポータル](https://portal.azure.com) より「<ボット名>-luis-Authoring」を開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/10257a6d-7af1-b9fd-d55e-e5bf69bfbe14.png)

2\. Key1 をコピー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/9f7a00ed-91d4-fe5d-3110-f26f388e83c7.png)

3\. Composer の Settings より「Show keys」を有効にし、authorizationKey にコピーしたキーを張り付け。また defaultLanguage を「ja-jp」に変更。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/342be83e-2fb8-5af9-f558-cc86827ca0f3.png)

## 変更の反映

1\.「Restart Bot」をクリック。LUIS に変更したことから、LUIS の発行画面が表示される。設定したキーと言語が反映されていることを確認して「OK」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/d21886d4-2fce-7871-f3bc-e0fe9379e705.png)

2\. ステータスが「Publishing..」になるので、終わるまで待つ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/fe915efd-9376-7d37-0412-d53ad1491d5d.png)

3\. [LUIS ポータル](https://www.luis.ai/) にログインして、LUIS アプリができていることを確認。表示されない場合は、正しい Azure サブスクリプションとリソースが選択されているか確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/f822c19d-4499-7746-3296-7e8a96fcabb3.png)

4\. Intents に「Hello」ができていることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/d3b4b081-1d05-feb2-f8b7-98091416d517.png)

5\. 例文が Composer で設定したものが入っていることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/dcbe00a3-f76e-2d65-8bff-b7296d796cc9.png)

## テスト

LINE クライアントよりあいさつを送信。設定したものと微妙に異なっても問題ないことを確認。

<img width="450" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/768f2b94-e4bd-16a4-fcff-1a5cc93a2600.png"/>

期待した通りに動作しない場合は、トリガーに例文を追加してボットを再起動すると LUIS が更新されるため、色々試してください。

## 精度の設定

LUIS は登録したインテントの中から、ユーザーの入力の意図に近い可能性が高いものを返します。LUIS はインテントと同時に可能性をスコアで返すため、スコアを条件に入れて絞ることができます。

1\. メインダイアログより Hello トリガーを選択。Condition に条件を追加。ここではスコアが 0.7 より大きい場合を条件に設定。

- #Hello で Hello インテントの結果を取得
- #Hello.Score でスコアを取得

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/f5d368d6-6dee-b76b-efc7-8e40a9feac1e.png)

2\. スコアの結果は LINE では確認できないため、ボットを再起動後、エミュレータを起動。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/415e5a69-4c93-0ba4-ecf9-9588fd7ee297.png)

3\. エミュレーターより挨拶を送信し、「LuisV3 Trace」を確認。ここでスコアが確認可能。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/4394efaf-f1e3-bb21-f236-a0ea07dac466.png)

# より高度なダイアログ

ダイアログの重要な機能として、ユーザーに対して入力を要求する機能があります。

- ユーザーに対して質問を送信
- 回答が期待した型か(文字列か、数字か、日付かなど) を確認
- 回答が期待した条件を満たしているか確認
- 期待と異なる場合にリトライの実行
- 期待した回答であった場合回答の記憶
- 最後の質問まで進む

ユーザーの回答を記憶する領域として Composer ではいくつかの「記憶領域」が用意されています。ここでは dialog 領域と user 領域を使用します。

- dialog 領域: ダイアログが終わるとデータは消える
- user: ユーザーに紐づいているためデータは残る

尚、クラウドに発行するとバックエンドとして Cosmos DB が使われるためサービスを再起動してもデータは失われませんが、ローカル開発中はデータはメモリにしかないため、ボットを再起動するたびにデータが無くなる点に留意してください。

## ダイアログの更新

挨拶ダイアログに体調を聞く機能を付けてみましょう。

1\. HelloDialog の BeginDialog を開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/ddc349ca-953f-ba26-7fbb-d0803ca43d14.png)

2\. 挨拶の応答に続いて「＋」をクリック。「Ask a question」より「Number input」を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/57f2303f-678f-efed-2b68-21c5a190205b.png)

3\.「Bot Asks」に質問を入力。ここでは本日の体温を確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/5978b1b5-8d65-4195-9f38-cbf2149ead82.png)

4\.「User Input」を選択して「Property to fill」に「dialog.bodyTemperature」を設定。これでユーザーの回答が dialog 領域の bodyTemperature プロパティに保存される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/f68f6be8-a692-0b2c-c3e9-16dbe249703c.png)

5\.「Other」にリトライの条件を入力。

- Unrecognized Prompt: 型が違う場合の応答メッセージ
- Validation Rules: And 条件となる複数の条件。this.value でユーザーが入力した値を取得
- Invalid Prompt: 条件を満たさない場合の応答メッセージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/20db1032-b7f9-db9b-a71e-dfe7427872e2.png)

6\. 次に「Create a condition」より「Branch: if/else」を追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/06b5d4c4-da0e-1822-999b-cf67dd950428.png)

7\. 条件に dialog.bodyTemperature>37.5 を指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/3d68d203-13d3-f90e-da3e-c4063497d274.png)

8\. True ブランチに「Ask a question」より「Multiple choice」を追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/59a053d4-058b-3415-c53f-57bbd7597d40.png)

9\. 質問を追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/3f6753ee-abd8-e7a1-36f7-2cc1a2e1f261.png)

10\.「User Input」で user.healthCondition を指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/b2741183-2617-474e-7cf6-63768cb091f6.png)

11\. プロパティの下にスクロールして、選択肢を追加。また「Include numbers」と「Append choices」のチェックを外す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/45a35f5f-39fc-8799-4768-04c0c02b2be0.png)

## エミュレーターでテスト

1\. ボットを再起動して、エミュレーターで接続。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/fd358bb5-10b4-f370-78c9-6798d396f6a7.png)

2\. 挨拶を送信。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/3b316dfa-5c4f-b128-a31c-1d797eab7bba.png)

3\. 条件に合わない値を送信して挙動を確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/22fdb753-6543-cbe7-143e-4d0f67b6934f.png)

4\. 38.5 を送った後、ボットの記憶域に dialog.bodyTemperature が無いことを確認。まだダイアログは続いているが、これ以降で使う場所がないため、削除済。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/1ba545fb-155c-881b-6933-60bb0605e10e.png)

5\. 任意の回答を選択。既にダイアログは終わっているが、user 記憶域にあるデータは残っていることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/7b8d57dc-1dc1-3c46-e069-f18efd26a0b3.png)

## LINE でテスト

LINE はモバイルにしかない機能があり、複数選択の既定のオプションの場合、モバイルでしかうまく動作しません。

モバイルから接続して動作を確認。選択肢の表示のされ方を確認すると、オプションが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/5040638e-9e89-85c2-cdf8-387f7019d635.png)

## 他のオプション

Confirm は表示の仕方を何パターンかから指定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/3fcdfb16-2d81-1e3c-ab10-85cc8646feba.png)

それぞれエミュレーターでは異なる表示をサポートしますが、LINE チャンネルが全てをサポートするわけではないので、色々試してください。

# まとめ

今回はより高度なトリガーとして自然言語処理に対応したほか、ダイアログではユーザーとの複数回のやり取りをどのように記憶するかについて紹介しました。次回は文字列以外のデータの扱いを見ていきます。

[次の記事へ](https://qiita.com/kenakamu/items/efb880fa923a5596f882)