#はじめに
前回のやまびこBOT を DialogFlow と連携させて、より「BOTらしい」アプリケーションを実装してみたいと思います。
#DialogFlow の準備
今回はこちらの投稿にある例(前半「Intentを作る」まで)に倣って、DialogFlow 側のテスト環境を準備しました。
尚、DialogFlow の詳しい設定方法等は、紹介した投稿内で丁寧に説明されていますので、ここでは割愛します。
#DialogFlow Python SDK のインストール
DialogFlow Python SDK をインストールします。
$ pip install apiai -t lib
尚、Python on GAE では、C言語で開発されたモジュールをアップロードしても利用することが出来ない(仮にアップロードしても動かない)為、GAE側で用意された組み込みサードパーティ ライブラリを使う必要があります。
そこで、DialogFlow Python SDK
をインストールした際、依存関係でインストールされた numpy
がC言語で開発されている為、これをディレクトリごと削除し、Python仮想環境へ numpy
をインストールし直します。
また、インストールする numpy
のバージョンは GAE 組み込みモジュールのバージョンに合わせます。
$ rm -rf lib/numpy*
$ pip install numpy==1.6.1
app.yaml
に GAE の組み込みモジュール numpy
を利用する設定を追加します。
$ cat <<EOF >>app.yaml
libraries:
- name: numpy
version: "1.6.1"
EOF
#DialogFlow のアクセストークンを取得
DialogFlow を API 経由で利用する場合、Client access token
が必要なため、次の手順でアクセストークンを取得します。
DialogFlow コンソールを開き、エージェント名の右側に表示されている歯車マークをクリックします。
表示されたページに Client access token
が表示されます。
#アクセストークンを環境変数として設定
app.yaml
内にアクセストークンを環境変数として設定することもできますが、トークンはその性質上秘匿したい情報にあたり、GitHub に誤ってコミットされないよう別ファイルに定義します。
秘匿したい環境変数を定義する secret.yaml
を作成し、アクセストークンを記述します。
$ cat <<EOF >secure.yaml
env_variables:
CLIENT_ACCESS_TOKEN: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
EOF
app.yaml
に、secret.yaml
をインクルードする設定を追加します。
$ cat <<EOF >>app.yaml
includes:
- secret.yaml
EOF
.gitignore
へ secret.yaml
を追加します。
$ cat <<EOF >>.gitignore
secret.yaml
EOF
#BOTアプリケーションの変更
Hangouts Chat からのリクエストメッセージを DialogFlow に渡し、DialogFlow からのレスポンスメッセージを Hangouts Chat へ返すよう、前回作成した bot.py
を変更します。
$ vi bot.py
#!/usr/bin/env python
# coding: utf-8
"""Example bot that returns a synchronous response."""
from flask import Flask, request, json
app = Flask(__name__)
import os
import re
from apiai import ApiAI
from uuid import uuid4
@app.route('/', methods=['POST'])
def on_event():
"""Handles an event from Hangouts Chat."""
event = request.get_json()
if event['type'] == 'ADDED_TO_SPACE' and event['space']['type'] == 'ROOM':
text = 'Thanks for adding me to "%s"!' % event['space']['displayName']
elif event['type'] == 'MESSAGE':
''' 元のコードをコメントアウト
text = 'You said: `%s`' % event['message']['text']
'''
''' 追加(ここから) '''
ai = ApiAI(os.environ['CLIENT_ACCESS_TOKEN'])
req = ai.text_request() #リクエストはテキストデータ
req.lang = 'ja' #リクエストメッセージは日本語(ja)
req.session_id = str(uuid4()) #DialogFlow間のセッションIDをランダムなUUID型でセット
req.query = re.sub(r'^@.* ', '', event['message']['text']) #メッセージからメンション("@ボット名 ")を削除
res = req.getresponse() #DialogFlowへリクエスト、レスポンスを取得
dic = json.loads(res.read()) #レスポンスボディを辞書型に変換
text = dic['result']['fulfillment']['speech'] #レスポンスボディからテキストメッセージを取得
''' 追加(ここまで) '''
else:
return
return json.jsonify({'text': text})
if __name__ == '__main__':
app.run(port=8080, debug=True)
#ローカルテスト
テストデータ(event.json
)のメッセージ部分(['message']['text'])を、DialogFlow にリクエストする日本語メッセージ(@Demo 1日の東京を予約
等)へ変更します。
{
"type": "MESSAGE",
"eventTime": "2017-03-02T19:02:59.910959Z",
"space": {
"name": "spaces/AAAAAAAAAAA",
"displayName": "Chuck Norris Discussion Room",
"type": "ROOM"
},
"message": {
"name": "spaces/AAAAAAAAAAA/messages/CCCCCCCCCCC",
"sender": {
"name": "users/12345678901234567890",
"displayName": "Chuck Norris",
"avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg",
"email": "chuck@example.com"
},
"createTime": "2017-03-02T19:02:59.910959Z",
"text": "@Demo 1日の東京を予約",
"thread": {
"name": "spaces/AAAAAAAAAAA/threads/BBBBBBBBBBB"
},
"annotations": [
{
"length": 8,
"startIndex": 0,
"userMention": {
"type": "MENTION",
"user": {
"avatarUrl": "https://.../avatar.png",
"displayName": "TestBot",
"name": "users/1234567890987654321",
"type": "BOT"
}
},
"type": "USER_MENTION"
}
]
},
"user": {
"name": "users/12345678901234567890",
"displayName": "Chuck Norris",
"avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg",
"email": "chuck@example.com"
}
}
ローカル開発サーバを起動します。
$ dev_appserver.py .
別ターミナルから、BOTへテストデータをリクエストしてみます。
$ curl http://localhost:8080 -X POST H "Content-Type: application/json" -d @event.json
{
"text": "2018-05-01 \u306e \u6771\u4eac\u30bf\u30a6\u30f3\u30db\u30c6\u30eb \u3092\u4e88\u7d04\u3057\u307e\u3057\u305f\u3002"
}
上記のようにレスポンスメッセージにマルチバイト文字が含まれていると、マルチバイト文字が Unicode にエンコードされて表示されます。
そういう場合は、レスポンスを jq
にパイプすることで Unicode がデコードされて正しく表示されます。
もし jq
がインストールされていない場合は、EPEL からインストールしましょう。(インストール方法は割愛します)
$ curl http://localhost:8080 -X POST H "Content-Type: application/json" -d @event.json | jq
{
"text": "2018-05-01 の 東京タウンホテル を予約しました。"
}
#BOTアプリケーションのデプロイ
ローカルテストで問題がなければ、BOTアプリケーションを GAE へデプロイします。
$ gcloud app deploy
#Hangouts Chat からテスト
Hangouts Chat から BOT にメッセージを送り、動作を確認します。
BOTへダイレクトメッセージを送ると、次のようなレスポンスが返ってくると思います。
#次回
Hangouts Chat ではテキストメッセージの他に、カードメッセージ
と呼ばれる、より複雑なフォマットのメッセージをサポートしています。
次回は、そのカードメッセージを BOT に実装してみたいと思います。