refactor(ocr): split legacy and vnext figure entrypoints

This commit is contained in:
LLLin000 2026-07-03 12:01:11 +08:00
parent 3feabf1569
commit f95925b226
3 changed files with 103 additions and 0 deletions

View file

@ -2978,6 +2978,29 @@ def _infer_missing_main_figure_numbers(
def build_figure_inventory(structured_blocks: list[dict], page_width: float = 1200, page_pdf_lines_by_page: dict[int, list[dict]] | None = None) -> dict[str, Any]:
return build_figure_inventory_legacy(structured_blocks, page_width, page_pdf_lines_by_page)
def build_figure_inventory_vnext(structured_blocks: list[dict], page_width: float = 1200, page_pdf_lines_by_page: dict[int, list[dict]] | None = None) -> dict[str, Any]:
return {
"pipeline_mode": "vnext",
"matched_figures": [],
"ambiguous_figures": [],
"unmatched_legends": [],
"unmatched_assets": [],
"unresolved_clusters": [],
"held_figures": [],
"rejected_legends": [],
"page_ledger": {},
"residual_ledger": {},
"local_pairing_hypotheses": [],
"completeness": {
"total_numbered_legends": 0,
"accounted_for": 0,
"details": [],
},
}
def build_figure_inventory_legacy(structured_blocks: list[dict], page_width: float = 1200, page_pdf_lines_by_page: dict[int, list[dict]] | None = None) -> dict[str, Any]:
legends: list[dict] = []
held_figures: list[dict] = []
rejected_legends: list[dict] = []

View file

@ -0,0 +1,45 @@
from __future__ import annotations
import json
from pathlib import Path
from paperforge.worker.ocr_figures import (
build_figure_inventory_legacy,
build_figure_inventory_vnext,
)
def _figure_asset_ids(fig: dict[str, object]) -> list[str]:
ids = {str(x) for x in fig.get("asset_block_ids", [])}
ids.update(str(asset.get("block_id", "")) for asset in fig.get("matched_assets", []))
return sorted(x for x in ids if x)
def compare_inventories(legacy: dict[str, object], vnext: dict[str, object]) -> dict[str, object]:
return {
"legacy_matched_count": len(legacy.get("matched_figures", [])),
"vnext_matched_count": len(vnext.get("matched_figures", [])),
"legacy_unresolved_count": len(legacy.get("unresolved_clusters", [])),
"vnext_unresolved_count": len(vnext.get("unresolved_clusters", [])),
"legacy_unmatched_legend_count": len(legacy.get("unmatched_legends", [])),
"vnext_unmatched_legend_count": len(vnext.get("unmatched_legends", [])),
"legacy_consumed_block_ids": sorted(
{bid for fig in legacy.get("matched_figures", []) for bid in _figure_asset_ids(fig)}
),
"vnext_consumed_block_ids": sorted(
{bid for fig in vnext.get("matched_figures", []) for bid in _figure_asset_ids(fig)}
),
}
def main(blocks_path: str) -> int:
blocks = [json.loads(line) for line in Path(blocks_path).read_text(encoding="utf-8").splitlines() if line.strip()]
legacy = build_figure_inventory_legacy(blocks)
vnext = build_figure_inventory_vnext(blocks)
print(json.dumps(compare_inventories(legacy, vnext), ensure_ascii=False, indent=2))
return 0
if __name__ == "__main__":
import sys
raise SystemExit(main(sys.argv[1]))

View file

@ -6424,3 +6424,38 @@ def test_recover_internal_figure_number_inside_overlap_gate():
# Line that covers >15% of asset -> edge_band_score = 0
large_line = [100, 100, 500, 600] # covers large area
assert _asset_edge_band_score(large_line, asset) == 0.0
# --- Task 1: Legacy/vnext mechanical split ---
def test_build_figure_inventory_wrapper_stays_legacy_path(monkeypatch):
from paperforge.worker import ocr_figures
called = {"legacy": 0, "vnext": 0}
def fake_legacy(*args, **kwargs):
called["legacy"] += 1
return {"source": "legacy"}
def fake_vnext(*args, **kwargs):
called["vnext"] += 1
return {"source": "vnext"}
monkeypatch.setattr(ocr_figures, "build_figure_inventory_legacy", fake_legacy)
monkeypatch.setattr(ocr_figures, "build_figure_inventory_vnext", fake_vnext)
result = ocr_figures.build_figure_inventory([], 1200)
assert result == {"source": "legacy"}
assert called == {"legacy": 1, "vnext": 0}
def test_vnext_entrypoint_is_callable_without_cutover():
from paperforge.worker.ocr_figures import build_figure_inventory_vnext
result = build_figure_inventory_vnext([], 1200)
assert isinstance(result, dict)
assert result.get("pipeline_mode") == "vnext"
assert result.get("matched_figures") == []