feat(ai): 建立 PixelRAG OCR VLM replay contract
Some checks failed
CD Pipeline / deploy (push) Has been cancelled

This commit is contained in:
ogt
2026-07-09 23:01:54 +08:00
parent 48c978b455
commit 440b199135
12 changed files with 739 additions and 14 deletions

View File

@@ -1310,11 +1310,12 @@ def test_collect_ai_automation_smoke_uses_worst_status(monkeypatch):
monkeypatch.setattr(smoke, "_sitewide_visual_qa_check", lambda: smoke._check("visual", "ok", "ok"))
monkeypatch.setattr(smoke, "_external_mcp_rag_integration_check", lambda: smoke._check("external mcp rag", "ok", "ok"))
monkeypatch.setattr(smoke, "_pixelrag_rag_candidate_replay_check", lambda: smoke._check("pixelrag replay", "ok", "ok"))
monkeypatch.setattr(smoke, "_pixelrag_ocr_vlm_replay_check", lambda: smoke._check("pixelrag ocr vlm", "ok", "ok"))
result = smoke.collect_ai_automation_smoke(record_history=False)
assert result["status"] == "critical"
assert result["summary"] == {"ok": 30, "warning": 1, "critical": 1, "total": 32}
assert result["summary"] == {"ok": 31, "warning": 1, "critical": 1, "total": 33}
def test_pchome_controlled_apply_drift_monitor_reports_verified_zero_drift(monkeypatch):
@@ -3843,6 +3844,7 @@ def test_collect_ai_automation_smoke_persists_recent_history(tmp_path, monkeypat
monkeypatch.setattr(smoke, "_sitewide_visual_qa_check", lambda: smoke._check("visual", "ok", "ok"))
monkeypatch.setattr(smoke, "_external_mcp_rag_integration_check", lambda: smoke._check("external mcp rag", "ok", "ok"))
monkeypatch.setattr(smoke, "_pixelrag_rag_candidate_replay_check", lambda: smoke._check("pixelrag replay", "ok", "ok"))
monkeypatch.setattr(smoke, "_pixelrag_ocr_vlm_replay_check", lambda: smoke._check("pixelrag ocr vlm", "ok", "ok"))
first = smoke.collect_ai_automation_smoke(history_limit=5)
second = smoke.collect_ai_automation_smoke(history_limit=5)
@@ -3898,7 +3900,7 @@ def test_scheduled_automation_health_summary_reads_history_without_side_effects(
json.dumps({
"generated_at": datetime.now().isoformat(timespec="seconds"),
"status": "ok",
"summary": {"ok": 32, "warning": 0, "critical": 0, "total": 32},
"summary": {"ok": 33, "warning": 0, "critical": 0, "total": 33},
"checks": [
{
"name": "PChome 受控落地 drift monitor",
@@ -4006,6 +4008,23 @@ def test_scheduled_automation_health_summary_reads_history_without_side_effects(
"blocked_pages_are_not_product_data": True,
"next_machine_action": "run_ocr_vlm_replay_then_promotion_gate",
},
},
{
"name": "PixelRAG OCR/VLM replay contract",
"status": "ok",
"summary": "PixelRAG OCR/VLM replay contract receipts=1, ready=1, blocked=0, invalid=0, field_contracts=7",
"details": {
"policy": "read_only_pixelrag_ocr_vlm_replay_contract_v1",
"receipt_count": 1,
"replay_ready_count": 1,
"blocked_count": 0,
"invalid_count": 0,
"tile_input_count": 4,
"field_contract_count": 7,
"extraction_execution_performed": False,
"blocked_pages_are_not_product_data": True,
"next_machine_action": "run_ollama_first_vlm_replay_worker",
},
}
],
}, ensure_ascii=False) + "\n",
@@ -4024,7 +4043,7 @@ def test_scheduled_automation_health_summary_reads_history_without_side_effects(
)
assert summary["policy"] == "read_only_ai_automation_scheduled_health_summary"
assert summary["status"] == "ok"
assert summary["summary"]["total"] == 29
assert summary["summary"]["total"] == 30
assert summary["summary"]["primary_human_gate_count"] == 0
assert summary["summary"]["writes_database_count"] == 0
assert pchome_family["status"] == "ok"
@@ -5700,6 +5719,13 @@ def test_scheduled_automation_health_summary_reads_history_without_side_effects(
)
assert pixelrag_rag_replay_family["status"] == "ok"
assert pixelrag_rag_replay_family["details"]["eligible_count"] == 1
pixelrag_ocr_vlm_replay_family = next(
item for item in summary["families"]
if item["key"] == "pixelrag_ocr_vlm_replay"
)
assert pixelrag_ocr_vlm_replay_family["status"] == "ok"
assert pixelrag_ocr_vlm_replay_family["details"]["replay_ready_count"] == 1
assert pixelrag_ocr_vlm_replay_family["details"]["extraction_execution_performed"] is False
assert summary["scheduled_outputs"]["telegram_send_in_preview"] is False
assert summary["scheduled_outputs"]["writes_database"] is False
assert summary["automation_policy"]["primary_flow"] == "ai_controlled"
@@ -6316,6 +6342,11 @@ def test_surface_html_readback_check_is_part_of_ai_smoke(monkeypatch):
"ok",
"pixelrag replay ok",
))
monkeypatch.setattr(smoke, "_pixelrag_ocr_vlm_replay_check", lambda: smoke._check(
"PixelRAG OCR/VLM replay contract",
"ok",
"pixelrag ocr vlm ok",
))
result = smoke.collect_ai_automation_smoke(record_history=False)
@@ -6331,7 +6362,7 @@ def test_surface_html_readback_check_is_part_of_ai_smoke(monkeypatch):
item for item in result["checks"]
if item["name"] == "Sitewide visual QA readback"
)
assert result["summary"]["total"] == 32
assert result["summary"]["total"] == 33
assert surface_check["status"] == "ok"
assert surface_check["details"]["checked_surface_count"] == 10
assert sitewide_check["status"] == "ok"

