はじめに
タイトルにある通り Python + Flask + ngrok + LINE Messaging API で簡単なタイマー機能を持つ LINE-bot を作成してみました。
短時間で作成することができるので興味がある方は気軽にチャレンジしてみてください。
環境
- macOS Catalina 10.15.5
- Homebrew 2.4.9
- Python 3.8.3
- pip 20.2.1
手順
① LINE Developers - チャネルの作成
- LINE Developers にてお手持ちのLINEアカウント等でログイン
- プロバイダー作成を選択し任意の名称を入力
- チャネル設定にて Messaging API を選択
- 各項目を入力(以下、必須項目)
- チャネルの種類 : Messaging API
- プロバイダー : 先ほど入力したプロバイダー名
- チャネル名 : LINEアプリ内表示名
- チャネル説明 : 簡単な機能説明や作成者名等
- 大業種 : e.g. 個人
- 小業種 : e.g. 学生
- 利用規約に同意して作成
- チャネルの登録が完了したら下記の2点をメモしておきます。
- Messaging API 設定 -> チャネルアクセストークン(空欄の場合は発行)
- チャネル基本設定 -> チャネルシークレット
② 仮想環境の構築
今回はvenv
を用いて、Workspace
というディレクトリにlineVenv
という名前で仮想環境を構築していきます。
% mkdir Workspace
% cd Workspace
% python3 -m venv lineVenv
下記コマンドを実行後、ターミナルの行の先頭に(lineVenv)
との表記があれば成功です。
% . lineVenv/bin/active
続いてpip
を用いて、Flask
とLINE Messaging API SDK for Python
をインストールしていきます。
必要なパッケージは下記コマンドでインストールすることができます。
% pip3 install flask
% pip3 install line-bot-sdk
以上で仮想環境の構築は終了です。
③ bot プログラムの実装
さて、先ほどインストールした LINE Messaging API for SDK の GitHub 内のREADME.rst
を参考にしながらタイマー機能を持つ bot プログラムを実装していきます。
先ほどのディレクトリにapp.py
を作成し、以下のように記述します。
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
from time import time
from datetime import timedelta
app = Flask(__name__)
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN') #チャネルアクセストークン
handler = WebhookHandler('YOUR_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:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
user = {}
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
id = event.source.user_id #LINEのユーザーIDの取得
if event.message.text == "start":
if not id in user: #新規ユーザーの場合
user[id] = {}
user[id]["total"] = 0
user[id]["start"] = time() #start実行時の時間を取得
totalTimeStr = timedelta(seconds = user[id]["total"]) #s -> h:m:s
reply_message = f"Start Timer\n\nTotal: {totalTimeStr}"
elif event.message.text == "stop":
end = time() #end実行時の時間を取得
dif = int(end - user[id]["start"]) #経過時間を取得
user[id]["total"] += dif #総時間を更新
timeStr = timedelta(seconds = dif)
totalTimeStr = timedelta(seconds = user[id]["total"])
reply_message = f"Stop Timer\n\nTime: {timeStr}s\nTotal: {totalTimeStr}"
elif event.message.text == "reset":
user[id]["total"] = 0 #総時間を0にリセット
totalTimeStr = timedelta(seconds = user[id]["total"])
reply_message = f"Reset Timer\n\nTotal: {totalTimeStr}"
else:
reply_message = "Please send \"start\" or \"stop\"or \"reset\"" #指定外の3語に対する応答
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=reply_message))
if __name__ == "__main__":
app.run()
これで完成のように見えますが、あと2点下記の箇所を変更を加える箇所があります。
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN') #チャネルアクセストークン
handler = WebhookHandler('YOUR_CHANNEL_SECRET') #チャネルシークレット
ここで必要になるのが①でメモしたチャネルアクセストークンとチャネルシークレットです。
YOUR_CHANNEL_ACCESS_TOKEN
とYOUR_CHANNEL_SECRET
にそれぞれコピペしてください。
⑤ 実行
さて、いよいよ実行に移ります。
先ほどの仮想環境でflask run
と実行すると以下のように表示されます。
% flask run
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
http://127.0.0.1:5000
というアドレスがありますが、localhostなのでLAN外からアクセスすることができません。
(つまりLINEのサーバーからアクセスすることができず、Webhookを利用できないという状態)
デプロイしてしまうという手もありますが、他の方法を探していたところngrok
というツールが便利そうでした。
ngrokの利用方法 https://qiita.com/hirokisoccer/items/7033c1bb9c85bf6789bd
ということでflask run
を実行しているターミナルとは別のターミナルを開いて、以下のコマンドでインストールします。
% brew install ngrok
ngrok公式サイトから実行ファイルをダウンロードすることもできます。
インストール完了後ngrok http 5000
と実行すると以下のように表示されます。
% ngrok http 5000
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Session Expires 7 hours, 59 minutes
Version 2.3.35
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://xxxxxxxxxxxx.ngrok.io -> http://localhost:5000
Forwarding https://xxxxxxxxxxxx.ngrok.io -> http://localhost:5000
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
これでhttps://xxxxxxxxxxxx.ngrok.io
というパブリックなURLを介してhttp://127.0.0.1:5000
にアクセスすることができるようになりました。
⑥ LINE Developers - Webhook 設定 ・ 応答設定
Webhook 用の URL を取得することができたので LINE Developers に戻ります。
Messaging API 設定 -> Webhook 設定 の以下の2点を変更します。
- Webhook URL :
https://xxxxxxxxxxxx.ngrok.io
- Webhook の利用 : 有効
LINE 公式アカウント機能の以下の2点を変更します。
- グループ・複数人チャットへの参加を許可する : 無効
- 応答メッセージ : 無効
以上ですべての手順が終了です。
テスト
下記より LINE の友達追加を行い、プログラム内で指定したリクエストを送ってみます。
Messaging API 設定 -> QRコード / ボットのベーシックID
こちら は本記事内容を再現した bot です。(デプロイ済み)
参考までにどうぞ。
おまけ
今回作成した LINE-bot のデプロイに Heroku(無料版)は不向きでした。
Heroku では公開ポート番号が一定ではない為、リクエストが複数回でひとまとまりといった処理は安定しません。
無料で安定させるという条件では PythonAnywhere だと上手くいきました。
参考サイト
LINE Developers - Documents - Messaging API
LINE Messaging API SDK for Python
ngrokの利用方法