mirror of
https://github.com/lllin000/PaperForge.git
synced 2026-07-22 06:50:53 +00:00
Revert "revert: restore original Phase 2 figure/table matching logic"
This reverts commit 0a2988b89f.
This commit is contained in:
parent
0a2988b89f
commit
2e2e8cb8e4
2 changed files with 369 additions and 5 deletions
|
|
@ -74,3 +74,149 @@ def test_unmatched_assets_are_preserved() -> None:
|
|||
|
||||
assert inventory["official_figure_count"] == 0
|
||||
assert len(inventory["unmatched_assets"]) == 1
|
||||
|
||||
|
||||
def test_extract_figure_number_basic() -> None:
|
||||
from paperforge.worker.ocr_figures import _extract_figure_number
|
||||
assert _extract_figure_number("Figure 1. Caption") == 1
|
||||
|
||||
|
||||
def test_extract_figure_number_fig_dot() -> None:
|
||||
from paperforge.worker.ocr_figures import _extract_figure_number
|
||||
assert _extract_figure_number("Fig. 2. Test") == 2
|
||||
|
||||
|
||||
def test_extract_figure_number_supplementary() -> None:
|
||||
from paperforge.worker.ocr_figures import _extract_figure_number
|
||||
assert _extract_figure_number("Supplementary Fig. S3") == 3
|
||||
|
||||
|
||||
def test_extract_figure_number_extended_data() -> None:
|
||||
from paperforge.worker.ocr_figures import _extract_figure_number
|
||||
assert _extract_figure_number("Extended Data Fig. 4.") == 4
|
||||
|
||||
|
||||
def test_extract_figure_number_decimal_truncated() -> None:
|
||||
from paperforge.worker.ocr_figures import _extract_figure_number
|
||||
result = _extract_figure_number("Figure 1.2. Magnified view")
|
||||
assert result == 1 or result == 1.2
|
||||
|
||||
|
||||
def test_extract_figure_number_none() -> None:
|
||||
from paperforge.worker.ocr_figures import _extract_figure_number
|
||||
assert _extract_figure_number("Some random text") is None
|
||||
|
||||
|
||||
def test_extract_figure_number_multiline() -> None:
|
||||
from paperforge.worker.ocr_figures import _extract_figure_number
|
||||
assert _extract_figure_number("Figure 3.\nDescription continues") == 3
|
||||
|
||||
|
||||
def test_formal_legend_detection_explicit_figure_prefix() -> None:
|
||||
from paperforge.worker.ocr_figures import build_figure_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "K001",
|
||||
"page": 1,
|
||||
"block_id": "p1_b1",
|
||||
"role": "figure_caption",
|
||||
"text": "Figure 1. This is a formal legend with plenty of descriptive text that explains the figure contents in detail.",
|
||||
"bbox": [50, 400, 550, 450],
|
||||
},
|
||||
{
|
||||
"paper_id": "K001",
|
||||
"page": 1,
|
||||
"block_id": "p1_b2",
|
||||
"role": "figure_asset",
|
||||
"text": "",
|
||||
"bbox": [50, 50, 550, 380],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_figure_inventory(structured_blocks)
|
||||
|
||||
assert len(inventory["matched_figures"]) == 1
|
||||
assert inventory["matched_figures"][0]["figure_number"] == 1
|
||||
assert len(inventory["matched_figures"][0]["matched_assets"]) == 1
|
||||
assert inventory["matched_figures"][0]["confidence"] == 0.85
|
||||
|
||||
|
||||
def test_candidate_legend_geometry_match() -> None:
|
||||
from paperforge.worker.ocr_figures import build_figure_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "K001",
|
||||
"page": 1,
|
||||
"block_id": "p1_b1",
|
||||
"role": "figure_caption",
|
||||
"text": "Figure 1. Formal legend that establishes a width profile.",
|
||||
"bbox": [50, 420, 550, 460],
|
||||
},
|
||||
{
|
||||
"paper_id": "K001",
|
||||
"page": 1,
|
||||
"block_id": "p1_b2",
|
||||
"role": "figure_caption",
|
||||
"text": "No figure prefix but short and profile-matched",
|
||||
"bbox": [60, 350, 540, 380],
|
||||
},
|
||||
{
|
||||
"paper_id": "K001",
|
||||
"page": 1,
|
||||
"block_id": "p1_b3",
|
||||
"role": "figure_asset",
|
||||
"text": "",
|
||||
"bbox": [60, 50, 540, 330],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_figure_inventory(structured_blocks)
|
||||
|
||||
assert len(inventory["matched_figures"]) == 2
|
||||
match_texts = [m["text"] for m in inventory["matched_figures"]]
|
||||
assert any("No figure prefix" in t for t in match_texts)
|
||||
|
||||
|
||||
def test_legend_only_figure_no_asset_match() -> None:
|
||||
from paperforge.worker.ocr_figures import build_figure_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "K001",
|
||||
"page": 2,
|
||||
"block_id": "p2_b1",
|
||||
"role": "figure_caption",
|
||||
"text": "Figure 2. This caption has no matching asset on the same page.",
|
||||
"bbox": [50, 700, 550, 750],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_figure_inventory(structured_blocks)
|
||||
|
||||
assert len(inventory["matched_figures"]) == 1
|
||||
assert inventory["matched_figures"][0]["figure_number"] == 2
|
||||
assert len(inventory["matched_figures"][0]["matched_assets"]) == 0
|
||||
assert "legend_only" in inventory["matched_figures"][0]["flags"]
|
||||
assert inventory["matched_figures"][0]["confidence"] == 0.4
|
||||
|
||||
|
||||
def test_unmatched_legends_populated() -> None:
|
||||
from paperforge.worker.ocr_figures import build_figure_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "K001",
|
||||
"page": 3,
|
||||
"block_id": "p3_b1",
|
||||
"role": "figure_caption",
|
||||
"text": "Figure 3. Caption with no figure asset at all.",
|
||||
"bbox": [50, 700, 550, 750],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_figure_inventory(structured_blocks)
|
||||
|
||||
assert len(inventory["unmatched_legends"]) == 1
|
||||
assert inventory["unmatched_legends"][0]["block_id"] == "p3_b1"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
"""Phase 2 contract tests for table inventory.
|
||||
|
||||
paperforge.worker.ocr_tables does not exist yet -- tests will fail until
|
||||
Task 7 implements the module.
|
||||
"""
|
||||
"""Task 5 tests for hardened table matching."""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
|
|
@ -63,3 +59,225 @@ def test_table_without_asset_is_tracked_as_unmatched_caption() -> None:
|
|||
|
||||
assert inventory["official_table_count"] == 0
|
||||
assert len(inventory["unmatched_captions"]) == 1
|
||||
|
||||
|
||||
def test_continuation_table_matches_same_page_asset() -> None:
|
||||
from paperforge.worker.ocr_tables import build_table_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 10,
|
||||
"block_id": "p10_a1",
|
||||
"role": "table_asset",
|
||||
"text": "continued data",
|
||||
"bbox": [100, 100, 600, 400],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 10,
|
||||
"block_id": "p10_c1",
|
||||
"role": "table_caption",
|
||||
"text": "Table 1 (Continued)",
|
||||
"bbox": [100, 420, 600, 460],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_table_inventory(structured_blocks)
|
||||
|
||||
assert len(inventory["tables"]) == 1
|
||||
t = inventory["tables"][0]
|
||||
assert t["is_continuation"] is True
|
||||
assert t["has_asset"] is True
|
||||
assert t["asset_block_id"] == "p10_a1"
|
||||
|
||||
|
||||
def test_continuation_does_not_increment_official_count() -> None:
|
||||
from paperforge.worker.ocr_tables import build_table_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 5,
|
||||
"block_id": "p5_a1",
|
||||
"role": "table_asset",
|
||||
"text": "table data",
|
||||
"bbox": [100, 100, 600, 400],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 5,
|
||||
"block_id": "p5_c1",
|
||||
"role": "table_caption",
|
||||
"text": "Table 1. Main data",
|
||||
"bbox": [100, 420, 600, 460],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 6,
|
||||
"block_id": "p6_a1",
|
||||
"role": "table_asset",
|
||||
"text": "continued data",
|
||||
"bbox": [100, 100, 600, 300],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 6,
|
||||
"block_id": "p6_c1",
|
||||
"role": "table_caption",
|
||||
"text": "Table 1 (Continued)",
|
||||
"bbox": [100, 320, 600, 360],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_table_inventory(structured_blocks)
|
||||
|
||||
assert inventory["official_table_count"] == 1
|
||||
normal = [t for t in inventory["tables"] if not t["is_continuation"]]
|
||||
continued = [t for t in inventory["tables"] if t["is_continuation"]]
|
||||
assert len(normal) == 1
|
||||
assert len(continued) == 1
|
||||
assert normal[0]["has_asset"] is True
|
||||
assert continued[0]["has_asset"] is True
|
||||
|
||||
|
||||
def test_continuation_without_asset_has_has_asset_false() -> None:
|
||||
from paperforge.worker.ocr_tables import build_table_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 10,
|
||||
"block_id": "p10_c1",
|
||||
"role": "table_caption",
|
||||
"text": "Table 1 (Continued)",
|
||||
"bbox": [100, 100, 600, 140],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_table_inventory(structured_blocks)
|
||||
|
||||
assert len(inventory["tables"]) == 1
|
||||
assert inventory["tables"][0]["is_continuation"] is True
|
||||
assert inventory["tables"][0]["has_asset"] is False
|
||||
assert len(inventory["unmatched_captions"]) == 1
|
||||
|
||||
|
||||
def test_multi_signal_scoring_prefers_better_asset() -> None:
|
||||
from paperforge.worker.ocr_tables import build_table_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 3,
|
||||
"block_id": "p3_a1",
|
||||
"role": "table_asset",
|
||||
"text": "far table",
|
||||
"bbox": [50, 600, 300, 800],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 3,
|
||||
"block_id": "p3_a2",
|
||||
"role": "table_asset",
|
||||
"text": "near table",
|
||||
"bbox": [50, 50, 550, 300],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 3,
|
||||
"block_id": "p3_c1",
|
||||
"role": "table_caption",
|
||||
"text": "Table 3. Nearby data",
|
||||
"bbox": [50, 310, 550, 350],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_table_inventory(structured_blocks)
|
||||
|
||||
assert inventory["official_table_count"] == 1
|
||||
t = inventory["tables"][0]
|
||||
assert t["asset_block_id"] == "p3_a2"
|
||||
|
||||
|
||||
def test_continuation_matches_only_same_page_not_adjacent() -> None:
|
||||
from paperforge.worker.ocr_tables import build_table_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 4,
|
||||
"block_id": "p4_a1",
|
||||
"role": "table_asset",
|
||||
"text": "wrong page",
|
||||
"bbox": [100, 100, 600, 400],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 5,
|
||||
"block_id": "p5_a1",
|
||||
"role": "table_asset",
|
||||
"text": "same page",
|
||||
"bbox": [100, 100, 600, 400],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 5,
|
||||
"block_id": "p5_c1",
|
||||
"role": "table_caption",
|
||||
"text": "Table 2 (cont.)",
|
||||
"bbox": [100, 420, 600, 460],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_table_inventory(structured_blocks)
|
||||
|
||||
assert len(inventory["tables"]) == 1
|
||||
t = inventory["tables"][0]
|
||||
assert t["is_continuation"] is True
|
||||
assert t["asset_block_id"] == "p5_a1"
|
||||
|
||||
|
||||
def test_multiple_captions_match_correct_assets_in_order() -> None:
|
||||
from paperforge.worker.ocr_tables import build_table_inventory
|
||||
|
||||
structured_blocks = [
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 5,
|
||||
"block_id": "a5b",
|
||||
"role": "table_asset",
|
||||
"text": "table 1 body",
|
||||
"bbox": [100, 100, 600, 400],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 5,
|
||||
"block_id": "c5a",
|
||||
"role": "table_caption",
|
||||
"text": "Table 1. First",
|
||||
"bbox": [100, 420, 600, 460],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 6,
|
||||
"block_id": "a6b",
|
||||
"role": "table_asset",
|
||||
"text": "table 2 body",
|
||||
"bbox": [100, 100, 600, 400],
|
||||
},
|
||||
{
|
||||
"paper_id": "KEY001",
|
||||
"page": 6,
|
||||
"block_id": "c6a",
|
||||
"role": "table_caption",
|
||||
"text": "Table 2. Second",
|
||||
"bbox": [100, 420, 600, 460],
|
||||
},
|
||||
]
|
||||
|
||||
inventory = build_table_inventory(structured_blocks)
|
||||
|
||||
assert inventory["official_table_count"] == 2
|
||||
assert inventory["tables"][0]["asset_block_id"] == "a5b"
|
||||
assert inventory["tables"][1]["asset_block_id"] == "a6b"
|
||||
|
|
|
|||
Loading…
Reference in a new issue