IBM Cloud FunctionからWatson MLのWebサービスを呼び出す

# はじめに
IBM Cloud FunctionからWatson MLで作ったWebサービスを呼ぶということをやってみました。
今まで知らなかったのですが、Cloud Functionに対してサービスをバインドすることが可能で、こうしておくとCloud Function上のコードに認証情報を含める必要がなく便利です。(SCORING_URLはまだ手で設定していますが。。。)
その手順について記載します。

# 前提
[Github](https://github.com/makaishi2/wml-kidney-sample)に説明のあるWebサービスをCALL先とします。
(このWebサービスの作成手順はまだネットにアップしていなかったので、近々アップします)

# SCORING URLの確認
Watson Studioのモデル管理画面から、接続対象のWebサービスのSCORING URLを確認してエディタなどに保存します。
SCORING URLは、Warson Studioプロジェクト管理画面から
「Deployments」タブ->詳細画面->「Implementaion」タブで確認可能です。

![スクリーンショット 2018-07-10 20.34.37.png](https://qiita-image-store.s3.amazonaws.com/0/206130/a1ed7015-e3aa-cf18-4cc3-c756e5c45583.png)

# サービスの作成
IBM Cloudのダッシュボードから「Functions」を選択します。

![スクリーンショット 2018-07-10 20.17.07.png](https://qiita-image-store.s3.amazonaws.com/0/206130/52e2a6fc-dfa2-bbe2-ea0d-e7eb78f21612.png)

下の画面が表示されたら「作成の開始」をクリックします。

![スクリーンショット 2018-07-10 20.17.23.png](https://qiita-image-store.s3.amazonaws.com/0/206130/724fefe5-b5ed-680a-7906-6f183806bd31.png)

次の画面では「Create Action」をクリック。

![スクリーンショット 2018-07-10 20.17.38.png](https://qiita-image-store.s3.amazonaws.com/0/206130/a4186eb2-84f9-c191-2cb2-d4dcef58fa52.png)

下の画面が出たら、
**Action Name:** wml-kidney-service
**Runtime:** Python 3
を入力して「Create」をクリック。

![スクリーンショット 2018-07-10 20.18.23.png](https://qiita-image-store.s3.amazonaws.com/0/206130/125d74ef-2291-6d2c-72b2-513e30851be4.png)

コード編集画面が出たら、コードの中身を下記のものに置き換えて下さい。
(scoring_urlの定義は、上のステップで取得したものにします。)
置き換えが終わったら、「Save」をクリックします。

```py3
#
#
# main() will be run when you invoke this action
#
# @param Cloud Functions actions accept a single parameter, which must be a JSON object.
#
# @return The output of this action, which must be a JSON object.
#
#
import sys
import requests
import urllib3
import json

def main(dict):
    age = dict['AGE']
    bp = dict['BP']
    al = dict['AL']
    sc = dict['SC']
    pot = dict['POT']
    pcv = dict['PCV']

    # Token取得
    creds = dict['__bx_creds']['pm-20']
    print(creds)
    wml_username = creds['username']
    wml_password = creds['password']
    wml_instance_id = creds['instance_id']
    wml_url = creds['url']
    auth = '{username}:{password}'.format(username = wml_username, password = wml_password)
    header_basic_auth = urllib3.util.make_headers(basic_auth=auth)
    url = '{}/v3/identity/token'.format(wml_url)
    mltoken =  json.loads( requests.get(url, headers=header_basic_auth).text )['token']
    #print('mltoken = ', mltoken)
    
    # Scoring API呼出し
    scoring_url = 'xxxx'
    header_token = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + mltoken}
    value1 = [None, age, bp, al, sc, pot, pcv]
    payload_scoring = {"fields": ["CLASS", "AGE", "BP", "AL", "SC", "POT", "PCV"], "values": [value1]}
    #print(payload_scoring)
    scoring_response = requests.post(scoring_url, json=payload_scoring, headers=header_token)
    print(scoring_response)
    
    # 結果解析
    res = json.loads( scoring_response.text )
    print(res)
    fields = res['fields']
    ret_list = res['values']
    ret = ret_list[0]
    cls = ''
    prob = 0
    for index, field in enumerate(fields):
        if field == '$L-CLASS':
            cls = ret[index]
        if field == '$LC-CLASS':
            prob = round(ret[index], 4)
    ret = {cls: prob}
    return(ret)
```

# Cloud Functionプラグインの導入
Cloud Functionプラグインの導入がまだの場合(bx wskコマンドが使えない)は、下記リンクからプラグインの導入を行います。
[Cloud Functionプラグイン](https://console.bluemix.net/docs/openwhisk/bluemix_cli.html#cloudfunctions_cli)

# MLサービスとのバインド

まず、次のコマンドで作成したFunctionサービスの名称を確認します。

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

次のコマンドで、Watson MLサービスとバインドします。

```sh
$ bx wsk service bind pm-20 wml-kidney-service
```

複数のWatson MLサービスがある場合は、以下のようにインスタンス名もオプションで追加します。

```sh
$ bx wsk service bind pm-20 wml-kidney-service --instance <instance_name>
```

正常にバインドされているかどうかは、次のコマンドでわかります。

```sh
bx wsk action get wml-kidney-service
```
バインドされている場合、usernameやpasswordなどの情報も、``__bx_creds``の配下に設定されています。


# テスト用パラメータの設定
Cloud Functionの管理画面から「アクション」->「wml-kidney-service」を選択し、先ほど作ったCloud Functionの詳細画面を表示します。

![スクリーンショット 2018-07-10 20.53.13.png](https://qiita-image-store.s3.amazonaws.com/0/206130/857f5842-cc66-d7e0-7f3a-b6c6a2d10d65.png)

メニューから「Parameters」を選択し、「Add」をクリックして、以下のパラメータとデフォルト値を順に設定していきます。


|変数  |値    |
|-----|------|
|AGE  |21    |
|BP   |90    |
|AL   |4     |
|SC   |1.7   |
|POT  |3.5   |
|PCV  |23    |

下の図のように全部設定が終わったら、「Save」をクリックして下さい。

![スクリーンショット 2018-07-10 20.57.15.png](https://qiita-image-store.s3.amazonaws.com/0/206130/0e822b5a-d839-f02a-6c74-121211235edd.png)

# テスト
これですべての設定が完了しました。
メニューから再び「Code」を選択し、画面右の「Invoke」をクリックします。

![スクリーンショット 2018-07-10 21.09.05.png](https://qiita-image-store.s3.amazonaws.com/0/206130/66454f7c-a494-ab3f-caf8-90cb868645c0.png)

うまくいくと、下の図のような結果が帰ってきます。
うまくいかない場合は、エラーメッセージを元にデバッグを行って下さい。

(注意)bindコマンドはソースコードを修正する度に発行しなおす必要があります。

![スクリーンショット 2018-07-10 21.09.20.png](https://qiita-image-store.s3.amazonaws.com/0/206130/c7b0ede4-6ef9-19a2-f2a0-4dfcfed5a297.png)