Messaging API(LINE)とCOTOHA API(NTT Com)を利用したBotアプリ(Python)をHerokuにデプロイする

はじめに

今年のゴールデンウィーク改元もあり10日間の大型連休だった。

平成から令和という節目を迎え、例年とはちょっと違い、年越しのような心持ちになった。

かねてから興味があったことにチャレンジするには良い機会になるよなぁ、ってことで始めてみた。

記事のタイトルはなかなか立派な感じがするが、今回やったことは、もうすでに多くの方がやりつくしていることの寄せ集め。

大切なのは手を動かして、自分なりのアウトプットをすることだと思っているので、あくまでもマイペース。  

目次

Botアプリの概要

友達登録したチャンネル上でLINEでメッセージ(文章)を送ると、原始人がカタコトの日本語で返事をしてくれるというもの。

返事といっても会話のキャッチボールが成立するわけではなく、こちらが送った文章をそのまま「原始人コトバ」に変換して送り返すだけのいわゆるエコーアプリである。

f:id:pachiquli:20190512161928p:plain
完成版のスクリーンショット
 

非IT(SEとかプログラマとかではない職業)の友人にお披露目してみたものの、何がおもしろいのか、何がすごいのか理解できないらしく反応はイマイチだった(まぁ当然だよね)。

やはり便利なものでないとウケない(会話が盛り上がらない)のはちょっと寂しい。

 

Botアプリを構成するもの

言語

API

  • Messaging API(LINE)
    • LINEのメッセージ受信、応答に使用
  • COTOHA API(NTT Com)
    • 日本語の構文解析、変換に使用
    • メッセージを「原始人コトバ」に変換するBotアプリの核となるもの

サーバー

  • Heroku
    • Botアプリをデプロイ先となる無料で使えるクラウドサーバー

Botアプリ開発の前提条件

※ツールのインストールやアカウント作成方法については割愛

開発マシンのOS

今回はWindows10環境で作成。

ツール

以下のツールをインストールする必要がある。

アカウント作成

以下のアカウント(無料)を作成する必要がある。

Botアプリのソースコード

ファイル構成

フォルダ名称は任意でOK。今回はline-bot-genshijinという名称で作成。

直下に必要なファイルをすべて配置する。

line-bot-genshijin
 ├ main.py
 ├ genshijin.py
 ├ Procfile
 ├ requirements.txt
 └ runtime.txt

 

main.py
LINE Messaging API を利用するための認証、APIの呼び出し、別モジュールに切り分けた「原始人コトバ」変換処理の呼び出しを行っている。

import os
import sys
import json
import requests

import genshijin as gj

from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)

from linebot.exceptions import (
    InvalidSignatureError
)

from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)

app = Flask(__name__)

# LINE Token
channel_secret = os.getenv('LINE_CHANNEL_SECRET', None)
channel_access_token = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', None)
if channel_secret is None:
    print('Specify LINE_CHANNEL_SECRET as environment variable.')
    sys.exit(1)
if channel_access_token is None:
    print('Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.')
    sys.exit(1)

line_bot_api = LineBotApi(channel_access_token)
handler = WebhookHandler(channel_secret)


@app.route("/callback", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']

    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)


    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'


@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):

    # ゲンシジン語に翻訳
    result = gj.translate(event.message.text)

    # LINE APIによる応答メッセージ送信
    line_bot_api.reply_message(
    event.reply_token,
    TextSendMessage(text=result)
    )

if __name__ == "__main__":
    port = int(os.getenv("PORT", 8000))
    app.run(host="0.0.0.0", port=port)

 

genshijin.py
「原始人コトバ」変換処理の本体。LINEチャンネルに送信されたメッセージを受け取り、変換後の文字列をリターンする。COTOHA API を利用するための認証、APIの呼び出しはここで行っている。

import os
import json
import requests

# cotoha Token
BASE_URL = "https://api.ce-cotoha.com/api/dev/nlp/"
client_id = os.getenv('COTOHA_CLIENT_ID', None)
client_secret = os.getenv('COTOHA_CLIENT_SECRET', None)
if client_id is None:
    print('Specify COTOHA_CLIENT_ID as environment variable.')
    sys.exit(1)
if client_secret is None:
    print('Specify COTOHA_CLIENT_SECRET as environment variable.')
    sys.exit(1)


