refactor: solidify startup UX and engine-aware preprocessing

- Slim core deps: move ML stack to optional extras (paddle/tables/figures/scientific/full)
- Lazy settings proxy with config search paths (env var, cwd, user dir)
- New commands: init, demo, setup [basic|full], first-run guard on run/watch
- Engine-aware preprocessing: Paddle gets original image (fixes dark mode 0.83->0.95)
- Results table shows Skipped count; lazy run-dir creation
- kg_ocr marked experimental with extra, Docker defaults with OCR_PIPELINE_CONFIG
- 25/25 tests, ruff clean
This commit is contained in:
2026-07-19 22:14:54 +02:00
parent deab02610b
commit a0211155fa
59 changed files with 2426 additions and 629 deletions

View File

@@ -33,9 +33,13 @@ class FigureDetector:
try:
import layoutparser as lp
model_class = getattr(lp, "Detectron2LayoutModel", None) or getattr(lp, "AutoLayoutModel", None)
model_class = getattr(lp, "Detectron2LayoutModel", None) or getattr(
lp, "AutoLayoutModel", None
)
if model_class is None:
raise RuntimeError("layoutparser has no compatible layout model backend; install Detectron2")
raise RuntimeError(
"layoutparser has no compatible layout model backend; install Detectron2"
)
self._predictor = model_class(
config_path=settings.detectors.figures.model,
label_map={0: "Text", 1: "Title", 2: "List", 3: "Table", 4: "Figure"},
@@ -104,9 +108,13 @@ class CaptionExtractor:
try:
import layoutparser as lp
model_class = getattr(lp, "Detectron2LayoutModel", None) or getattr(lp, "AutoLayoutModel", None)
model_class = getattr(lp, "Detectron2LayoutModel", None) or getattr(
lp, "AutoLayoutModel", None
)
if model_class is None:
raise RuntimeError("layoutparser has no compatible layout model backend; install Detectron2")
raise RuntimeError(
"layoutparser has no compatible layout model backend; install Detectron2"
)
self._predictor = model_class(
config_path=settings.detectors.captions.model,
label_map={0: "Text", 1: "Title", 2: "List", 3: "Table", 4: "Figure"},

View File

@@ -80,7 +80,12 @@ class TableDetector:
):
resized_box = [float(x) for x in box]
scale_x, scale_y = original_width / 800, original_height / 800
box = [resized_box[0] * scale_x, resized_box[1] * scale_y, resized_box[2] * scale_x, resized_box[3] * scale_y]
box = [
resized_box[0] * scale_x,
resized_box[1] * scale_y,
resized_box[2] * scale_x,
resized_box[3] * scale_y,
]
x1, y1, x2, y2 = map(int, box)
x1, x2 = max(0, x1), min(original_width, x2)
y1, y2 = max(0, y1), min(original_height, y2)