Watson Assistant から IBM Cloud Functions の Action を呼び出す方法

(2018/6/19 Conversation -> Assistant の変更他、最新の情報にUpdate)

Watson Assistant(以降Assistant)の Dialog ノードから IBM Cloud Functions (以降ICF)の Actionを直接呼び出せるようになったので、設定手順を記載します。

>- 2018年6月現在この機能はβ版での提供となります。
>- 米国南部、ドイツのAssistant及びICFのインスタンスが前提となります。

#概要
例えば天気予報を教えてくれるチャットボットを作成する場合、これまでの実装では下図のようにAssistantで抽出されたIntentやEntityに基づき、ユーザーアプリケーションが外部のサービス（ここではWeather Company Data）を呼び出す必要がありました。

![wcs.png](https://qiita-image-store.s3.amazonaws.com/0/235649/f10d721f-f6e1-0f28-3aa0-7cf63b59050f.png)

ICFを使用するとAssistantのDialogノードからICFで定義したActionを直接呼び出すことができるようになります。ICFが外部サービスを呼び出し、応答の内容を生成することができるため、結果Assistantからの応答内容を動的に変化させることができるようになります。

![wcsicf.png](https://qiita-image-store.s3.amazonaws.com/0/235649/fcb56d24-97ba-bb63-10a1-6b814c7321cf.png)

以降では前述の天気予報チャットボットを題材に、AssistantとICFの連携手順を記載します。

# Weather Company Dataインスタンスの作成 
IBM Cloudにログインし、Weather Company Dataサービスのインスタンスを作成します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/8772d7a4-3bfd-e47a-113b-987be4797e92.png)

作成したサービスの資格情報は後ほど必要になるので保存しておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/2d2b58ad-8137-94d1-452a-72ca5faefb03.png)

# ICFのActionの作成
IBM Cloudのカタログから「機能」を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/1b0bb1a3-d537-2f1c-795e-ffa370982657.png)

「作成の開始」を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/b794961a-de1e-498d-10f4-eb2458c3eccc.png)

「アクションの作成」を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/7a309a9d-dd69-0ac5-ff1f-60237d48f684.png)

「アクション名」「ランタイム」を指定して、「作成」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/f874a02e-03e5-cf65-9790-1d1159325421.png)

>ランタイムはNode.js、Python、PHP等、好みのものを指定できます。今回はNode.jsを使用します。

開いたエディターでNode.jsのコードを作成します。

```JavaScript
var request = require('request');

var main = function(params){
    var options = {
        json:true,
        auth:{
            'user':'aaaaaa',
            'password':'bbbbbb'
        }
    }
   
    return new Promise(function(resolve, reject) {
        options.url = 'https://twcservice.mybluemix.net/api/weather/v3/location/search?query=' + encodeURI(params.location) + '&language=ja-JP';
        request.get(options, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                var lat = body.location.latitude[0];
                var lng = body.location.longitude[0];
                
                options.url = 'https://twcservice.mybluemix.net/api/weather/v1/geocode/' + lat + '/' + lng + '/forecast/daily/3day.json?language=ja-JP';
                request.get(options, function (error, response, body) {
                    if (!error && response.statusCode == 200) {
                        var forecast = body.forecasts[0].narrative;                     
                        resolve({"forecast":forecast});
                    }else{
                        reject();
                    }
                })
            } else {
                reject();           
            }
        })
    })
}
```

### コードの解説
- user、passwordには前述の手順で保存した Weather Company Data の資格情報を使用します。
- １つ目の request.get で入力のlocation名の緯度、経度を取得します。
- ２つ目の request.get で入力の緯度、経度の地点の天気予報を取得します。

作成したコードはこの画面でテストすることができます。コードを保存したら、「入力の変更」ボタンをクリックし、Actionへの入力値を指定します。今回の例では以下のようにlocationの名前を入力とします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/8f5395e7-a844-db9c-71fe-6fb90623e66f.png)

「起動」ボタンをクリックし、結果が正常に返ってくることを確認します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/d3df41cf-9792-6e8e-a6f8-01ce2435af0e.png)

# Assistant設定に必要な情報の取得
## Namespace名、Action名の取得
画面左側の「エンドポイント」を選択し、表示されるHTTPメソッドからNamespace名、Action名を保存しておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/40eeed6c-f55d-d890-0b8a-1ddcadaab372.png)
> 一般的にNamespace名は「*組織名_スペース名*」という形式になります。

## API キーの取得
以下の手順でAssistantからICFのActionを呼び出すために必要なAPIキーを取得します。

画面左上の「<-アクション」から前のページに戻ります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/68f11a1c-f108-2f1d-81ef-0f5212f2cd8b.png)

「開始」セクションの「APIキー」を選択し、右側の画面で ![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/7014143d-7bd6-51e7-c1a8-66d7ab201ec7.png) をクリックして、伏字で表示されたキーを保存しておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/34846f35-005e-3eba-e1ff-50c2baa0f77b.png)

> APIキーは xxxxxx:yyyyyy のようにコロン(:)で区切られた2つのフィールドから成っており、１番目のフィールドが user、２番目のフィールドが password となります。

# AssistantのDialogフローの作成
Assistantのワークスペースを作成し、Intent、Entityを定義します。簡単のため、Intentは#weather、Entityは@location のみ作成します。（詳細な手順は省略）

Intentの構成例
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/c4e8f64b-a04f-272c-d954-442baba63b4a.png)

Entityの構成例
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/c22efe38-ca81-e1f2-9151-1c73e2d0a987.png)

Dialogフローにノードを追加し、条件式（If bot recognizes）は #weather 及び @location を設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/450a4819-c088-e810-3027-804ccdc16bbc.png)

JSON editorには以下のように ICF の Action を呼び出すための JSON を定義をします。

```JavaScript
{
  "actions": [
    {
      "name": "/scorg01_dev/getWeather",
      "type": "server",
      "parameters": {
        "location": "@location"
      },
      "credentials": "$private.my_credentials",
      "result_variable": "context.getWeather_result"
    }
  ]
}
```

### JSONの解説
- name には前述の手順で確認した /Namespace名/Action名 を設定します。
- parameters は Action への入力となります。
- credentials は ICF を呼び出すための APIキーになります。
- Action からの出力は result_variable に指定した変数に格納されます。

作成したノードに子ノードを追加し、条件式（If bot recognizes）は true、応答（Then response with）は $getWeather_result.forecast を設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/e26a166f-32d3-6423-8e3e-c387efa5ffd5.png)

親ノードで「Skip user input」を選択し、子ノードへのユーザー入力をスキップします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/703bf4ec-de5f-adf8-fafe-b829823e5536.png)

# Dialog フローのテスト
Try it outパネルから「Manage Context」を選択し、context変数 $private.my_credentials を設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/879f7eeb-215e-70d7-38a4-ab480a8c648f.png)

設定値は前述の手順で確認した、ICFのAPIキーに含まれるuser及びパスワードになります。

```JavaScript
{"user":"xxxxxx","password":"yyyyyy"}
```

Try it out パネルから天気を聞くと応答が @location の値に従って変わることが確認できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/235649/0e39f9f8-9ce0-b973-0fe5-de42e8a388bf.png)