def translate(document):
    def auth(client_id, client_secret):
        token_url = "https://api.ce-cotoha.com/v1/oauth/accesstokens"
        headers = {
            "Content-Type": "application/json",
            "charset": "UTF-8"
        }

        data = {
            "grantType": "client_credentials",
            "clientId": client_id,
            "clientSecret": client_secret
        }
        r = requests.post(token_url,
                        headers=headers,
                        data=json.dumps(data))
        return r.json()["access_token"]

    def parse(sentence, access_token):
        base_url = BASE_URL
        headers = {
            "Content-Type": "application/json",
            "charset": "UTF-8",
            "Authorization": "Bearer {}".format(access_token)
        }
        data = {
            "sentence": sentence,
            "type": "default"
        }
        r = requests.post(base_url + "v1/parse",
                        headers=headers,
                        data=json.dumps(data))
        return r.json()

    access_token = auth(client_id, client_secret)
    parse_document = parse(document, access_token)
    result_list = list()
    for chunks in parse_document['result']:
        for token in chunks["tokens"]:
            if token["pos"] != "格助詞" and token["pos"] != "連用助詞" and token["pos"] != "引用助詞" and token["pos"] != "終助詞":
                result_list.append(token["kana"])

    return ' '.join(result_list)

 

Procfile
Heroku用の設定ファイル。一番最初に起動させるプログラムは何かをHerokuに教えてあげるためのもの。

web: python main.py

 

requirements.txt
今回のPythonソースコードで利用しているライブラリを定義する。バージョンは記載しなくても動くが、仕事としての開発環境であればきちんと書くべきだと思う。

Flask==0.12.2
line-bot-sdk==1.5.0
requests

 

runtime.txt
Herokuで実行したいPythonのバージョンを指定する。
(Heroku用の設定ファイル?きちんと理解していないのだが、PythonフレームワークであるDjangoを利用する場合は必要かもしれないが、今回使用するFlaskフレームワークではなくて良いかもしれない…)

python-3.6.6

 

BotアプリをHerokuにデプロイ

Herokuアプリケーションの新規作成

まずは用意したソースコード一式を格納したフォルダに移動する。

cd line-bot-genshijin

 

Git管理するためにローカルリポジトリを作成する。

git init

 

Herokuに新規アプリケーション(サーバー)を作成する。aqueous-dusk-45716という名称でアプリケーションが作成されたことがコマンドの実行結果からわかる。このタイミングでリモートリポジトリも作成される。

heroku create

Creating app... done, ⬢ aqueous-dusk-45716

 

リモートリポジトリが作成されたことの確認。名称はherokuに関連付けられたことがわかる。

git remote -v

heroku  https://git.heroku.com/aqueous-dusk-45716.git (fetch)
heroku  https://git.heroku.com/aqueous-dusk-45716.git (push)

 

ここでHerokuダッシュボードを確認してみる。aqueous-dusk-45716という名称のアプリケーションが存在しているのがわかる。

f:id:pachiquli:20190508010339j:plain
Herokuアプリケーションの一覧

 

Herokuサーバーの環境変数定義

ついでなのでサーバー環境変数を定義しておく。

LINEやCOTOHAのAPIを利用するために必要な認証用情報はLINE Developersのダッシュボード、COTOHA APIダッシュボードでそれぞれ発行できるが、Pythonソースコードに直接記入するのはスマートではない。

今回はそういった認証用の情報はサーバー環境変数に定義する。

 

アプリケーション内の Settingsタブ - Config Vars の Reveal Config Varsボタンを押下すると、隠されていた環境変数一覧が表示される(初期の段階は何も定義なし)。

f:id:pachiquli:20190508011449j:plain
Heroku サーバー環境変数
 

変数名と値を入力し、Addボタンを押下。

f:id:pachiquli:20190508011337j:plain
Heroku サーバー環境変数の追加
 

定義したサーバー環境変数は以下のようにPythonコードから取得できる。os.getenv()の第一引数はHerokuサーバーの環境変数で定義した変数名と一致させる必要がある。

main.py(抜粋)

channel_secret = os.getenv('LINE_CHANNEL_SECRET', None)
channel_access_token = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', None)

genshijin.py(抜粋)

client_id = os.getenv('COTOHA_CLIENT_ID', None)
client_secret = os.getenv('COTOHA_CLIENT_SECRET', None)

 

正しく設定できたか確認(値は伏字にしている)。

heroku config

=== line-genshijin Config Vars
COTOHA_CLIENT_ID:          xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
COTOHA_CLIENT_SECRET:      xxxxxxxxxxxxxxxxx
LINE_CHANNEL_ACCESS_TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx…xxxxx
LINE_CHANNEL_SECRET:       xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

 

