Some checks failed
CD Pipeline / deploy (push) Failing after 59s
- 建立 Gitea Actions CD pipeline (.gitea/workflows/cd.yaml) - 部署模式: rsync Python 檔案至 188 → docker restart (volume mount) - Dockerfile/requirements 變動時自動重建 Docker image - 部署通知: Telegram (開始/成功/失敗) - 健康檢查: https://mo.wooo.work/health (最多 5 次重試) - 同步最新 CLAUDE.md / ADR-008 / memory (2026-04-19) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
163 lines
5.0 KiB
Python
163 lines
5.0 KiB
Python
# cSpell:ignore momo goodsimg
|
||
"""
|
||
驗證商品圖片 URL 是否正確對應到 i_code
|
||
檢查圖片 URL 中是否包含正確的商品編號
|
||
"""
|
||
import os
|
||
import sys
|
||
import re
|
||
from sqlalchemy import create_engine
|
||
from sqlalchemy.orm import sessionmaker
|
||
|
||
# 設定路徑
|
||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||
sys.path.insert(0, BASE_DIR)
|
||
|
||
from database.models import Product
|
||
|
||
# 資料庫路徑
|
||
DB_PATH = os.path.join(BASE_DIR, 'data', 'momo_database.db')
|
||
|
||
def verify_image_urls(sample_size: int = 50):
|
||
"""
|
||
驗證商品圖片 URL 是否正確對應到 i_code
|
||
|
||
Args:
|
||
sample_size: 抽樣檢查的商品數量
|
||
"""
|
||
print("🔍 驗證商品圖片 URL 是否正確對應...\n")
|
||
|
||
if not os.path.exists(DB_PATH):
|
||
print(f"❌ 資料庫檔案不存在: {DB_PATH}")
|
||
return
|
||
|
||
try:
|
||
engine = create_engine(f"sqlite:///{DB_PATH}")
|
||
Session = sessionmaker(bind=engine)
|
||
session = Session()
|
||
|
||
# 查詢有圖片的商品(隨機抽樣)
|
||
products = session.query(Product).filter(
|
||
Product.image_url != None,
|
||
Product.image_url != ''
|
||
).limit(sample_size).all()
|
||
|
||
total = len(products)
|
||
print(f"📊 抽樣檢查 {total} 個有圖片的商品\n")
|
||
print("=" * 80)
|
||
|
||
correct_count = 0
|
||
incorrect_count = 0
|
||
unclear_count = 0
|
||
|
||
for idx, product in enumerate(products, 1):
|
||
i_code = product.i_code
|
||
image_url = product.image_url
|
||
|
||
print(f"\n[{idx}/{total}] 商品: [{i_code}]")
|
||
print(f" 名稱: {product.name[:50]}...")
|
||
print(f" 圖片: {image_url}")
|
||
|
||
# 檢查圖片 URL 是否包含正確的 i_code
|
||
is_correct = check_image_url_match(i_code, image_url)
|
||
|
||
if is_correct == True:
|
||
print(f" ✅ 正確: 圖片 URL 包含商品編號")
|
||
correct_count += 1
|
||
elif is_correct == False:
|
||
print(f" ❌ 錯誤: 圖片 URL 不包含商品編號!")
|
||
incorrect_count += 1
|
||
else:
|
||
print(f" ⚠️ 無法確定: 需要人工檢查")
|
||
unclear_count += 1
|
||
|
||
session.close()
|
||
|
||
print("\n" + "=" * 80)
|
||
print("📊 驗證結果")
|
||
print("=" * 80)
|
||
print(f"✅ 正確: {correct_count}/{total} ({correct_count/total*100:.1f}%)")
|
||
print(f"❌ 錯誤: {incorrect_count}/{total} ({incorrect_count/total*100:.1f}%)")
|
||
print(f"⚠️ 無法確定: {unclear_count}/{total} ({unclear_count/total*100:.1f}%)")
|
||
|
||
if incorrect_count > 0:
|
||
print(f"\n⚠️ 警告: 發現 {incorrect_count} 個商品的圖片 URL 不正確!")
|
||
print("💡 建議: 執行 update_all_images.py 重新更新所有商品圖片")
|
||
elif correct_count == total:
|
||
print(f"\n🎉 太好了!所有抽樣商品的圖片 URL 都正確對應到 i_code")
|
||
|
||
except Exception as e:
|
||
print(f"❌ 驗證失敗: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
|
||
def check_image_url_match(i_code: str, image_url: str) -> bool | None:
|
||
"""
|
||
檢查圖片 URL 是否包含正確的 i_code
|
||
|
||
Args:
|
||
i_code: 商品編號
|
||
image_url: 圖片 URL
|
||
|
||
Returns:
|
||
True: 正確匹配
|
||
False: 不匹配
|
||
None: 無法確定
|
||
"""
|
||
if not image_url:
|
||
return None
|
||
|
||
# MOMO 圖片 URL 的標準格式:
|
||
# 1. https://og.momoshop.com.tw/{timestamp}/goodsimg/{XXXX}/{YYY}/{ZZZ}/{i_code}_L.jpg
|
||
# 2. https://i{1-8}.momoshop.com.tw/{timestamp}/goodsimg/{path}/{i_code}_O.webp
|
||
|
||
# 提取 URL 中的商品編號部分
|
||
# 純數字商品: 0014/548/538/14548538_L.jpg
|
||
# TP 商品: TP000/0829/0000/375/TP00008290000375_O.webp
|
||
|
||
if i_code.startswith('TP'):
|
||
# TP 開頭的商品
|
||
# 檢查 URL 是否包含完整的 i_code
|
||
if i_code in image_url:
|
||
return True
|
||
else:
|
||
return False
|
||
else:
|
||
# 純數字商品
|
||
# 格式: /0014/548/538/14548538_
|
||
try:
|
||
code_num = str(int(i_code)) # 去除前導零
|
||
|
||
# 檢查 URL 是否包含商品編號
|
||
if f"/{code_num}_" in image_url or f"/{code_num}." in image_url:
|
||
return True
|
||
|
||
# 檢查分段格式 (例如 /0014/548/538/ 對應 14548538)
|
||
code_str = code_num.zfill(8)
|
||
part3 = code_str[-3:]
|
||
part2 = code_str[-6:-3]
|
||
part1 = code_str[:-6].zfill(4)
|
||
|
||
# 檢查是否包含這個路徑結構
|
||
path_pattern = f"/{part1}/{part2}/{part3}/"
|
||
if path_pattern in image_url:
|
||
return True
|
||
|
||
return False
|
||
|
||
except ValueError:
|
||
# 無法轉換為數字
|
||
return None
|
||
|
||
|
||
if __name__ == "__main__":
|
||
import argparse
|
||
|
||
parser = argparse.ArgumentParser(description='驗證商品圖片 URL')
|
||
parser.add_argument('--sample-size', type=int, default=50, help='抽樣檢查的商品數量(預設: 50)')
|
||
|
||
args = parser.parse_args()
|
||
|
||
verify_image_urls(sample_size=args.sample_size)
|