LoginSignup
3
2

[無料][2024年版] LINE Messaging API v3 + Python(Flask) でボットを作る [その2 - テストアプリ編]

Last updated at Posted at 2024-01-05

まずは最終目標

では準備も終わったところで、具体的なボットの中身に入っていきたいと思います。本格的なチャットボットの類は当然 ChatGPT などを使った方が良いので、分野限定的な(ニッチな)情報検索ツールとしてのボットを作ることにします。

今回は、ビートルズの楽曲情報を引き出すためのツールを作ろうかと思います。私がスクレイピングなどでまとめたデータはこちらのレポジトリにありますので、よければご自由にお使いください。

搭載予定機能は以下のようになります

・楽曲名からYouTube動画の検索
・楽曲名から歌詞の取得
・楽曲名から演奏動画や楽譜の検索
・楽曲名から曲情報の検索
・アルバム名から楽曲一覧の取得
・歌詞の単語から楽曲検索
・その他おまけ機能

などです。何回に分けて、少しずつ機能を増やしていきたいと思います。

また、あくまでこれは私の例です。私のコードを参考に、勝手にアレンジしてお好みのボットを作ってみて下さい。

ちなみにまだまだ現在進行形ですが、作成したボットはこちらになります。ぜひ友達登録して使ってみて下さい。

LINE BOT ID : @711mvjit

711mvjit.png

テストアプリの作成

各機能の具体的なプログラムは順次実装するとして、まずはLINEボットが動く状態にしなければなりません。テストプログラムで動作の確認をします。今回は Flask を使うので、以下のようなディレクトリ構成にします。

linebot/
 ├ venv/  ## 仮想環境
 ├ .env  ## チャンネルトークンなどの記載
 ├ data/  ## そのうちデータを入れる
 ├ templates/  ## そのうちウェブサイトを作る
 ├ requirements.txt  ## ライブラリ一覧
 ├ .gitignore  ## GitHub用
 └ app.py  ## メインプログラム

LINE messaging API では、ユーザーがボットに対して行った動作はWebhookイベントとして受信します。イベントには以下のようなものがあります。

おそらくよく使うのはこの3つでしょう

  • フォローイベント : ユーザーがボットを友達追加(or ブロック解除)した場合に受け取る Webhook
  • メッセージイベント : テキスト、動画、スタンプなど何らかの「メッセージ」をユーザーがボットに送信した場合に受け取る Webhook
  • ポストバックイベント : ボタン・画像を押す、クイックリプライを選択するなどの動作を行ったときに受け取る Webhook

このうち、フォローイベントとメッセージイベントを使った、以下のようなテストプログラムを作ります

  1. 友達追加した際に、"Thank You!" と送るe
  2. メッセージを送った際に、その内容をユーザーネームと共にオウム返しする

それでは具体的に app.py を編集していきます。コードは、公式SDKのGitHubページから大半をコピペします。

インポート部分

Flask, linebot, os をインポートします。仮想環境の構築とライブラリのインストールが済んでいない方は前回の記事を参考にして下さい。

app.py
# -*- coding: utf-8 -*-
from flask import Flask, request, abort
from linebot.v3 import WebhookHandler
from linebot.v3.exceptions import InvalidSignatureError
from linebot.v3.messaging import (
	ApiClient, Configuration, MessagingApi,
	ReplyMessageRequest, PushMessageRequest,
	TextMessage, PostbackAction
)
from linebot.v3.webhooks import (
	FollowEvent, MessageEvent, PostbackEvent, TextMessageContent
)
import os

環境変数部分

LINE Developer アカウントで発行した2つのトークンをプログラムに渡す必要がありますが、直接コード内に書くのはオススメできません。環境変数として .env ファイルから別途読み込む形式が基本です。詳しくはこちらなどを参考にして下さい。その際に、仮想環境内で python-dotenv のインストールが必要になります。

(venv) linebot $ pip install python-dotenv

その上で、.env ファイルにチャンネルシークレットと、チャンネルアクセストークンを以下のように記載します。LINE Developers の「チャネル基本設定」「Messaging API設定」の項目からそれぞれ確認できます

.env
CHANNEL_ACCESS_TOKEN=4KJ......
CHANNEL_SECRET=549......

ここまで準備できたら、app.py 内でこれらの値を読み込み、以下のように割り当てます。

app.py
## .env ファイル読み込み
from dotenv import load_dotenv
load_dotenv()

## 環境変数を変数に割り当て
CHANNEL_ACCESS_TOKEN = os.environ["CHANNEL_ACCESS_TOKEN"]
CHANNEL_SECRET = os.environ["CHANNEL_SECRET"]

また、.env を GitHub に間違ってアップしてしまわないよう、.gitignore ファイルに書きこんでおくのも忘れないで下さい。私は Mac なので、.DS_Store などを除外するためによくこう書きます。

.gitignore
**/.DS_Store  ## 不要な管理ファイルの除外
**/__pycache__  ## キャッシュファイルの除外
.env  ## 環境変数ファイル
venv  ## 仮想環境

おまじない部分

大半をサンプルコードからコピペして使います。Flask アプリの作成と、コールバックでの認証等に関するものです。

