Bot Builder v4 : 会話のハンドオフシナリオとサンプルの紹介

今回は公式ドキュメントにある、[会話をボットから人間に移行する](https://docs.microsoft.com/ja-jp/azure/bot-service/bot-service-design-pattern-handoff-human?view=azure-bot-service-4.0) について C# の サンプルの紹介をします。

# サンプル

C# は公式のサンプルが無かったのですが、GitHub でいくつかシナリオを実現するサンプルがありました。その中でも今回は以下のものを試してみました。
[GitHub: intermediator-bot-sample](https://github.com/tompaana/intermediator-bot-sample)

## 動作の仕組み

BotBuilder v4.0 のミドルウェアの仕組みを使って、必要に応じて会話をチャネル間で転送する仕組みとなっています。ミドルウェアについては [Bot Builder v4 でボット開発 : アダプター、TurnContext、Activity](https://qiita.com/kenakamu/items/55c93c044a9ee99bbe22) を参照してください。

図で表すと以下の様になっています。

**通常フロー**

- ユーザーがボットに話しかける
- ミドルウェアでは処理をバイパス
- ユーザーがメッセージを受けとる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/12d409f3-838a-09ea-e3dc-aecdc89450c3.png)

**ハンドオフフロー**

- ユーザーがボットに話しかける
- ミドルウェアでハンドオフが必要と判断したら別のチャネルに転送 (ここでは Teams)
- Teams 側から担当が回答
- ミドルウェアがハンドオフ途中であることを判断して、元のチャネルに転送
- ユーザーがメッセージを受けとる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/80b2a1f4-30f4-dff9-2dce-df853952ed03.png)

会話のステータスはすべて外部ストレージ (Azure Storage) に保存されます。

以下にいくつかサンプルアプリで重要な機能について紹介します。

## 接続トリガー

通常の処理とハンドオフの処理はトリガーが必要となり、公式ドキュメントでもいくつかシナリオが提示されていますが、このサンプルでは単純に "human" という文字列があればハンドオフとしています。

## 切断コマンド

担当がチャットをボットに戻したい場合は、```disconnect``` コマンドを送ることで、ユーザーが通常のボットフローに戻ります。

## ハンドオフ対象のチャネル

構成ファイル (appsettings.json) にある ```NoDirectConversationsWithChannels``` 設定に対して設定したチャネルは全て転送対象となります。

## Watch/Unwatch

ハンドオフ対象のチャネルでも、常にハンドオフリクエストが来ないよう、コマンドでコントロールすることが出来るようになっています。

ボットアカウントを指定して ```watch``` を実行することでリクエストが来るようになります。
<img width=500 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/c6194ea7-ed5b-9b8b-c55d-b6bf59d08821.png" />

逆に ```unwatch``` を送信することでリクエストが来なくなります。

## 対応する担当の決定

構成された全てのチャネルに対して一斉通知が送られるため、だれが対応するか決める必要があります。このサンプルでは以下のようなカードを送って、初めに「Accept」を送った人が担当となります。

<img width=500 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/3373b986-ae70-2a70-3ccf-caf4e1d85fa3.png" />

# 試してみよう

大体の流れが分かったので試してみましょう。

## Azure リソースの準備

1\. Azure ポータルより「Web App Bot」を追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/08796f95-bb79-a1d2-3333-2062673bf02e.png)

2\. C# の Echo Bot テンプレートで作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/79344856-d55d-abe3-7da4-be55432b0a98.png)

3\. 任意の 2 チャネルを構成。ここでは Microsoft Teams と LINE チャネルを構成。
[参考: Bot Builder v4 : Microsoft Team に接続する](https://qiita.com/kenakamu/items/0000dbea292f5c1be1f8)
[参考: Bot Builder v4 : LINE に接続する](https://qiita.com/kenakamu/items/28b641d1476b9e0a8969)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/db9ac886-b818-2658-e661-613e0edebeac.png)

4\. ストレージアカウントを追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/367e0dd4-6027-5864-4d45-ca5f0214d1bd.png)

5\. 任意の名前を付けて作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/ecc34d29-a85d-112d-4d70-e6afa80d269c.png)

6\. アクセスキーから接続文字列を取得しておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/3632f6c4-7e44-53c1-4f40-2bd6f6ae4013.png)

## サンプルアプリ

1\. Git クローンでレポジトリをクローン。

```shell
git clone https://github.com/tompaana/intermediator-bot-sample 
```
2\. Visual Studio で IntermediatorBotSample.sln ソリューションを起動。

3\. appsettings.json を開き、必要な情報を追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/a78cf119-ea90-3375-7ade-d4c60870318a.png)

4\. 発行より構築した App Service に発行。

# 動作の確認

1\. Teams よりボットに対して ```@myhandoffbot watch``` を送信。Teams 側で待ち受け状態になったことを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/e0b29169-dc6e-d4c0-13d6-34560cfa3188.png)

2\. LINE より「human」を含む文章を送付。Teams 側にアシスト要求くることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/05c981bb-bb97-d746-0923-3ff7daa0d025.png)

3\. Accept をクリック。その後 LINE からのメッセージが Teams に来ることを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/beead737-0af6-e476-7486-a60af7668bce.png)

4\. ```@myhandoffbot disconnect``` を送ってハンドオフが終了することを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/72fb9b85-ae9b-40cb-dce6-c77ad02b7192.png)

5\. ```@myhandoffbot unwatch``` を実行してアシスト要求が来ないことを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/245e8af1-2628-8df9-f527-b0eb548b7eab.png)

# まとめ

今回のサンプルはミドルウェアを使った実装で、個人的にはとても気に入っています。他にも実装の方法はありますが、こちらも是非一度試してみてください。

[目次に戻る](https://qiita.com/kenakamu/items/6dc043cfc1f199032883)