LINE Messaging APIでリッチメニューの画像切り替えをする際に404エラーが発生
解決したいこと
LINE Messagin APIを使ってデフォルトのリッチメニューの選択肢で出品者か購入者を選択した際に、専用のリッチメニューを表示させたいです。そこでリッチメニューにアップロードする画像が404エラーが起きてアップロードできない状態になっているので解決方法を教えてください。
発生している問題・エラー
2024-09-26T03:57:17.456010+00:00 app[web.1]: 画像アップロードステータス(出品者用): 404
2024-09-26T03:57:17.456023+00:00 app[web.1]: 購入者用リッチメニューを作成中...
2024-09-26T03:57:17.456024+00:00 app[web.1]: リッチメニュー作成中...
2024-09-26T03:57:17.875782+00:00 app[web.1]: リッチメニューID: richmenu-....
2024-09-26T03:57:17.875960+00:00 app[web.1]: 購入者用リッチメニューID: richmenu-....
2024-09-26T03:57:17.875963+00:00 app[web.1]: リッチメニューに画像をアップロード中...: https://res.cloudinary.com/.../image/upload/.../buyer_image.jpg
2024-09-26T03:57:18.565488+00:00 app[web.1]: 画像アップロードステータス(購入者用): 404
該当するソースコード
import os
from flask import Flask, request, abort
import requests
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage
app = Flask(__name__)
# LINE Messaging APIのチャネルアクセストークンとシークレット
LINE_ACCESS_TOKEN = os.environ["LINE_CHANNEL_ACCESS_TOKEN"]
LINE_CHANNEL_SECRET = os.environ["LINE_CHANNEL_SECRET"]
DATABASE_URL = os.environ["DATABASE_URL"]
HEROKU_APP_NAME = os.environ["HEROKU_APP_NAME"]
line_bot_api = LineBotApi(LINE_ACCESS_TOKEN)
handler = WebhookHandler(LINE_CHANNEL_SECRET)
# リッチメニューを作成するAPI
def create_rich_menu(rich_menu_data):
print("リッチメニュー作成中...") # ログ追加
url = "https://api.line.me/v2/bot/richmenu"
headers = {
"Authorization": f"Bearer {LINE_ACCESS_TOKEN}",
"Content-Type": "application/json"
}
response = requests.post(url, headers=headers, json=rich_menu_data)
# レスポンスからrichMenuIdを取得
if response.status_code == 200:
rich_menu_id = response.json().get("richMenuId")
print(f"リッチメニューID: {rich_menu_id}") # ログ追加
return rich_menu_id
else:
print(f"エラー: {response.status_code}") # ログ追加
print(response.text)
return None
# リッチメニューに画像をアップロードする関数
def upload_rich_menu_image(rich_menu_id, image_url):
print(f"リッチメニューに画像をアップロード中...: {image_url}") # ログ追加
url = f"https://api.line.me/v2/bot/richmenu/{rich_menu_id}/content"
headers = {
"Authorization": f"Bearer {LINE_ACCESS_TOKEN}",
"Content-Type": "image/jpeg"
}
# with open(image_url, 'rb') as img_file:
# response = requests.post(url, headers=headers, data=img_file)
# print(f"画像アップロードステータス: {response.status_code}") # ログ追加
# return response.status_code
# 画像をリモートURLからダウンロード
response = requests.get(image_url, stream=True)
if response.status_code == 200:
response.raw.decode_content = True
img_data = response.content
# LINEのAPIに画像を送信
response = requests.post(url, headers=headers, data=img_data)
return response.status_code
else:
print(f"Image download failed: {response.status_code}")
return response.status_code
# 出品者向けリッチメニューのデータ
rich_menu_data_seller = {
"size": {"width": 2500, "height": 1686},
"selected": False,
"name": "出品者メニュー",
"chatBarText": "出品者メニューを開く",
"areas": [
{
"bounds": {"x": 0, "y": 0, "width": 1250, "height": 843},
"action": {"type": "message", "text": "クーポン"}
},
{
"bounds": {"x": 1250, "y": 0, "width": 1250, "height": 843},
"action": {"type": "message", "text": "お問い合わせ"}
},
{
"bounds": {"x": 0, "y": 843, "width": 1250, "height": 843},
"action": {"type": "message", "text": "出品する"}
},
{
"bounds": {"x": 1250, "y": 843, "width": 1250, "height": 843},
"action": {"type": "message", "text": "イベント"}
}
]
}
# 購入者向けリッチメニューのデータ
rich_menu_data_buyer = {
"size": {"width": 2500, "height": 1686},
"selected": False,
"name": "購入者メニュー",
"chatBarText": "購入者メニューを開く",
"areas": [
{
"bounds": {"x": 0, "y": 0, "width": 1250, "height": 843},
"action": {"type": "message", "text": "クーポン"}
},
{
"bounds": {"x": 1250, "y": 0, "width": 1250, "height": 843},
"action": {"type": "message", "text": "お問い合わせ"}
},
{
"bounds": {"x": 0, "y": 843, "width": 1250, "height": 843},
"action": {"type": "message", "text": "新作アートを見る"}
},
{
"bounds": {"x": 1250, "y": 843, "width": 1250, "height": 843},
"action": {"type": "message", "text": "購入履歴"}
}
]
}
# 出品者用リッチメニューを作成し、IDを取得
print("出品者用リッチメニューを作成中...") # ログ追加
rich_menu_id_seller = create_rich_menu(rich_menu_data_seller)
if rich_menu_id_seller:
print(f"出品者用リッチメニューID: {rich_menu_id_seller}")
# リッチメニューIDに画像をアップロード
image_url = "https://res.cloudinary.com/dblgbhtex/image/upload/v1727322302/seller_image_druhei.jpg"
upload_response = upload_rich_menu_image(rich_menu_id_seller, image_url)
print(f"画像アップロードステータス(出品者用): {upload_response}")
# 購入者用リッチメニューを作成し、IDを取得
print("購入者用リッチメニューを作成中...") # ログ追加
rich_menu_id_buyer = create_rich_menu(rich_menu_data_buyer)
if rich_menu_id_buyer:
print(f"購入者用リッチメニューID: {rich_menu_id_buyer}")
# リッチメニューIDに画像をアップロード
image_url = "https://res.cloudinary.com/dblgbhtex/image/upload/v1727322301/buyer_image_yz5bgk.jpg"
upload_response = upload_rich_menu_image(rich_menu_id_buyer, image_url)
print(f"画像アップロードステータス(購入者用): {upload_response}")
# ユーザーごとのリッチメニュー割り当て関数
def set_rich_menu_to_user(user_id, rich_menu_id):
print(f"リッチメニューをユーザー {user_id} に割り当て中...") # ログ追加
url = f'https://api.line.me/v2/bot/user/{user_id}/richmenu/{rich_menu_id}'
headers = {
'Authorization': f'Bearer {LINE_ACCESS_TOKEN}'
}
response = requests.post(url, headers=headers)
print(f"リッチメニュー割り当てステータス: {response.status_code}") # ログ追加
return response.status_code
@app.route("/callback", methods=['POST'])
def callback():
print("Webhookを受信しました。") # ログ追加
# LINEの署名を検証
signature = request.headers['X-Line-Signature']
body = request.get_data(as_text=True)
print(f"リクエストボディ: {body}") # ログ追加
try:
handler.handle(body, signature)
except InvalidSignatureError:
print("署名の検証に失敗しました。") # ログ追加
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
print(f"メッセージを受信しました: {event.message.text}") # ログ追加
user_id = event.source.user_id
text = event.message.text
if text == "購入者として友達になる":
# 購入者向けリッチメニューを表示
print("購入者用リッチメニューを設定します。") # ログ追加
set_rich_menu_to_user(user_id, rich_menu_id_buyer)
line_bot_api.reply_message(event.reply_token, TextMessage(text="購入者向けメニューに切り替えました。"))
elif text == "出品者として友達になる":
# 出品者向けリッチメニューを表示
print("出品者用リッチメニューを設定します。") # ログ追加
set_rich_menu_to_user(user_id, rich_menu_id_seller)
line_bot_api.reply_message(event.reply_token, TextMessage(text="出品者向けメニューに切り替えました。"))
if __name__ == "__main__":
print("アプリケーションが起動しました。") # ログ追加
port = int(os.environ.get("PORT", 8000))
app.run(host="0.0.0.0", port=port)
自分で試したこと
まず最初に同じ層のフォルダにstatic/imagesを作成し、そこに画像を格納し、パスで指定しましたがNot found errorが発生しました。chom 644に設定し他のプロセスでもアクセスできる権限に変更してもエラーは解消されませんでした。
次にcloudinaryを使用して外部のurlからダウンロードする方法で試してみましたが、依然404エラーが発生するままです。
自分で調べてみても解決方法が記載されている記事が見つからないため、お教えていただけますと嬉しいです。
よろしくお願いいたします。
0 likes