app.py
## Flask アプリのインスタンス化
app = Flask(__name__)

## LINE のアクセストークン読み込み
configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(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'

イベントハンドラ部分

ここからメインプログラムになります。テストアプリに実装する機能を再掲します。

  1. 友達追加した際に、"Thank You!" と送る
  2. メッセージを送った際に、その内容をユーザーネームと共にオウム返しする
1. 友達追加時のメッセージ

フォローイベントを受信した時の処理をします。関数名は handle_follow() 以外にしても構いません。messages の部分は、リストにするのを忘れないで下さい。

app.py
## 友達追加時のメッセージ送信
@handler.add(FollowEvent)
def handle_follow(event):
	## APIインスタンス化
	with ApiClient(configuration) as api_client:
		line_bot_api = MessagingApi(api_client)

	## 返信
	line_bot_api.reply_message(ReplyMessageRequest(
		replyToken=event.reply_token,
		messages=[TextMessage(text='Thank You!')]
	))

ちなみに、友達追加時のメッセージ (Greeting message) は LINE Official Account Manager でも設定できてしまうので、動作確認のためにそちらはオフにしておきましょう。友達追加して、何もメッセージが送られてこないことを確認して下さい。

Screenshot 2024-01-05 at 20.06.12.png

2. オウム返しメッセージ

これは公式のサンプルコードほぼそのままですが、せっかくなので一工夫加えます。Webhook の情報には UserID はあるものの、ユーザーネームはわかりません。これを取得するために、APIを呼びます。

また、handler.add の部分で TextMessageContent を指定することで、「テキストメッセージの時のみ反応する」ようにします。これを指定しないと、動画やスタンプなどあらゆるメッセージで反応するようになります。

app.py
## オウム返しメッセージ
@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):
	## APIインスタンス化
	with ApiClient(configuration) as api_client:
		line_bot_api = MessagingApi(api_client)

	## 受信メッセージの中身を取得
	received_message = event.message.text

	## APIを呼んで送信者のプロフィール取得
	profile = line_bot_api.get_profile(event.source.user_id)
	display_name = profile.display_name

	## 返信メッセージ編集
	reply = f'{display_name}さんのメッセージ\n{received_message}'

	## オウム返し
	line_bot_api.reply_message(ReplyMessageRequest(
		replyToken=event.reply_token,
		messages=[TextMessage(text=reply)]
	))

プログラム起動部分

最後に、プログラムを起動するコードを付け加えます。ポート番号は 8000 にしていますが、これは他の数字でも構いません。コードを起動してアプリケーションサーバーを立ち上げるのに私は gunicorn というものを使うので、そのデフォルトポートであるこの数字を使っています。

app.py
## ボット起動コード
if __name__ == "__main__":
	## ローカルでテストする時のために、`debug=True` にしておく
	app.run(host="0.0.0.0", port=8000, debug=True)

起動確認用ウェブページ

ここまででLINEボットとしてのコードは十分なのですが、デプロイが完了してアプリが起動しているかどうかの確認ページも作っておきます。Flask はウェブ作成をするのためのツールでもありますので、そのルーティング機能で簡単に実装できます。先ほどの if __name__... の上にこれを追加します

app.py
## 起動確認用ウェブサイトのトップページ
@app.route('/', methods=['GET'])
def toppage():
	return 'Hello world!'

デプロイが完了した後、Render で発行されたURLにジャンプして、"Hello world!" が表示されていればきちんと起動しているということになります。

ここまでの app.py のコードは、最下部に全てまとめてありますので使って下さい。

デプロイ準備

Flask 単体でもアプリケーションサーバー立ち上げは可能なのですが、テスト用の簡易的なものなのでここはやはり gunicorn などを使うことをおすすめします。ということで、これもインストールしてしまいましょう。

(venv) linebot $ pip install gunicorn

これらインストールしたライブラリのリストは、requirements.txt として書き出しておく必要があります。これがないと、デプロイする時にどのライブラリをインストールすればいいかわからないからです。以下のコマンドを実行します。

(venv) linebot $ pip freeze > requirements.txt

書き出しが成功すると、以下のようになライブラリとバージョンが指定されたファイルができているはずです。

requirements.txt
aenum==3.1.15
aiohttp==3.9.1
...
Flask==3.0.0
...
gunicorn==21.2.0
...
line-bot-sdk==3.7.0
...
python-dotenv==1.0.0
...

ここに、Flask, gunicorn, line-bot-sdk, python-dotenv の4つがきちんとあることを確認して下さい。バージョンは同じでなくとも構いません(上記は Python3.11.6、pip23.3.1 の場合です)。もしなければ、仮想環境が有効化されていることを確認した上で $ pip install line-bot-sdk flask python-dotenv gunicorn しましょう。

ここまでで、ディレクトリ・ファイル構成は以下のようになっているはずです。

linebot/
 ├ venv/
 ├ .env
 ├ requirements.txt
 ├ .gitignore
 └ app.py

そして、この app.pyrequirements.txt を GitHub にアップします。くれぐれも .env はアップしないようにして下さい。.gitignore がきちんと書かれているか確認して下さい。