Herokuのアプリケーション名を任意の名称に変更

heroku createコマンドで作成されるアプリケーションの名称はランダムに設定される。

動作には全く問題ないのだが、せっかく作るならば好きな名称にしたほうが愛着がわくし、アプリケーションが複数になると、どれに何をデプロイしたのかわからなくなってくる。

今回はランダムに設定されたアプリケーションの名称(aqueous-dusk-45716)をline-genshijinに変更する。

 

アプリケーション内の Settingsタブ - Nameの名称を変更するだけ。ただし、画面のWarningメッセージに表示されている通り、Gitのリモートリポジトリ名を変更する必要がある。

f:id:pachiquli:20190508015658j:plain
Heroku アプリケーション名変更

 

やり方についてはWarningメッセージ内のリンク先に記載された内容と全く同じ手順を行えばよい。

 

  • 名称herokuは旧アプリケーション名(aqueous-dusk-45716)のリモートリポジトリに関連付けられていのでいったん削除。
  • 名称herokuにリモートリポジトリとして新アプリケーション名line-genshijinを関連付ける。
git remote rm heroku
heroku git:remote -a line-genshijin

 

リモートリポジトリと関連付けられた名称が更新されていることの確認。

git remote -v

heroku  https://git.heroku.com/line-genshijin.git (fetch)
heroku  https://git.heroku.com/line-genshijin.git (push)

 

Herokuへデプロイ

ローカルリポジトリへadd、commit、そしてリモートリポジトリへpush。pushすると自動でデプロイされる。

git add .
git commit -m "first commit"
git push heroku master

 

HerokuのDyno(プロセスのようなもの)が起動しているか確認。1つのDynoが動作しているようだ。

heroku ps:scale web=1

Scaling dynos... done, now running web at 1:Free

 

LINE DevelopersでWebhook設定

LINE Developersのダッシュボードで事前に作成しておいたMessaging APIのチャンネルでHerokuにデプロイしたBotアプリとの関連付けを行う。

メッセージ送受信設定

ここでは以下の設定を行う。

  • Webhook送信
    • [利用する]に設定する。
  • Webhook URL
    • https://{HEROKU_APP_NAME}.herokuapp.com/callback」の形式で入力する。
    • {HEROKU_APP_NAME}」の箇所は、デプロイ済みのHerokuアプリケーション名称。
    • 今回のケースだと「https://line-genshijin.herokuapp.com/callback」となる。
      f:id:pachiquli:20190508202148j:plain
      LINE Developers メッセージ送信設定

 

Webhook URLについては設定後確認できる。接続確認ボタンを押下するとエラーメッセージが表示されるが問題はない。

f:id:pachiquli:20190508203810j:plain
接続確認エラー(問題ない)

 

LINE Developersのデフォルト設定だと自動応答メッセージも一緒に送信されてしまうので「利用しない」に変更する。

f:id:pachiquli:20190508210253j:plain
自動応答メッセージは「利用しない」
 

ここまでで、今回のBotアプリは完成となる。

 

最後に作成したチャンネルをトモダチ登録。

LINE Developersダッシュボードの チャンネル基本設定タブ > 基本情報 > 変更はこちらリンク からLINE Official Account Managerダッシュボードを開く。

f:id:pachiquli:20190508213740j:plain
LINE Official Account Managerダッシュボードを開く

 

LINE Official Account Managerダッシュボードの ホーム > 友だち追加 で表示されるURLにアクセスするとチャンネルが追加できる。

f:id:pachiquli:20190508213020j:plain
友だち追加

 

その他の設定

アプリアイコンや友達追加時のあいさつメッセージを設定すればオリジナリティのあるチャンネルに仕上がる。

LINE Developersダッシュボードからいろいろとカスタムできるのでお好みであれこれ試してみると良い。

 

おわりに

はじめて技術系の記事を書いたがとても時間がかかり苦労した。ちょっと気合を入れて細かく書きすぎたような気がする。

しかし、自分自身分からないことが多い中でインターネットで調べてみても肝心なところが記載されていなくて理解できないことが多かったので、なるべくわからない人目線で書くように心がけた次第である。

技術系の内容にかかわらず、世の中、毎日のように記事を書いている人がいらっしゃるが、改めてすごいなぁと感じた。

これに懲りずに今後もアウトプットしていくようにがんばろうと思う。

 

参考にさせて頂いた記事

一人じゃ完成させることはできなかった…。

先人の方々が残された情報はとても勉強になった。感謝します。

【参考】