PythonによるLINE Botローカル開発環境構築(Docker,ngrok)
LINE Messaging APIを使用したLINE Botの実装をPythonで行っています。
本番環境はFaas(Cloud Functions)かHerokuあたりを利用予定です。
開発生産性を考えると、本番環境にデプロイする前にローカルで動作確認できるようにし、アジリティ高く開発したいですよね。
また、Pythonは自分の経験上ローカルへのインストールの罠が多いため、Docker環境を利用します。
そこで本記事では、PythonによるLINE Botローカル開発環境構築の解説をします。
準備
LINE Bot開発における下記の基本的な準備を終えていることを前提とします。
- LINE Messaging APIに対応したチャネルを用意していること
- 新しく作成したチャネルに友だち登録をしていること
- チャネルシークレット, チャネルアクセストークンを把握していること
-
Messaging API設定 -> Webhook設定
の Webhookの利用がオンになっていること -
LINE Official Account Manager → 応答設定 → 応答機能
のチャットが恩になっていること - こちらの設定のみ、LINE DevelopersではなくLINE Official Account Managerから行うため注意が必要です
補足) 設定関連のスクリーンショット
設定関連はLINE Developersで行うのがおすすめです。LINE Official Account Managerでは一部の設定ができないため注意が必要です。
詳しい進め方は下記が参考になります。
ファイル
概要
ファイル構成は下記のとおりで、.env, .gitignore, Dockerfile, compose.yaml, main.py, requirements.txtについて記します。
$ tree -a -L 1
.
├── .env
├── .env.sample
├── .git
├── .gitignore
├── Dockerfile
├── README.md
├── compose.yaml
├── main.py
└── requirements.txt
2 directories, 8 files
main.py
基本は、line-bot-sdk-pythonのUsageを流用しています。
唯一の追加箇所にして一番の肝は、ngrokを使用していることです。
PublicなURLを発行してローカルホストへフォワード(プロキシ)しています。
ENV=dev
の時のみngrokを起動しています。
import os
from flask import Flask, request, abort
from linebot.v3 import (
WebhookHandler
)
from linebot.v3.exceptions import (
InvalidSignatureError
)
from linebot.v3.messaging import (
Configuration,
ApiClient,
MessagingApi,
ReplyMessageRequest,
TextMessage
)
from linebot.v3.webhooks import (
MessageEvent,
TextMessageContent
)
app = Flask(__name__)
configuration = Configuration(access_token=os.getenv('LINE_CHANNEL_ACCESS_TOKEN'))
handler = WebhookHandler(os.getenv('LINE_CHANNEL_SECRET'))
@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:
app.logger.info("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):
with ApiClient(configuration) as api_client:
line_bot_api = MessagingApi(api_client)
line_bot_api.reply_message_with_http_info(
ReplyMessageRequest(
reply_token=event.reply_token,
messages=[TextMessage(text=event.message.text)]
)
)
def forward():
import ngrok
listener = ngrok.forward(8888, authtoken_from_env=True)
print(f"Ingress established at {listener.url()}")
if __name__ == "__main__":
if os.getenv('ENV') == 'dev':
forward()
app.run(port=8888)
.env
NGROK_AUTHTOKEN には、ngrokのSign upによって生成されたトークンを記載します。
NGROK_AUTHTOKEN=
LINE_CHANNEL_SECRET=
LINE_CHANNEL_ACCESS_TOKEN=
.gitignore
git commitしないよう気をつけましょう。
.env
Dockerfile, compose.yaml
# Dockerfile
FROM python:3.12
RUN apt-get update -y && \
apt install -y wget make
RUN pip install --upgrade pip
WORKDIR /app
COPY ./ ./
RUN pip install --requirement requirements.txt
EXPOSE 8888
# compose.yaml
version: "3"
services:
python:
build:
context: .
volumes:
- ./:/app
ports:
- "8888:8888"
command: python main.py
environment:
ENV: "dev"
NGROK_AUTHTOKEN: "${NGROK_AUTHTOKEN}"
LINE_CHANNEL_SECRET: "${LINE_CHANNEL_SECRET}"
LINE_CHANNEL_ACCESS_TOKEN: "${LINE_CHANNEL_ACCESS_TOKEN}"
サーバー起動〜動作確認
サーバー起動
ビルドしてから、
docker compose build
起動します。
$ docker compose up
WARN[0000] Found orphan containers ([llm-linebot-ngrok-1]) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
[+] Running 1/0
✔ Container llm-linebot-python-1 Created 0.0s
Attaching to llm-linebot-python-1
llm-linebot-python-1 | * Tip: There are .env or .flaskenv files present. Do "pip install python-dotenv" to use them.
llm-linebot-python-1 | Ingress established at https://bd9b-114-186-50-114.ngrok-free.app
llm-linebot-python-1 | * Serving Flask app 'main'
llm-linebot-python-1 | * Debug mode: off
llm-linebot-python-1 | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
llm-linebot-python-1 | * Running on http://127.0.0.1:8888
llm-linebot-python-1 | Press CTRL+C to quit
llm-linebot-python-1 | 127.0.0.1 - - [25/Dec/2023 03:04:16] "POST /callback HTTP/1.1" 200 -
https://bd9b-114-186-50-114.ngrok-free.app
PublicなURLが発行されましたね。
このURLを次のステップで使います。
Webhook URLに登録する
LINEのコンソールから Webhook URL に登録します。
Pythonのflaskサーバーは /callback
で待ち受けているため、上記のngrokによって発行されたURL `https://bd9b-114-186-50-114.ngrok-free.app` +`/callback` を記載します。
動作確認
最後に動作確認をしましょう。
友だち登録したBotに何かしらメッセージを送信します。
同じメッセージが帰ってきたら成功です!
デバッグ
「このアカウントでは個別のお問い合わせを受け付けておりません。」と応答される
動作確認の際に、メッセージを送信すると、下記のメッセージがBotから返信されることがあります。
メッセージありがとうございます!
申し訳ありませんが、このアカウントでは個別のお問い合わせを受け付けておりません。
次の配信までお待ちください(moon smile)
これは自動応答メッセージがオンになっているのが原因です。下記を参考に、応答メッセージをオフにすることで解決します。
既読マークはつくが返信が来ない
サーバー起動〜動作確認の手順をもう一度試してみてください。
ngrokは起動の都度URLが変わるため、Webhook URLへの登録も再度行う必要があります。
Discussion