Flask で開発する LINE ChatBot
LINE Chatbot 開発を行ったときのメモです.LINE Developers の管理画面から作成することもできますが,今回は Messaging API を利用して開発します.基本的には公式の LINE Documentation が情報豊富ですが,自分で開発したときの流れを備忘録として残していきます.
前提
- LINE アカウントは持っているものとする
- LINE Developers の開発者登録も済んでいるものとする
- LINE Developers では Providers まで作成済みとする
- バックエンドは Python のフレームワーク Flask を利用
- GitHub の使い方には触れない
- Heroku へのデプロイ方法の記述は最小限にする
開発環境
- Macbook : macOS Monterey (12.3.1)
- Python : 3.10.0
- Flask : 2.1.2
- line-bot-sdk : 2.2.1
1. Messaging API
LINE の ChatBot を作成するためには LINE Developers のコンソールから Messaging API の設定をします.やはり公式ドキュメント(MessagingAPI)が一番わかりやすいです.
- LINE Developers の管理画面にアクセスする
- Providers からアカウントを選択
- Channels で
Create Messaging API channel
を選択 - アプリの名前やアイコンなど必要な設定を入れていく
- アカウントの Channels に作成した Bot が追加されていれば OK
- Channel を作成すると「LINE Official Account」にもアカウントが作成されている
2. Flask アプリの作成
次に LINE Bot からのリクエストを受けるバックエンド側の API を作成します.任意の場所にプロジェクトルートとなるディレクトリを作成します.今回は chatbot-backend
という名前です.構成は以下のようになっています.
chatbot-backend
L app.js
L Procfile
L README.md
L requirements.txt
L runtime.txt
-
pip install flask
で Flask をインストール
2.1. Flask の動作確認
はじめに Flask の動作確認から行います.
-
app.py
を編集して最小構成の- Flask も公式ドキュメントを基本とします
from flask import Flask
# generate instance
app = Flask(__name__)
# endpoint
@app.route("/")
def test():
return "<h1>It Works!</h1>"
- プロジェクトルートから
app.py
のあるapp
ディレクトリへ移動する -
flask run
でローカルに Web サーバを起動 - ブラウザから
localhost (127.0.0.1:5000)
にアクセス - 画面に
IT Works!
と表示されれば OK
2.2. Heroku へのデプロイ
つぎに Heroku へのデプロイを行います.パブリックな API として正常に動作することを確認した後に LINE ChatBot とのつなぎこみを行います.作成したプロジェクト (chatbot-backend
) は GitHub のリモートリポジトリに push
しておいてください.
Heroku の準備
- Heroku のアカウント登録を行う
-
Create new app
でアプリを作成する -
ドキュメントを参考に
Heroku CLI
をインストールする - プロジェクトルートで
Heroku login
-
heroku git:remote -a app-name
でローカルとリモートを接続
Flask デプロイの準備
-
pip freeze > requirements.txt
で Flask で利用するパッケージを書き込む- 必要ないものも入ってしまうことがあるので手で記述
- とりあえず以下のものが記述されていれば OK
Flask==2.1.2
Jinja2==3.1.2
gunicorn==20.1.0
line-bot-sdk==2.2.1
-
Procfile
の編集- Heroku は Web を動かすためのコマンドを記述する Procfile がないとうごかない
- プロジェクトルートに配置する
web: gunicorn app:app --log-file=-
-
runtime.txt
の編集
python-3.10.0
- runtime に指定できるバージョンは決まっているので注意が必要 (ここでは最新)
デプロイ
- Git コマンドでデプロイする
git push heroku main
- Heroku の管理画面の「Deploy」から GitHub のリポジトリと接続することで GitHub への push と同時に Heroku へデプロイする設定が入れられます (楽です)
- Web アプリとしての設定を入れる
heroku ps:scale web=1
- アプリケーションを開く
heroku open
- ブラウザが開いて "It Works!" が表示されれば OK
ここまでで API のデプロイまでが完了しました.あとは LINE Bot 側から API を叩くようにつなぎこみができれば完成です.
3. LINE ChatBot と API を繋ぐ
LINE の ChatBot 側から今デプロイした API を叩きチャットボットとしての機能を完結させます.
3.1. Webhook の設定
- LINE Developers コンソールでチャンネルアクセストークンを発行しておく
- 発行したトークンを環境変数として Heroku にセットする
heroku config:set ACCESS_TOKEN="アクセストークン" --app アプリ名
heroku config:set CHANNEL_SECRET="チャンネルシークレット" --app アプリ名
- LINE Developers のコンソールから Messaging API の設定を行う
- 「あいさつメッセージ」と「応答メッセージ」の設定は「無効」にする
- Webhook URL を設定する
- Heroku にデプロイしたときに払い出された URL を指定する
https://hoge.herokuapp.com/callback
-
callback
を追加するようにする
これで Webhook の設定は完了ですが,まだ app.py
のソースコードを書き換えていないので「検証」はうまくいきません.次で Flask のソースコードを書き換えます.
3.2. app.py にエンドポイントを追加する
公式ドキュメントの「Heroku でサンプルボットを作成する」のページに line-bot-sdk-python のリポジトリへのリンクがあるので,ここの README を参考に Flask にソースコードを追加します.ただしコピペではうまく行かなかったので適宜変更をしていく必要があります.
-
app.py
を以下のように編集します- 以下のコードは 2.1 節で作成した
app.py
にline-bot-sdk-python
のサンプルコードを追加した完成形です
- 以下のコードは 2.1 節で作成した
from flask import Flask
from flask import request
import os
from linebot import (LineBotApi, WebhookHandler)
from linebot.exceptions import (InvalidSignatureError)
from linebot.models import (MessageEvent, TextMessage, TextSendMessage,)
# generate instance
app = Flask(__name__)
# get environmental value from heroku
ACCESS_TOKEN = os.environ["ACCESS_TOKEN"]
CHANNEL_SECRET = os.environ["CHANNEL_SECRET"]
line_bot_api = LineBotApi(ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)
# endpoint
@app.route("/")
def test():
return "<h1>It Works!</h1>"
# endpoint from linebot
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
# handle message from LINE
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=event.message.text))
if __name__ == "__main__":
app.run()
- サンプルコードと違う点として以下のような処理を追加しています
- Heroku にセットした環境変数を取ってくる処理を追加
-
import os
も忘れずに
-
- Messaging API からの「検証」で POST のリクエストをさばくために Flask の
request
というモジュールが必要なので追加from flask import request
- これがないと request が undefined 的なエラーで怒られました
- Heroku にセットした環境変数を取ってくる処理を追加
- LINE Developers コンソールの Messaging API 設定タブの「検証」を行い,「成功」と表示されればつなぎ込みは完了!!
3.3. オウム返し
ChatBot 開発における Hello, World 的な定番機能であるオウム返しを試します.app.py
の @handler.add
の部分がメッセージイベントの処理部分です.特に修正しなくてもこのままでオウム返しができます.
ユーザからのメッセージは event
の中に含まれます.event
は json
形式のデータになっており以下のようなデータで構成されています.
{
"message": {
"id": "xxxxx",
"text": "sample",
"type": "text"
},
"mode": "active",
"replyToken": "xxxxxxxxxx",
"source": {
"type": "user",
"userId": "xxxxxxxxxxxxxxx"
},
"timestamp": 1655090322382,
"type": "message"
}
event.message.text
がユーザが送信してきたメッセージなので app.py
の TextSendMessage()
でそのまま指定することでオウム返しができるようになっています.
4. ChatBot としての機能を実装する
ここまでで,ChatBot の本体である API と Messaging API をつないで動かすことに成功しました.ここからはようやく ChatBot としての機能を実装していきます.今回はサンプルなので機械学習などは使わずルールベースで返答を返していきます.
4.1. 追加機能の実装準備
追加の機能を直接 app.py
に書いてしまうとコードが読みづらいので,役割分担してプロジェクトルートに src
フォルダを作成し,Python のモジュールとして実装して app.py
から呼び出すようにします.フォルダ構成は以下のようになっています.
chatbot-backend
L app.js
L Procfile
L README.md
L requirements.txt
L runtime.txt
L src
L dict
L mydict.py
L services
L handle_message_service.py
src
以下は自作の単語辞書を格納する dict
というフォルダと,ボットとしての機能を格納していく services
というフォルダを作成します.
4.2. 単語辞書の作成
まずは特定の単語が来たらなにか返答をしてほしいのでその辞書を手作りします.ボットとしてはあまりいい方法ではないですが,今回はお試しということでこのような方法をとります.
-
dict
以下にmydict.json
を作成する -
mydict.json
の中身は以下のようにする- テスト用なので登録するセリフは適当でよいです
{
"test": "ChatBot Works!",
"sample": "Hi, I am sample ChatBot!",
"hello": "Hello, World!",
"おはよう": "おはようございます!コーヒーでもどうですか?",
"こんにちは": "こんにちは!お昼は何をたべましたか?",
"こんばんは": "こんばんは、いい夜をお過ごしください。",
"except": "すみません、よくわかりませんでした。"
}
これで辞書の準備は OK です.
4.3. メッセージの処理
特定のメッセージに反応して返信を行う機能を作ります.
-
src/services
以下にhandle_message_service.py
というファイルを作る -
handle_message_service.py
を次のようにする
import json
class handle_message_service :
def generate_reply_message(receivedMessage) :
json_file = open('/app/src/dict/mydict.json', 'r')
mydict = json.load(json_file)
for key in mydict :
if (receivedMessage == key) :
return mydict[key]
return mydict['except']
この handle_message_service.py
はユーザが送信したメッセージを処理するためのプログラムです.今回は json で作成した辞書を読み込んでそれを json のキーと照らし合わせて一致した値を返すようにしています.
4.4. app.py を書き換える
最後に app.py
から handle_message_service.py
を呼び出すように書き換えます.app.py
の中身を以下のようにします.
- 作成した
handle_message_service.py
をモジュールとして読み込むため import 文にfrom src.services.handle_message_service import *
を追加 -
@handler.add
の処理を以下のように書き換える
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
# メッセージ生成用のモジュール呼び出し
reply = handle_message_service.generate_reply_message(event.message.text)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=reply))
こうすることで今後ユーザから送信されてきたメッセージの処理を書き換える際に app.py
を処理する必要はなくなり hanndle_message_service.py
だけを修正すればいいだけにしています.全体像としては以下のようになります.
from flask import Flask
from flask import request
import os
from linebot import (LineBotApi, WebhookHandler)
from linebot.exceptions import (InvalidSignatureError)
from linebot.models import (MessageEvent, TextMessage, TextSendMessage,)
from src.services.handle_message_service import * # 追加した行
# generate instance
app = Flask(__name__)
# get environmental value from heroku
ACCESS_TOKEN = os.environ["ACCESS_TOKEN"]
CHANNEL_SECRET = os.environ["CHANNEL_SECRET"]
line_bot_api = LineBotApi(ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)
# endpoint
@app.route("/")
def test():
return "<h1>It Works!</h1>"
# endpoint from linebot
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
# handle message from LINE
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
# メッセージ処理のモジュール呼び出し
reply = handle_message_service.generate_reply_message(event.message.text)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=reply))
if __name__ == "__main__":
app.run()
これで今回作ったサンプルのチャットボットのプログラムは完成です.Heroku にデプロイして動かしてみます.
きちんと返ってきているので成功です!
まとめ
LINE のチャットボット開発系の情報はググればたくさん出てきますが,自分で開発したときのフローをメモとして残しました.今回はすべて決め打ちで返事を返すだけの,チャットボットと言えるか怪しいプログラムですが,ここまで形ができていればあとは中身を書き換えていけばいいだけなので開発に集中できます.今後は機械学習のライブラリの導入などを行ってチャットボットっぽくしていきたいと思います.
Discussion