feat: persist document_structure.json, thread structure truth through downstream pipeline

This commit is contained in:
Research Assistant 2026-06-06 13:10:56 +08:00
parent 674809a2ae
commit 2bf7e73fff
3 changed files with 38 additions and 3 deletions

View file

@ -1760,7 +1760,10 @@ def postprocess_ocr_result(vault: Path, key: str, all_results: list[dict]) -> tu
backfill_span_metadata_from_pdf(all_raw_blocks, source_pdf_path)
write_raw_blocks_jsonl(artifacts.blocks_raw, all_raw_blocks)
structured = build_structured_blocks(all_raw_blocks)
structured = build_structured_blocks(
all_raw_blocks,
structure_output_dir=artifacts.blocks_structured.parent,
)
write_structured_blocks_jsonl(artifacts.blocks_structured, structured)
# Write role-level span profiles
from paperforge.worker.ocr_profiles import write_role_span_profiles

View file

@ -7,7 +7,10 @@ from typing import Any
from paperforge.worker.ocr_roles import assign_block_role
def build_structured_blocks(raw_blocks: list[dict]) -> list[dict]:
def build_structured_blocks(
raw_blocks: list[dict],
structure_output_dir: str | Path | None = None,
) -> list[dict]:
# Group raw blocks by page so assign_block_role can see page-local context
by_page: dict[int, list[dict]] = {}
for block in raw_blocks:
@ -86,9 +89,35 @@ def build_structured_blocks(raw_blocks: list[dict]) -> list[dict]:
rows = rescue_roles_with_document_context(rows, paper_context["role_profiles"], doc_structure)
# Persist document structure artifact for downstream debugging
if doc_structure and structure_output_dir:
_write_document_structure_json(doc_structure, structure_output_dir)
return rows
def _write_document_structure_json(doc_structure, output_dir: str | Path) -> None:
"""Serialize DocumentStructure to JSON for downstream inspection."""
import dataclasses
if hasattr(doc_structure, "_asdict"):
data = doc_structure._asdict()
elif dataclasses.is_dataclass(doc_structure):
data = dataclasses.asdict(doc_structure)
else:
return
# Convert non-serializable types
for k, v in data.items():
if hasattr(v, "_asdict"):
data[k] = v._asdict()
elif dataclasses.is_dataclass(v):
data[k] = dataclasses.asdict(v)
output_path = Path(output_dir) / "document_structure.json"
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
def write_structured_blocks_jsonl(path: Path, rows: list[dict]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w", encoding="utf-8") as f:

View file

@ -67,7 +67,10 @@ def run_derived_rebuild_for_keys(vault: Path, keys: list[str]) -> dict:
# Rebuild structured blocks
from paperforge.worker.ocr_blocks import build_structured_blocks, write_structured_blocks_jsonl
structured = build_structured_blocks(all_raw_blocks)
structured = build_structured_blocks(
all_raw_blocks,
structure_output_dir=artifacts.blocks_structured.parent,
)
write_structured_blocks_jsonl(artifacts.blocks_structured, structured)
# Write role-level span profiles
from paperforge.worker.ocr_profiles import write_role_span_profiles