Optimize PChome review queue paging
Some checks failed
CD Pipeline / deploy (push) Has been cancelled

This commit is contained in:
OoO
2026-05-24 18:31:26 +08:00
parent 5aa2412dee
commit 5d4927c119
6 changed files with 40 additions and 13 deletions

View File

@@ -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 中文標籤,讓「待對比」能拆成商品線不符、款式版本不符、可回刷或仍低信心。

View File

@@ -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 # 用於模板顯示

View File

@@ -2,7 +2,7 @@
> **最後更新**: 2026-05-24 (台北時間)
> **狀態**: 🟢 四 AI Agent 自動化閉環已落地LLM 路由紅線升級為 Ollama-first 三主機級聯Gemini 備援預設關閉
> **適用版本**: V10.443
> **適用版本**: V10.444
---

View File

@@ -13,6 +13,7 @@
## 📅 詳細更新日誌 (考古存檔)
### 2026-05-24PChome 近門檻身份回收第二輪
- **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 筆仍低信心,作為後續人工覆核與批次回刷前的安全量化。

View File

@@ -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,

View File

@@ -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")