This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
> 本文件定義專案開發的核心準則與不可違反的規範
|
||||
> **建立日期**: 2026-01-12
|
||||
> **當前版本**: V10.45 (AI product pick list and improved PChome matching)
|
||||
> **當前版本**: V10.46 (Fix product pick sales date casting)
|
||||
> **最後更新**: 2026-05-01
|
||||
|
||||
---
|
||||
|
||||
4
app.py
4
app.py
@@ -95,8 +95,8 @@ except Exception as e:
|
||||
sys_log.error(f"無法檢測磁碟空間: {e}")
|
||||
|
||||
# 🚩 系統版本定義 (備份與顯示用)
|
||||
# 🚩 2026-05-01 V10.45: AI product pick list and improved PChome matching
|
||||
SYSTEM_VERSION = "V10.45"
|
||||
# 🚩 2026-05-01 V10.46: Fix product pick sales date casting
|
||||
SYSTEM_VERSION = "V10.46"
|
||||
|
||||
# ==========================================
|
||||
# 🔒 SQL Injection 防護函數
|
||||
|
||||
@@ -76,12 +76,12 @@ def _fetch_candidates(conn, limit: int) -> List[Dict[str, Any]]:
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
"商品ID" AS sku,
|
||||
SUM(CASE WHEN snapshot_date >= CURRENT_DATE - 7
|
||||
SUM(CASE WHEN snapshot_date::date >= CURRENT_DATE - 7
|
||||
THEN COALESCE("銷售金額"::numeric, 0) ELSE 0 END) AS sales_7d,
|
||||
SUM(CASE WHEN snapshot_date >= CURRENT_DATE - 14
|
||||
AND snapshot_date < CURRENT_DATE - 7
|
||||
SUM(CASE WHEN snapshot_date::date >= CURRENT_DATE - 14
|
||||
AND snapshot_date::date < CURRENT_DATE - 7
|
||||
THEN COALESCE("銷售金額"::numeric, 0) ELSE 0 END) AS sales_prev_7d,
|
||||
SUM(CASE WHEN snapshot_date >= CURRENT_DATE - 7
|
||||
SUM(CASE WHEN snapshot_date::date >= CURRENT_DATE - 7
|
||||
THEN COALESCE("數量"::numeric, 0) ELSE 0 END) AS qty_7d
|
||||
FROM daily_sales_snapshot
|
||||
GROUP BY "商品ID"
|
||||
@@ -157,6 +157,10 @@ def _fetch_candidates(conn, limit: int) -> List[Dict[str, Any]]:
|
||||
return [dict(row) for row in conn.execute(sql, {"limit": max(limit * 6, 100)}).mappings().all()]
|
||||
except Exception as exc:
|
||||
logger.warning("[ProductPickAgent] sales-aware query failed, fallback without sales: %s", exc)
|
||||
try:
|
||||
conn.rollback()
|
||||
except Exception:
|
||||
pass
|
||||
fallback = text("""
|
||||
WITH latest_momo AS (
|
||||
SELECT
|
||||
@@ -315,8 +319,10 @@ def _write_pick(conn, pick: Dict[str, Any]) -> None:
|
||||
def generate_product_pick_list(engine, limit: int = 30) -> ProductPickResult:
|
||||
"""產生並保存 AI 建議挑品清單。"""
|
||||
generated_at = datetime.now().isoformat(timespec="seconds")
|
||||
with engine.begin() as conn:
|
||||
with engine.connect() as conn:
|
||||
rows = _fetch_candidates(conn, limit)
|
||||
|
||||
with engine.begin() as conn:
|
||||
scored = [_score_candidate(row) for row in rows if _to_float(row.get("pchome_price")) > 0]
|
||||
picks = [
|
||||
pick for pick in scored
|
||||
|
||||
@@ -148,6 +148,8 @@ def test_ai_product_pick_agent_uses_real_competitor_data_and_dashboard_action():
|
||||
assert "'product_pick'" in agent_source
|
||||
assert "PChomeProductPickAgent" in agent_source
|
||||
assert "PChome 價格優勢" in agent_source
|
||||
assert "snapshot_date::date" in agent_source
|
||||
assert "conn.rollback()" in agent_source
|
||||
|
||||
assert "@ai_bp.route('/api/ai/product-picks/generate', methods=['POST'])" in route_source
|
||||
assert "generate_product_pick_list(engine" in route_source
|
||||
|
||||
Reference in New Issue
Block a user