Heading vs Body Classification + Document Outline
Nothing in the framework maps line height to heading levels or builds a section outline —
ocr/structure and element_parse are purely positional, and text_blocks groups
paragraphs / lists but does not rank them. heading_segment adds the standard heuristic:
a line whose height exceeds heading_ratio times the median line height is a heading, and
distinct heading heights become heading levels (the tallest is level 1). From that it emits
a flat document outline.
Pure-stdlib over plain line dicts (text + bbox); fully unit-testable with no image and no OCR
engine. Reuses table_grid_fill’s box-bounds reader. Imports no PySide6.
Headless API
from je_auto_control import classify_lines, outline
for item in classify_lines(ocr_lines, heading_ratio=1.2):
print(item["role"], item["level"], item["text"])
for heading in outline(ocr_lines):
print(" " * (heading["level"] - 1) + heading["text"])
classify_lines tags each line {box, text, role, level} — role is "heading" or
"body", level is the heading level (1 = tallest, 0 for body). outline returns just
the headings in top-to-bottom order as {level, text, top} — a document table of contents.
Executor commands
AC_classify_lines (lines / heading_ratio → {count, lines}) and AC_outline
(lines / heading_ratio → {count, headings}). They are exposed as the MCP tools
ac_classify_lines / ac_outline (read-only) and as the Script Builder commands
Classify Headings vs Body / Document Outline under OCR.