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を使います。こちらから会員登録します。登録するとホーム画面にAPI keysタブがあるので、クリックしてAPIキーを取得します。このAPIは英語のAPIなので日本語で来る都市名を英語に変換する必要があります。そこで、今度はIBM CloudのLanguage Translatorを使って翻訳をしたいと思います。IBM Cloudのダッシュボード画面の「リソースの作成」から「Language Translator」を選択してリソースを作成します。作成出来たら、「Manage」タブをクリックしそこに書かれているAPIキーをコピーします。二つのAPIキーをメモ出来たら、Functionsでアクションを作成していきます。

アクションの作成

続いてIBM Cloud Functionsでアクションを作成していきます。こちらを参考にして、初期設定を完了させましょう。その後、Codeタブをクリックして、はじめから書かれていたコードを消して、以下のコードに書き換えてください。


#
#
# 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で設定した都市の天気が出力されたら正常に動いています

URLの生成

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

Watson Assistantの設定

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

Skillの設定をします。Nameは何でもOKですが、Languageは日本語で設定します。設定が終わったら、Create dialog skillをクリックして完了させます。

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

webhookを使うための準備

今度はWatson Assistantとwebhookの接続設定をします。Options タブを選択して、Webhooksを開きます。そのURLの欄に先程生成したWebhookのURLを記入します。URLを記入する際には、URLの最後に.jsonを入れるようにしてください。拡張子を指定することで、Web アクションの機能を利用して、希望する応答のコンテンツ・タイプを指定できます。Web Actionで設定しているので、Headersには特に値を設定する必要はありません。

フローの作成

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

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

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

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

完成

これで完成です。あとはAssistantのTry itをクリックして、テストチャットで都市名を入力してみてください、ちゃんと指定された都市の天気が返答されたら成功です。