Q&A

Line Bot Designer で作成した Flex Message を linebot で送信したい

やりたいこと

Line Bot DesignerでFlex Messageを作成したjsonをline botで送信したいと考えているのですが。 そのままのjsonデータでは送信することが出来ず、送信できるフォーマットにする方法をご教示いただきたく存じます。

作成したjson・作成したいjson

作成したjson ※文字化けするためダブルコーテーションは外してあります。

{
  type: flex,
  altText: Flex Message,
  contents: {
    type: bubble,
    direction: ltr,
    header: {
      type: box,
      layout: vertical,
      contents: [
        {
          type: text,
          text: 水,
          align: center
        }
      ]
    },
    hero: {
      type: image,
      url: https://images-na.ssl-images-amazon.com/images/I/81dkWPlc-AL._SX522_.jpg,
      size: full,
      aspectRatio: 1.51:1,
      aspectMode: fit
    },
    footer: {
      type: box,
      layout: horizontal,
      contents: [
        {
          type: button,
          action: {
            type: uri,
            label: 購入,
            uri: https://www.amazon.co.jp/天然水-【Amazon-co-jp-限定】サントリー-南アルプスの天然水-2L×9本/dp/B07F1CCSJZ/ref=sr_1_1_sspa?__mk_ja_JP=カタカナ&keywords=水&qid=1563628084&s=gateway&sr=8-1-spons&psc=1
          }
        }
      ]
    }
  }
}

送信できるフォーマット

       bubble = BubbleContainer(
            direction='ltr',
            hero=ImageComponent(
                url='https://example.com/cafe.jpg',
                size='full',
                aspect_ratio='20:13',
                aspect_mode='cover',
                action=URIAction(uri='http://example.com', label='label')
            ),
            body=BoxComponent(
                layout='vertical',
                contents=[
                    # title
                    TextComponent(text='Brown Cafe', weight='bold', size='xl'),
                    # review
                    BoxComponent(
                        layout='baseline',
                        margin='md',
                        contents=[
                            IconComponent(size='sm', url='https://example.com/gold_star.png'),
                            IconComponent(size='sm', url='https://example.com/grey_star.png'),
                            IconComponent(size='sm', url='https://example.com/gold_star.png'),
                            IconComponent(size='sm', url='https://example.com/gold_star.png'),
                            IconComponent(size='sm', url='https://example.com/grey_star.png'),
                            TextComponent(text='4.0', size='sm', color='#999999', margin='md',
                                          flex=0)
                        ]
                    ),
                    # info
                    BoxComponent(
                        layout='vertical',
                        margin='lg',
                        spacing='sm',
                        contents=[
                            BoxComponent(
                                layout='baseline',
                                spacing='sm',
                                contents=[
                                    TextComponent(
                                        text='Place',
                                        color='#aaaaaa',
                                        size='sm',
                                        flex=1
                                    ),
                                    TextComponent(
                                        text='Shinjuku, Tokyo',
                                        wrap=True,
                                        color='#666666',
                                        size='sm',
                                        flex=5
                                    )
                                ],
                            ),
                            BoxComponent(
                                layout='baseline',
                                spacing='sm',
                                contents=[
                                    TextComponent(
                                        text='Time',
                                        color='#aaaaaa',
                                        size='sm',
                                        flex=1
                                    ),
                                    TextComponent(
                                        text="10:00 - 23:00",
                                        wrap=True,
                                        color='#666666',
                                        size='sm',
                                        flex=5,
                                    ),
                                ],
                            ),
                        ],
                    )
                ],
            ),
            footer=BoxComponent(
                layout='vertical',
                spacing='sm',
                contents=[
                    # callAction, separator, websiteAction
                    SpacerComponent(size='sm'),
                    # callAction
                    ButtonComponent(
                        style='link',
                        height='sm',
                        action=URIAction(label='CALL', uri='tel:000000'),
                    ),
                    # separator
                    SeparatorComponent(),
                    # websiteAction
                    ButtonComponent(
                        style='link',
                        height='sm',
                        action=URIAction(label='WEBSITE', uri="https://example.com")
                    )
                ]
            ),
        )

このようなフォーマットにしたいです。

試したこと

一応記事を読んでみたのですが、pythonを始めて日が浅く私の実力では理解ができませんでした。

読んだ記事 Flex Message を使ってリッチUIなLINEボットを作る Flex Message のJSON文字列をそのまま利用する

補足情報(FW/ツールのバージョンなど)

python version 3.7.2

よろしくお願いいたします。

  • 2
  • 4
  • 5131
  • twitter facebook

無事作成することができました。 ご丁寧にご教示いただきありがとうございました。

  • 1

flex_message_json_string の中身のJSON文字列の中身が間違っているかと思います.

