V10.553 瘦身 current 比價結果查詢
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
================================================================================
|
||||
|
||||
【已完成】
|
||||
- V10.553 優化 current PPT/AI 比價結果查詢:`fetch_competitor_comparison_results()` 的 current/latest MOMO 價格改用 `JOIN LATERAL` 取單品最新價,移除 `ROW_NUMBER() OVER (PARTITION BY p.id ...)` window scan;歷史報表的 `end_date` cutoff 仍保留在 lateral 子查詢內,維持「指定期間截止日前最新 MOMO 價」語意不變。這能降低簡報、OpenClaw/AI payload 與比價匯出在大量 price_records 下的查詢成本。
|
||||
- V10.552 收斂決策查詢的新鮮度口徑:`fetch_top_competitor_risks()`、PChome review queue、review sample 與 current PPT/AI 比價結果都不再把 `expires_at IS NULL` 當成有效現價,只接受 `expires_at > CURRENT_TIMESTAMP` 的 PChome identity_v2 價格。未知新鮮度只留在 coverage 的診斷欄位與 V10.551 刷新入口,不再進入價格風險、簡報、AI 決策或覆核排除條件。
|
||||
- V10.551 收斂未知新鮮度刷新與補抓排序:`_fetch_expired_identity_skus()` / `_fetch_expired_identity_recovery_skus()` 將 `expires_at IS NULL` 視為必須刷新或可搜尋救援的未知新鮮度 identity,和 V10.549「未知新鮮度不算可決策覆蓋率」口徑對齊;兩條路徑改用 `JOIN LATERAL` 取最新 MOMO 價,移除 product-wide window scan。`_fetch_unmatched_priority_skus()` 也改用 lateral 最新價,並優先重搜低風險 `no_result / refresh_no_result`,讓 V10.550 的安全召回詞先用在最可能被救回的商品。
|
||||
- V10.550 補安全搜尋召回詞:`_build_variant_recall_search_plan()` 對低風險穩定品類新增 `品牌 + 品類` 的補搜尋詞,讓 `no_result / refresh_no_result` 更有機會找到 PChome 候選後再交給 matcher 安全判斷;美甲片、指甲油、唇彩、香氛/精油、粉底、防曬、任選/色號/款式等高 variant 風險商品不走通用召回,DASHING DIVA 仍只走既有 line-specific recall + sort fallback。此變更不改 `MIN_MATCH_SCORE`、hard veto、fresh-search write safety 或 stronger existing match 覆寫保護。
|
||||
|
||||
@@ -402,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
|
||||
# ==========================================
|
||||
# 系統版本與路徑
|
||||
# ==========================================
|
||||
SYSTEM_VERSION = "V10.552"
|
||||
SYSTEM_VERSION = "V10.553"
|
||||
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
|
||||
public_url = PUBLIC_URL # 用於模板顯示
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
## 📅 詳細更新日誌 (考古存檔)
|
||||
|
||||
### 2026-06-01:PChome 比價新鮮度操作閉環
|
||||
- **V10.553 current PPT/AI 比價結果查詢瘦身**: `fetch_competitor_comparison_results()` 不再用 `ROW_NUMBER() OVER (PARTITION BY p.id ...)` 掃 `price_records` 取得 current/latest MOMO 價格,改為 `JOIN LATERAL` 逐商品取最新價;有指定 `end_date` 的歷史報表仍把 `pr.timestamp < DATE(:end_date) + INTERVAL '1 day'` 放在 lateral 子查詢中,保留「截止日前最新 MOMO 價」語意。這降低簡報、OpenClaw/AI payload 與比價匯出在大量價格紀錄下的查詢成本。
|
||||
- **V10.552 決策查詢新鮮度口徑收斂**: Top competitor risks、PChome review queue、review sample 與 current PPT/AI 比價結果全部改成只吃 `cp.expires_at > CURRENT_TIMESTAMP` 的有效 PChome identity_v2 價格,不再把 `expires_at IS NULL` 當作有效現價。未知新鮮度現在只作 coverage 診斷與刷新入口,不會被用來產生價格風險、簡報、AI 決策或從覆核隊列中排除。
|
||||
- **V10.551 未知新鮮度刷新與補抓排序收斂**: `expires_at IS NULL` 的 identity_v2 價格現在會被 `_fetch_expired_identity_skus()` 與 `_fetch_expired_identity_recovery_skus()` 視為需要刷新 / 可搜尋救援的未知新鮮度資料,避免 V10.549 已排除出可決策覆蓋率後卻沒有刷新入口;兩條路徑都改用 `JOIN LATERAL` 取最新 MOMO 價,不再做 product-wide window scan。`_fetch_unmatched_priority_skus()` 同步改為 lateral latest price,且把低風險 `no_result / refresh_no_result` 排到補抓前段,讓安全召回詞優先投入最可能回收的 SKU。
|
||||
- **V10.550 安全搜尋召回詞補強**: `competitor_price_feeder` 在既有精準搜尋詞之外,對低風險穩定品類補上一組 `品牌 + 品類` recall keyword,提升 `no_result / refresh_no_result` 找到候選的機率;高 variant 風險商品如美甲片、指甲油、唇彩、香氛/精油、粉底、防曬與含任選/色號/款式/香味的商品不走通用召回。DASHING DIVA 仍保留既有 line-specific recall 與 PChome sort fallback;本次不更動 `MIN_MATCH_SCORE`、hard veto、auto write safety 或 stronger existing match 保護。
|
||||
|
||||
@@ -1717,12 +1717,17 @@ def fetch_competitor_comparison_results(
|
||||
p.id AS product_id,
|
||||
p.i_code AS sku,
|
||||
p.name,
|
||||
pr.price AS momo_price,
|
||||
ROW_NUMBER() OVER (PARTITION BY p.id ORDER BY pr.timestamp DESC, pr.id DESC) AS rn
|
||||
latest_price.price AS momo_price
|
||||
FROM products p
|
||||
JOIN price_records pr ON pr.product_id = p.id
|
||||
JOIN LATERAL (
|
||||
SELECT pr.price
|
||||
FROM price_records pr
|
||||
WHERE pr.product_id = p.id
|
||||
{momo_price_cutoff}
|
||||
ORDER BY pr.timestamp DESC, pr.id DESC
|
||||
LIMIT 1
|
||||
) latest_price ON TRUE
|
||||
WHERE p.status = 'ACTIVE'
|
||||
{momo_price_cutoff}
|
||||
),
|
||||
{valid_competitor_cte},
|
||||
{attempt_cte}
|
||||
@@ -1756,8 +1761,7 @@ def fetch_competitor_comparison_results(
|
||||
LEFT JOIN valid_competitor vc ON vc.sku = lm.sku
|
||||
LEFT JOIN latest_attempt la ON la.sku = lm.sku
|
||||
{sales_join}
|
||||
WHERE lm.rn = 1
|
||||
AND lm.momo_price > 0
|
||||
WHERE lm.momo_price > 0
|
||||
ORDER BY {order_expr}
|
||||
LIMIT :limit
|
||||
""")
|
||||
|
||||
@@ -56,6 +56,9 @@ def test_competitor_ppt_results_keep_pending_diagnostics_in_export():
|
||||
def test_competitor_ppt_results_use_history_for_dated_reports():
|
||||
source = (ROOT / "services" / "competitor_intel_repository.py").read_text(encoding="utf-8")
|
||||
route_source = (ROOT / "routes" / "openclaw_bot_routes.py").read_text(encoding="utf-8")
|
||||
comparison_source = source.split("def fetch_competitor_comparison_results", 1)[1].split(
|
||||
"def build_competitor_intel_payload", 1
|
||||
)[0]
|
||||
|
||||
assert "requested_historical_prices" in source
|
||||
assert "use_history_prices" in source
|
||||
@@ -63,6 +66,11 @@ def test_competitor_ppt_results_use_history_for_dated_reports():
|
||||
assert "cph.crawled_at >= DATE(:start_date)" in source
|
||||
assert "cph.crawled_at < DATE(:end_date) + INTERVAL '1 day'" in source
|
||||
assert "pr.timestamp < DATE(:end_date) + INTERVAL '1 day'" in source
|
||||
assert "FROM products p\n JOIN LATERAL" in comparison_source
|
||||
assert "WHERE pr.product_id = p.id" in comparison_source
|
||||
assert "ORDER BY pr.timestamp DESC, pr.id DESC" in comparison_source
|
||||
assert "ROW_NUMBER() OVER (PARTITION BY p.id" not in comparison_source
|
||||
assert "WHERE lm.rn = 1" not in comparison_source
|
||||
assert "'competitor_price_history' AS competitor_source" in source
|
||||
assert "\"competitor_source\"" in source
|
||||
assert "\"pc_crawled_at\"" in source
|
||||
|
||||
Reference in New Issue
Block a user