diff --git a/crates/edgeparse-core/src/pdf/raster_table_ocr.rs b/crates/edgeparse-core/src/pdf/raster_table_ocr.rs index debee15..736007e 100644 --- a/crates/edgeparse-core/src/pdf/raster_table_ocr.rs +++ b/crates/edgeparse-core/src/pdf/raster_table_ocr.rs @@ -154,9 +154,14 @@ if result is None: print('[]') raise SystemExit(0) -boxes = getattr(result, 'boxes', []) or [] -txts = getattr(result, 'txts', []) or [] -scores = getattr(result, 'scores', []) or [] +# RapidOCR returns NumPy arrays for these fields; `arr or []` raises +# "truth value of an array ... is ambiguous", so normalise explicitly. +boxes = getattr(result, 'boxes', None) +boxes = [] if boxes is None else list(boxes) +txts = getattr(result, 'txts', None) +txts = [] if txts is None else list(txts) +scores = getattr(result, 'scores', None) +scores = [] if scores is None else list(scores) out = [] for box, text, score in zip(boxes, txts, scores): if not text or not str(text).strip(): diff --git a/crates/edgeparse-python/src/lib.rs b/crates/edgeparse-python/src/lib.rs index 5ac5192..96e75d3 100644 --- a/crates/edgeparse-python/src/lib.rs +++ b/crates/edgeparse-python/src/lib.rs @@ -2,7 +2,8 @@ use pyo3::exceptions::PyRuntimeError; use pyo3::prelude::*; use edgeparse_core::api::config::{ - ImageFormat, ImageOutput, OutputFormat, ProcessingConfig, ReadingOrder, TableMethod, + HybridBackend, HybridMode, ImageFormat, ImageOutput, OutputFormat, ProcessingConfig, + ReadingOrder, TableMethod, }; use edgeparse_core::output; @@ -18,6 +19,11 @@ use std::path::Path; /// reading_order: Reading order algorithm — "xycut" or "off". Default: "xycut". /// table_method: Table detection method — "default" or "cluster". Default: "default". /// image_output: Image output mode — "off", "embedded", or "external". Default: "off". +/// hybrid: Hybrid OCR backend — "off" or "docling-fast". Default: "off". +/// "docling-fast" enables OCR recovery of image-based text and tables +/// (requires pdftoppm, tesseract, and optionally rapidocr on the host). +/// hybrid_mode: Hybrid triage — "auto" (route complex pages) or "full" (all +/// pages). Only applies when hybrid is enabled. Default: "auto". /// /// Returns: /// The extracted content as a string in the requested format. @@ -31,7 +37,10 @@ use std::path::Path; reading_order = "xycut", table_method = "default", image_output = "off", + hybrid = "off", + hybrid_mode = "auto", ))] +#[allow(clippy::too_many_arguments)] fn convert( input_path: &str, format: &str, @@ -40,6 +49,8 @@ fn convert( reading_order: &str, table_method: &str, image_output: &str, + hybrid: &str, + hybrid_mode: &str, ) -> PyResult { let pdf_path = Path::new(input_path); if !pdf_path.exists() { @@ -78,6 +89,14 @@ fn convert( _ => ImageOutput::Off, }, image_format: ImageFormat::Png, + hybrid: match hybrid { + "docling-fast" => HybridBackend::DoclingFast, + _ => HybridBackend::Off, + }, + hybrid_mode: match hybrid_mode { + "full" => HybridMode::Full, + _ => HybridMode::Auto, + }, ..ProcessingConfig::default() }; @@ -118,6 +137,8 @@ fn convert( /// format: Output format — "markdown", "json", "html", or "text". Default: "markdown". /// pages: Optional page range string, e.g. "1,3,5-7". /// password: Optional password for encrypted PDFs. +/// hybrid: Hybrid OCR backend — "off" or "docling-fast". Default: "off". +/// hybrid_mode: Hybrid triage — "auto" or "full". Default: "auto". /// /// Returns: /// The path to the created output file. @@ -129,6 +150,8 @@ fn convert( format = "markdown", pages = None, password = None, + hybrid = "off", + hybrid_mode = "auto", ))] fn convert_file( input_path: &str, @@ -136,9 +159,11 @@ fn convert_file( format: &str, pages: Option<&str>, password: Option<&str>, + hybrid: &str, + hybrid_mode: &str, ) -> PyResult { let content = convert( - input_path, format, pages, password, "xycut", "default", "off", + input_path, format, pages, password, "xycut", "default", "off", hybrid, hybrid_mode, )?; let out_dir = Path::new(output_dir); diff --git a/sdks/python/edgeparse/__init__.py b/sdks/python/edgeparse/__init__.py index 1346dc9..61c7418 100644 --- a/sdks/python/edgeparse/__init__.py +++ b/sdks/python/edgeparse/__init__.py @@ -23,6 +23,8 @@ def convert( reading_order: str = "xycut", table_method: str = "default", image_output: str = "off", + hybrid: str = "off", + hybrid_mode: str = "auto", ) -> str: """Convert a PDF file and return the extracted content as a string. @@ -43,6 +45,14 @@ def convert( Table detection method. ``"default"`` or ``"cluster"``. image_output: Image output mode. ``"off"`` (default), ``"embedded"``, or ``"external"``. + hybrid: + Hybrid OCR backend. ``"off"`` (default) or ``"docling-fast"``. + ``"docling-fast"`` enables OCR recovery of image-based text and tables + and requires ``pdftoppm`` and ``tesseract`` (and optionally ``rapidocr``) + to be available on the host. + hybrid_mode: + Hybrid triage mode. ``"auto"`` (default) routes complex pages to OCR; + ``"full"`` runs OCR on every page. Only applies when ``hybrid`` is enabled. Returns ------- @@ -57,6 +67,8 @@ def convert( reading_order=reading_order, table_method=table_method, image_output=image_output, + hybrid=hybrid, + hybrid_mode=hybrid_mode, ) @@ -67,6 +79,8 @@ def convert_file( format: str = "markdown", pages: Optional[str] = None, password: Optional[str] = None, + hybrid: str = "off", + hybrid_mode: str = "auto", ) -> str: """Convert a PDF file and write the output to a file. @@ -83,6 +97,10 @@ def convert_file( Optional page range string, e.g. ``"1,3,5-7"``. password: Optional password for encrypted PDFs. + hybrid: + Hybrid OCR backend. ``"off"`` (default) or ``"docling-fast"``. + hybrid_mode: + Hybrid triage mode. ``"auto"`` (default) or ``"full"``. Returns ------- @@ -95,6 +113,8 @@ def convert_file( format=format, pages=pages, password=password, + hybrid=hybrid, + hybrid_mode=hybrid_mode, ) diff --git a/sdks/python/edgeparse/_types.py b/sdks/python/edgeparse/_types.py index a6f2e16..fec4207 100644 --- a/sdks/python/edgeparse/_types.py +++ b/sdks/python/edgeparse/_types.py @@ -16,3 +16,9 @@ # Valid image output modes IMAGE_OUTPUTS = ("off", "embedded", "external") + +# Valid hybrid OCR backends +HYBRID_BACKENDS = ("off", "docling-fast") + +# Valid hybrid triage modes +HYBRID_MODES = ("auto", "full")