mirror of
https://github.com/lllin000/PaperForge.git
synced 2026-07-22 06:50:53 +00:00
fix: make non-body families authoritative against body flow
This commit is contained in:
parent
b9b661dbad
commit
f35470fb70
3 changed files with 104 additions and 2 deletions
|
|
@ -515,6 +515,42 @@ def resolve_final_role(
|
|||
],
|
||||
)
|
||||
|
||||
if current_role == "body_paragraph" and style_family:
|
||||
_NON_BODY_FAMILIES = {"reference_like", "table_caption_like", "legend_like", "heading_like", "support_like"}
|
||||
_STRONG_AUTHORITIES = {
|
||||
"figure_marker",
|
||||
"figure_family_anchor",
|
||||
"reference_marker",
|
||||
"reference_family_anchor",
|
||||
"table_marker",
|
||||
"heading_marker",
|
||||
"body_family_anchor",
|
||||
}
|
||||
if style_family in _NON_BODY_FAMILIES and style_family_authority in _STRONG_AUTHORITIES:
|
||||
if (
|
||||
style_family == "legend_like"
|
||||
and _looks_like_late_figure_narrative_prose(str(block.get("text") or ""))
|
||||
):
|
||||
pass # narrative prose stays body_paragraph
|
||||
else:
|
||||
_FAMILY_ROLE_MAP = {
|
||||
"reference_like": "reference_item",
|
||||
"table_caption_like": "table_caption_candidate",
|
||||
"legend_like": "figure_caption_candidate",
|
||||
"heading_like": "section_heading",
|
||||
}
|
||||
mapped_role = _FAMILY_ROLE_MAP.get(style_family)
|
||||
if mapped_role:
|
||||
return RoleAssignment(
|
||||
role=mapped_role,
|
||||
confidence=max(current_confidence, 0.78),
|
||||
evidence=[
|
||||
f"late role resolution: non-body family '{style_family}' overrides body_paragraph",
|
||||
f"style_family_authority={style_family_authority or 'none'}",
|
||||
f"context_source={context_source}",
|
||||
],
|
||||
)
|
||||
|
||||
return RoleAssignment(
|
||||
role=current_role,
|
||||
confidence=current_confidence,
|
||||
|
|
|
|||
|
|
@ -248,8 +248,9 @@ def test_normalize_document_structure_keeps_reference_family_anchor_anchor_first
|
|||
|
||||
assert doc.reference_family_anchor is not None
|
||||
assert doc.reference_family_anchor["status"] == "ACCEPT"
|
||||
assert normalized_blocks[3]["role"] == "body_paragraph"
|
||||
assert normalized_blocks[4]["role"] == "body_paragraph"
|
||||
# Non-body family override: reference_like + reference_family_anchor → reference_item
|
||||
assert normalized_blocks[3]["role"] == "reference_item"
|
||||
assert normalized_blocks[4]["role"] == "reference_item"
|
||||
|
||||
|
||||
def test_normalize_document_structure_wires_style_family_artifacts_into_blocks() -> None:
|
||||
|
|
|
|||
|
|
@ -1353,3 +1353,68 @@ def test_pipeline_does_not_commit_final_semantic_role_before_zone_and_family_par
|
|||
for row in rows:
|
||||
assert "seed_role" in row, f"block {row['block_id']} missing seed_role"
|
||||
assert row["seed_role"] != "unassigned", f"seed_role should never be 'unassigned', got {row['seed_role']}"
|
||||
|
||||
|
||||
def test_body_paragraph_overridden_to_reference_item_when_style_family_is_reference_like():
|
||||
from paperforge.worker.ocr_roles import resolve_final_role
|
||||
|
||||
block = {
|
||||
"role": "body_paragraph",
|
||||
"role_confidence": 0.6,
|
||||
"style_family": "reference_like",
|
||||
"style_family_authority": "reference_marker",
|
||||
"zone": "body_zone",
|
||||
"marker_signature": {"type": "reference_pattern"},
|
||||
}
|
||||
result = resolve_final_role(block)
|
||||
assert result.role == "reference_item"
|
||||
assert result.confidence >= 0.78
|
||||
|
||||
|
||||
def test_body_paragraph_overridden_to_figure_caption_when_style_family_is_legend_like():
|
||||
from paperforge.worker.ocr_roles import resolve_final_role
|
||||
|
||||
block = {
|
||||
"role": "body_paragraph",
|
||||
"role_confidence": 0.6,
|
||||
"style_family": "legend_like",
|
||||
"style_family_authority": "figure_marker",
|
||||
"zone": "body_zone",
|
||||
"marker_signature": {"type": "figure_number"},
|
||||
"text": "Figure 3.",
|
||||
}
|
||||
result = resolve_final_role(block)
|
||||
assert result.role == "figure_caption_candidate"
|
||||
assert result.confidence >= 0.78
|
||||
|
||||
|
||||
def test_body_paragraph_overridden_to_table_caption_when_style_family_is_table_caption_like():
|
||||
from paperforge.worker.ocr_roles import resolve_final_role
|
||||
|
||||
block = {
|
||||
"role": "body_paragraph",
|
||||
"role_confidence": 0.6,
|
||||
"style_family": "table_caption_like",
|
||||
"style_family_authority": "table_marker",
|
||||
"zone": "body_zone",
|
||||
"marker_signature": {"type": "table_number"},
|
||||
"text": "Table 2.",
|
||||
}
|
||||
result = resolve_final_role(block)
|
||||
assert result.role == "table_caption_candidate"
|
||||
assert result.confidence >= 0.78
|
||||
|
||||
|
||||
def test_body_paragraph_survives_when_style_family_authority_is_weak():
|
||||
from paperforge.worker.ocr_roles import resolve_final_role
|
||||
|
||||
block = {
|
||||
"role": "body_paragraph",
|
||||
"role_confidence": 0.6,
|
||||
"style_family": "reference_like",
|
||||
"style_family_authority": "fallback",
|
||||
"zone": "body_zone",
|
||||
"marker_signature": {"type": "none"},
|
||||
}
|
||||
result = resolve_final_role(block)
|
||||
assert result.role == "body_paragraph"
|
||||
|
|
|
|||
Loading…
Reference in a new issue