Watson AssistantのWebhookを触ってみた

最近久々にWatson Assistantを触っていたら、見た目がだいぶ変わっていました。そして、よく見るとなんとwebhookが使えるようになっていたんです。ん？webhook？今まで結構Assistantを触ってきましたけどそんな機能聞いたことありませんでした。というわけで、今回はWatson AssistantのWebhook機能を触ってみたのでその覚書きです。

# Watson Assistantのwebhookとは？
Watson Assistantでの会話フローを作る際に外部アプリケーションとやり取りを行うときの手段の一つとしてこのwebhookを使うようです。webhookを設定したフローを使用することでそれがトリガーになって予め設定したパラメータを外部アプリケーションにPOSTするようになるそうです。これによってAssistantの機能が更に拡張されるということです。他のWatson APIを呼び出すやり方もありますし、自分で作成したFunctionを呼び出す方法もありです。

# とりあえず作ってみた
早速Watson Assistantのフローにwebhookを組み込んでみたいと思います。今回は世界各国の都市名を指定したら、その都市の天気を返すシンプルなボットを作ってみます。天気を聞き出す部分は以前紹介したIBM Cloud Fucntionsを使って実装します。
## APIの用意
今回は天気を呼び出すために、Open Weather Mapを使います。[こちら](https://home.openweathermap.org/)から会員登録します。登録するとホーム画面に```API keys```タブがあるので、クリックしてAPIキーを取得します。このAPIは英語のAPIなので日本語で来る都市名を英語に変換する必要があります。そこで、今度はIBM CloudのLanguage Translatorを使って翻訳をしたいと思います。IBM Cloudのダッシュボード画面の「リソースの作成」から「Language Translator」を選択してリソースを作成します。作成出来たら、「Manage」タブをクリックしそこに書かれているAPIキーをコピーします。二つのAPIキーをメモ出来たら、Functionsでアクションを作成していきます。

## アクションの作成
続いてIBM Cloud Functionsでアクションを作成していきます。[こちら](https://qiita.com/K_M95/items/1cc94f03c91c7d17b4e2#%E3%81%A8%E3%82%8A%E3%81%82%E3%81%88%E3%81%9A%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F)を参考にして、初期設定を完了させましょう。その後、```Code```タブをクリックして、はじめから書かれていたコードを消して、以下のコードに書き換えてください。

```python

#
#
# 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
import requests
from watson_developer_cloud import LanguageTranslatorV3


def main(dict):
    translator_key = dict["TRANSLATOR_API_KEY"]
    language_translator = LanguageTranslatorV3(
        version='2018-05-01',
        iam_apikey=translator_key,
        url="https://gateway.watsonplatform.net/language-translator/api"
    )
    # Assistantから受け取った都市名を変数に格納、テストをするときはサンプルの値を格納
    try:
        text = dict["call_city"]
    except KeyError:
        text = dict["CITY"]
    # APIでリクエストする用に翻訳
    model = "ja-en"
    translation = language_translator.translate(
    text=text,
    model_id=model).get_result()
    
    # OpenWeatherMapを使う
    city_name = translation["translations"][0]["translation"]
    weather_key = dict["WEATHER_API_KEY"]
    api = "http://api.openweathermap.org/data/2.5/weather?units=metric&q={city}&APPID={key}"
    url = api.format(city = city_name, key = weather_key)
    print(url)
    response = requests.get(url)
    data = response.json()
    print(data["weather"][0]["main"])
    
    # 更に日本語で返答するために翻訳
    text = data["weather"][0]["main"]
    model = "en-ja"
    translation = language_translator.translate(
    text=text,
    model_id=model).get_result()
    
    return { 'condition': translation["translations"][0]["translation"] }

```
以前説明しましたが、このコードの中にある```dict```はアクションに定義している```Parameters```のことを指します。APIキーなどはParametersに定義しておくと安全なコードになってこのまま他の人にシェアしても安全です。また、LanguageTranslatorはIBM Cloud Functionsに予めWatson SDKをセットアップされているのでそのまま使います。

## パラメータを設定
それでは、前述の通りまだAPIキーをParametersに定義していないので、必要なパラメータの設定を行ってきます。アクションの画面から```Parameters```タブをクリックして、必要な値を定義していきます。Parametersに定義する変数は下記の表にまとめています。**Parametersの中のParameter Valueは必ずダブルクオテーションで囲むようにしてください。**

|Parameter Name   |  Parameter Value  | 
|:-----------------|:------------------|
| TRANSLATOR_API_KEY |  "YOUR_OPEN_WEATHER_API_KEY"| 
| WEATHER_API_KEY |    "YOUR_LANGUAGE_TRANSLATOR_API_KEY" | 
| CITY        |           "動作確認用にPOSTする都市名を日本語で" |

## 動作確認
それでは、作成したアクションが正しく動作するかを確認するために、もう一度Codeタブに戻って画面右上の```Invoke```ボタンをクリックして動作確認します。ぎこちない訳だと思いますが、```CITY```で設定した都市の天気が出力されたら正常に動いています
![コメント 2019-10-26 181429.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/5e9df6e6-9a6a-d780-7630-030e266c55ae.png)

## URLの生成
Functionsでの作業の最後はwebhook URLを使えるようにするための準備をします。```Endpoints```タブをクリックして、```Enable as Web Action```にチェックを入れてセーブしてください。すると、Webアクションを呼び出すことのできるURLが生成されるので、これをコピーします。

![コメント 2019-10-26 194305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/b536580d-75f2-78fa-587a-2a7fc3afc10a.png)


# Watson Assistantの設定
Assistantに接続するためのアクションが出来たので、今度はボットの本体を作ります。今回は都市名を認識したらアクションを動作するノードを実行するだけなので、エンティティに都市名を並べるだけです。Language Translatorと同様にWatson Assistantのリソースを作成して、Skillsタブ（画面右上にある吹き出しマークではない方のアイコン）をクリックして、```Create skill```で新たにスキルを作成します。以下の画面が出てきたら、Dialog skillを選択して、Nextボタンをクリックします。

![コメント 2019-10-26 182651.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/d02c5312-3102-7281-1ae4-3d3cdcdfdb2e.png)

Skillの設定をします。Nameは何でもOKですが、Languageは日本語で設定します。設定が終わったら、```Create dialog skill```をクリックして完了させます。
![スクリーンショット 2019-10-26 00.54.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/411227ce-644b-e2a3-c03b-7e613fe68eb1.png)

Skillの編集画面が出たら、```Entity```タブを開き、```My entities```から都市名のエンティティを作成します。このあとフローを作成する際にエンティティ名は```city```として進めます。

![コメント 2019-10-26 184022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/7e9ba7dc-3237-405b-74df-d94ab4083533.png)

## webhookを使うための準備
今度はWatson Assistantとwebhookの接続設定をします。```Options``` タブを選択して、Webhooksを開きます。そのURLの欄に先程生成したWebhookのURLを記入します。URLを記入する際には、URLの最後に```.json```を入れるようにしてください。拡張子を指定することで、Web アクションの機能を利用して、希望する応答のコンテンツ・タイプを指定できます。Web Actionで設定しているので、Headersには特に値を設定する必要はありません。
![Inkedコメント 2019-10-26 193800_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/f9c59076-a3a6-f714-cda5-1ca218453de2.jpeg)

## フローの作成
いよいよフローを作成していきます。とは言っても全体のフローは下の通りにあまり複雑なものではありません。この中の「天気を教えて」ノードが新たに追加するノードになります。```Add node```をクリックして設定をしていきます。

![コメント 2019-10-26 184522.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/400aeceb-b9bd-96a7-bc79-e1fdf6a56c7c.png)

設定画面を開くとまだwebhookが有効になっていないので、webhookの実行を選択出来ません、そこで設定画面の右上の```Customize```をクリックして、WebhookをONにします。終わったら、```Apply```をクリックします。

![コメント 2019-10-26 185344.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/2ac6de94-d58f-09ef-1ee8-17d35781545c.png)

これでwebhookを使える状態なので、ノードで実行するアクションを設定します。```city```が入力されたら実行するので、ParametersのKEYには```call_city```と入力し、Valueには入力されたテキストを変数に格納したいので、```<? input.text ?>```とタグを埋め込むことで変数に格納します。下の```Return variable```にはwebhookの実行結果を格納する変数名を定義します。この場合は```webhook_result_1```です。

![コメント 2019-10-26 185004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/d47fb7a1-d46d-ca9b-ba3e-ec4105e0dc28.png)


更に下にスクロールすることで、結果に対してどんな返答をするのかを設定します。今回の場合は、```webhook_result_1```が取得出来たら、その結果を返答します。今回作成したアクションの返り値は```{ 'condition': translation["translations"][0]["translation"] }```となっているのでこのconditionを取り出すために、返答では```$webhook_result_1.condition```としています。この時、引用する変数と文字列の間は必ず半角スペースで開けてください。

![コメント 2019-10-26 190616.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/f9cb6bc5-a7a7-0fb0-58ce-a165456d28ad.png)

#完成
これで完成です。あとはAssistantの```Try it```をクリックして、テストチャットで都市名を入力してみてください、ちゃんと指定された都市の天気が返答されたら成功です。
![コメント 2019-10-26 193231.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/20d6911c-d4f6-0a0a-0e68-4d88166964dd.png)