Render にデプロイ

前回の準備編でアカウントを作ってあれば、"New Web Service" から新しくアプリを作ります。

Screenshot 2024-01-05 at 21.53.51.png

GitHub の linebot レポジトリと連携します。リストにない場合は、右側の "Configure Account" からレポジトリを追加します。

Screenshot 2024-01-05 at 21.57.16.png

ボットの名前を設定します。Region は一番近い Singapore にしていますが、多分どこでもそこまで変わらないはずです。

Screenshot 2024-01-05 at 21.59.20.png

起動時のコマンドを設定します。

  • gunicorn をインストールしている
  • ファイル名が app.py で、Flask のインスタンス名が app

ならいじる必要はありません。

次の Instance Type ですが、今回のテーマは [無料] なので、当然 Free を選択します。

Screenshot 2024-01-05 at 22.06.22.png

最後の Environment Variables の項目に、.env に記載しておいた CHANNEL_ACCESS_TOKENCHANNEL_SECRET を入力します。ここで設定することで、.env ファイルがなくても環境変数として取り込むことができるようになります。

Screenshot 2024-01-05 at 22.08.32.png

Create Web を押すと、自動でデプロイが始まり、ログが表示されます。

Screenshot 2024-01-05 at 22.13.18.png

左側の "Event" にデプロイ履歴が表示されます。デプロイが成功すると、✅マークが付きます。失敗した場合は、ファイルが欠けているか、バージョンの問題がほとんどです。ログと睨めっこして修正が必要です。

Screenshot 2024-01-05 at 22.16.21.png

上部に表示されているWebページのリンクにアクセスします。きちんと Hello world! と表示されていますね。

Screenshot 2024-01-05 at 22.18.09.png

Webhook 設定

デプロイが成功したら、ボットの Webhook の設定をします。LINE Developers のコンソールにいき、チャネルを選択します。

"Messaging API設定" の項目から、"Webhook設定" にいき、ここに Render で割り当てられた URL に /callback を足したものを登録します。さらに検証ボタンを押して、「成功」と表示されればOKです。その下にある "Webhookの利用" にチェックを付けるのを忘れないで下さい。

Screenshot 2024-01-05 at 22.30.11.png

ボット動作確認

これで設定は終了です。実際にLINE内で動作を確認してみましょう。

LINE Developers 内に表示されているQRを読み込んで友達登録する(2回目以降は右上の三本線メニューから、ブロック→ブロック解除する)と、Thank You! のメッセージが送られてきます。さらにユーザーネーム付きのオウム返しも成功しています。

IMG_65959FF5E5B4-1.jpeg

ということでテストアプリ編は終了です。次回から本番ボットの実装に入ります。

app.py 全コード

app.py
# -*- coding: utf-8 -*-
from flask import Flask, request, abort
from linebot.v3 import WebhookHandler
from linebot.v3.exceptions import InvalidSignatureError
from linebot.v3.messaging import (
	ApiClient, Configuration, MessagingApi,
	ReplyMessageRequest, PushMessageRequest,
	TextMessage, PostbackAction
)
from linebot.v3.webhooks import (
	FollowEvent, MessageEvent, PostbackEvent, TextMessageContent
)
import os

## .env ファイル読み込み
from dotenv import load_dotenv
load_dotenv()

## 環境変数を変数に割り当て
CHANNEL_ACCESS_TOKEN = os.environ["CHANNEL_ACCESS_TOKEN"]
CHANNEL_SECRET = os.environ["CHANNEL_SECRET"]

## Flask アプリのインスタンス化
app = Flask(__name__)

## LINE のアクセストークン読み込み
configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(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(FollowEvent)
def handle_follow(event):
	## APIインスタンス化
	with ApiClient(configuration) as api_client:
		line_bot_api = MessagingApi(api_client)

	## 返信
	line_bot_api.reply_message(ReplyMessageRequest(
		replyToken=event.reply_token,
		messages=[TextMessage(text='Thank You!')]
	))
	
## オウム返しメッセージ
@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):
	## APIインスタンス化
	with ApiClient(configuration) as api_client:
		line_bot_api = MessagingApi(api_client)

	## 受信メッセージの中身を取得
	received_message = event.message.text

	## APIを呼んで送信者のプロフィール取得
	profile = line_bot_api.get_profile(event.source.user_id)
	display_name = profile.display_name

	## 返信メッセージ編集
	reply = f'{display_name}さんのメッセージ\n{received_message}'

	## オウム返し
	line_bot_api.reply_message(ReplyMessageRequest(
		replyToken=event.reply_token,
		messages=[TextMessage(text=reply)]
	))

## 起動確認用ウェブサイトのトップページ
@app.route('/', methods=['GET'])
def toppage():
	return 'Hello world!'

## ボット起動コード
if __name__ == "__main__":
	## ローカルでテストする時のために、`debug=True` にしておく
	app.run(host="0.0.0.0", port=8000, debug=True)

目次 : [無料][2024年版] LINE Messaging API v3 + Python(Flask) でボットを作る

GitHub レポジトリ
older_version 内に、各回時点での app.pyrequirements.txt があります。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2