Llama-2が登場!8bit+LoRAでRLHFファインチューニングを試す方法はこちら

【LINE Messaging API】Pythonでカルーセルメッセージは簡単に作れる!10個より多く表示させたい場合の対処法も紹介!

皆さんはカルーセルメッセージをどのように使っているでしょうか。

例えば、なにか検索した結果をラインで表示できるようにするために使うなど様々な使い方がありますよね。

ではさっそく基本的なPythonでカルーセルメッセージを作成していきます。

目次

カルーセルメッセージの作成

基本的には、以下のコードで作成できます。

import re
from linebot import LineBotApi

line_bot_api = LineBotApi(os.environ['channel_access_token'])

columns_list = []
columns_list.append(CarouselColumn(title="タイトルだよ", text="よろしくね", actions=[PostbackAction(label="詳細を表示", data=f"詳細表示"), PostbackAction(label="削除", data=f"削除")]))
columns_list.append(CarouselColumn(title="タイトルだよ", text="よろしくね", actions=[PostbackAction(label="詳細を表示", data=f"詳細表示"), PostbackAction(label="削除", data=f"削除")]))
carousel_template_message = TemplateSendMessage(
                alt_text='会話ログを表示しています',
                template=CarouselTemplate(columns=columns_list)
                )
line_bot_api.reply_message(event.reply_token, messages=carousel_template_message)
作成したカルーセルメッセージ

簡単ですね。

カルーセルメッセージの制限

カルーセルメッセージの制限の一つとして最大で10個しかカラムを表示できないというものがあります。

そのほかの詳しい説明はこちらを参照してください。

これに対処するための方法について解説していきたいと思います。

では簡単な例として都道府県をカルーセルメッセージで表示させてボタンを押すと県庁所在地を教えてくれるLine botを作りながら10個以上のものを表示させたい時の対処法を紹介します。

データの用意

まず都道府県と県庁所在地のデータを用意します。

次のような形式のxlsxファイルを用意しました。今回は都道府県.xlsxとして保存しています。

都道府県県庁所在地
北海道札幌市
青森県青森市
岩手県盛岡市
宮城県仙台市
秋田県秋田市
山形県山形市

ファイルは次のように配置してください。

├─app.py
├─都道府県.xlsx
└─ info
    └─.env

info/.envファイルの中は次のようになっています。

CHANNEL_ACCESS_TOKEN=ここにチャンネルアクセストークンを入力してください
CHANNEL_SECRET=ここにチャンネルシークレットを入力してください

コード全体

はじめにすべてのコードを載せておきます。

from flask import Flask, request, abort
import os
import re
import pandas as pd
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,TemplateSendMessage,CarouselTemplate,CarouselColumn,
    PostbackEvent,
    QuickReply, QuickReplyButton
)
from linebot.models.actions import PostbackAction
import dotenv

app = Flask(__name__)
dotenv.load_dotenv("./info/.env")
line_bot_api = LineBotApi(os.environ["CHANNEL_ACCESS_TOKEN"])
handler = WebhookHandler(os.environ["CHANNEL_SECRET"])
df = pd.read_excel("都道府県.xlsx")

@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:
        abort(400)
    return 'OK'

# メッセージを受け取った時のアクション
@handler.add(MessageEvent, message=TextMessage)
def send_infomation(event):
    if event.reply_token == "00000000000000000000000000000000":
        return
    msg = event.message.text
    if msg == "都道府県について教えて":
        make_quick_reply(event.reply_token, "都道府県について表示しますか?")

