API.AIを試す

Slackのbotなどを作るときに、API.AIを使うと面白いか便利かもねという話を聞いたので試しています。

api.ai

API.AIってどういうものか

API.AIの概要は公式ドキュメントの説明がわかりやすいのでそちらを読むのをオススメします。

Introduction · API.AI

自分が思った要点はこのあたり:

  • 自然言語のテキスト入力を解析、パラメータに変換して外部のWebhookに流せる
    • 日本語にも対応している
    • 定型文で返すのならWebhookに流さなくてもできる感じ
  • SlackなどとのインテグレーションはAPI.AI側でやってくれる
  • Webhookでは簡単なJSONレスポンスを返すことで、api.ai側からインテグレーション先への応答を返してくれる
    • 音声読み上げとの連携もしやすい
  • 解析、変換の部分は機械学習エンジンが入っていて、学習データを与えてモデルを構築できる
  • 各種プログラミング言語、プラットフォーム向けのSDKが提供されている

音声入力からのテキスト変換もapi.aiがやってたみたいですが、Deprecatedになってて、今はOSの機能か外部サービスを使うのを推奨しているみたいです。

自分の理解ではSlack、API.AI、webhookの関係を図にするとこんな感じ。ドキュメントのほうにも図があるので、そちらも参照されたし。

f:id:nullpobug:20170606121048p:plain

2016年にGoogleに買収されて、GCPとの連携が強化されていってるのかな。現状、利用は無料。

試してみる

とりあえず、Slackからの発言をfulfillmentサービスのwebhookで受け取って、レスポンスを返すというのを試してみることにします。

今回は、Contextは使わず単純な文章の加工だけをやってみます。

この記事以外のサンプルコードだと、Webhookのドキュメントにあるものも参考にするとよさそう。

GitHub - api-ai/apiai-weather-webhook-sample

エージェントを登録する

左メニューのエージェント名が表示される部分のドロップダウンから「Create new agent」をクリックしてエージェント作成画面を表示。

エージェント名の入力と言語を日本語にしてSAVE。 f:id:nullpobug:20170606202324p:plain

エンティティを登録する

エンティティは、ユーザー入力から得られる値の定義です。

左メニューのENTITIESのところにある「+」ボタンをクリックしてエンティティの追加画面を表示。 f:id:nullpobug:20170606202331p:plain エンティティ名をfood、値を「お好み焼き」「たこ焼き」で入力してSAVE。 f:id:nullpobug:20170606202335p:plain ここで定義するもの以外にシステム定義のものや自由入力も扱えます。

インテントを登録する

インテントは、ユーザー発言をどのように変換、取り扱うかのルールの定義です。

左メニューのINTENTのところにある「+」ボタンをクリックしてインテントの追加画面を表示。 f:id:nullpobug:20170606205037p:plain UserSaysに「大阪でたこ焼き食べます」と入力してEnterキーを押すと、エンティティが認識されます。今回の場合、「大阪」の部分は @sys.geo-city 、「たこ焼き」の部分は作成しておいたエンティティの @food と判定されました。

f:id:nullpobug:20170606205038p:plain

@sys.geo-cityは組み込みのエンティティです。一覧はドキュメントに記載があります。

Entities · API.AI

SAVEボタンをクリックして保存します。

右ペインの「Try it now」のテキストボックスに、「東京でたこ焼きを食べます」と入力してパラメータの変換を試すと、geo-cityは「東京」、foodは「たこ焼き」として認識されました。 f:id:nullpobug:20170606205039p:plain

「SHOW JSON」ボタンをクリックすると、後述するfulfillmentサービスで外部に送信されるJSONを確認できます。 f:id:nullpobug:20170606205040p:plain

Webhook用のサーバーを用意する

今回はインテントで変換したパラメータをWebhookで処理します。

Webhook用のWebサーバーとしてPythonとFlaskで簡単なレスポンスを返すものを用意しました。Pythonのバージョンは3.6です。

main.py:

from flask import Flask, request, jsonify

app = Flask(__name__)


@app.route("/", methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)
    resp = jsonify(process_request(req))
    return resp


def process_request(request_data):
    if "result" not in request_data:
        return {}
    food = request_data['result']['parameters']['food']
    city = request_data['result']['parameters']['geo-city']
    message = "場所: {}, 食べ物: {}".format(city, food)
    return {
            "data": {"slack": {"text": message}},
        }


if __name__ == "__main__":
    app.run()

パラメータで受け取った内容から定型文を生成して返すぐらいのものです。

起動はpythonコマンドにソースコードのファイルを指定します。

$ python main.py

起動すると、localhost:5000でlistenされます。

fulfillmentサービスを設定する

fulfillmentは外部サービスなどでレスポンスを返す機能です。先程用意したWebhookでレスポンスを返すように設定します。

webhookはapi.ai側から通信できる必要があります。どこかにデプロイしてもいいのですが、お試しなのでngrokを使いました。

ngrokコマンドが使える状態で、次のコマンドを実行すると、localhost:5000にngrok経由で外部からアクセスできるようになります。

$ ngrok http 5000

fulfillmentのWebhookにURLを設定してSAVEしておきます。

f:id:nullpobug:20170606205035p:plain

また、インテントの編集画面の下部に「Use Webhook」というチェックボックスがあるので、チェックしてSAVEしておきます。

f:id:nullpobug:20170606205041p:plain

Slackのインテグレーションを設定する

Slackのbotとして動かすため、左メニューの「Integrations」からSlackのインテグレーションをONにします。

Slackへの接続ダイアログが表示されるので、任意のスラックグループを選びます。個人用のSlackを作って試すことをオススメします。

f:id:nullpobug:20170606205036p:plain

Slackのインテグレーションを有効にすると、Slack側にはapiai_botというアカウントが現れます。

動作確認

Slackでテスト用に追加されたapiai_botにDMで話しかけてみます。

正常動作していれば、botから応答があります。

f:id:nullpobug:20170606205043p:plain

与えた文章から得たパラメータで応答されることを確認できました。

感想

自然言語処理の部分を作り込むのは結構面倒なものですが、API.AIが肩代わりしてくれるのはうれしいですね。

API.AIのコンソールのUIがわかりづらい(どこがクリックできるのか、入力できるのかなど見た目でわからない、ラベルがない入力エリアなど)のですが、今後改善されることに期待したいです。

学習部分の調整は大変そうですが、いろいろ試していきたいです。