Optimize PChome review queue paging
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
================================================================================
|
||||
|
||||
【已完成】
|
||||
- V10.444 瘦身 PChome 覆核頁查詢:`fetch_competitor_review_queue_page()` 將覆核隊列總數與當頁資料合併在單一 SQL 內取回,避免 `/?filter=pchome_review` 為 count/page 重複掃 `latest_momo`、`latest_attempt`、`valid_competitor` CTE;保留狀態分流、人工覆核與正式價格寫入保護不變。
|
||||
- V10.443 補 PChome rescore 人工覆核入隊:`audit_competitor_match_attempt_rescore.py --apply-accepted` 只追加 `rescore_accepted_current` attempt 進人工覆核隊列,不直接寫 `competitor_prices` / `competitor_price_history`;商品看板新增「重算可採用」分流與狀態文案,讓可救回候選先由人審確認再正式更新價差。
|
||||
- V10.442 降噪 `/cicd` 舊 GitLab 探測:沒有明確啟用 `GITLAB_ENABLED=true` 與 token 時,不再打退役的 `192.168.0.110:8929` 或 SSH fallback,正式 responsive smoke 造訪 `/cicd` 只呈現空 pipeline 狀態,不污染 app logs。
|
||||
- V10.441 補 PChome matcher re-score audit 與商品看板原因標籤:新增 read-only `competitor_match_attempt_rescore_audit` / `scripts/audit_competitor_match_attempt_rescore.py`,可用最新版 matcher 重新分類既有 `competitor_match_attempts`,預設不寫 DB、不更新正式價格;商品看板同步補蘭蔻/達特醫/hoi/Saugella/Lactacyd 等 focused matcher reason 中文標籤,讓「待對比」能拆成商品線不符、款式版本不符、可回刷或仍低信心。
|
||||
|
||||
@@ -325,7 +325,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
|
||||
# ==========================================
|
||||
# 系統版本與路徑
|
||||
# ==========================================
|
||||
SYSTEM_VERSION = "V10.443"
|
||||
SYSTEM_VERSION = "V10.444"
|
||||
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
|
||||
public_url = PUBLIC_URL # 用於模板顯示
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> **最後更新**: 2026-05-24 (台北時間)
|
||||
> **狀態**: 🟢 四 AI Agent 自動化閉環已落地;LLM 路由紅線升級為 Ollama-first 三主機級聯,Gemini 備援預設關閉
|
||||
> **適用版本**: V10.443
|
||||
> **適用版本**: V10.444
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
## 📅 詳細更新日誌 (考古存檔)
|
||||
|
||||
### 2026-05-24:PChome 近門檻身份回收第二輪
|
||||
- **V10.444 PChome 覆核頁查詢瘦身**: `fetch_competitor_review_queue_page()` 將原本 count + page 兩次重跑 review CTE 改成單次 SQL 的 `total_rows` + `paged_rows` 查詢,同步取得總數與頁面資料,降低 `/?filter=pchome_review` 對 `latest_momo` / `latest_attempt` / `valid_competitor` 的重複掃描;正式站小批次 rescore 入隊後,用於維持核心比價覆核頁可操作速度。
|
||||
- **V10.443 PChome rescore 人工覆核入隊**: `scripts/audit_competitor_match_attempt_rescore.py --apply-accepted` 只會把最新版 matcher 已通過門檻的舊低信心候選追加為 `rescore_accepted_current` attempt,進入商品看板人工覆核隊列;不寫 `competitor_prices`、不寫 `competitor_price_history`,必須由操作員按「採用同款」後才正式更新 PChome 價差。Dashboard 補上「重算可採用待審」分流與狀態文案,避免安全回刷候選混在一般低信心項目裡。
|
||||
- **V10.442 CI/CD legacy GitLab 探測降噪**: `/cicd` 舊 GitLab pipeline API 預設改為 disabled,除非明確設定 `GITLAB_ENABLED=true` 並提供 `GITLAB_TOKEN`,否則不再打 `192.168.0.110:8929` 或 SSH fallback;正式 responsive smoke 造訪 `/cicd` 時只呈現可診斷空狀態,不再把已退役 GitLab endpoint 的 connection refused / permission denied 寫成錯誤噪音。
|
||||
- **V10.441 PChome matcher re-score audit**: 新增 read-only `competitor_match_attempt_rescore_audit` 服務與 `scripts/audit_competitor_match_attempt_rescore.py`,可針對既有 `competitor_match_attempts` 用最新版 matcher 重新分類成 `accepted_current` / `unit_comparable_current` / `identity_veto_current` / `low_score_current`,預設不寫 DB、不更新正式價格;商品看板同步補蘭蔻/達特醫/hoi/Saugella/Lactacyd 等 focused matcher reason 中文標籤。正式抽樣中 31 筆舊 `strong_exact_spec_match` 低信心資料,最新版 matcher 可讀出 10 筆 gate pass、1 筆單位價、11 筆 hard veto、9 筆仍低信心,作為後續人工覆核與批次回刷前的安全量化。
|
||||
|
||||
@@ -961,24 +961,33 @@ def _fetch_competitor_review_queue_page_uncached(
|
||||
"limit": per_page,
|
||||
"offset": (page - 1) * per_page,
|
||||
}
|
||||
count_sql = text(cte + " SELECT COUNT(*) AS total FROM review_rows")
|
||||
page_sql = text(cte + """
|
||||
SELECT *
|
||||
FROM review_rows
|
||||
ORDER BY
|
||||
priority_rank ASC,
|
||||
momo_price DESC NULLS LAST,
|
||||
best_match_score DESC NULLS LAST,
|
||||
attempted_at DESC NULLS LAST
|
||||
LIMIT :limit OFFSET :offset
|
||||
, total_rows AS (
|
||||
SELECT COUNT(*) AS total_count
|
||||
FROM review_rows
|
||||
),
|
||||
paged_rows AS (
|
||||
SELECT *
|
||||
FROM review_rows
|
||||
ORDER BY
|
||||
priority_rank ASC,
|
||||
momo_price DESC NULLS LAST,
|
||||
best_match_score DESC NULLS LAST,
|
||||
attempted_at DESC NULLS LAST
|
||||
LIMIT :limit OFFSET :offset
|
||||
)
|
||||
SELECT paged_rows.*, total_rows.total_count
|
||||
FROM total_rows
|
||||
LEFT JOIN paged_rows ON TRUE
|
||||
""")
|
||||
|
||||
with engine.connect() as conn:
|
||||
total = int(conn.execute(count_sql, params).scalar() or 0)
|
||||
rows = conn.execute(page_sql, page_params).mappings().all()
|
||||
total = int(rows[0].get("total_count") or 0) if rows else 0
|
||||
item_rows = [dict(row) for row in rows if row.get("sku")]
|
||||
|
||||
return {
|
||||
"items": [_format_competitor_review_item(dict(row)) for row in rows],
|
||||
"items": [_format_competitor_review_item(row) for row in item_rows],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"per_page": per_page,
|
||||
|
||||
@@ -39,6 +39,22 @@ def test_competitor_dashboard_hot_paths_use_latest_price_lateral_lookup():
|
||||
assert "lm.rn = 1" not in body
|
||||
|
||||
|
||||
def test_competitor_review_queue_page_uses_single_paged_total_query():
|
||||
source = (ROOT / "services/competitor_intel_repository.py").read_text(encoding="utf-8")
|
||||
page_body = _function_body(
|
||||
source,
|
||||
"_fetch_competitor_review_queue_page_uncached",
|
||||
"_fetch_competitor_review_queue_uncached",
|
||||
)
|
||||
|
||||
assert "total_rows AS" in page_body
|
||||
assert "paged_rows AS" in page_body
|
||||
assert "LEFT JOIN paged_rows ON TRUE" in page_body
|
||||
assert "SELECT COUNT(*) AS total FROM review_rows" not in page_body
|
||||
assert "rows[0].get(\"total_count\")" in page_body
|
||||
assert "if row.get(\"sku\")" in page_body
|
||||
|
||||
|
||||
def test_competitor_feeder_persists_all_match_attempt_outcomes():
|
||||
source = (ROOT / "services/competitor_price_feeder.py").read_text(encoding="utf-8")
|
||||
migration = (ROOT / "migrations/023_competitor_match_attempts.sql").read_text(encoding="utf-8")
|
||||
|
||||
Reference in New Issue
Block a user