mirror of
https://github.com/docling-project/docling.git
synced 2026-05-17 13:10:38 +00:00
03532938b5
* feat: Inference engines abstraction for image classification model family with HF Transformers and ONNX runtime Implements runtime abstraction for image classification models with support for both ONNX Runtime and HuggingFace Transformers engines. Users can switch between engines without model retraining, similar to the object detection abstraction (#2959). Key components: - BaseImageClassificationEngine with factory pattern - OnnxRuntimeImageClassificationEngine and TransformersImageClassificationEngine implementations - Shared HfVisionModelMixin for common HF model utilities - Engine-specific configuration options - Test suite and example demonstrating runtime engine switching Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * Add missing files and re-export for backward compat Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * Don't run with OCR in the example. Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * Remove excess onnxruntime related options for inuts and outputs Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * feat: centralize torch compile defaults with DOCLING_INFERENCE_COMPILE_TORCH_MODELS Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * feat: Add Kserve2 API engine for image classifier and object detection models (#2999) * fix: add failed pages to DoclingDocument for page break consistency (#2939) * fix: add failed pages to DoclingDocument for page break consistency When some PDF pages fail to parse, they were not added to DoclingDocument.pages, causing page break markers to be incorrect during export. This adds failed/skipped pages with their size info (if available) to maintain correct page numbering and structure. - Add _add_failed_pages_to_document() method in StandardPdfPipeline - Add test cases for failed page handling - Add test cases for normal page handling (regression test) - Add test PDF files Signed-off-by: jhchoi1182 <jhchoi1182@gmail.com> * fix: ensure resource cleanup and simplify type hints - Wrap page_backend usage in try-finally to guarantee unload (prevents resource leaks). - Simplify redundant 'float | None | None' type hint. Signed-off-by: jhchoi1182 <jhchoi1182@gmail.com> * fix: add groundtruth for normal_4pages.pdf and exclude failing PDFs from e2e test Signed-off-by: jhchoi1182 <jhchoi1182@gmail.com> * fix: ensure correct status assertion for failed pages in tests Signed-off-by: jhchoi1182 <jhchoi1182@gmail.com> --------- Signed-off-by: jhchoi1182 <jhchoi1182@gmail.com> * fix: Use timezone-aware datetime (#2947) * Use timezone-aware datetime for profiling timestamps Updated timestamp recording to use timezone-aware datetime. Signed-off-by: Nikhil Singh <124866156+Ritinikhil@users.noreply.github.com> * run formatter Signed-off-by: Michele Dolfi <dol@zurich.ibm.com> --------- Signed-off-by: Nikhil Singh <124866156+Ritinikhil@users.noreply.github.com> Signed-off-by: Michele Dolfi <dol@zurich.ibm.com> Co-authored-by: Michele Dolfi <dol@zurich.ibm.com> * fix(asciidoc): handle commas in image alt text (#2983) * Fix: Handle commas in AsciiDoc image alt text - Modified _parse_picture() to gracefully handle alt text containing commas - Commas in alt text are now preserved instead of causing ValueError - Added test case with realistic auto-generated alt text - split('=', 1) prevents issues when values contain '=' characters * DCO Remediation Commit for n0rdp0l <n90.w135@gmail.com> I, n0rdp0l <n90.w135@gmail.com>, hereby add my Signed-off-by to this commit:ee752491fcSigned-off-by: n0rdp0l <n90.w135@gmail.com> * style: fix ruff formatting in test_backend_asciidoc.py Signed-off-by: n0rdp0l <n90.w135@gmail.com> --------- Signed-off-by: n0rdp0l <n90.w135@gmail.com> Co-authored-by: Michele Dolfi <dol@zurich.ibm.com> * chore: bump version to 2.73.1 [skip ci] * First attempt at establishing API Kserve2 facet Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * refactor: improve KServe v2 engine implementation after code review - Add comprehensive error handling to KserveV2HttpClient - Catch and wrap Timeout, ConnectionError, HTTPError with context - Validate response formats with clear error messages - Refactor URL building to eliminate duplication - Extract _build_model_url() helper method - Single source of truth for infer_url and model_metadata_url - Make URL required parameter (remove default localhost:8000) - Update ApiKserveV2*EngineOptions to require explicit URL - Add preset validation with helpful error messages - Rename constants for clarity: TRITON_* → KSERVE_V2_* - Add comment explaining KServe v2 uses Triton type system - Improve error messages with actual values - Show counts, shapes, and supported types in validation errors - Document official KServe Python SDK alternative - Note async-only requirement and alpha status - Update tests for required URL parameter Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * Cleanup in kserve http helper and options Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * Further cleanup Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * Fix for remote-services on tablemodel Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * fix: improved deserialization of engine_options (#3008) * add registry of discriminated subclasses Signed-off-by: Michele Dolfi <dol@zurich.ibm.com> * fix detection of engine_type value Signed-off-by: Michele Dolfi <dol@zurich.ibm.com> --------- Signed-off-by: Michele Dolfi <dol@zurich.ibm.com> * Add options serialization improvements Signed-off-by: Christoph Auer <cau@zurich.ibm.com> --------- Signed-off-by: jhchoi1182 <jhchoi1182@gmail.com> Signed-off-by: Nikhil Singh <124866156+Ritinikhil@users.noreply.github.com> Signed-off-by: Michele Dolfi <dol@zurich.ibm.com> Signed-off-by: n0rdp0l <n90.w135@gmail.com> Signed-off-by: Christoph Auer <cau@zurich.ibm.com> Co-authored-by: jhchoi1182 <jhchoi1182@gmail.com> Co-authored-by: Nikhil Singh <124866156+Ritinikhil@users.noreply.github.com> Co-authored-by: Michele Dolfi <dol@zurich.ibm.com> Co-authored-by: Felix Wente <63914035+n0rdp0l@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Michele Dolfi <97102151+dolfim-ibm@users.noreply.github.com> * Fixes from review Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * DCO Remediation Commit for Christoph Auer <cau@zurich.ibm.com> I, Christoph Auer <cau@zurich.ibm.com>, hereby add my Signed-off-by to this commit:4cdb01e6d3Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * DCO Remediation Commit for Christoph Auer <60343111+cau-git@users.noreply.github.com> I, Christoph Auer <60343111+cau-git@users.noreply.github.com>, hereby add my Signed-off-by to this commit:e293ba3270Signed-off-by: Christoph Auer <60343111+cau-git@users.noreply.github.com> Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * Add fallback for API variants Signed-off-by: Christoph Auer <cau@zurich.ibm.com> * Recreate uv.lock Signed-off-by: Christoph Auer <cau@zurich.ibm.com> --------- Signed-off-by: Christoph Auer <cau@zurich.ibm.com> Signed-off-by: jhchoi1182 <jhchoi1182@gmail.com> Signed-off-by: Nikhil Singh <124866156+Ritinikhil@users.noreply.github.com> Signed-off-by: Michele Dolfi <dol@zurich.ibm.com> Signed-off-by: n0rdp0l <n90.w135@gmail.com> Signed-off-by: Christoph Auer <60343111+cau-git@users.noreply.github.com> Co-authored-by: jhchoi1182 <jhchoi1182@gmail.com> Co-authored-by: Nikhil Singh <124866156+Ritinikhil@users.noreply.github.com> Co-authored-by: Michele Dolfi <dol@zurich.ibm.com> Co-authored-by: Felix Wente <63914035+n0rdp0l@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Michele Dolfi <97102151+dolfim-ibm@users.noreply.github.com>
170 lines
5.7 KiB
Python
Vendored
170 lines
5.7 KiB
Python
Vendored
# %% [markdown]
|
|
#
|
|
# What this example does
|
|
# - Demonstrates runtime abstraction for object detection engines
|
|
# - Demonstrates runtime abstraction for image classification engines
|
|
# - Runs the same layout detection task with both ONNX Runtime and Transformers engines
|
|
# - Runs picture classification with the corresponding ONNX Runtime or Transformers engine
|
|
# - Shows how to easily switch between inference engines while using the same model
|
|
# - Detects document structure elements (text blocks, tables, figures, etc.)
|
|
#
|
|
# Requirements
|
|
# - Python 3.10+
|
|
# - Install Docling: `pip install docling[onnxruntime]`
|
|
#
|
|
# How to run (from repo root)
|
|
# - `python docs/examples/model_family_engines_example.py`
|
|
#
|
|
# ## Example code
|
|
# %%
|
|
|
|
import logging
|
|
import sys
|
|
|
|
from docling_core.types.doc.base import ImageRefMode
|
|
|
|
from docling.datamodel.accelerator_options import AcceleratorDevice, AcceleratorOptions
|
|
from docling.datamodel.base_models import InputFormat
|
|
from docling.datamodel.image_classification_engine_options import (
|
|
OnnxRuntimeImageClassificationEngineOptions,
|
|
TransformersImageClassificationEngineOptions,
|
|
)
|
|
from docling.datamodel.object_detection_engine_options import (
|
|
OnnxRuntimeObjectDetectionEngineOptions,
|
|
TransformersObjectDetectionEngineOptions,
|
|
)
|
|
from docling.datamodel.picture_classification_options import (
|
|
DocumentPictureClassifierOptions,
|
|
)
|
|
from docling.datamodel.pipeline_options import (
|
|
LayoutObjectDetectionOptions,
|
|
PdfPipelineOptions,
|
|
)
|
|
from docling.document_converter import (
|
|
DocumentConverter,
|
|
ImageFormatOption,
|
|
PdfFormatOption,
|
|
)
|
|
|
|
_log = logging.getLogger(__name__)
|
|
|
|
|
|
def is_onnxruntime_available() -> bool:
|
|
"""Return True when onnxruntime can be imported in this environment."""
|
|
try:
|
|
import onnxruntime
|
|
except ImportError:
|
|
return False
|
|
return True
|
|
|
|
|
|
def _build_engine_options(engine_kind: str):
|
|
"""Build paired layout/classification runtime options from a single selector."""
|
|
if engine_kind == "onnxruntime":
|
|
return (
|
|
"ONNX Runtime",
|
|
OnnxRuntimeObjectDetectionEngineOptions(),
|
|
OnnxRuntimeImageClassificationEngineOptions(),
|
|
)
|
|
if engine_kind == "transformers":
|
|
return (
|
|
"Transformers",
|
|
TransformersObjectDetectionEngineOptions(compile_model=False),
|
|
TransformersImageClassificationEngineOptions(compile_model=False),
|
|
)
|
|
raise ValueError(f"Unsupported engine kind: {engine_kind}")
|
|
|
|
|
|
def run_with_engine(engine_kind: str, input_doc_path: str):
|
|
"""Run layout detection and picture classification with paired engines."""
|
|
(
|
|
engine_name,
|
|
layout_engine_options,
|
|
picture_engine_options,
|
|
) = _build_engine_options(engine_kind)
|
|
|
|
_log.info(f"{'=' * 80}")
|
|
_log.info("Running conversion with %s runtime", engine_name)
|
|
_log.info(f"{'=' * 80}\n")
|
|
|
|
# Configure pipeline options
|
|
pipeline_options = PdfPipelineOptions()
|
|
pipeline_options.do_ocr = False
|
|
pipeline_options.do_table_structure = True
|
|
pipeline_options.do_picture_classification = True
|
|
pipeline_options.generate_page_images = True
|
|
pipeline_options.generate_picture_images = True
|
|
pipeline_options.images_scale = 2.0
|
|
pipeline_options.accelerator_options = AcceleratorOptions(
|
|
device=AcceleratorDevice.CPU
|
|
)
|
|
|
|
# Create layout options with the specified engine
|
|
layout_options = LayoutObjectDetectionOptions.from_preset("layout_heron_default")
|
|
layout_options.engine_options = layout_engine_options
|
|
|
|
pipeline_options.layout_options = layout_options
|
|
|
|
# Create picture-classifier options with the same engine family as layout
|
|
picture_classifier_options = DocumentPictureClassifierOptions.from_preset(
|
|
"document_figure_classifier_v2"
|
|
)
|
|
picture_classifier_options.engine_options = picture_engine_options
|
|
|
|
pipeline_options.picture_classification_options = picture_classifier_options
|
|
|
|
# Create converter with the configured pipeline
|
|
converter = DocumentConverter(
|
|
format_options={
|
|
InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options),
|
|
InputFormat.IMAGE: ImageFormatOption(pipeline_options=pipeline_options),
|
|
}
|
|
)
|
|
|
|
# Convert the document
|
|
result = converter.convert(input_doc_path)
|
|
|
|
# Save output with engine-specific filename
|
|
output_filename = f"model_family_engines_{engine_kind}.html"
|
|
result.document.save_as_html(output_filename, image_mode=ImageRefMode.EMBEDDED)
|
|
_log.info(
|
|
"Completed %s run: output=%s, pictures=%d",
|
|
engine_name,
|
|
output_filename,
|
|
len(result.document.pictures),
|
|
)
|
|
|
|
return result
|
|
|
|
|
|
def main():
|
|
# Configure logging to display info messages
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
)
|
|
logging.getLogger("docling").setLevel(logging.INFO)
|
|
|
|
# Use a sample PDF from the test data (path relative to repo root)
|
|
input_doc_path = "tests/data/pdf/2206.01062.pdf"
|
|
|
|
# Run 1: ONNX Runtime Engine (if available in the current environment)
|
|
if is_onnxruntime_available():
|
|
# Uses automatic device selection via pipeline accelerator options
|
|
run_with_engine("onnxruntime", input_doc_path)
|
|
else:
|
|
_log.warning(
|
|
"Skipping ONNX engine run: onnxruntime is not available for Python %d.%d. "
|
|
"Use Python < 3.14 and install `docling[onnxruntime]`.",
|
|
sys.version_info.major,
|
|
sys.version_info.minor,
|
|
)
|
|
|
|
# Run 2: Transformers Engine
|
|
# Uses PyTorch with HuggingFace Transformers and automatic device selection
|
|
run_with_engine("transformers", input_doc_path)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|