feat(crawler): read back pixelrag visual evidence

This commit is contained in:
ogt
2026-07-09 17:39:33 +08:00
parent 14a8a2052d
commit 1a435b4c78
4 changed files with 286 additions and 0 deletions

View File

@@ -2,6 +2,7 @@ import json
import shutil
import subprocess
import sys
from datetime import datetime, timezone
import pytest
@@ -234,6 +235,107 @@ def test_pixelrag_ai_automation_route_returns_assessment_and_manifest():
assert manifest["capture_target"]["platform"] == "pchome"
def _write_capture_receipt(root, *, platform="pchome", manifest_id="manifest-1"):
target_dir = root / platform / manifest_id
tiles_dir = target_dir / "tiles"
tiles_dir.mkdir(parents=True)
screenshot = target_dir / "fullpage.png"
tile_0 = tiles_dir / "tile_000.png"
tile_1 = tiles_dir / "tile_001.png"
screenshot.write_bytes(b"png")
tile_0.write_bytes(b"png")
tile_1.write_bytes(b"png")
receipt = {
"success": True,
"policy": "read_only_pixelrag_visual_capture_artifact_v1",
"status": "captured",
"generated_at": datetime.now(timezone.utc).isoformat(),
"manifest_id": manifest_id,
"capture_target": {
"platform": platform,
"crawler": "PChomeCrawler.visual_fallback",
"trigger_reason": "parser_empty",
"url": "https://24h.pchome.com.tw/",
},
"http_status": 200,
"page_metrics": {
"final_url": "https://24h.pchome.com.tw/",
"title": "PChome 24h購物",
},
"tile_plan": {
"planned_tile_count": 6,
"emitted_tile_count": 2,
},
"files": [
{"kind": "fullpage_screenshot", "path": str(screenshot)},
{"kind": "tile", "path": str(tile_0)},
{"kind": "tile", "path": str(tile_1)},
],
}
(target_dir / "capture_receipt.json").write_text(
json.dumps(receipt, ensure_ascii=False),
encoding="utf-8",
)
return target_dir / "capture_receipt.json"
def test_pixelrag_visual_evidence_readback_reports_latest_receipt(tmp_path):
from services.pixelrag_crawler_integration_service import (
READBACK_POLICY,
build_pixelrag_visual_evidence_readback,
)
receipt_path = _write_capture_receipt(tmp_path)
payload = build_pixelrag_visual_evidence_readback(
artifact_root=tmp_path,
platform="pchome",
manifest_id="manifest-1",
)
assert payload["policy"] == READBACK_POLICY
assert payload["status"] == "ok"
assert payload["summary"]["receipt_count"] == 1
assert payload["summary"]["tile_file_count"] == 2
assert payload["summary"]["missing_file_count"] == 0
assert payload["summary"]["http_status"] == 200
assert payload["latest_receipt"]["path"] == str(receipt_path)
assert payload["next_machine_action"] == "keep_pixelrag_visual_evidence_receipt"
assert payload["controlled_apply"]["db_write"] is False
def test_pixelrag_visual_evidence_readback_warns_when_missing(tmp_path):
from services.pixelrag_crawler_integration_service import build_pixelrag_visual_evidence_readback
payload = build_pixelrag_visual_evidence_readback(artifact_root=tmp_path, platform="momo")
assert payload["success"] is False
assert payload["status"] == "warning"
assert payload["summary"]["receipt_count"] == 0
assert payload["next_machine_action"] == "run_pixelrag_visual_capture_worker"
def test_pixelrag_visual_evidence_readback_route_returns_payload(tmp_path, monkeypatch):
from flask import Flask
from routes import system_public_routes as routes
from services import pixelrag_crawler_integration_service as service
_write_capture_receipt(tmp_path, platform="pchome", manifest_id="route-manifest")
monkeypatch.setattr(service, "DEFAULT_ARTIFACT_ROOT", str(tmp_path))
app = Flask(__name__)
with app.test_request_context(
"/api/ai-automation/pixelrag-visual-evidence-readback"
"?platform=pchome&manifest_id=route-manifest&max_age_hours=999"
):
response = routes.ai_automation_pixelrag_visual_evidence_readback_api.__wrapped__()
payload = response.get_json()
assert payload["policy"] == "read_only_pixelrag_visual_evidence_readback_v1"
assert payload["status"] == "ok"
assert payload["manifest_id"] == "route-manifest"
assert payload["summary"]["tile_file_count"] == 2
def test_pixelrag_capture_worker_dry_run_plans_artifact_outputs(tmp_path):
if not shutil.which("node"):
pytest.skip("node is required for the dry-run capture worker test")