View File

@@ -0,0 +1,144 @@
import json
import subprocess
import sys
from datetime import datetime, timezone
def _write_receipt(root, *, platform, manifest_id, title, url, http_status=200):
receipt_dir = root / platform / manifest_id
tiles_dir = receipt_dir / "tiles"
tiles_dir.mkdir(parents=True)
screenshot = receipt_dir / "screenshot.png"
screenshot.write_bytes(b"png")
files = [{"kind": "screenshot", "path": str(screenshot)}]
for index in range(4):
tile = tiles_dir / f"tile-{index}.png"
tile.write_bytes(b"tile")
files.append({"kind": "tile", "path": str(tile)})
receipt = {
"generated_at": datetime.now(timezone.utc).isoformat(),
"status": "captured",
"manifest_id": manifest_id,
"http_status": http_status,
"capture_target": {
"platform": platform,
"url": url,
"crawler": "PixelRAGMarketplaceSearch.visual_fallback",
},
"page_metrics": {
"title": title,
"final_url": url,
},
"tile_plan": {
"planned_tile_count": 4,
"emitted_tile_count": 4,
},
"files": files,
}
path = receipt_dir / "capture_receipt.json"
path.write_text(json.dumps(receipt, ensure_ascii=False), encoding="utf-8")
return path
def test_pixelrag_ocr_vlm_replay_contract_splits_ready_and_blocked_receipts(tmp_path):
from services.pixelrag_ocr_vlm_replay_service import (
POLICY,
build_pixelrag_ocr_vlm_replay_contract,
)
_write_receipt(
tmp_path,
platform="shopee_tw",
manifest_id="shopee-ok",
title="Shopee 防曬乳",
url="https://shopee.tw/search?keyword=%E9%98%B2%E6%9B%AC%E4%B9%B3",
)
_write_receipt(
tmp_path,
platform="coupang_tw",
manifest_id="coupang-403",
title="Access Denied",
url="https://www.tw.coupang.com/search?q=iphone",
http_status=403,
)
payload = build_pixelrag_ocr_vlm_replay_contract(artifact_root=tmp_path)
by_platform = {item["platform"]: item for item in payload["replay_items"]}
assert payload["policy"] == POLICY
assert payload["status"] == "warning"
assert payload["summary"]["receipt_count"] == 2
assert payload["summary"]["replay_ready_count"] == 1
assert payload["summary"]["blocked_count"] == 1
assert payload["summary"]["extraction_execution_performed"] is False
assert by_platform["shopee_tw"]["replay_status"] == "ready_for_ocr_vlm_replay"
assert by_platform["shopee_tw"]["ready_for_ollama_vlm_worker"] is True
assert len(by_platform["shopee_tw"]["input_tiles"]) == 4
assert "price" in {
field["field"] for field in by_platform["shopee_tw"]["field_contract"]
}
assert by_platform["coupang_tw"]["replay_status"] == "blocked"
assert by_platform["coupang_tw"]["next_machine_action"] == (
"run_platform_probe_or_use_structured_api"
)
assert payload["model_route_contract"]["hosted_vlm_api_allowed"] is False
assert payload["replay_contract"]["writes_price_tables"] is False
assert payload["controlled_apply"]["primary_human_gate_count"] == 0
def test_pixelrag_ocr_vlm_replay_cli_outputs_machine_readable_json(tmp_path):
_write_receipt(
tmp_path,
platform="shopee_tw",
manifest_id="shopee-ok",
title="Shopee 防曬乳",
url="https://shopee.tw/search?keyword=sunscreen",
)
completed = subprocess.run(
[
sys.executable,
"scripts/ops/report_pixelrag_ocr_vlm_replay.py",
"--artifact-root",
str(tmp_path),
"--platform",
"shopee_tw",
],
capture_output=True,
check=False,
text=True,
)
assert completed.returncode == 0
payload = json.loads(completed.stdout)
assert payload["summary"]["receipt_count"] == 1
assert payload["summary"]["replay_ready_count"] == 1
assert payload["replay_items"][0]["platform"] == "shopee_tw"
assert payload["replay_items"][0]["automation_boundary"]["vlm_execution_performed"] is False
def test_pixelrag_ocr_vlm_replay_route_returns_readback(tmp_path, monkeypatch):
from flask import Flask
from routes import system_public_routes as routes
from services import pixelrag_ocr_vlm_replay_service as service
_write_receipt(
tmp_path,
platform="shopee_tw",
manifest_id="shopee-ok",
title="Shopee 防曬乳",
url="https://shopee.tw/search?keyword=sunscreen",
)
monkeypatch.setattr(service, "DEFAULT_ARTIFACT_ROOT", str(tmp_path))
app = Flask(__name__)
with app.test_request_context(
"/api/ai-automation/pixelrag-ocr-vlm-replay?platform=shopee_tw"
):
response = routes.ai_automation_pixelrag_ocr_vlm_replay_api.__wrapped__()
payload = response.get_json()
assert payload["policy"] == "read_only_pixelrag_ocr_vlm_replay_contract_v1"
assert payload["summary"]["receipt_count"] == 1
assert payload["summary"]["replay_ready_count"] == 1
assert payload["replay_contract"]["writes_database"] is False