Hangouts Chat のチャットボットを、Python on Google App Engineを使って実装してみた(1)

はじめに

Hangouts Chat が一般公開されて1か月と少し経ちました。
一般公開されてからこれまで、GAE + DialogFlowAmazon API Gateway + AWS Lambda + DialogFlow、といった組み合わせで、いくつか Hangouts Chat 向けのチャットボットを実装し、社内向けに公開してきました。
そういう訳で、備忘も兼ねて Hangouts Chat BOT の実装手順をまとめていきたいと思います。
尚、今回は入門的な内容となっていますので、これから Hangouts Chat BOT を開発したい方の一助となれば幸いです。

BOT実装の流れ

GAEへの Hangouts Chat BOT 実装は、次の手順で進めます。

  1. GCPにプロジェクトを作成
  2. ローカルマシンに Python on GAE 開発環境を準備
  3. Python Flask Skeletonのダウンロード ~ ローカルテスト
  4. BOTアプリの準備 ~ ローカルテスト
  5. BOTアプリをGAEにデプロイ ~ 動作テスト
  6. Hangouts Chat API の有効化、ボット設定 ~ 動作テスト

実装環境

  • Python on Google App Engine スタンダード環境
  • BOTのWebフレームワークには Flask を利用
  • HTTPエンドポイントなBOTで、リクエストに対し同期応答

GCPにプロジェクトを作成

初めてGCPにアカウントを作成した場合、新しいプロジェクトを作成します。
また既存のプロジェクトを利用するなら、この手順は省略できます。
尚、プロジェクト作成手順の詳細は割愛します。

ローカルマシンに Python on GAE 開発環境を準備

ローカル環境

  • OS は CentOS7
  • pyenvpyenv-virtualenv によるPython開発環境がセットアップ済

Google Cloud SDKのインストール

このページを参考に、次の手順で Google Cloud SDKPython 関連の追加コンポーネント をインストールします。

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
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
app.yaml
- url: .*  # This regex directs all routes to main.app
  script: main.app

↓↓↓変更

app.yaml
- url: .*  # This regex directs all routes to main.app
  script: bot.app

チャットボットのローカル動作テスト

テストデータの準備

このページにあるイベントフォーマットの例を元に、テスト用のリクエストデータ event.json を準備します。

$ vi event.json

ADDED_TO_SPACEイベントのテストデータ

イベントタイプが ADDED_TO_SPACEのイベントは、チャットルームにBOTを追加した際、ボットに送信されます。

event.json
{
  "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のイベントは、ボット宛にテキストメッセージが送信されます。

event.json
{
  "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 を追記

app.yaml
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 とサービスの有効化 をクリックします。
screencapture-console-cloud-google-apis-dashboard-2018-04-10-16_21_30.png

検索欄に Hangouts を入力すると Hangouts Chat API が表示されるので、それをクリックします。
screencapture-console-cloud-google-apis-library-2018-04-10-16_22_32.png

有効にする をクリックします。
screencapture-console-cloud-google-apis-library-chat-googleapis-com-2018-04-10-16_22_52.png

BOTの設定

API 有効化後、Hangouts Chat APIの概要ページに遷移するので、設定タブをクリックし、ボットに関する設定を入力します。

screencapture-console-cloud-google-apis-api-chat-googleapis-com-hangouts-chat-2018-04-10-16_32_37.png

項目 説明
ボット名 Hangout Chat 上でのボットの表示名
アバターのURL Hangout Chat 上で、ボットのアイコンとなる画像URL
説明 ボットの役割、機能等の説明文
機能 ボット宛のダイレクトメッセージ送信、ボットのチャットルーム内利用を有効、無効化
接続設定 Bot URLを選択し、GAEのターゲットURLを指定
確認トークン Hangouts Chatからボット宛のリクエストイベントデータに付加されるトークン。ボット側のアプリでこのトークンをチェックすることで、セキュリティを向上できる。
権限 Hangouts Chatでのボットの利用権限。ボットを利用できるドメインユーザーの範囲を指定

Hangouts Chat 上で動作テスト

ボットにダイレクトメッセージを送信

Hangouts Chat の左上にある ユーザー、チャットルーム、bot を検索からボット名を入力すると、今回作成したボットが表示されるので、そのボットをクリックします。
2018-04-10_16h34_19.png

何かメッセージを送信すると、BOTから You said: (送信したメッセージ)が返ってきます。
screencapture-chat-google-dm-jNN4pAAAAAE-2018-04-10-16_36_02.png

チャットルームからボット宛にメッセージ送信

ボットを追加したいチャットルームを開き、上部にある <チャットルーム名> > ユーザーと bot を追加 をクリックします。
2018-04-10_16h37_20.png

検索欄にボット名を入力し、表示されたボットをクリックします。
screencapture-chat-google-room-AAAAgZEsEWA-2018-04-10-16_37_57.png

チャットルームに追加された旨のメッセージがボットから返されます。
あとはボット宛とわかるメンション(@ボット名)を付けてメッセージを送信します。
screencapture-chat-google-room-AAAAgZEsEWA-2018-04-10-16_39_08.png

次回

今回の内容により、GAE への Hangouts Chat BOT 実装の雰囲気を掴んでもらえたと思いますので、次回は Google DialogFlow を利用し、もう少し「ボットらしい」モノの実装方法を投稿したいと思います。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.