Bot Framework Composer で チャットボットをノンコーディング開発 (2) Dialog (+ユーザー入力、外部 API 利用、条件分岐)

Bot Framework Composer は、Bot Framework をベースとしたチャットボットアプリを GUI で作成するツールです。ダイアログの作成や LUIS や QnAMaker を利用した自然言語処理の組み込みをノンコーディングで作成できます。

- Bot Framework Composer で チャットボットをノンコーディング開発 シリーズ
    - (1) [ひとまず EchoBot 編](https://qiita.com/annie/items/93ffbbc2f0981257751e)
    - (2) Dialog (+ユーザー入力、外部 API 利用、条件分岐) 編 (このページ)
    - (3) [Language Understanding (LUIS) で自然言語処理を追加 編](https://qiita.com/annie/items/bae1067ff3adbe820d08)


今回は Bot Framework Composer を使って、ユーザーの入力を元に外部 API を利用して情報を取得、結果をユーザーに返信する Dialog (対話フローを行う処理(ひとかたまり))を作成してみます。

例として、郵便番号を入力すると 今の天気 or 天気予報 を返答するチャットボットを作成します。


- 準備
    - Bot Framework Composer
    - 天気情報 API (Open Weather Map)

- 手順
    - [1. 新規チャットボットアプリの作成と初期動作確認](#1-%E6%96%B0%E8%A6%8F%E3%83%81%E3%83%A3%E3%83%83%E3%83%88%E3%83%9C%E3%83%83%E3%83%88%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E4%BD%9C%E6%88%90%E3%81%A8%E5%88%9D%E6%9C%9F%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D)
    - 2. Dialog の新規作成と Trigger による起動設定
        - [2-1. Dialog の新規作成](#2-1-dialog-%E3%81%AE%E6%96%B0%E8%A6%8F%E4%BD%9C%E6%88%90)
        - [2-2. キーワードと Trigger の設定](#2-2-%E3%82%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%89%E3%81%A8-trigger-%E3%81%AE%E8%A8%AD%E5%AE%9A)
        - [2-3. Dialog への接続確認](#2-3-dialog-%E3%81%B8%E3%81%AE%E6%8E%A5%E7%B6%9A%E7%A2%BA%E8%AA%8D)
    - 3. ユーザー入力＆外部 API を使った情報取得とフローの設定
        - [3-1. ユーザー入力値の取得と検証](#3-1-%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E5%85%A5%E5%8A%9B%E5%80%A4%E3%81%AE%E5%8F%96%E5%BE%97%E3%81%A8%E6%A4%9C%E8%A8%BC)
        - [3-2. 外部 API のリクエストとレスポンスの取得](#3-2-%E5%A4%96%E9%83%A8-api-%E3%81%AE%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%A8%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%81%AE%E5%8F%96%E5%BE%97)
        - [3-3. API レスポンスの値を使った返答](#3-3-api-%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%81%AE%E5%80%A4%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E8%BF%94%E7%AD%94)
    - [4. 動作の確認](#4-%E5%8B%95%E4%BD%9C%E3%81%AE%E7%A2%BA%E8%AA%8D)


# 準備

## Bot Framework Composer

[(1)ひとまずEchoBot編](https://qiita.com/annie/items/93ffbbc2f0981257751e) の手順で、ダウンロード＆インストールしておきます

## 天気情報 API (Open Weather Map)

天気情報を取得する API は、登録するだけで無償で使える [Open Weather Map](https://openweathermap.org/) を利用します。例えば 〒100-0001 の現在の天気を取得するには、以下の URL に GET または POST で API Call します。
**http://api.openweathermap.org/data/2.5/weather?zip=100-0001,jp&units=metric&lang=ja&APPID=YOUR_API_KEY**

> 郵便番号は xxx-xxxx (3桁-4桁) で jp を地域指定、YOUR_ API_KEY に登録して取得できる API Key を入力します。
- [Open Weather Map: Current weather data](https://openweathermap.org/current)

天気情報は、Response Body で以下のような Json で取得できます。

```
{
  "coord":{
    "lon":139.76, "lat":35.68
  },
  "weather":[
    {
      "id":801, "main":"Clouds", "description":"薄い雲", "icon":"02d"
    }
  ],
  "base":"stations",
  "main":{
    "temp":20.86, "pressure":1013, "humidity":35, "temp_min":18.89, "temp_max":22.22
  },
  :
```

# 手順

## 1. 新規チャットボットアプリの作成と初期動作確認

[(1)ひとまずEchoBot編](https://qiita.com/annie/items/93ffbbc2f0981257751e) の手順で、Bot Framework Composer を起動し、ブラウザーで開きます。
Home 画面の [+New] をクリックします。

![20191113_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/a65ed1d8-da35-57ef-5568-d6944db9a69b.png)

*Create from scratch?* ダイアログボックスが表示されるので、**Create from scratch** に✔(チェック)をつけて 右下の **[Next]** をクリックします。

![20191113_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/24fa89f3-e3c7-b0fd-5796-18f1f7cc1a20.png)

*Define conversation objective* ダイアログボックスで、必要事項を入力します。

- Name **[必須]** : お好きな名前を入力してください。ここでは **WeatherBot** と入力
- Description : お好みで入力
- Location : (デフォルトのままで構いません。必要に応じて変更してください)

入力できたら、右下の **[Next]** をクリックして初期設定を完了します。

![20191113_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/0c1772f3-29e9-c2a3-2077-3ef7c2dd63aa.png)

チャットボットアプリの名前.Main (ここでは *WeatherBot.Main*) と表示されたフロー画面が表示されます。
WeatherBot.Main には **Conversation started** というフローがデフォルトで作成されています。**Conversation started** をクリックします。

![20191113_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/827cf7cc-d3aa-e4bc-c3d6-a90ba889e185.png)

画面中央にデフォルトで作成されている Trigger (チャットボットが反応するためのトリガー) が表示されます。

> ユーザーからの最初のアクセス (ConversationUpdate) がトリガーとなります。

![20191113_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/d9bdd690-841c-fdb1-94a7-45fca315245a.png)

ユーザーから最初のアクセスがあった場合に応答を返す処理を追加します。*Conversation started* Trigger の下にある **(+)** をクリックし、表示されるメニューから **Send a response** を選択します。

![20191113_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/750e6e18-ac02-6140-2ab9-8e9b09320c8c.png)

画面右側に *Send a response* ペインが表示されます。テキストボックスにユーザーへの初期応答文言を入力します。

![20191113_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/cb3c6967-dc31-9860-1230-8217287ebfa8.png)

ここで一度 Bot の動きを確認します。画面右上の **[Start Bot]** をクリックします。

![20191113_08-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/d352a591-f7df-e74b-4ebc-e83d1b95850b.png)

[Start Bot] が [Restart Bot] という表記に変わり、 その横に表示される **Test in Emulator** をクリックして、Bot Framework Emulator を起動します。

![20191113_08-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/9a4684d8-4ae2-c0eb-294f-b9914b94de82.png)

Bot Framework Emulator で初期応答が表示されたら、チャットボットアプリは正常に作成されています。

![20191113_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/cc68c89c-71d7-f776-356a-3390ade246eb.png)

## 2. Dialog の新規作成と Trigger による起動設定

### 2-1. Dialog の新規作成

"今の天気" を取得する Dialog を作成します。
画面左側の Dialog メニューにある **(+) New Dialog..** をクリックします。

![20191113_10-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/67c9976d-4d95-2927-8001-721cd75882c0.png)

*Define conversation objective* ダイアログボックスで、情報を入力します。

- Name **[必須]** : Dialog の名前を入力します(半角英数字)。ここでは **getCurrentWeather** と入力
- Description : お好みで入力

入力できたら、右下の **[Next]** をクリックして初期設定を完了します。

![20191113_10-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/6b1b6f5a-7151-7450-b0b7-94ea99b1ebc7.png)

画面左側の Dialog メニューに **getCurrentWeather** が追加され、画面右側に Dialog の起動設定を行う *getCurrentWeather* ペインが表示されます。

![20191113_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/9f775c71-ebad-e137-946b-91e60873be43.png)

*getCurrentWeather* Dialog が呼び出されたら、応答を返すように設定しておきます。
画面左側の Dialog メニューの *getCurrentWeather* の下にある **BeginDialog** をクリックします。

![20191113_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/ccbe1e95-6815-99da-7198-531486f9eda6.png)

*BeginDialog* 画面中央に表示されている Trigger の下にある **(+)** をクリックし、表示されるメニューから **Send a response** を選択します。

![20191113_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/14128fb1-25ef-6fe4-7c45-b9d61390f8b1.png)

画面右側に表示される *Send a response* ペインでユーザーへの応答文言を入力します。

![20191113_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/c5a4ab5d-8e50-2225-622e-1a8bcf4432f9.png)

### 2-2. キーワードと Trigger の設定

WeatherBot.Main の中でユーザーが "今の天気" というキーワードを入力 (またはメニューを選択) した場合に getCurrentWeather が起動するようにします。

まず、 WeatherBot.Main にキーワード とそれを格納する *Weather* という Intent (グループ) を登録します。
画面左側の Dialog メニューから WeatherBot.Main をクリックします。画面右側に表示される *WeatherBot* ペイン、*Recognizer Type* のドロップダウンボックスから **Regular Expression** を選択します。
表示される **[Add]** をクリックします。

![20191113_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/4ab8b0d4-fcd0-d434-2cc5-62173bdc5e22.png)

キーワードと Intent を以下のように入力します。

- Intent **[必須]** : Intent (キーワードのグループ名)を入力します。ここでは **CurrentWeather** と入力
- Pattern **[必須]** : キーワードを入力します。ここでは **今の天気** と入力

![20191113_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/3c65c3ef-f9a8-af10-dad4-089eb98bbca1.png)

次に *getCurrentWeather* が *CurrentWeather* Intent に設定したキーワードで起動するように　Trigger を設定します。
画面左側 Dialog メニュー にある **WeatherBot.Main** > *Comversation state* の下にある **(+) New Trigger..** をクリックします。

![20191113_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/cf892b96-e98f-941b-808f-f53a6308af4e.png)

*Create Trigger* ダイアログボックスで以下の設定を行います。

- What is type of this trigger? **[必須]** : **Intent** を選択
- Which intent do you want to handle? **[必須]** : **CurrentWeather** を選択

右下の **[Submit]** をクリックして設定を完了します。

![20191113_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/752019d8-2422-32d1-6ca4-b313da6052da.png)

画面左側の Dialog メニューに **CurrentWeather** という Trigger が追加され、画面中央にもデフォルトで作成された *Trigger* という Trigger 起動のメソッドが表示されます。

![20191113_17-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/485aa21f-8522-b773-983e-9dac53059c01.png)

Trigger の下にある **(+)** をクリックし、表示されるメニューから **Dialog Management** > **Begin a new dialog** を選択します。

![20191113_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/219c7261-cc1b-a6e4-ffbf-b4aaa0e46581.png)

画面右側に *Begin a new dialog* ペインが表示されます。
*Dialog name* のドロップダウンボックスから **getCurrentWeather** を選択します。

![20191113_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/e019c9be-70b8-e9f0-fb83-60ba17568e7d.png)

### 2-3. Dialog への接続確認

*getCurrentWeather* Dialog で行う作業とフローを全部設定する前に、キーワードを入力したら Trigger から *getCurrentWeather* Dialog が呼び出されるか動作確認を行います。

右上の **[Restart Bot]** をクリックして、変更を反映させます。

Bot Framework Emulator 側でも **Restart Conversation** をクリックして、再度接続を行います。 
初期応答が表示され、**今の天気** と入力すると *GetCurrentWeather* の応答が返されれば Dialog の呼び出しは成功です。

![20191113_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/2b108d27-90f2-d7e8-5354-025aba9b16a1.png)

## 3. ユーザー入力＆外部 API を使った情報取得とフローの設定

*getCurrentWeather* Dialog で行う作業とフローを設定していきます。
この Dialog では、ユーザーからの入力 (郵便番号) を受け取って、外部 API を利用して天気情報を取得して返答します。

### 3-1. ユーザー入力値の取得と検証

画面左側 Dialog メニュー の *getCurrentWeather* Dialog をクリックし、表示される **BeginDialog** をクリックします。
画面中央に表示されている **BeginDialog** のフロー画面で、*Send a response* ボックスの下にある **(+)** をクリックし、表示されるメニューから **Ask a question** > **Text Input** を選択します。

![20191113_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/5d883275-e0a7-f3df-9de9-c0cf3a6a862c.png)

*Bot Asks* と *User Answers (Text)* というボックスが追加され、画面右側に *Text input* ペインが表示されます。
*Bot Asks* のタブにある *Prompt* の欄にユーザーの入力を促すメッセージを入力します。
また、*Prompt settings* の Default value に "**100-0001**"(東京) を設定しておきます。また、**Always Prompt** に ✓(チェック) をつけておきます。

![20191113_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/ed484572-fdc3-f5ca-581e-630bdc3a65e9.png)

*User Input* タブをクリックします。ユーザー入力を取得するプロパティなどを設定します。

- Property to fill : **user.zipcode**
- Output Format: **trim**

> ここでは user.zipcode というカスタムクラスを作成し、ユーザー入力値を取得します。

![20191113_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/faf2d9d7-78c3-db44-4a12-a1837486670a.png)

*Other* タブをクリックします。ユーザー入力の検証を行い、入力値が Empty または正しくない場合は再度入力を促すメッセージを返答します。

- Unrecognized Prompt: Empty だった場合に入力を促すメッセージを入力します
- Validation Rules: **length(this.value)==8**
- Invalid Prompt: 正しい入力を促すメッセージを入力します

![20191113_24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/b9d4e0f6-1a63-064a-f853-bdba0755a648.png)

### 3-2. 外部 API のリクエストとレスポンスの取得

画面中央の *User Answers (Text)* ボックスの下にある **(+)** をクリックし、表示されるメニューから **Send an HTTP request** > **Access external resources** を選択します。

![20191113_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/f5baa469-dce7-9ce0-30b4-30a77d9a03c3.png)

*Send an HTTP request* というボックスが追加され、画面右側に *Send an HTTP request* ペインが表示されるので、以下のように設定します。

- HTTP method : **GET**
- Url: **http://api.openweathermap.org/data/2.5/weather?zip={user.zipcode},jp&units=metric&lang=ja&APPID=YOUR_API_KEY**
- Result property: **dialog.api_response**
- Response type: **Json**

> この設定では user.zipcode の値(郵便番号) を用いて、API Call します。
> また、API Response を dialog.api_response という Build-in クラスに格納します。これにより、API Response の Status Code (dialog.api_response.statusCode) や Body (dialog.api_response.content), Message (dialog.api_response.content.message) が容易に取得できます。

![20191113_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/cf245a0d-a596-ff5f-44a5-0e5802059061.png)

### 3-3. API レスポンスの値を使った返答

外部 API から正しく情報が取得できたら (=Status Code: 200) Body から情報を取り出します。
画面中央の *Send an HTTP request* ボックスの下にある **(+)** をクリックし、表示されるメニューから **Create a condition** > **Branch: if/else** を選択します。

![20191113_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/bbb93afe-793b-e3a5-2f9f-2d07ee3cd174.png)

*Branch: if/else* ボックスが追加され、True と False に分かれたフローも追加されます。
画面右側に *Branch: if/else* ペインが表示されるので、Condition を以下のように入力します。

- Condition: **dialog.api_response.statusCode==200**

![20191113_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/20b62d3f-8fa4-4e14-c6a0-efef99652dd0.png)

*Branch: if/else* ボックスの下の **True** のフローに表示される **(+)** をクリックし、**Manage Properties** > **Set a property** を選択します。

![20191113_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/2c6e6321-20ff-3dbd-7ac7-0345b78b3c64.png)

画面右側に表示される *Set a property* ペインで以下のように設定します。

- Property: **dialog.weather**
- Value: **dialog.api_response.content**

> この設定では dialog.weather というカスタムクラスを作成し、API からの Response の Body 部分を格納します。それにより以下のように情報が取得できます。
- 現在の天気(日本語): dialog.weather.weather[0].description
- 現在の気温(℃): dialog.weather.main.temp

![20191113_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/af7ae510-f607-5a92-bb59-29bfa22796c6.png)

*Set a Property* ボックスの下にある **(+)** をクリックし、表示されるメニューから **Send a response** を選択します。

![20191113_31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/41f87f65-cd2c-817e-d887-4c99c9221f12.png)

画面右側に表示される *Send a response* ペインで、取得した情報を使って返答を作成します。

> 例えば **天気: {dialog.weather.weather[0].description}、気温: {dialog.weather.main.temp}℃ です** のように設定します

![20191113_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/3020f070-867b-e721-d26b-577a19c9d5ab.png)

今度は *Branch: if/else* ボックスの下の **False** のフローに表示される **(+)** をクリックし、**Send a response** を選択します。

![20191113_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/97073756-782e-1179-6c86-60dfb84dc9a8.png)

画面右側に表示される *Send a response* ペインで API Call 失敗とエラーコードを返答するように設定します。

> 例えば **API Call に失敗しました: {dialog.api_response.content.message}** のように設定します

![20191113_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/8bcfd6c7-ca75-266e-0a06-098158b6a4b3.png)

最後に、この Dialog を終了する処理を追加します。*Branch:if/else* の分岐が終わった後の **(+)** をクリックし、**Dialog Management** > **End This dialog** を選択します。

![20191219_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/775acba1-52c7-51b1-1142-3f4552fd6cdf.png)

これで Dialog の作成は完了です。

![20191219_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/ac66f7b7-4b50-896d-ddb6-3a86ce945cb1.png)

## 4. 動作の確認

画面右上の **[Restart Bot]** をクリックして、変更を反映させます。
Bot Framework Emulator も再読み込みを行い、動作を確認します。
"今の天気" と入力したのち、郵便番号の入力を促されたら入力、天気と気温が表示されたら getCurrentWeather Dialog をつかったチャットボットアプリは完成です。

![20191113_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/0bd8ba23-6abc-0b9f-0d33-214a980a487c.png)