IBM Cloud FunctionからNLUを呼び出す

# はじめに
IBM Cloud Functionシリーズの続きです。
前の記事[IBM Cloud FunctionからWatson MLのWebサービスを呼び出す](https://qiita.com/makaishi2/items/e483f14d8042cbb9ba29)を書いている時に気付いたのですが、IBM Cloud FunctionのActionでは、bxコマンドでサービスとバインドしておくと、認証情報を簡単に取れます。
この仕組みを使って、NLUのエンティティ抽出を行うサービスを作ってみました。

# サービスの作成
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:** nlu-servce
**Runtime:** Python 3
を入力して「Create」をクリック。

![スクリーンショット 2018-07-11 9.44.34.png](https://qiita-image-store.s3.amazonaws.com/0/206130/05aa4b0e-d459-881b-a758-b9d2ddf1583e.png)

コード編集画面が出たら、コードの中身を下記のものに置き換えて下さい。
置き換えが終わったら、「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 json
from watson_developer_cloud import NaturalLanguageUnderstandingV1
from watson_developer_cloud.natural_language_understanding_v1 \
  import Features, EntitiesOptions, KeywordsOptions, ConceptsOptions, CategoriesOptions, RelationsOptions, SentimentOptions

def main(dict):
    # 解析対象文
    text = dict['text']

    # 認証情報の取得
    creds = dict['__bx_creds']['natural-language-understanding']
    #print(creds)
    username = creds['username']
    password = creds['password']
    
    # NLUクライアントインスタンス生成
    
    natural_language_understanding = NaturalLanguageUnderstandingV1(
        username = username,
        password = password,
        version='2018-03-16')
        
    # NLU呼出し
    response = natural_language_understanding.analyze( text = text, features = Features(
        #relations = RelationsOptions()
        entities = EntitiesOptions(),
        #concepts = ConceptsOptions(),
        #keywords = KeywordsOptions(),
        #sentiment = SentimentOptions(),
        #categories = CategoriesOptions()
    ))
    
    # 結果解析
    entities = response['entities']
    person = ''
    company = ''
    location = ''
    for item in entities:
        if item['type'] == 'Organization':
            company = item['text']
        if item['type'] == 'Person':
            person = item['text']
        if item['type'] == 'Location':
            location = item['text']
        
    return { 'person': person, 'company': company, 'location': location }
```

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

# サービスのバインド
次にNLUサービスと、今作ったCloud FunctionのActionとのバインドを行います。
これを行うことにより上記コードのうち、

```py3
    creds = dict['__bx_creds']['natural-language-understanding']
    username = creds['username']
    password = creds['password']
```

の部分でNLUの認証情報を取得できるようになります。

まず、次のコマンドで作成したFunctionサービスの名称を確認します。
``/<org_name>_<space_name>/nlu-service``というactionが存在するはずです。

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

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

```sh
$ bx wsk service bind natural-language-understanding nlu-service
```

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

```sh
$ bx wsk service bind natural-language-understanding nlu-service --instance <instance_name>
```

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

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

# パラメータの設定
Cloud Functionサービスが解析対象パラメータ(text)を受け取れるようにします。
また、テスト用にパラメータのデフォルト値も設定します。

Cloud Functionの管理画面から「アクション」->「nlu-service」を選択し、先ほど作ったCloud Functionの詳細画面を表示します。

![スクリーンショット 2018-07-11 9.56.11.png](https://qiita-image-store.s3.amazonaws.com/0/206130/c3b3cabc-6050-fa6e-dce5-3c836c2feaf5.png)

メニューから「Parameters」を選択し、「Add」をクリックして、以下のパラメータ``text``とデフォルト値を設定します。
``text``のデフォルト値はテスト用の解析対象テキストです。なんでもいいのですが、私は下のような自己紹介文を設定しました。デフォルト値に文字列を設定する場合、ダブルクオートで囲む必要がありますので、注意して下さい。

```txt
"はじめまして。私は日本アイ・ビー・エムの山田花子です。私は大阪から来ました。"
```

![スクリーンショット 2018-07-11 16.30.32.png](https://qiita-image-store.s3.amazonaws.com/0/206130/69cc1b6b-c867-7fa2-cc60-c8b247638315.png)

これで準備完了です。コードのタブに戻って「invoke」をクリックします。

![スクリーンショット 2018-07-11 10.32.16.png](https://qiita-image-store.s3.amazonaws.com/0/206130/687c2e69-7b0b-d0f7-0a1e-ce913871a4a7.png)

うまくいくと下のような結果がかえってくるはずです。
Entityとして**Company**(「日本アイ・ビー・エム」)、**Person**(「山田花子」)、**Location**(「大阪」)が取れているのがわかると思います。

![スクリーンショット 2018-07-11 16.33.42.png](https://qiita-image-store.s3.amazonaws.com/0/206130/34922891-e936-decb-6e62-2517595792b7.png)

うまくいかない場合は、Pythonのソースに適宜print文を入れてデバッグして下さい。
コードを修正した場合、``bx wsk service bind``文は再発行する必要がありますので、その点を注意して下さい。