# PostbackActionがあった時のアクション
@handler.add(PostbackEvent)
def on_postback(event):
    postback_msg = event.postback.data
    if re.search(r"都道府県を表示&num=[0-9]+", postback_msg):
        show_num = int(re.search(r"都道府県を表示&num=([0-9]+)", postback_msg).group(1))
        columns_list = []
        if show_num >= 5:
            for prefecture, capital in zip(df["都道府県"][9*show_num:], df["県庁所在地"][9*show_num:]):
                columns_list.append(CarouselColumn(title=f"{prefecture}", text="県庁所在地を表示しますか", actions=[PostbackAction(label="表示します", data=f"{prefecture}の県庁所在地は{capital}です")]))
            carousel_template_message = TemplateSendMessage(
                            alt_text='都道府県について表示しています',
                            template=CarouselTemplate(columns=columns_list)
                            )
            line_bot_api.reply_message(event.reply_token, messages=carousel_template_message)
        else:
            for prefecture, capital in zip(df["都道府県"][9*show_num:9*show_num+9], df["県庁所在地"][9*show_num:9*show_num+9]):
                columns_list.append(CarouselColumn(title=f"{prefecture}", text="県庁所在地を表示しますか", actions=[PostbackAction(label="表示します", data=f"{prefecture}の県庁所在地は{capital}です")]))
            columns_list.append(CarouselColumn(title=f"次を表示する", text="次へ", actions=[PostbackAction(label="次の都道府県を表示", data=f"都道府県を表示&num={show_num + 1}")]))
            carousel_template_message = TemplateSendMessage(
                            alt_text='都道府県について表示しています',
                            template=CarouselTemplate(columns=columns_list)
                            )
            line_bot_api.reply_message(event.reply_token, messages=carousel_template_message)

    if postback_msg == "キャンセル":
        messages = TextSendMessage(text="キャンセルしました")
        line_bot_api.reply_message(event.reply_token, messages=messages)

    if re.search(r".+の県庁所在地は.+です", postback_msg):
        text = re.search(r"(.+の県庁所在地は.+です)", postback_msg).group(1)
        messages = TextSendMessage(text=text)
        line_bot_api.reply_message(event.reply_token, messages=messages)

def make_quick_reply(token, text):
    items = []
    items.append(QuickReplyButton(action=PostbackAction(label='表示する', data='都道府県を表示&num=0')))
    items.append(QuickReplyButton(action=PostbackAction(label='キャンセル', data='キャンセル')))
    messages = TextSendMessage(text=text,
                            quick_reply=QuickReply(items=items))
    line_bot_api.reply_message(token, messages=messages)

作成したLine botの概要

作成したLine botは次のような流れで県庁所在地を答えます。

  1. 「都道府県について教えて」とメッセージを送るとクイックリプライで「表示する」「キャンセル」を選択できます。
  2. 「表示する」を押した場合は都道府県の名前が書かれたカルーセルメッセージが9個と「次を表示する」と書かれたカルーセルメッセージが一つ出現します。「キャンセル」が押された場合は、「キャンセルしました」とメッセージを送ります。
  3. 都道府県の名前が書かれたカルーセルメッセージには県庁所在地を「表示します」と書かれたボタンがあります。また、「次を表示する」と書かれたカルーセルメッセージには「次の都道府県を表示」と書かれたボタンがあります。
  4. 「表示します」のボタンを押すとその都道府県の県庁所在地が表示されます。「次の都道府県を表示」のボタンを押すと続きの都道府県から順番に表示されます。

大まかな流れとしては、次の画像を参考にしてください。

表示するを押すと、都道府県が表示されます。そして、右にスライドしていくと次のようなカルーセルメッセージが出てきます。

「次の都道府県を表示」を押すと次の画像のようなカルーセルメッセージが出てきます。

「表示する」を押すと、県庁所在地を教えてくれます。

コードの説明

まずはFlaskなど必要なものをインポート・呼び出しをします。

from flask import Flask, request, abort
import os
import re
import pandas as pd
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,TemplateSendMessage,CarouselTemplate,CarouselColumn,
    PostbackEvent,
    QuickReply, QuickReplyButton
)
from linebot.models.actions import PostbackAction
import dotenv

app = Flask(__name__)
dotenv.load_dotenv("./info/.env")
line_bot_api = LineBotApi(os.environ["CHANNEL_ACCESS_TOKEN"])
handler = WebhookHandler(os.environ["CHANNEL_SECRET"])
df = pd.read_excel("都道府県.xlsx")

必ず必要な部分

必ず必要な部分はこちらです。

@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:
        abort(400)
    return 'OK'

メッセージを受け取った時のコード

メッセージを受け取った時の処理はこちらになります。

「都道府県について教えて」とメッセージを受け取るとクイックリプライを送るようにしています。

# メッセージを受け取った時のアクション
@handler.add(MessageEvent, message=TextMessage)
def send_infomation(event):
    if event.reply_token == "00000000000000000000000000000000":
        return
    msg = event.message.text
    if msg == "都道府県について教えて":
        make_quick_reply(event.reply_token, "都道府県について表示しますか?")

クイックリプライを定義

クイックリプライを定義します。

工夫としてはPostbackAction(label=’表示する’, data=’都道府県を表示&num=0′)としているところです。

