Watson AssistantからIBM Cloud Functionsを呼び出す

# はじめに
この記事は、[IBM Cloud Functionsで、日本語天気照会機能を実装する](https://qiita.com/makaishi2/items/8a447a82271bb1a0bdce)の続編です。
この記事でIBM Cloud上に作ったIBM Cloud Functionの機能をWatson Conversationから呼び出してみます。
完成後のアプリケーションイメージは下記のものとなります。
(天気しか答えてくれない単細胞なBOTです)

(2018-05-24 全面改定)

![スクリーンショット 2018-05-24 14.17.15.png](https://qiita-image-store.s3.amazonaws.com/0/206130/04ee4141-eab5-12a3-ce20-7bd3d891356c.png)

参照URL [Create and invoke Actions](https://console.bluemix.net/docs/openwhisk/openwhisk_actions.html#openwhisk_apicall_action)

# 前提
前の記事で書いた日本語天気照会サービスが、自分のIBM Cloud環境上で動いている必要があります。
また、Watson Assistantを使うので、同じ環境でWatson Assistantが利用可能な状態であることとします。

# 事前準備
認証などで必要な情報を事前に取得します。

## Action名の取得
Action名の取得に関しては、前の記事で確認方法を示したとおり、

```sh
$ bx wsk action list
```

のコマンドで取得します。
``/<org_name>_<space_name>/weather-jp``  の形式になっているはずです。

## API Keyの取得
IBM Cloud Functionsの管理画面から下の図のように「開始」->「APIキー」をクリックします。APIキーの画面が表示されたら、画面右下のクリップボードへのコピーのアイコンをクリックして、APIキーを取得し、テキストエディタなどに張り付けます。

![conv-func-2.png](https://qiita-image-store.s3.amazonaws.com/0/206130/e905618b-b6ad-1c9b-1275-e14b9466f023.png)

APIキーは ``xxxxxx:yyyyyy``のようにコロンで区切られた形式となっています。
コロンより前が**user id**、コロンより後が**password**になります。

# Conversationの実装
続いて、Conversationの構築を行います。

## Assistantワークスペースの作成
通常の手順でAssistantワークスペースを作成します。
言語は日本語、名称はなんでもいいですが例えば「天気予報BOT」などとします。

## インテントの作成
``#weather``というインテントを作成します。例文は天気の問い合わせに関するものとします。
例えば、次のようなものを指定して下さい。
「天気を教えて」「天気を知りたい」「天気予報をお願い」「天気は？」「天気を教えて下さい」

## ダイアログの作成
次の図のような3階層のダイアログノードを追加します。

![スクリーンショット 2018-05-24 14.37.18.png](https://qiita-image-store.s3.amazonaws.com/0/206130/801d8498-a5f6-7b05-fb10-5ec2d0736bcc.png)

### トップレベル
**名称:** weather
**条件:** #weather
**メッセージ:** どこの天気を知りたいですか

![スクリーンショット 2018-05-24 14.30.28.png](https://qiita-image-store.s3.amazonaws.com/0/206130/9feb2ab8-c670-aef5-fd9f-855a991baceb.png)

### 2階層目
**名称:** query_weather
**条件:** ture
**メッセージ:** (設定なし)

![スクリーンショット 2018-05-24 14.30.48.png](https://qiita-image-store.s3.amazonaws.com/0/206130/90834c5b-f406-eaf8-4821-0ac52a22e34a.png)

### 3階層目
**名称:** display_weather
**条件:** ture
**メッセージ:** ``$weather.city_jp の気温は $weather.c_temp 度。天気は $weather.cond_jp です。``

![スクリーンショット 2018-05-24 14.31.06.png](https://qiita-image-store.s3.amazonaws.com/0/206130/4d293787-8c8e-1382-7cb4-be3101ab47b0.png)

## フロー設定
2階層目から3階層目にJump to (Evaluate Responses)の設定を行います。

## JSON設定
「ようこそ」ノードと、「query_weather」ノードの2箇所でJSON設定を行います。

###「ようこそ」ノード
ノード編集画面からJSONエディタを開いて、次のような設定を追加して下さい。
ユーザーIDとパスワードは事前に調べたCloud FunctionsのユーザーAPIキーで置き換えます。

```json
     "context": {
        "private": {
          "my_credentials": {
            "user": "your_user_id",
            "password": "your_password"
          }
        }
      }
```

設定後のJSONは次の図のようになっているはずです。

![スクリーンショット 2018-05-24 14.44.17.png](https://qiita-image-store.s3.amazonaws.com/0/206130/fa5decd0-aa2a-e9ed-3127-0bef29ecb2db.png)

###「query_weather」ノード
ノード編集画面からJSONエディタを開いて次のような項目を追加します。
**name**は事前に調べた**action名**で置き換えて下さい。

```json
     "actions": [
        {
          "name": "/your_space_your_dev/weather-jp",
          "type": "server",
          "parameters": {
            "city": "<? input.text ?>"
          },
          "credentials": "$private.my_credentials",
          "result_variable": "context.weather"
        }
      ],
```

設定後のJSONエディタは下の図のようになっているはずです。

![スクリーンショット 2018-05-24 14.52.09.png](https://qiita-image-store.s3.amazonaws.com/0/206130/a8d34735-38a7-9f46-32a1-21f262c6718e.png)

# テスト
お疲れ様でした。これで天気の会話しかできない単能天気BOTは完成したはずです。
「Try it out」機能を呼出して動作することを確認してみましょう。
以下に会話サンプルを示します。

![スクリーンショット 2018-05-24 14.57.37.png](https://qiita-image-store.s3.amazonaws.com/0/206130/4fa8db0f-e184-5c43-673e-4bca3fccaa47.png)


# 解説
以上の手順で動くデモはあっという間にできたと思います。
どういう仕組みでこの機能を呼び出せているかを説明します。

## 「ようこそ」ノードでの設定
コンテキスト変数として"private.my_credentials"という変数を設定しました。
この変数は、Cloud Function呼出し時に認証情報として利用します。
手順を簡略化するため、認証情報をワークスペースにハードコードしていますが、実際にはアプリケーションサーバー側で持たせて、初期設定でコンテキストにいれるようにとのガイドが、リファレンス [Create and invoke Actions](https://console.bluemix.net/docs/openwhisk/openwhisk_actions.html#openwhisk_apicall_action)に記載されています。

## 「天気照会」ノード(weather_query)での設定
Cloud Functionsの呼出しを実際に行う、一番肝となるノードです。
**actions**という項目をjsonに含めることで、Cloud Function呼出しが行われます。

具体的な設定項目の意味は以下の通りです。

**name**: Action名を指定します
**type**: server か clientを指定します。今回の使い方の場合は serverになります。
**parameters**: Cloud Function呼出し時のパラメータの指定をjson形式で行います。今回作ったパラメータは**city**という変数のみ使うので、この変数を指定します。
本当はエンティティとマッチングするところなのですが、辞書の整備が面倒なので、入力がまるごと都市名になるような会話設計にして、入力値をまるごとパラメータで渡すようにしています。
**credentials**: Action呼出し時の認証情報を指定します。
**result_variable**: Cloud Functionの戻り値をどの変数に保存するかを指定します。

```json
{
  "output": {},
  "actions": [
    {
      "name": "/xxxxxxxxx_yyy/weather-jp",
      "type": "server",
      "parameters": {
        "city": "<? input.text ?>"
      },
      "credentials": "$private.my_credentials",
      "result_variable": "context.weather"
    }
  ]
}
```

##「天気表示」(weather_display)ノードの設定
「天気照会」ノードの子ノードとして「天気表示」ノードを作り、ここでCloud Functionの照会結果を表示します。
このノードは、通常のConversation Nodeの使い方で、特別なことは行っていません。

![conv-func-6.png](https://qiita-image-store.s3.amazonaws.com/0/206130/d0d0d922-4d95-1741-4483-17acb9cf05f3.png)