修正 PChome 覆蓋率活躍商品分母
All checks were successful
CD Pipeline / deploy (push) Successful in 1m21s

This commit is contained in:
OoO
2026-05-20 11:42:35 +08:00
parent 6bf05ec2f1
commit a1818da1f3
5 changed files with 20 additions and 3 deletions

View File

@@ -4,6 +4,7 @@
================================================================================
【已完成】
- V10.317 修正 PChome 比價覆蓋率分子:`fetch_competitor_coverage()` 的 valid_matches 改成 `ACTIVE + 有 MOMO 最新價` 商品與有效 PChome `identity_v2` 價格的交集,不再把非活躍或無 MOMO 現價的舊 competitor_prices 列入覆蓋率,避免 daily/growth/PPT/AI 報表高估比價資料品質。
- V10.315 修正競品簡報/報表指定日期取價:`fetch_competitor_comparison_results()` 在有 start/end date 時改讀 `competitor_price_history` 的期間快照MOMO 價格也取期間結束前最新價;沒有指定日期才使用目前有效 `competitor_prices`,避免把今天的 PChome 快取價塞回歷史 daily/growth/PPT 判讀。
- V10.314 擴大 PChome 候選池與搜尋韌性PChome 搜尋 API 改為依 limit 掃多頁並對 429/5xx/timeout 做有限重試feeder 預設每個商品最多 5 組搜尋詞、每詞 20 候選、2 頁,且搜尋清理不再刪掉括號/方括號內的品牌與規格,讓正確候選更有機會進 matcher而不是長期停在「待對比」。
- V10.312 強化 PChome 商品身份比對防錯配matcher 開始解析 mg/mcg 劑量、件組套組與多規格集合60ml+150ml vs 60ml+20ml、10mg vs 20mg、10片 vs 10盒、精華 vs 化妝水都會進硬否決或單位價覆核,不再靠單一規格重疊放行;覆核診斷同步新增「劑量差異」標籤,降低核心比價錯配污染 daily/growth/PPT/AI 分析。

View File

@@ -320,7 +320,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.316"
SYSTEM_VERSION = "V10.317"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL # 用於模板顯示

View File

@@ -608,3 +608,4 @@ POSTGRES_HOST=momo-db
| 2026-05-20 | PChome 商品身份比對仍可能因單一規格重疊誤放行 | V10.312 起 matcher 解析 mg/mcg 劑量、件組套組、多規格集合與同數字不同單位;劑量/容量/重量/件數/品類衝突會硬否決或導向單位價覆核,避免錯配污染 Dashboard、daily/growth、PPT 與 AI 競價分析 |
| 2026-05-20 | 正確 PChome 候選常因只掃第一頁或搜尋詞丟失品牌/規格而未進入 matcher | V10.314 起搜尋 API 依 limit 掃多頁、對暫時性錯誤有限重試feeder 預設 5 組搜尋詞、20 候選、2 頁,並保留括號/方括號內品牌與規格,提升覆核隊列與正式比價的候選品質 |
| 2026-05-20 | 指定日期競品簡報可能混用目前 `competitor_prices` 快取價 | V10.315 起 `fetch_competitor_comparison_results()` 有 start/end date 時改用 `competitor_price_history` 期間快照MOMO 價格取報表結束日前最新價;即時報表才使用目前有效 `competitor_prices` |
| 2026-05-20 | PChome 覆蓋率分子可能被非活躍或無 MOMO 現價 SKU 膨脹 | V10.317 起 `fetch_competitor_coverage()``valid_matches` 改為 active MOMO latest price 與有效 PChome `identity_v2` 價格交集,確保 daily/growth/PPT/AI 看到的比價資料品質不被舊快取列高估 |

View File

@@ -274,7 +274,7 @@ def _cached_payload(cache_key: str, producer, ttl_seconds: int = COMPETITOR_INTE
def fetch_competitor_coverage(engine) -> dict:
return _cached_payload(
f"coverage:v3:floor={PCHOME_MATCH_SCORE_FLOOR}:manual_reviews=1",
f"coverage:v4:floor={PCHOME_MATCH_SCORE_FLOOR}:manual_reviews=1",
lambda: _fetch_competitor_coverage_uncached(engine),
)
@@ -349,7 +349,10 @@ def _fetch_competitor_coverage_uncached(engine) -> dict:
{attempt_cte}
SELECT
(SELECT COUNT(*) FROM latest_momo WHERE rn = 1) AS active_with_price,
(SELECT COUNT(*) FROM valid_competitor) AS valid_matches,
(SELECT COUNT(*)
FROM latest_momo lm
JOIN valid_competitor vc ON vc.sku = lm.sku
WHERE lm.rn = 1) AS valid_matches,
(SELECT COUNT(*)
FROM latest_momo lm
LEFT JOIN valid_competitor vc ON vc.sku = lm.sku

View File

@@ -69,6 +69,18 @@ def test_competitor_ppt_results_use_history_for_dated_reports():
assert "指定期間 competitor_price_history" in route_source
def test_competitor_coverage_counts_only_active_product_intersection():
source = (ROOT / "services" / "competitor_intel_repository.py").read_text(encoding="utf-8")
coverage_source = source.split("def _fetch_competitor_coverage_uncached", 1)[1].split(
"def _fetch_manual_review_summary", 1
)[0]
assert "coverage:v4" in source
assert "(SELECT COUNT(*) FROM valid_competitor) AS valid_matches" not in coverage_source
assert "FROM latest_momo lm\n JOIN valid_competitor vc ON vc.sku = lm.sku" in coverage_source
assert "WHERE lm.rn = 1) AS valid_matches" in coverage_source
def test_competitor_ppt_and_ai_use_momo_minus_pchome_gap_direction():
ppt_source = (ROOT / "services" / "ppt_generator.py").read_text(encoding="utf-8")
route_source = (ROOT / "routes" / "openclaw_bot_routes.py").read_text(encoding="utf-8")