# type = flex
{  
  "type": "flex",
  "altText": "Flex Message",
  "contents": {
    "type": "bubble",
    "direction": "ltr",
		...

ではなく,

# type = bubble or carousel
{
    "type": "bubble",
    "direction": "ltr",
		...
}

で flex_message_json_string を初期化するようにしてください,

また, FlexSendMessage(alt_text="hoge", contents=flex_message_json_dict) が, メッセージ送信時にどのようなJSONになっているかは

print( FlexSendMessage(alt_text="hoge", contents=flex_message_json_dict) )

すれば確認できます.(TextSendMessageなど他のクラスでも同様に確認できます)

※それと, JSON文字列のダブルクオーテーションもお忘れなく.

  • 0

ご回答ありがとうございます。 試しに

main.py
from flask import Flask, request, abort
import os
import json

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)

from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
    SourceUser, SourceGroup, SourceRoom,
    TemplateSendMessage, ConfirmTemplate, MessageAction,
    ButtonsTemplate, ImageCarouselTemplate, ImageCarouselColumn, URIAction,
    PostbackAction, DatetimePickerAction,
    CameraAction, CameraRollAction, LocationAction,
    CarouselTemplate, CarouselColumn, PostbackEvent,
    StickerMessage, StickerSendMessage, LocationMessage, LocationSendMessage,
    ImageMessage, VideoMessage, AudioMessage, FileMessage,
    UnfollowEvent, FollowEvent, JoinEvent, LeaveEvent, BeaconEvent,
    MemberJoinedEvent, MemberLeftEvent,
    FlexSendMessage, BubbleContainer, ImageComponent, BoxComponent,
    TextComponent, SpacerComponent, IconComponent, ButtonComponent,
    SeparatorComponent, QuickReply, QuickReplyButton,
    ImageSendMessage)

app = Flask(__name__)

flex_message_json_string="""
{  
  type: flex,
  altText: Flex Message,
  contents: {
    type: bubble,
    direction: ltr,
    header: {
      type: box,
      layout: vertical,
      contents: [
        {
          type: text,
          text: ,
          align: center
        }
      ]
    },
    hero: {
      type: image,
      url: https://images-na.ssl-images-amazon.com/images/I/81dkWPlc-AL._SX522_.jpg,
      size: full,
      aspectRatio: 1.51:1,
      aspectMode: fit
    },
    footer: {
      type: box,
      layout: horizontal,
      contents: [
        {
          type: button,
          action: {
            type: uri,
            label: 購入,
            uri: https://www.amazon.co.jp/天然水-【Amazon-co-jp-限定】サントリー-南アルプスの天然水-2L×9本/dp/B07F1CCSJZ/ref=sr_1_1_sspa?__mk_ja_JP=カタカナ&keywords=水&qid=1563628084&s=gateway&sr=8-1-spons&psc=1
          }
        }
      ]
    }
  }
}
"""

flex_message_json_dict = json.loads(flex_message_json_string)

#環境変数取得
YOUR_CHANNEL_ACCESS_TOKEN = os.environ[YOUR_CHANNEL_ACCESS_TOKEN]
YOUR_CHANNEL_SECRET = os.environ[YOUR_CHANNEL_SECRET]

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:
        abort(400)

    return OK

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    line_bot_api.reply_message(
        event.reply_token,
        FlexSendMessage(
            alt_text=alt_text,
            contents=flex_message_json_dict
        )
    )

if __name__ == __main__:
#    app.run()
    port = int(os.getenv(PORT))
    app.run(host=0.0.0.0, port=port)

を作成してみたのですが

2019-07-31T15:26:22.885896+00:00 app[web.1]: File "main.py", line 98, in callback 2019-07-31T15:26:22.885899+00:00 app[web.1]: handler.handle(body, signature) 2019-07-31T15:26:22.885901+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/linebot/webhook.py", line 260, in handle 2019-07-31T15:26:22.885904+00:00 app[web.1]: func(event) 2019-07-31T15:26:22.885906+00:00 app[web.1]: File "main.py", line 110, in handle_message 2019-07-31T15:26:22.885908+00:00 app[web.1]: contents=flex_message_json_dict 2019-07-31T15:26:22.885911+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/linebot/api.py", line 101, in reply_message 2019-07-31T15:26:22.885913+00:00 app[web.1]: '/v2/bot/message/reply', data=json.dumps(data), timeout=timeout 2019-07-31T15:26:22.885918+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/linebot/api.py", line 903, in _post 2019-07-31T15:26:22.885920+00:00 app[web.1]: self.__check_error(response) 2019-07-31T15:26:22.885922+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/linebot/api.py", line 926, in __check_error 2019-07-31T15:26:22.885924+00:00 app[web.1]: raise LineBotApiError(response.status_code, error) 2019-07-31T15:26:22.885927+00:00 app[web.1]: linebot.exceptions.LineBotApiError: LineBotApiError: status_code=400, error_response={"details": [{"message": "May not be empty", "property": "messages[0].contents"}], "message": "The request body has 1 error(s)"}

と言ったエラーになってしまい 色々試したのですが解決できず もう一度お力添えいただければ幸いです よろしくお願いいたします。

  • 0

実は,line-bot-sdk-pythondict(辞書) をメッセージの中身として送信できます.

なので下のように,送信したいJSON文字列を json.loadsdict に変換して,FlexSendMessage.contents に渡せば,Flex Message Simulator で作成したJSONをそのまま使えます.

import json

# 送信したいJSON文字列
flex_message_json_string="""
{
  "type": "bubble",
  "hero": ...,
	...
"""

# JSON文字列をdict型に変換
flex_message_json_dict = json.loads(flex_message_json_string)

line_bot_api.reply_message(
    event.reply_token,
    FlexSendMessage(
		alt_text='alt_text',
		# contentsパラメタに, dict型の値を渡す
		contents=flex_message_json_dict
    )
)

不明点あれば,お気軽に返信ください.

  • 1
Are you sure? question.vm