このnum=0によってどれくらい次を表示しているかを管理することができます。

def make_quick_reply(token, text):
    items = []
    items.append(QuickReplyButton(action=PostbackAction(label='表示する', data='都道府県を表示&num=0')))
    items.append(QuickReplyButton(action=PostbackAction(label='キャンセル', data='キャンセル')))
    messages = TextSendMessage(text=text,
                            quick_reply=QuickReply(items=items))
    line_bot_api.reply_message(token, messages=messages)

PostbackActionがあった場合のコード

次にpostbackactionがあった場合のコードについてみていきます。

工夫点としては、postback_msgを正規表現で条件付けしていることが挙げられます。

このようにすることでどれだけ次を表示すればいいかを管理することができます。

その他にも正規表現を使って情報を伝達しており様々なことに応用できます。

# PostbackActionがあった時のアクション
@handler.add(PostbackEvent)
def on_postback(event):
    postback_msg = event.postback.data
    if re.search(r"都道府県を表示&num=[0-9]+", postback_msg):
        show_num = int(re.search(r"都道府県を表示&num=([0-9]+)", postback_msg).group(1))
        columns_list = []
        if show_num >= 5:
            for prefecture, capital in zip(df["都道府県"][9*show_num:], df["県庁所在地"][9*show_num:]):
                columns_list.append(CarouselColumn(title=f"{prefecture}", text="県庁所在地を表示しますか", actions=[PostbackAction(label="表示します", data=f"{prefecture}の県庁所在地は{capital}です")]))
            carousel_template_message = TemplateSendMessage(
                            alt_text='都道府県について表示しています',
                            template=CarouselTemplate(columns=columns_list)
                            )
            line_bot_api.reply_message(event.reply_token, messages=carousel_template_message)
        else:
            for prefecture, capital in zip(df["都道府県"][9*show_num:9*show_num+9], df["県庁所在地"][9*show_num:9*show_num+9]):
                columns_list.append(CarouselColumn(title=f"{prefecture}", text="県庁所在地を表示しますか", actions=[PostbackAction(label="表示します", data=f"{prefecture}の県庁所在地は{capital}です")]))
            columns_list.append(CarouselColumn(title=f"次を表示する", text="次へ", actions=[PostbackAction(label="次の都道府県を表示", data=f"都道府県を表示&num={show_num + 1}")]))
            carousel_template_message = TemplateSendMessage(
                            alt_text='都道府県について表示しています',
                            template=CarouselTemplate(columns=columns_list)
                            )
            line_bot_api.reply_message(event.reply_token, messages=carousel_template_message)

    if postback_msg == "キャンセル":
        messages = TextSendMessage(text="キャンセルしました")
        line_bot_api.reply_message(event.reply_token, messages=messages)

    if re.search(r".+の県庁所在地は.+です", postback_msg):
        text = re.search(r"(.+の県庁所在地は.+です)", postback_msg).group(1)
        messages = TextSendMessage(text=text)
        line_bot_api.reply_message(event.reply_token, messages=messages)

カルーセルメッセージを10個より多く表示させたい場合

カルーセルメッセージを10個より多く表示させたい場合の対処法としては、正規表現を使うことを紹介しました。今回の方法のメリットとしては、情報を伝えることができる点にあると思います。例えば、連続して質問に答えてもらうボットを作るとしたら、それらの情報をポストバックメッセージとして記録できます。このように正規表現を使えば多くのことができるようになります。

最後に

今回紹介した方法は、私の調べでは他のサイトに載っていなかったので紹介いたしました。

クイックリプライの作り方
あわせて読みたい
【LINE Messaging API】Pythonでクイックリプライを簡単に作成!クイックリプライを使った簡単なLINEbot... 何かと便利なクイックリプライをpythonで作る方法を説明します。また、クイックリプライを使った簡単なじゃんけんbotを作ったので参考にしてください。では、さっそくクイックリプライの簡単な作成方法を解説します。
リッチメニューの作り方
あわせて読みたい
【LINE Messaging API】簡単!PythonでLINEのリッチメニューを簡単に作成! PythonでLINEのリッチメニューを作りたいという方は多いのではないでしょうか。しかし、こちらのgithubや他の記事を参考にしてみてもよく分からない方もいると思います。で今回は、classで機能をまとめることはせずにいろいろと説明していきます。

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次