#はじめに
Hangouts Chat が一般公開されて1か月と少し経ちました。
一般公開されてからこれまで、GAE + DialogFlow
、Amazon API Gateway + AWS Lambda + DialogFlow
、といった組み合わせで、いくつか Hangouts Chat
向けのチャットボットを実装し、社内向けに公開してきました。
そういう訳で、備忘も兼ねて Hangouts Chat BOT
の実装手順をまとめていきたいと思います。
尚、今回は入門的な内容となっていますので、これから Hangouts Chat BOT
を開発したい方の一助となれば幸いです。
#BOT実装の流れ
GAEへの Hangouts Chat BOT
実装は、次の手順で進めます。
- GCPにプロジェクトを作成
- ローカルマシンに
Python on GAE
開発環境を準備 - Python Flask Skeletonのダウンロード ~ ローカルテスト
- BOTアプリの準備 ~ ローカルテスト
- BOTアプリをGAEにデプロイ ~ 動作テスト
- Hangouts Chat API の有効化、ボット設定 ~ 動作テスト
#実装環境
- Python on Google App Engine スタンダード環境
- BOTのWebフレームワークには
Flask
を利用 - HTTPエンドポイントなBOTで、リクエストに対し同期応答
GCPにプロジェクトを作成
初めてGCPにアカウントを作成した場合、新しいプロジェクトを作成します。
また既存のプロジェクトを利用するなら、この手順は省略できます。
尚、プロジェクト作成手順の詳細は割愛します。
#ローカルマシンに Python on GAE 開発環境を準備
##ローカル環境
- OS は
CentOS7
-
pyenv
とpyenv-virtualenv
によるPython開発環境がセットアップ済
##Google Cloud SDKのインストール
このページを参考に、次の手順で Google Cloud SDK
と Python 関連の追加コンポーネント
をインストールします。
###YUMリポジトリの追加
$ sudo tee -a /etc/yum.repos.d/google-cloud-sdk.repo << EOM
[google-cloud-sdk]
name=Google Cloud SDK
baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOM
###Google Cloud SDK、追加コンポーネントのインストール
$ sudo yum install google-cloud-sdk google-cloud-sdk-app-engine-python google-cloud-sdk-app-engine-python-extras
###Google Cloud SDKの初期設定
前述のページを参考に、Google Cloud SDK の初期設定を行います。
$ gcloud init
##Python Flask Skeleton for Google App Engine
GitHub リポジトリ で公開されている Google App Engine 向け Python Flask スケルトン
をローカル環境の任意のディレクトリ(今回は ~/projects/chatbot
)にダウンロードします。
$ git clone https://github.com/GoogleCloudPlatform/appengine-flask-skeleton.git ~/projects/chatbot
##pyenv+virtualenvで仮想環境準備
チャットボットを開発するディレクトリ下で Python2.7 最新版が利用出来るよう、Python 仮想環境を準備します。
$ pyenv virtualenv 2.7.14 chatbot
$ cd ~/projects/chatbot
$ pyenv local chatbot
$ python -V
Python 2.7.14
##Flaskと依存モジュールのアップデート
前述でダウンロードした Google App Engine 向け Python Flask スケルトン
には、予め Flask と依存モジュールが同梱(./lib
ディレクトリ内)されていますが、次のコマンドで最新バージョンにアップデートします。
$ pip install -U -r requirements.txt -t lib
##ローカル動作テスト
次のコマンドでローカル開発サーバ(dev_appserver.py)を起動します。
$ dev_appserver.py .
別ターミナルを起動し、localhost の 8080 ポートにアクセスします。
問題が無ければ、レスポンスで Hello World!
文字列が返されます。
$ curl http://localhost:8080
Hello World!
#チャットボット準備
Google App Engine 向け Python Flask スケルトン
の環境を利用し、簡単なチャットボットを実装します。
尚、今回はボットに話しかけた内容が、そのままボットから返される やまびこ
ボットとなります。
##ボットのPythonコード
Hangouts Chat | Google Developers
ページ内の Creating new bots にあるPythonサンプルコードを、bot.py
というファイル名で保存します。
尚、コード2行目には、念のため coding: utf-8
を追記しています。
$ 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__)
@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']
else:
return
return json.jsonify({'text': text})
if __name__ == '__main__':
app.run(port=8080, debug=True)
##デプロイ設定ファイル(app.yaml)の変更
追加した bot.py
が全てのHTTPリクエストのルートとなるよう、app.yaml内のハンドラ設定を変更します。
$ vi app.yaml
- url: .* # This regex directs all routes to main.app
script: main.app
↓↓↓変更
- url: .* # This regex directs all routes to main.app
script: bot.app
#チャットボットのローカル動作テスト
##テストデータの準備
このページにあるイベントフォーマットの例を元に、テスト用のリクエストデータ event.json
を準備します。
$ vi event.json
###ADDED_TO_SPACEイベントのテストデータ
イベントタイプが ADDED_TO_SPACE
のイベントは、チャットルームにBOTを追加した際、ボットに送信されます。
{
"type": "ADDED_TO_SPACE",
"eventTime": "2017-03-02T19:02:59.910959Z",
"space": {
"name": "spaces/AAAAAAAAAAA",
"displayName": "Chuck Norris Discussion Room",
"type": "ROOM"
},
"user": {
"name": "users/12345678901234567890",
"displayName": "Chuck Norris",
"avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg",
"email": "chuck@example.com"
}
}
###MESSAGEイベントのテストデータ
イベントタイプが MESSAGE
のイベントは、ボット宛にテキストメッセージが送信されます。
{
"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": "@TestBot Violence is my last option.",
"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 .
別コンソールを開き、テストデータ event.json
をボットにPOSTします。
$ curl http://localhost:8080 -X POST -H "Content-Type: application/json" -d @event.json
ADDED_TO_SPACE
イベントをPOSTした場合、ボットから次のレスポンスが返されます。
{
"text": "Thanks for adding me to \"Chuck Norris Discussion Room\"!"
}
MESSAGE
イベントをPOSTした場合、ボットから次のレスポンスが返されます。
{
"text": "You said: `@TestBot Violence is my last option.`"
}
#ボットアプリをGAEにデプロイ
##サービスIDの変更(必要に応じて)
プロジェクト上で、既にGAEをサービスID default
として利用している場合、誤って default
サービスにデプロイしないよう、別のサービスIDを設定します。今回、新しく作成したプロジェクトにデプロイする場合は、この手順は省略できます。
ちなみにサービスIDを設定しない場合、サービスIDはdefault
が暗黙的に設定され、ターゲットURLは https://<プロジェクトID>.appspot.com
となります。
またサービスIDを設定した場合は、ターゲットURLは https://<サービスID>-dot-<プロジェクトID>.appspot.com
となります。
$ vi app.yaml
service
を追記
service: chatbot
##GAEへデプロイ
gcloud
コマンドでボットをGAEにデプロイします。
途中デプロイ先のリージョンを問われるので、任意のリージョンを指定する必要があります。
$ gcloud app deploy
・・・
[1] europe-west2 (supports standard and flexible)
[2] us-east1 (supports standard and flexible)
[3] us-east4 (supports standard and flexible)
[4] asia-northeast1 (supports standard and flexible)
[5] asia-south1 (supports standard and flexible)
[6] australia-southeast1 (supports standard and flexible)
[7] southamerica-east1 (supports standard and flexible)
[8] northamerica-northeast1 (supports standard and flexible)
[9] us-central (supports standard and flexible)
[10] europe-west3 (supports standard and flexible)
[11] europe-west (supports standard and flexible)
[12] cancel
Please enter your numeric choice: 4
・・・
descriptor: [/path/to/projects/chatbot/app.yaml]
source: [/path/to/projects/chatbot]
target project: [<Project-ID>]
target service: [default]
target version: [20180410t123456]
target url: [https://<Project-ID>.appspot.com]
Do you want to continue (Y/n)? y
・・・
##操作テスト
ローカル動作テストと同様に、テスト用リクエストデータをGAEのターゲットURLにPOSTして動作を確認します。
$ curl https://<Project-ID>.appspot.com -X POST -H "Content-Type: application/json" -d @event.json
{
"text": "You said: `@TestBot Violence is my last option.`"
}
以上の手順で、GAEにボットを実装できました。
#Hangouts Chat API の設定
##Hangouts Chat API の有効化
GCPコンソールから、API とサービス
> ダッシュボード
を開き、API とサービスの有効化
をクリックします。
検索欄に Hangouts
を入力すると Hangouts Chat API
が表示されるので、それをクリックします。
##BOTの設定
API 有効化後、Hangouts Chat APIの概要ページに遷移するので、設定タブをクリックし、ボットに関する設定を入力します。
項目 | 説明 |
---|---|
ボット名 | Hangout Chat 上でのボットの表示名 |
アバターのURL | Hangout Chat 上で、ボットのアイコンとなる画像URL |
説明 | ボットの役割、機能等の説明文 |
機能 | ボット宛のダイレクトメッセージ送信、ボットのチャットルーム内利用を有効、無効化 |
接続設定 |
Bot URL を選択し、GAEのターゲットURLを指定 |
確認トークン | Hangouts Chatからボット宛のリクエストイベントデータに付加されるトークン。ボット側のアプリでこのトークンをチェックすることで、セキュリティを向上できる。 |
権限 | Hangouts Chatでのボットの利用権限。ボットを利用できるドメインユーザーの範囲を指定 |
#Hangouts Chat 上で動作テスト
##ボットにダイレクトメッセージを送信
Hangouts Chat の左上にある ユーザー、チャットルーム、bot を検索
からボット名を入力すると、今回作成したボットが表示されるので、そのボットをクリックします。
何かメッセージを送信すると、BOTから You said: (送信したメッセージ)
が返ってきます。
##チャットルームからボット宛にメッセージ送信
ボットを追加したいチャットルームを開き、上部にある <チャットルーム名>
> ユーザーと bot を追加
をクリックします。
検索欄にボット名を入力し、表示されたボットをクリックします。
チャットルームに追加された旨のメッセージがボットから返されます。
あとはボット宛とわかるメンション(@ボット名)を付けてメッセージを送信します。
#次回
今回の内容により、GAE への Hangouts Chat BOT 実装の雰囲気を掴んでもらえたと思いますので、次回は Google DialogFlow を利用し、もう少し「ボットらしい」モノの実装方法を投稿したいと思います。