feat: persist role_span_profiles.json and wire into rebuild pipeline

This commit is contained in:
Research Assistant 2026-06-06 11:16:43 +08:00
parent 5320e825ee
commit 94de2dbbc7
4 changed files with 40 additions and 0 deletions

View file

@ -1754,6 +1754,9 @@ def postprocess_ocr_result(vault: Path, key: str, all_results: list[dict]) -> tu
write_raw_blocks_jsonl(artifacts.blocks_raw, all_raw_blocks)
structured = build_structured_blocks(all_raw_blocks)
write_structured_blocks_jsonl(artifacts.blocks_structured, structured)
# Write role-level span profiles
from paperforge.worker.ocr_profiles import write_role_span_profiles
write_role_span_profiles(structured, artifacts.blocks_structured.parent)
# --- Phase 2: metadata resolution ---
metadata_dir = ocr_root / "metadata"

View file

@ -6,6 +6,9 @@ profile-quality scoring, span cross-validation, role-family comparison.
from __future__ import annotations
import json
from pathlib import Path
def extract_block_span_profile(block: dict) -> dict | None:
"""Extract a normalized style profile dict from a block's span_metadata.
@ -231,3 +234,18 @@ def cross_validate_with_span(
"suggested_roles": suggested_roles,
"match_details": {tentative_role: current_match},
}
def write_role_span_profiles(
blocks: list[dict],
output_dir: str | Path,
) -> Path:
"""Build and write role_span_profiles.json.
Returns the path to the written file.
"""
profiles = build_role_span_profiles(blocks)
output_path = Path(output_dir) / "role_span_profiles.json"
with open(output_path, "w", encoding="utf-8") as f:
json.dump(profiles, f, indent=2, ensure_ascii=False)
return output_path

View file

@ -60,6 +60,9 @@ def run_derived_rebuild_for_keys(vault: Path, keys: list[str]) -> dict:
structured = build_structured_blocks(all_raw_blocks)
write_structured_blocks_jsonl(artifacts.blocks_structured, structured)
# Write role-level span profiles
from paperforge.worker.ocr_profiles import write_role_span_profiles
write_role_span_profiles(structured, artifacts.blocks_structured.parent)
# Read source metadata
source_meta = read_json(artifacts.source_metadata) if artifacts.source_metadata.exists() else {}

View file

@ -103,3 +103,19 @@ def test_build_structured_blocks_carries_span_metadata() -> None:
]
rows = build_structured_blocks(raw_blocks)
assert rows[0].get("span_metadata") == span_data
def test_role_span_profiles_written_to_output() -> None:
"""Verify that role_span_profiles.json is written during rebuild."""
import json
from paperforge.worker.ocr_profiles import build_role_span_profiles
blocks = [
{"role": "section_heading", "span_metadata": {"size": 16.0, "flags": "bold"}},
{"role": "body_paragraph", "span_metadata": {"size": 10.0, "flags": 0}},
]
profiles = build_role_span_profiles(blocks)
# Must be JSON-serializable
dumped = json.dumps(profiles)
assert "section_heading" in dumped
assert "body_paragraph" in dumped