Linebot の画像の管理
line へ投稿した画像が保持される期間を調べる
✅ LINE Bot API による画像メッセージの保持期間
項目 内容
originalContentUrl / previewImageUrl 外部URLのため、LINEサーバーには保存されない
LINEサーバー側での画像保存 ❌ なし(開発者が画像URLを提供するだけ)
ユーザー端末での表示保持 一時的にキャッシュされるが、LINE側での保証なし
画像が消える条件 URL先のファイルが削除・非公開になると表示不能になる
originalContentUrl に指定された画像は LINEアプリで直接URLにアクセスして表示しているだけ。
そのため、Google Drive 上の画像を削除すると即時表示できなくなります。
LINE自体には画像が保存されていないため、画像の「保持期間」という概念は存在しません。
既読前に削除されると見えない:「タップしても開けない」状態に。
表示後に削除されると再表示できないこともある:一部キャッシュは残るが再読み込み時にエラーになる可能性。
✅ 安全な運用方針(おすすめ)
* 送信後に数分~数時間だけDriveに画像を保持
→ ユーザーが確実に見られる時間を確保
* ログに送信済みの画像IDと時刻を記録し、後でバッチ削除
とのこと
つまり削除してしまうと閲覧不可能になる
ただ現状の用途は
在庫管理の動作の画像確認
チラシの商品の画像の確認
なので
2日、つまり48時間後には不要になる
このため48時間経過後に削除するようにモジュールを作成する
これでストレージ圧迫を回避できるはず
なお設定時間は今後変更する可能性が高いため
Config.jsonで設定値を変更可能にする
"image_retention_hours": 48 // ← 追加(削除までの保持時間)
の項目を追加
そして削除モジュール
vim delete_old_images.py
で
import json
import datetime
from googleapiclient.discovery import build
from google.oauth2 import service_account
# 設定ファイルの読み込み
with open("config.json", "r") as f:
config = json.load(f)
FOLDER_ID = config["google_drive_folder_id"]
RETENTION_HOURS = config.get("image_retention_hours", 48) # 設定がなければ48時間
# Google Drive API 認証
SCOPES = ["https://www.googleapis.com/auth/drive"]
SERVICE_ACCOUNT_FILE = "service_account.json"
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
drive_service = build("drive", "v3", credentials=creds)
def get_drive_images(folder_id=FOLDER_ID):
query = f"'{folder_id}' in parents and mimeType contains 'image/' and trashed=false"
results = drive_service.files().list(q=query, fields="files(id, name, createdTime)").execute()
return results.get("files", [])
def delete_old_images(files, hours_threshold):
now = datetime.datetime.utcnow()
for file in files:
created_time_str = file.get("createdTime")
if created_time_str:
created_time = datetime.datetime.strptime(created_time_str, "%Y-%m-%dT%H:%M:%S.%fZ")
delta = now - created_time
if delta.total_seconds() > hours_threshold * 3600:
try:
drive_service.files().delete(fileId=file["id"]).execute()
print(f"✅ Deleted: {file['name']} (created: {created_time})")
except Exception as e:
print(f"⚠️ Error deleting file {file['id']}: {e}")
if __name__ == "__main__":
files = get_drive_images()
if not files:
print("No images found.")
else:
delete_old_images(files, hours_threshold=RETENTION_HOURS)
しかし実行すると
⚠️ Error deleting file : <HttpError 403 when requesting https://www.googleapis.com/drive/v3/files/? returned "The user does not have sufficient permissions for this file.". Details: "[{'message': 'The user does not have sufficient permissions for this file.', 'domain': 'global', 'reason': 'insufficientFilePermissions'}]">
となる
これはファイルの所有者が自分のアカウントで
サービスアカウントでアップしたファイルではないため
このためサービスアカウント権限に編集権限を与えるか
サービスアカウントでgoogle drive へアップする必要がある
現在 yolov8 で画像の出力はできているので
サービスアカウントで出力された画像をGoogle Drive へアップロードするモジュールが欲しい
ということで作成
drive_uploader.py
内容を
import os
import json
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.oauth2 import service_account
# 設定ファイルの読み込み
with open("config.json", "r") as f:
config = json.load(f)
FOLDER_ID = config["google_drive_folder_id"]
SERVICE_ACCOUNT_FILE = "service_account.json"
SCOPES = ["https://www.googleapis.com/auth/drive"]
# 認証と Drive API の初期化
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES
)
drive_service = build("drive", "v3", credentials=creds)
def upload_image_to_drive(filepath, folder_id=FOLDER_ID):
"""
指定した画像ファイルを Google Drive にアップロードする
:param filepath: 画像ファイルのパス
:param folder_id: Drive フォルダ ID
:return: アップロードされたファイルの ID(失敗時は None)
"""
if not os.path.exists(filepath):
print(f"❌ File not found: {filepath}")
return None
filename = os.path.basename(filepath)
file_metadata = {
"name": filename,
"parents": [folder_id],
"mimeType": "image/jpeg"
}
media = MediaFileUpload(filepath, mimetype="image/jpeg")
try:
file = drive_service.files().create(
body=file_metadata,
media_body=media,
fields="id"
).execute()
print(f"✅ Uploaded to Drive: {filename} (ID: {file['id']})")
return file["id"]
except Exception as e:
print(f"⚠️ Upload failed: {e}")
return None
def get_public_url(file_id):
"""
指定されたファイルIDを誰でも見られるように公開設定し、表示用URLを返す
:param file_id: アップロード済みファイルの ID
:return: 公開URL(失敗時は None)
"""
try:
drive_service.permissions().create(
fileId=file_id,
body={"role": "reader", "type": "anyone"},
).execute()
return f"https://drive.google.com/thumbnail?id={file_id}&sz=w1000"
except Exception as e:
print(f"⚠️ Failed to make public: {e}")
return None
として保存
次にアップロードテスト
Yolov8の結果をアップしたいので
from drive_uploader import upload_image_to_drive, get_public_url
file_id = upload_image_to_drive("runs/detect/predict/image1.jpg")
if file_id:
url = get_public_url(file_id)
print("✅ 公開URL:", url)
でパスを
../inventory/runs/detect/predict26/image0.jpg
に変更して実行
なお、コピペするときに改行してしまうと
File "/Users/snowpool/aw10s/gas_iamge_bot/upload_test.py", line 3
file_id = upload_image_to_drive("../inventory/runs/detect/predict26/image0.jpg
^
SyntaxError: unterminated string literal (detected at line 3)
というようにエラーになるので注意
修正後再度実行すると
python upload_test.py ✅ Uploaded to Drive: image0.jpg (ID: ) ✅ 公開URL: https://drive.google.com/thumbnail?id=&sz=w1000
というように成功する
GoogleDrive の tmpフォルダにファイルがあるのも確認
次にこのファイルを削除できるかテストする
ただし48時間経っていないと削除対象にならないためとりあえず保留
48時間経過したので実験
python delete_old_images.py
✅ Deleted: image0.jpg (created: 2025-03-27 21:04:02.459000)
⚠️ Error deleting file : <HttpError 403 when requesting https://www.googleapis.com/drive/v3/files/? returned "The user does not have sufficient permissions for this file.". Details: "[{'message': 'The user does not have sufficient permissions for this file.', 'domain': 'global', 'reason': 'insufficientFilePermissions'}]">
となって削除完了