Add synthesize_part_box() as the single authoritative S5 part-box projection (T3 swap point): content-margin x-extent x part-band y-extent, BOTTOMLEFT coords; label_box retained as a separate anchor. build() attaches box per part. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
from api.services.docling.template import build, synthesize_part_box
|
|
|
|
|
|
def test_synthesize_part_box_uses_content_margins_and_band_y():
|
|
part_band = {"label": "01.1", "y_start": 712.34, "y_end": 601.27}
|
|
content_x_band = {"x_left": 54.04, "x_right": 521.96}
|
|
|
|
assert synthesize_part_box(part_band, content_x_band) == {
|
|
"l": 54.0,
|
|
"t": 712.3,
|
|
"r": 522.0,
|
|
"b": 601.3,
|
|
"coord_origin": "BOTTOMLEFT",
|
|
}
|
|
|
|
|
|
def test_synthesize_part_box_returns_none_without_margin_contract():
|
|
assert synthesize_part_box({"y_start": 700, "y_end": 650}, {}) is None
|
|
assert synthesize_part_box({"y_start": 700}, {"x_left": 50, "x_right": 520}) is None
|
|
|
|
|
|
def test_build_carries_label_box_as_anchor_and_single_synthesized_part_box():
|
|
structured = {
|
|
"board": "aqa",
|
|
"paper_code": "8463/1",
|
|
"questions": [{
|
|
"question": "01",
|
|
"parts": [{
|
|
"label": "01.1",
|
|
"page": 2,
|
|
"bbox": {"l": 40, "t": 720, "r": 70, "b": 705},
|
|
}],
|
|
}],
|
|
}
|
|
bands = {
|
|
"pages": {
|
|
"2": {
|
|
"main": [{"question": "01", "y_start": 730, "y_end": 0, "is_start": True}],
|
|
"part": [{"label": "01.1", "question": "01", "y_start": 720, "y_end": 610}],
|
|
}
|
|
}
|
|
}
|
|
furniture = {
|
|
"n_pages": 2,
|
|
"content_margins": {
|
|
"content_x_band": {"x_left": 55, "x_right": 515},
|
|
"per_page": {"2": {"top": 760, "bottom": 40, "left": 55, "right": 515}},
|
|
},
|
|
"items": [],
|
|
}
|
|
|
|
part = build(structured, bands, furniture)["pages"]["2"]["part_bands"][0]
|
|
|
|
assert part["label_box"] == {"l": 40, "t": 720, "r": 70, "b": 705}
|
|
assert part["box"] == {"l": 55, "t": 720, "r": 515, "b": 610, "coord_origin": "BOTTOMLEFT"}
|