docling 2.50.0__py3-none-any.whl → 2.52.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docling/backend/docling_parse_v4_backend.py +12 -0
- docling/cli/main.py +29 -0
- docling/datamodel/pipeline_options.py +17 -10
- docling/models/base_model.py +27 -2
- docling/models/easyocr_model.py +19 -9
- docling/models/picture_description_vlm_model.py +1 -1
- docling/models/vlm_models_inline/hf_transformers_model.py +1 -1
- docling/models/vlm_models_inline/nuextract_transformers_model.py +1 -1
- docling/pipeline/asr_pipeline.py +1 -13
- docling/pipeline/base_extraction_pipeline.py +17 -3
- docling/pipeline/base_pipeline.py +75 -9
- docling/pipeline/extraction_vlm_pipeline.py +9 -16
- docling/pipeline/simple_pipeline.py +6 -6
- docling/pipeline/standard_pdf_pipeline.py +6 -55
- docling/pipeline/threaded_standard_pdf_pipeline.py +102 -62
- docling/pipeline/vlm_pipeline.py +3 -15
- {docling-2.50.0.dist-info → docling-2.52.0.dist-info}/METADATA +15 -7
- {docling-2.50.0.dist-info → docling-2.52.0.dist-info}/RECORD +22 -22
- {docling-2.50.0.dist-info → docling-2.52.0.dist-info}/WHEEL +0 -0
- {docling-2.50.0.dist-info → docling-2.52.0.dist-info}/entry_points.txt +0 -0
- {docling-2.50.0.dist-info → docling-2.52.0.dist-info}/licenses/LICENSE +0 -0
- {docling-2.50.0.dist-info → docling-2.52.0.dist-info}/top_level.txt +0 -0
@@ -30,13 +30,21 @@ class DoclingParseV4PageBackend(PdfPageBackend):
|
|
30
30
|
page_no: int,
|
31
31
|
create_words: bool = True,
|
32
32
|
create_textlines: bool = True,
|
33
|
+
keep_chars: bool = False,
|
34
|
+
keep_lines: bool = False,
|
35
|
+
keep_images: bool = True,
|
33
36
|
):
|
34
37
|
self._ppage = page_obj
|
35
38
|
self._dp_doc = dp_doc
|
36
39
|
self._page_no = page_no
|
40
|
+
|
37
41
|
self._create_words = create_words
|
38
42
|
self._create_textlines = create_textlines
|
39
43
|
|
44
|
+
self._keep_chars = keep_chars
|
45
|
+
self._keep_lines = keep_lines
|
46
|
+
self._keep_images = keep_images
|
47
|
+
|
40
48
|
self._dpage: Optional[SegmentedPdfPage] = None
|
41
49
|
self._unloaded = False
|
42
50
|
self.valid = (self._ppage is not None) and (self._dp_doc is not None)
|
@@ -47,8 +55,12 @@ class DoclingParseV4PageBackend(PdfPageBackend):
|
|
47
55
|
|
48
56
|
seg_page = self._dp_doc.get_page(
|
49
57
|
self._page_no + 1,
|
58
|
+
keep_chars=self._keep_chars,
|
59
|
+
keep_lines=self._keep_lines,
|
60
|
+
keep_bitmaps=self._keep_images,
|
50
61
|
create_words=self._create_words,
|
51
62
|
create_textlines=self._create_textlines,
|
63
|
+
enforce_same_font=True,
|
52
64
|
)
|
53
65
|
|
54
66
|
# In Docling, all TextCell instances are expected with top-left origin.
|
docling/cli/main.py
CHANGED
@@ -48,6 +48,7 @@ from docling.datamodel.base_models import (
|
|
48
48
|
from docling.datamodel.document import ConversionResult
|
49
49
|
from docling.datamodel.pipeline_options import (
|
50
50
|
AsrPipelineOptions,
|
51
|
+
ConvertPipelineOptions,
|
51
52
|
EasyOcrOptions,
|
52
53
|
OcrOptions,
|
53
54
|
PaginatedPipelineOptions,
|
@@ -71,8 +72,13 @@ from docling.datamodel.vlm_model_specs import (
|
|
71
72
|
from docling.document_converter import (
|
72
73
|
AudioFormatOption,
|
73
74
|
DocumentConverter,
|
75
|
+
ExcelFormatOption,
|
74
76
|
FormatOption,
|
77
|
+
HTMLFormatOption,
|
78
|
+
MarkdownFormatOption,
|
75
79
|
PdfFormatOption,
|
80
|
+
PowerpointFormatOption,
|
81
|
+
WordFormatOption,
|
76
82
|
)
|
77
83
|
from docling.models.factories import get_ocr_factory
|
78
84
|
from docling.pipeline.asr_pipeline import AsrPipeline
|
@@ -626,10 +632,33 @@ def convert( # noqa: C901
|
|
626
632
|
backend=MetsGbsDocumentBackend,
|
627
633
|
)
|
628
634
|
|
635
|
+
# SimplePipeline options
|
636
|
+
simple_format_option = ConvertPipelineOptions(
|
637
|
+
do_picture_description=enrich_picture_description,
|
638
|
+
do_picture_classification=enrich_picture_classes,
|
639
|
+
)
|
640
|
+
if artifacts_path is not None:
|
641
|
+
simple_format_option.artifacts_path = artifacts_path
|
642
|
+
|
629
643
|
format_options = {
|
630
644
|
InputFormat.PDF: pdf_format_option,
|
631
645
|
InputFormat.IMAGE: pdf_format_option,
|
632
646
|
InputFormat.METS_GBS: mets_gbs_format_option,
|
647
|
+
InputFormat.DOCX: WordFormatOption(
|
648
|
+
pipeline_options=simple_format_option
|
649
|
+
),
|
650
|
+
InputFormat.PPTX: PowerpointFormatOption(
|
651
|
+
pipeline_options=simple_format_option
|
652
|
+
),
|
653
|
+
InputFormat.XLSX: ExcelFormatOption(
|
654
|
+
pipeline_options=simple_format_option
|
655
|
+
),
|
656
|
+
InputFormat.HTML: HTMLFormatOption(
|
657
|
+
pipeline_options=simple_format_option
|
658
|
+
),
|
659
|
+
InputFormat.MD: MarkdownFormatOption(
|
660
|
+
pipeline_options=simple_format_option
|
661
|
+
),
|
633
662
|
}
|
634
663
|
|
635
664
|
elif pipeline == ProcessingPipeline.VLM:
|
@@ -135,6 +135,8 @@ class EasyOcrOptions(OcrOptions):
|
|
135
135
|
recog_network: Optional[str] = "standard"
|
136
136
|
download_enabled: bool = True
|
137
137
|
|
138
|
+
suppress_mps_warnings: bool = True
|
139
|
+
|
138
140
|
model_config = ConfigDict(
|
139
141
|
extra="forbid",
|
140
142
|
protected_namespaces=(),
|
@@ -237,7 +239,9 @@ class PdfBackend(str, Enum):
|
|
237
239
|
|
238
240
|
|
239
241
|
# Define an enum for the ocr engines
|
240
|
-
@deprecated(
|
242
|
+
@deprecated(
|
243
|
+
"Use get_ocr_factory().registered_kind to get a list of registered OCR engines."
|
244
|
+
)
|
241
245
|
class OcrEngine(str, Enum):
|
242
246
|
"""Enum of valid OCR engines."""
|
243
247
|
|
@@ -255,11 +259,21 @@ class PipelineOptions(BaseOptions):
|
|
255
259
|
accelerator_options: AcceleratorOptions = AcceleratorOptions()
|
256
260
|
enable_remote_services: bool = False
|
257
261
|
allow_external_plugins: bool = False
|
262
|
+
artifacts_path: Optional[Union[Path, str]] = None
|
258
263
|
|
259
264
|
|
260
|
-
class
|
261
|
-
|
265
|
+
class ConvertPipelineOptions(PipelineOptions):
|
266
|
+
"""Base convert pipeline options."""
|
267
|
+
|
268
|
+
do_picture_classification: bool = False # True: classify pictures in documents
|
262
269
|
|
270
|
+
do_picture_description: bool = False # True: run describe pictures in documents
|
271
|
+
picture_description_options: PictureDescriptionBaseOptions = (
|
272
|
+
smolvlm_picture_description
|
273
|
+
)
|
274
|
+
|
275
|
+
|
276
|
+
class PaginatedPipelineOptions(ConvertPipelineOptions):
|
263
277
|
images_scale: float = 1.0
|
264
278
|
generate_page_images: bool = False
|
265
279
|
generate_picture_images: bool = False
|
@@ -291,13 +305,11 @@ class LayoutOptions(BaseModel):
|
|
291
305
|
|
292
306
|
class AsrPipelineOptions(PipelineOptions):
|
293
307
|
asr_options: Union[InlineAsrOptions] = asr_model_specs.WHISPER_TINY
|
294
|
-
artifacts_path: Optional[Union[Path, str]] = None
|
295
308
|
|
296
309
|
|
297
310
|
class VlmExtractionPipelineOptions(PipelineOptions):
|
298
311
|
"""Options for extraction pipeline."""
|
299
312
|
|
300
|
-
artifacts_path: Optional[Union[Path, str]] = None
|
301
313
|
vlm_options: Union[InlineVlmOptions] = NU_EXTRACT_2B_TRANSFORMERS
|
302
314
|
|
303
315
|
|
@@ -308,8 +320,6 @@ class PdfPipelineOptions(PaginatedPipelineOptions):
|
|
308
320
|
do_ocr: bool = True # True: perform OCR, replace programmatic PDF text
|
309
321
|
do_code_enrichment: bool = False # True: perform code OCR
|
310
322
|
do_formula_enrichment: bool = False # True: perform formula OCR, return Latex code
|
311
|
-
do_picture_classification: bool = False # True: classify pictures in documents
|
312
|
-
do_picture_description: bool = False # True: run describe pictures in documents
|
313
323
|
force_backend_text: bool = (
|
314
324
|
False # (To be used with vlms, or other generative models)
|
315
325
|
)
|
@@ -317,9 +327,6 @@ class PdfPipelineOptions(PaginatedPipelineOptions):
|
|
317
327
|
|
318
328
|
table_structure_options: TableStructureOptions = TableStructureOptions()
|
319
329
|
ocr_options: OcrOptions = EasyOcrOptions()
|
320
|
-
picture_description_options: PictureDescriptionBaseOptions = (
|
321
|
-
smolvlm_picture_description
|
322
|
-
)
|
323
330
|
layout_options: LayoutOptions = LayoutOptions()
|
324
331
|
|
325
332
|
images_scale: float = 1.0
|
docling/models/base_model.py
CHANGED
@@ -4,7 +4,13 @@ from collections.abc import Iterable
|
|
4
4
|
from typing import Any, Generic, Optional, Protocol, Type, Union
|
5
5
|
|
6
6
|
import numpy as np
|
7
|
-
from docling_core.types.doc import
|
7
|
+
from docling_core.types.doc import (
|
8
|
+
BoundingBox,
|
9
|
+
DocItem,
|
10
|
+
DoclingDocument,
|
11
|
+
NodeItem,
|
12
|
+
PictureItem,
|
13
|
+
)
|
8
14
|
from PIL.Image import Image
|
9
15
|
from typing_extensions import TypeVar
|
10
16
|
|
@@ -164,8 +170,17 @@ class BaseItemAndImageEnrichmentModel(
|
|
164
170
|
return None
|
165
171
|
|
166
172
|
assert isinstance(element, DocItem)
|
167
|
-
element_prov = element.prov[0]
|
168
173
|
|
174
|
+
# Allow the case of documents without page images but embedded images (e.g. Word and HTML docs)
|
175
|
+
if len(element.prov) == 0 and isinstance(element, PictureItem):
|
176
|
+
embedded_im = element.get_image(conv_res.document)
|
177
|
+
if embedded_im is not None:
|
178
|
+
return ItemAndImageEnrichmentElement(item=element, image=embedded_im)
|
179
|
+
else:
|
180
|
+
return None
|
181
|
+
|
182
|
+
# Crop the image form the page
|
183
|
+
element_prov = element.prov[0]
|
169
184
|
bbox = element_prov.bbox
|
170
185
|
width = bbox.r - bbox.l
|
171
186
|
height = bbox.t - bbox.b
|
@@ -183,4 +198,14 @@ class BaseItemAndImageEnrichmentModel(
|
|
183
198
|
cropped_image = conv_res.pages[page_ix].get_image(
|
184
199
|
scale=self.images_scale, cropbox=expanded_bbox
|
185
200
|
)
|
201
|
+
|
202
|
+
# Allow for images being embedded without the page backend or page images
|
203
|
+
if cropped_image is None and isinstance(element, PictureItem):
|
204
|
+
embedded_im = element.get_image(conv_res.document)
|
205
|
+
if embedded_im is not None:
|
206
|
+
return ItemAndImageEnrichmentElement(item=element, image=embedded_im)
|
207
|
+
else:
|
208
|
+
return None
|
209
|
+
|
210
|
+
# Return the proper cropped image
|
186
211
|
return ItemAndImageEnrichmentElement(item=element, image=cropped_image)
|
docling/models/easyocr_model.py
CHANGED
@@ -78,14 +78,17 @@ class EasyOcrModel(BaseOcrModel):
|
|
78
78
|
download_enabled = False
|
79
79
|
model_storage_directory = str(artifacts_path / self._model_repo_folder)
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
81
|
+
with warnings.catch_warnings():
|
82
|
+
if self.options.suppress_mps_warnings:
|
83
|
+
warnings.filterwarnings("ignore", message=".*pin_memory.*MPS.*")
|
84
|
+
self.reader = easyocr.Reader(
|
85
|
+
lang_list=self.options.lang,
|
86
|
+
gpu=use_gpu,
|
87
|
+
model_storage_directory=model_storage_directory,
|
88
|
+
recog_network=self.options.recog_network,
|
89
|
+
download_enabled=download_enabled,
|
90
|
+
verbose=False,
|
91
|
+
)
|
89
92
|
|
90
93
|
@staticmethod
|
91
94
|
def download_models(
|
@@ -147,7 +150,14 @@ class EasyOcrModel(BaseOcrModel):
|
|
147
150
|
scale=self.scale, cropbox=ocr_rect
|
148
151
|
)
|
149
152
|
im = numpy.array(high_res_image)
|
150
|
-
|
153
|
+
|
154
|
+
with warnings.catch_warnings():
|
155
|
+
if self.options.suppress_mps_warnings:
|
156
|
+
warnings.filterwarnings(
|
157
|
+
"ignore", message=".*pin_memory.*MPS.*"
|
158
|
+
)
|
159
|
+
|
160
|
+
result = self.reader.readtext(im)
|
151
161
|
|
152
162
|
del high_res_image
|
153
163
|
del im
|
@@ -67,7 +67,7 @@ class PictureDescriptionVlmModel(
|
|
67
67
|
self.model = AutoModelForImageTextToText.from_pretrained(
|
68
68
|
artifacts_path,
|
69
69
|
device_map=self.device,
|
70
|
-
|
70
|
+
dtype=torch.bfloat16,
|
71
71
|
_attn_implementation=(
|
72
72
|
"flash_attention_2"
|
73
73
|
if self.device.startswith("cuda")
|
@@ -112,7 +112,7 @@ class HuggingFaceTransformersVlmModel(BaseVlmPageModel, HuggingFaceModelDownload
|
|
112
112
|
self.vlm_model = model_cls.from_pretrained(
|
113
113
|
artifacts_path,
|
114
114
|
device_map=self.device,
|
115
|
-
|
115
|
+
dtype=self.vlm_options.torch_dtype,
|
116
116
|
_attn_implementation=(
|
117
117
|
"flash_attention_2"
|
118
118
|
if self.device.startswith("cuda")
|
@@ -144,7 +144,7 @@ class NuExtractTransformersModel(BaseVlmModel, HuggingFaceModelDownloadMixin):
|
|
144
144
|
self.vlm_model = AutoModelForImageTextToText.from_pretrained(
|
145
145
|
artifacts_path,
|
146
146
|
device_map=self.device,
|
147
|
-
|
147
|
+
dtype=self.vlm_options.torch_dtype,
|
148
148
|
_attn_implementation=(
|
149
149
|
"flash_attention_2"
|
150
150
|
if self.device.startswith("cuda")
|
docling/pipeline/asr_pipeline.py
CHANGED
@@ -208,25 +208,13 @@ class AsrPipeline(BasePipeline):
|
|
208
208
|
|
209
209
|
self.pipeline_options: AsrPipelineOptions = pipeline_options
|
210
210
|
|
211
|
-
artifacts_path: Optional[Path] = None
|
212
|
-
if pipeline_options.artifacts_path is not None:
|
213
|
-
artifacts_path = Path(pipeline_options.artifacts_path).expanduser()
|
214
|
-
elif settings.artifacts_path is not None:
|
215
|
-
artifacts_path = Path(settings.artifacts_path).expanduser()
|
216
|
-
|
217
|
-
if artifacts_path is not None and not artifacts_path.is_dir():
|
218
|
-
raise RuntimeError(
|
219
|
-
f"The value of {artifacts_path=} is not valid. "
|
220
|
-
"When defined, it must point to a folder containing all models required by the pipeline."
|
221
|
-
)
|
222
|
-
|
223
211
|
if isinstance(self.pipeline_options.asr_options, InlineAsrNativeWhisperOptions):
|
224
212
|
asr_options: InlineAsrNativeWhisperOptions = (
|
225
213
|
self.pipeline_options.asr_options
|
226
214
|
)
|
227
215
|
self._model = _NativeWhisperModel(
|
228
216
|
enabled=True, # must be always enabled for this pipeline to make sense.
|
229
|
-
artifacts_path=artifacts_path,
|
217
|
+
artifacts_path=self.artifacts_path,
|
230
218
|
accelerator_options=pipeline_options.accelerator_options,
|
231
219
|
asr_options=asr_options,
|
232
220
|
)
|
@@ -1,19 +1,33 @@
|
|
1
1
|
import logging
|
2
2
|
from abc import ABC, abstractmethod
|
3
|
+
from pathlib import Path
|
3
4
|
from typing import Optional
|
4
5
|
|
5
6
|
from docling.datamodel.base_models import ConversionStatus, ErrorItem
|
6
7
|
from docling.datamodel.document import InputDocument
|
7
8
|
from docling.datamodel.extraction import ExtractionResult, ExtractionTemplateType
|
8
|
-
from docling.datamodel.pipeline_options import BaseOptions
|
9
|
+
from docling.datamodel.pipeline_options import BaseOptions, PipelineOptions
|
10
|
+
from docling.datamodel.settings import settings
|
9
11
|
|
10
12
|
_log = logging.getLogger(__name__)
|
11
13
|
|
12
14
|
|
13
15
|
class BaseExtractionPipeline(ABC):
|
14
|
-
def __init__(self, pipeline_options:
|
16
|
+
def __init__(self, pipeline_options: PipelineOptions):
|
15
17
|
self.pipeline_options = pipeline_options
|
16
18
|
|
19
|
+
self.artifacts_path: Optional[Path] = None
|
20
|
+
if pipeline_options.artifacts_path is not None:
|
21
|
+
self.artifacts_path = Path(pipeline_options.artifacts_path).expanduser()
|
22
|
+
elif settings.artifacts_path is not None:
|
23
|
+
self.artifacts_path = Path(settings.artifacts_path).expanduser()
|
24
|
+
|
25
|
+
if self.artifacts_path is not None and not self.artifacts_path.is_dir():
|
26
|
+
raise RuntimeError(
|
27
|
+
f"The value of {self.artifacts_path=} is not valid. "
|
28
|
+
"When defined, it must point to a folder containing all models required by the pipeline."
|
29
|
+
)
|
30
|
+
|
17
31
|
def execute(
|
18
32
|
self,
|
19
33
|
in_doc: InputDocument,
|
@@ -54,5 +68,5 @@ class BaseExtractionPipeline(ABC):
|
|
54
68
|
|
55
69
|
@classmethod
|
56
70
|
@abstractmethod
|
57
|
-
def get_default_options(cls) ->
|
71
|
+
def get_default_options(cls) -> PipelineOptions:
|
58
72
|
pass
|
@@ -4,7 +4,8 @@ import time
|
|
4
4
|
import traceback
|
5
5
|
from abc import ABC, abstractmethod
|
6
6
|
from collections.abc import Iterable
|
7
|
-
from
|
7
|
+
from pathlib import Path
|
8
|
+
from typing import Any, Callable, List, Optional
|
8
9
|
|
9
10
|
from docling_core.types.doc import NodeItem
|
10
11
|
|
@@ -20,9 +21,19 @@ from docling.datamodel.base_models import (
|
|
20
21
|
Page,
|
21
22
|
)
|
22
23
|
from docling.datamodel.document import ConversionResult, InputDocument
|
23
|
-
from docling.datamodel.pipeline_options import
|
24
|
+
from docling.datamodel.pipeline_options import (
|
25
|
+
ConvertPipelineOptions,
|
26
|
+
PdfPipelineOptions,
|
27
|
+
PipelineOptions,
|
28
|
+
)
|
24
29
|
from docling.datamodel.settings import settings
|
25
30
|
from docling.models.base_model import GenericEnrichmentModel
|
31
|
+
from docling.models.document_picture_classifier import (
|
32
|
+
DocumentPictureClassifier,
|
33
|
+
DocumentPictureClassifierOptions,
|
34
|
+
)
|
35
|
+
from docling.models.factories import get_picture_description_factory
|
36
|
+
from docling.models.picture_description_base_model import PictureDescriptionBaseModel
|
26
37
|
from docling.utils.profiling import ProfilingScope, TimeRecorder
|
27
38
|
from docling.utils.utils import chunkify
|
28
39
|
|
@@ -36,6 +47,18 @@ class BasePipeline(ABC):
|
|
36
47
|
self.build_pipe: List[Callable] = []
|
37
48
|
self.enrichment_pipe: List[GenericEnrichmentModel[Any]] = []
|
38
49
|
|
50
|
+
self.artifacts_path: Optional[Path] = None
|
51
|
+
if pipeline_options.artifacts_path is not None:
|
52
|
+
self.artifacts_path = Path(pipeline_options.artifacts_path).expanduser()
|
53
|
+
elif settings.artifacts_path is not None:
|
54
|
+
self.artifacts_path = Path(settings.artifacts_path).expanduser()
|
55
|
+
|
56
|
+
if self.artifacts_path is not None and not self.artifacts_path.is_dir():
|
57
|
+
raise RuntimeError(
|
58
|
+
f"The value of {self.artifacts_path=} is not valid. "
|
59
|
+
"When defined, it must point to a folder containing all models required by the pipeline."
|
60
|
+
)
|
61
|
+
|
39
62
|
def execute(self, in_doc: InputDocument, raises_on_error: bool) -> ConversionResult:
|
40
63
|
conv_res = ConversionResult(input=in_doc)
|
41
64
|
|
@@ -108,15 +131,58 @@ class BasePipeline(ABC):
|
|
108
131
|
def is_backend_supported(cls, backend: AbstractDocumentBackend):
|
109
132
|
pass
|
110
133
|
|
111
|
-
# def _apply_on_elements(self, element_batch: Iterable[NodeItem]) -> Iterable[Any]:
|
112
|
-
# for model in self.build_pipe:
|
113
|
-
# element_batch = model(element_batch)
|
114
|
-
#
|
115
|
-
# yield from element_batch
|
116
134
|
|
135
|
+
class ConvertPipeline(BasePipeline):
|
136
|
+
def __init__(self, pipeline_options: ConvertPipelineOptions):
|
137
|
+
super().__init__(pipeline_options)
|
138
|
+
self.pipeline_options: ConvertPipelineOptions
|
117
139
|
|
118
|
-
|
119
|
-
|
140
|
+
# ------ Common enrichment models working on all backends
|
141
|
+
|
142
|
+
# Picture description model
|
143
|
+
if (
|
144
|
+
picture_description_model := self._get_picture_description_model(
|
145
|
+
artifacts_path=self.artifacts_path
|
146
|
+
)
|
147
|
+
) is None:
|
148
|
+
raise RuntimeError(
|
149
|
+
f"The specified picture description kind is not supported: {pipeline_options.picture_description_options.kind}."
|
150
|
+
)
|
151
|
+
|
152
|
+
self.enrichment_pipe = [
|
153
|
+
# Document Picture Classifier
|
154
|
+
DocumentPictureClassifier(
|
155
|
+
enabled=pipeline_options.do_picture_classification,
|
156
|
+
artifacts_path=self.artifacts_path,
|
157
|
+
options=DocumentPictureClassifierOptions(),
|
158
|
+
accelerator_options=pipeline_options.accelerator_options,
|
159
|
+
),
|
160
|
+
# Document Picture description
|
161
|
+
picture_description_model,
|
162
|
+
]
|
163
|
+
|
164
|
+
def _get_picture_description_model(
|
165
|
+
self, artifacts_path: Optional[Path] = None
|
166
|
+
) -> Optional[PictureDescriptionBaseModel]:
|
167
|
+
factory = get_picture_description_factory(
|
168
|
+
allow_external_plugins=self.pipeline_options.allow_external_plugins
|
169
|
+
)
|
170
|
+
return factory.create_instance(
|
171
|
+
options=self.pipeline_options.picture_description_options,
|
172
|
+
enabled=self.pipeline_options.do_picture_description,
|
173
|
+
enable_remote_services=self.pipeline_options.enable_remote_services,
|
174
|
+
artifacts_path=artifacts_path,
|
175
|
+
accelerator_options=self.pipeline_options.accelerator_options,
|
176
|
+
)
|
177
|
+
|
178
|
+
@classmethod
|
179
|
+
@abstractmethod
|
180
|
+
def get_default_options(cls) -> ConvertPipelineOptions:
|
181
|
+
pass
|
182
|
+
|
183
|
+
|
184
|
+
class PaginatedPipeline(ConvertPipeline): # TODO this is a bad name.
|
185
|
+
def __init__(self, pipeline_options: ConvertPipelineOptions):
|
120
186
|
super().__init__(pipeline_options)
|
121
187
|
self.keep_backend = False
|
122
188
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import inspect
|
2
2
|
import json
|
3
3
|
import logging
|
4
|
-
from pathlib import Path
|
5
4
|
from typing import Optional
|
6
5
|
|
7
6
|
from PIL.Image import Image
|
@@ -16,7 +15,10 @@ from docling.datamodel.extraction import (
|
|
16
15
|
ExtractionResult,
|
17
16
|
ExtractionTemplateType,
|
18
17
|
)
|
19
|
-
from docling.datamodel.pipeline_options import
|
18
|
+
from docling.datamodel.pipeline_options import (
|
19
|
+
PipelineOptions,
|
20
|
+
VlmExtractionPipelineOptions,
|
21
|
+
)
|
20
22
|
from docling.datamodel.settings import settings
|
21
23
|
from docling.models.vlm_models_inline.nuextract_transformers_model import (
|
22
24
|
NuExtractTransformersModel,
|
@@ -35,22 +37,10 @@ class ExtractionVlmPipeline(BaseExtractionPipeline):
|
|
35
37
|
self.accelerator_options = pipeline_options.accelerator_options
|
36
38
|
self.pipeline_options: VlmExtractionPipelineOptions
|
37
39
|
|
38
|
-
artifacts_path: Optional[Path] = None
|
39
|
-
if pipeline_options.artifacts_path is not None:
|
40
|
-
artifacts_path = Path(pipeline_options.artifacts_path).expanduser()
|
41
|
-
elif settings.artifacts_path is not None:
|
42
|
-
artifacts_path = Path(settings.artifacts_path).expanduser()
|
43
|
-
|
44
|
-
if artifacts_path is not None and not artifacts_path.is_dir():
|
45
|
-
raise RuntimeError(
|
46
|
-
f"The value of {artifacts_path=} is not valid. "
|
47
|
-
"When defined, it must point to a folder containing all models required by the pipeline."
|
48
|
-
)
|
49
|
-
|
50
40
|
# Create VLM model instance
|
51
41
|
self.vlm_model = NuExtractTransformersModel(
|
52
42
|
enabled=True,
|
53
|
-
artifacts_path=artifacts_path, # Will download automatically
|
43
|
+
artifacts_path=self.artifacts_path, # Will download automatically
|
54
44
|
accelerator_options=self.accelerator_options,
|
55
45
|
vlm_options=pipeline_options.vlm_options,
|
56
46
|
)
|
@@ -194,11 +184,14 @@ class ExtractionVlmPipeline(BaseExtractionPipeline):
|
|
194
184
|
class ExtractionTemplateFactory(ModelFactory[template]): # type: ignore
|
195
185
|
__use_examples__ = True # prefer Field(examples=...) when present
|
196
186
|
__use_defaults__ = True # use field defaults instead of random values
|
187
|
+
__check_model__ = (
|
188
|
+
True # setting the value to avoid deprecation warnings
|
189
|
+
)
|
197
190
|
|
198
191
|
return ExtractionTemplateFactory.build().model_dump_json(indent=2) # type: ignore
|
199
192
|
else:
|
200
193
|
raise ValueError(f"Unsupported template type: {type(template)}")
|
201
194
|
|
202
195
|
@classmethod
|
203
|
-
def get_default_options(cls) ->
|
196
|
+
def get_default_options(cls) -> PipelineOptions:
|
204
197
|
return VlmExtractionPipelineOptions()
|
@@ -6,21 +6,21 @@ from docling.backend.abstract_backend import (
|
|
6
6
|
)
|
7
7
|
from docling.datamodel.base_models import ConversionStatus
|
8
8
|
from docling.datamodel.document import ConversionResult
|
9
|
-
from docling.datamodel.pipeline_options import
|
10
|
-
from docling.pipeline.base_pipeline import
|
9
|
+
from docling.datamodel.pipeline_options import ConvertPipelineOptions
|
10
|
+
from docling.pipeline.base_pipeline import ConvertPipeline
|
11
11
|
from docling.utils.profiling import ProfilingScope, TimeRecorder
|
12
12
|
|
13
13
|
_log = logging.getLogger(__name__)
|
14
14
|
|
15
15
|
|
16
|
-
class SimplePipeline(
|
16
|
+
class SimplePipeline(ConvertPipeline):
|
17
17
|
"""SimpleModelPipeline.
|
18
18
|
|
19
19
|
This class is used at the moment for formats / backends
|
20
20
|
which produce straight DoclingDocument output.
|
21
21
|
"""
|
22
22
|
|
23
|
-
def __init__(self, pipeline_options:
|
23
|
+
def __init__(self, pipeline_options: ConvertPipelineOptions):
|
24
24
|
super().__init__(pipeline_options)
|
25
25
|
|
26
26
|
def _build_document(self, conv_res: ConversionResult) -> ConversionResult:
|
@@ -47,8 +47,8 @@ class SimplePipeline(BasePipeline):
|
|
47
47
|
return ConversionStatus.SUCCESS
|
48
48
|
|
49
49
|
@classmethod
|
50
|
-
def get_default_options(cls) ->
|
51
|
-
return
|
50
|
+
def get_default_options(cls) -> ConvertPipelineOptions:
|
51
|
+
return ConvertPipelineOptions()
|
52
52
|
|
53
53
|
@classmethod
|
54
54
|
def is_backend_supported(cls, backend: AbstractDocumentBackend):
|
@@ -15,18 +15,13 @@ from docling.datamodel.pipeline_options import PdfPipelineOptions
|
|
15
15
|
from docling.datamodel.settings import settings
|
16
16
|
from docling.models.base_ocr_model import BaseOcrModel
|
17
17
|
from docling.models.code_formula_model import CodeFormulaModel, CodeFormulaModelOptions
|
18
|
-
from docling.models.
|
19
|
-
DocumentPictureClassifier,
|
20
|
-
DocumentPictureClassifierOptions,
|
21
|
-
)
|
22
|
-
from docling.models.factories import get_ocr_factory, get_picture_description_factory
|
18
|
+
from docling.models.factories import get_ocr_factory
|
23
19
|
from docling.models.layout_model import LayoutModel
|
24
20
|
from docling.models.page_assemble_model import PageAssembleModel, PageAssembleOptions
|
25
21
|
from docling.models.page_preprocessing_model import (
|
26
22
|
PagePreprocessingModel,
|
27
23
|
PagePreprocessingOptions,
|
28
24
|
)
|
29
|
-
from docling.models.picture_description_base_model import PictureDescriptionBaseModel
|
30
25
|
from docling.models.readingorder_model import ReadingOrderModel, ReadingOrderOptions
|
31
26
|
from docling.models.table_structure_model import TableStructureModel
|
32
27
|
from docling.pipeline.base_pipeline import PaginatedPipeline
|
@@ -41,18 +36,6 @@ class StandardPdfPipeline(PaginatedPipeline):
|
|
41
36
|
super().__init__(pipeline_options)
|
42
37
|
self.pipeline_options: PdfPipelineOptions
|
43
38
|
|
44
|
-
artifacts_path: Optional[Path] = None
|
45
|
-
if pipeline_options.artifacts_path is not None:
|
46
|
-
artifacts_path = Path(pipeline_options.artifacts_path).expanduser()
|
47
|
-
elif settings.artifacts_path is not None:
|
48
|
-
artifacts_path = Path(settings.artifacts_path).expanduser()
|
49
|
-
|
50
|
-
if artifacts_path is not None and not artifacts_path.is_dir():
|
51
|
-
raise RuntimeError(
|
52
|
-
f"The value of {artifacts_path=} is not valid. "
|
53
|
-
"When defined, it must point to a folder containing all models required by the pipeline."
|
54
|
-
)
|
55
|
-
|
56
39
|
with warnings.catch_warnings(): # deprecated generate_table_images
|
57
40
|
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
58
41
|
self.keep_images = (
|
@@ -63,7 +46,7 @@ class StandardPdfPipeline(PaginatedPipeline):
|
|
63
46
|
|
64
47
|
self.reading_order_model = ReadingOrderModel(options=ReadingOrderOptions())
|
65
48
|
|
66
|
-
ocr_model = self.get_ocr_model(artifacts_path=artifacts_path)
|
49
|
+
ocr_model = self.get_ocr_model(artifacts_path=self.artifacts_path)
|
67
50
|
|
68
51
|
self.build_pipe = [
|
69
52
|
# Pre-processing
|
@@ -76,14 +59,14 @@ class StandardPdfPipeline(PaginatedPipeline):
|
|
76
59
|
ocr_model,
|
77
60
|
# Layout model
|
78
61
|
LayoutModel(
|
79
|
-
artifacts_path=artifacts_path,
|
62
|
+
artifacts_path=self.artifacts_path,
|
80
63
|
accelerator_options=pipeline_options.accelerator_options,
|
81
64
|
options=pipeline_options.layout_options,
|
82
65
|
),
|
83
66
|
# Table structure model
|
84
67
|
TableStructureModel(
|
85
68
|
enabled=pipeline_options.do_table_structure,
|
86
|
-
artifacts_path=artifacts_path,
|
69
|
+
artifacts_path=self.artifacts_path,
|
87
70
|
options=pipeline_options.table_structure_options,
|
88
71
|
accelerator_options=pipeline_options.accelerator_options,
|
89
72
|
),
|
@@ -91,37 +74,19 @@ class StandardPdfPipeline(PaginatedPipeline):
|
|
91
74
|
PageAssembleModel(options=PageAssembleOptions()),
|
92
75
|
]
|
93
76
|
|
94
|
-
# Picture description model
|
95
|
-
if (
|
96
|
-
picture_description_model := self.get_picture_description_model(
|
97
|
-
artifacts_path=artifacts_path
|
98
|
-
)
|
99
|
-
) is None:
|
100
|
-
raise RuntimeError(
|
101
|
-
f"The specified picture description kind is not supported: {pipeline_options.picture_description_options.kind}."
|
102
|
-
)
|
103
|
-
|
104
77
|
self.enrichment_pipe = [
|
105
78
|
# Code Formula Enrichment Model
|
106
79
|
CodeFormulaModel(
|
107
80
|
enabled=pipeline_options.do_code_enrichment
|
108
81
|
or pipeline_options.do_formula_enrichment,
|
109
|
-
artifacts_path=artifacts_path,
|
82
|
+
artifacts_path=self.artifacts_path,
|
110
83
|
options=CodeFormulaModelOptions(
|
111
84
|
do_code_enrichment=pipeline_options.do_code_enrichment,
|
112
85
|
do_formula_enrichment=pipeline_options.do_formula_enrichment,
|
113
86
|
),
|
114
87
|
accelerator_options=pipeline_options.accelerator_options,
|
115
88
|
),
|
116
|
-
|
117
|
-
DocumentPictureClassifier(
|
118
|
-
enabled=pipeline_options.do_picture_classification,
|
119
|
-
artifacts_path=artifacts_path,
|
120
|
-
options=DocumentPictureClassifierOptions(),
|
121
|
-
accelerator_options=pipeline_options.accelerator_options,
|
122
|
-
),
|
123
|
-
# Document Picture description
|
124
|
-
picture_description_model,
|
89
|
+
*self.enrichment_pipe,
|
125
90
|
]
|
126
91
|
|
127
92
|
if (
|
@@ -158,20 +123,6 @@ class StandardPdfPipeline(PaginatedPipeline):
|
|
158
123
|
accelerator_options=self.pipeline_options.accelerator_options,
|
159
124
|
)
|
160
125
|
|
161
|
-
def get_picture_description_model(
|
162
|
-
self, artifacts_path: Optional[Path] = None
|
163
|
-
) -> Optional[PictureDescriptionBaseModel]:
|
164
|
-
factory = get_picture_description_factory(
|
165
|
-
allow_external_plugins=self.pipeline_options.allow_external_plugins
|
166
|
-
)
|
167
|
-
return factory.create_instance(
|
168
|
-
options=self.pipeline_options.picture_description_options,
|
169
|
-
enabled=self.pipeline_options.do_picture_description,
|
170
|
-
enable_remote_services=self.pipeline_options.enable_remote_services,
|
171
|
-
artifacts_path=artifacts_path,
|
172
|
-
accelerator_options=self.pipeline_options.accelerator_options,
|
173
|
-
)
|
174
|
-
|
175
126
|
def initialize_page(self, conv_res: ConversionResult, page: Page) -> Page:
|
176
127
|
with TimeRecorder(conv_res, "page_init"):
|
177
128
|
page._backend = conv_res.input._backend.load_page(page.page_no) # type: ignore
|
@@ -20,10 +20,14 @@ import itertools
|
|
20
20
|
import logging
|
21
21
|
import threading
|
22
22
|
import time
|
23
|
+
import warnings
|
23
24
|
from collections import defaultdict, deque
|
24
25
|
from dataclasses import dataclass, field
|
25
26
|
from pathlib import Path
|
26
|
-
from typing import Any, Iterable, List, Optional, Sequence, Tuple
|
27
|
+
from typing import Any, Iterable, List, Optional, Sequence, Tuple, cast
|
28
|
+
|
29
|
+
import numpy as np
|
30
|
+
from docling_core.types.doc import DocItem, ImageRef, PictureItem, TableItem
|
27
31
|
|
28
32
|
from docling.backend.abstract_backend import AbstractDocumentBackend
|
29
33
|
from docling.backend.pdf_backend import PdfDocumentBackend
|
@@ -32,21 +36,16 @@ from docling.datamodel.document import ConversionResult
|
|
32
36
|
from docling.datamodel.pipeline_options import ThreadedPdfPipelineOptions
|
33
37
|
from docling.datamodel.settings import settings
|
34
38
|
from docling.models.code_formula_model import CodeFormulaModel, CodeFormulaModelOptions
|
35
|
-
from docling.models.
|
36
|
-
DocumentPictureClassifier,
|
37
|
-
DocumentPictureClassifierOptions,
|
38
|
-
)
|
39
|
-
from docling.models.factories import get_ocr_factory, get_picture_description_factory
|
39
|
+
from docling.models.factories import get_ocr_factory
|
40
40
|
from docling.models.layout_model import LayoutModel
|
41
41
|
from docling.models.page_assemble_model import PageAssembleModel, PageAssembleOptions
|
42
42
|
from docling.models.page_preprocessing_model import (
|
43
43
|
PagePreprocessingModel,
|
44
44
|
PagePreprocessingOptions,
|
45
45
|
)
|
46
|
-
from docling.models.picture_description_base_model import PictureDescriptionBaseModel
|
47
46
|
from docling.models.readingorder_model import ReadingOrderModel, ReadingOrderOptions
|
48
47
|
from docling.models.table_structure_model import TableStructureModel
|
49
|
-
from docling.pipeline.base_pipeline import
|
48
|
+
from docling.pipeline.base_pipeline import ConvertPipeline
|
50
49
|
from docling.utils.profiling import ProfilingScope, TimeRecorder
|
51
50
|
from docling.utils.utils import chunkify
|
52
51
|
|
@@ -294,7 +293,7 @@ class RunContext:
|
|
294
293
|
# ──────────────────────────────────────────────────────────────────────────────
|
295
294
|
|
296
295
|
|
297
|
-
class ThreadedStandardPdfPipeline(
|
296
|
+
class ThreadedStandardPdfPipeline(ConvertPipeline):
|
298
297
|
"""High-performance PDF pipeline with multi-threaded stages."""
|
299
298
|
|
300
299
|
def __init__(self, pipeline_options: ThreadedPdfPipelineOptions) -> None:
|
@@ -310,7 +309,7 @@ class ThreadedStandardPdfPipeline(BasePipeline):
|
|
310
309
|
# ────────────────────────────────────────────────────────────────────────
|
311
310
|
|
312
311
|
def _init_models(self) -> None:
|
313
|
-
art_path = self.
|
312
|
+
art_path = self.artifacts_path
|
314
313
|
self.keep_images = (
|
315
314
|
self.pipeline_options.generate_page_images
|
316
315
|
or self.pipeline_options.generate_picture_images
|
@@ -337,32 +336,20 @@ class ThreadedStandardPdfPipeline(BasePipeline):
|
|
337
336
|
self.reading_order_model = ReadingOrderModel(options=ReadingOrderOptions())
|
338
337
|
|
339
338
|
# --- optional enrichment ------------------------------------------------
|
340
|
-
self.enrichment_pipe = [
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
339
|
+
self.enrichment_pipe = [
|
340
|
+
# Code Formula Enrichment Model
|
341
|
+
CodeFormulaModel(
|
342
|
+
enabled=self.pipeline_options.do_code_enrichment
|
343
|
+
or self.pipeline_options.do_formula_enrichment,
|
344
|
+
artifacts_path=self.artifacts_path,
|
345
|
+
options=CodeFormulaModelOptions(
|
346
|
+
do_code_enrichment=self.pipeline_options.do_code_enrichment,
|
347
|
+
do_formula_enrichment=self.pipeline_options.do_formula_enrichment,
|
348
|
+
),
|
349
|
+
accelerator_options=self.pipeline_options.accelerator_options,
|
348
350
|
),
|
349
|
-
|
350
|
-
|
351
|
-
if code_formula.enabled:
|
352
|
-
self.enrichment_pipe.append(code_formula)
|
353
|
-
|
354
|
-
picture_classifier = DocumentPictureClassifier(
|
355
|
-
enabled=self.pipeline_options.do_picture_classification,
|
356
|
-
artifacts_path=art_path,
|
357
|
-
options=DocumentPictureClassifierOptions(),
|
358
|
-
accelerator_options=self.pipeline_options.accelerator_options,
|
359
|
-
)
|
360
|
-
if picture_classifier.enabled:
|
361
|
-
self.enrichment_pipe.append(picture_classifier)
|
362
|
-
|
363
|
-
picture_descr = self._make_picture_description_model(art_path)
|
364
|
-
if picture_descr and picture_descr.enabled:
|
365
|
-
self.enrichment_pipe.append(picture_descr)
|
351
|
+
*self.enrichment_pipe,
|
352
|
+
]
|
366
353
|
|
367
354
|
self.keep_backend = any(
|
368
355
|
(
|
@@ -374,19 +361,6 @@ class ThreadedStandardPdfPipeline(BasePipeline):
|
|
374
361
|
)
|
375
362
|
|
376
363
|
# ---------------------------------------------------------------- helpers
|
377
|
-
def _resolve_artifacts_path(self) -> Optional[Path]:
|
378
|
-
if self.pipeline_options.artifacts_path:
|
379
|
-
p = Path(self.pipeline_options.artifacts_path).expanduser()
|
380
|
-
elif settings.artifacts_path:
|
381
|
-
p = Path(settings.artifacts_path).expanduser()
|
382
|
-
else:
|
383
|
-
return None
|
384
|
-
if not p.is_dir():
|
385
|
-
raise RuntimeError(
|
386
|
-
f"{p} does not exist or is not a directory containing the required models"
|
387
|
-
)
|
388
|
-
return p
|
389
|
-
|
390
364
|
def _make_ocr_model(self, art_path: Optional[Path]) -> Any:
|
391
365
|
factory = get_ocr_factory(
|
392
366
|
allow_external_plugins=self.pipeline_options.allow_external_plugins
|
@@ -398,20 +372,6 @@ class ThreadedStandardPdfPipeline(BasePipeline):
|
|
398
372
|
accelerator_options=self.pipeline_options.accelerator_options,
|
399
373
|
)
|
400
374
|
|
401
|
-
def _make_picture_description_model(
|
402
|
-
self, art_path: Optional[Path]
|
403
|
-
) -> Optional[PictureDescriptionBaseModel]:
|
404
|
-
factory = get_picture_description_factory(
|
405
|
-
allow_external_plugins=self.pipeline_options.allow_external_plugins
|
406
|
-
)
|
407
|
-
return factory.create_instance(
|
408
|
-
options=self.pipeline_options.picture_description_options,
|
409
|
-
enabled=self.pipeline_options.do_picture_description,
|
410
|
-
enable_remote_services=self.pipeline_options.enable_remote_services,
|
411
|
-
artifacts_path=art_path,
|
412
|
-
accelerator_options=self.pipeline_options.accelerator_options,
|
413
|
-
)
|
414
|
-
|
415
375
|
# ────────────────────────────────────────────────────────────────────────
|
416
376
|
# Build - thread pipeline
|
417
377
|
# ────────────────────────────────────────────────────────────────────────
|
@@ -585,6 +545,86 @@ class ThreadedStandardPdfPipeline(BasePipeline):
|
|
585
545
|
elements=elements, headers=headers, body=body
|
586
546
|
)
|
587
547
|
conv_res.document = self.reading_order_model(conv_res)
|
548
|
+
|
549
|
+
# Generate page images in the output
|
550
|
+
if self.pipeline_options.generate_page_images:
|
551
|
+
for page in conv_res.pages:
|
552
|
+
assert page.image is not None
|
553
|
+
page_no = page.page_no + 1
|
554
|
+
conv_res.document.pages[page_no].image = ImageRef.from_pil(
|
555
|
+
page.image, dpi=int(72 * self.pipeline_options.images_scale)
|
556
|
+
)
|
557
|
+
|
558
|
+
# Generate images of the requested element types
|
559
|
+
with warnings.catch_warnings(): # deprecated generate_table_images
|
560
|
+
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
561
|
+
if (
|
562
|
+
self.pipeline_options.generate_picture_images
|
563
|
+
or self.pipeline_options.generate_table_images
|
564
|
+
):
|
565
|
+
scale = self.pipeline_options.images_scale
|
566
|
+
for element, _level in conv_res.document.iterate_items():
|
567
|
+
if not isinstance(element, DocItem) or len(element.prov) == 0:
|
568
|
+
continue
|
569
|
+
if (
|
570
|
+
isinstance(element, PictureItem)
|
571
|
+
and self.pipeline_options.generate_picture_images
|
572
|
+
) or (
|
573
|
+
isinstance(element, TableItem)
|
574
|
+
and self.pipeline_options.generate_table_images
|
575
|
+
):
|
576
|
+
page_ix = element.prov[0].page_no - 1
|
577
|
+
page = next(
|
578
|
+
(p for p in conv_res.pages if p.page_no == page_ix),
|
579
|
+
cast("Page", None),
|
580
|
+
)
|
581
|
+
assert page is not None
|
582
|
+
assert page.size is not None
|
583
|
+
assert page.image is not None
|
584
|
+
|
585
|
+
crop_bbox = (
|
586
|
+
element.prov[0]
|
587
|
+
.bbox.scaled(scale=scale)
|
588
|
+
.to_top_left_origin(
|
589
|
+
page_height=page.size.height * scale
|
590
|
+
)
|
591
|
+
)
|
592
|
+
|
593
|
+
cropped_im = page.image.crop(crop_bbox.as_tuple())
|
594
|
+
element.image = ImageRef.from_pil(
|
595
|
+
cropped_im, dpi=int(72 * scale)
|
596
|
+
)
|
597
|
+
|
598
|
+
# Aggregate confidence values for document:
|
599
|
+
if len(conv_res.pages) > 0:
|
600
|
+
with warnings.catch_warnings():
|
601
|
+
warnings.filterwarnings(
|
602
|
+
"ignore",
|
603
|
+
category=RuntimeWarning,
|
604
|
+
message="Mean of empty slice|All-NaN slice encountered",
|
605
|
+
)
|
606
|
+
conv_res.confidence.layout_score = float(
|
607
|
+
np.nanmean(
|
608
|
+
[c.layout_score for c in conv_res.confidence.pages.values()]
|
609
|
+
)
|
610
|
+
)
|
611
|
+
conv_res.confidence.parse_score = float(
|
612
|
+
np.nanquantile(
|
613
|
+
[c.parse_score for c in conv_res.confidence.pages.values()],
|
614
|
+
q=0.1, # parse score should relate to worst 10% of pages.
|
615
|
+
)
|
616
|
+
)
|
617
|
+
conv_res.confidence.table_score = float(
|
618
|
+
np.nanmean(
|
619
|
+
[c.table_score for c in conv_res.confidence.pages.values()]
|
620
|
+
)
|
621
|
+
)
|
622
|
+
conv_res.confidence.ocr_score = float(
|
623
|
+
np.nanmean(
|
624
|
+
[c.ocr_score for c in conv_res.confidence.pages.values()]
|
625
|
+
)
|
626
|
+
)
|
627
|
+
|
588
628
|
return conv_res
|
589
629
|
|
590
630
|
# ---------------------------------------------------------------- misc
|
docling/pipeline/vlm_pipeline.py
CHANGED
@@ -54,18 +54,6 @@ class VlmPipeline(PaginatedPipeline):
|
|
54
54
|
|
55
55
|
self.pipeline_options: VlmPipelineOptions
|
56
56
|
|
57
|
-
artifacts_path: Optional[Path] = None
|
58
|
-
if pipeline_options.artifacts_path is not None:
|
59
|
-
artifacts_path = Path(pipeline_options.artifacts_path).expanduser()
|
60
|
-
elif settings.artifacts_path is not None:
|
61
|
-
artifacts_path = Path(settings.artifacts_path).expanduser()
|
62
|
-
|
63
|
-
if artifacts_path is not None and not artifacts_path.is_dir():
|
64
|
-
raise RuntimeError(
|
65
|
-
f"The value of {artifacts_path=} is not valid. "
|
66
|
-
"When defined, it must point to a folder containing all models required by the pipeline."
|
67
|
-
)
|
68
|
-
|
69
57
|
# force_backend_text = False - use text that is coming from VLM response
|
70
58
|
# force_backend_text = True - get text from backend using bounding boxes predicted by SmolDocling doctags
|
71
59
|
self.force_backend_text = (
|
@@ -89,7 +77,7 @@ class VlmPipeline(PaginatedPipeline):
|
|
89
77
|
self.build_pipe = [
|
90
78
|
HuggingFaceMlxModel(
|
91
79
|
enabled=True, # must be always enabled for this pipeline to make sense.
|
92
|
-
artifacts_path=artifacts_path,
|
80
|
+
artifacts_path=self.artifacts_path,
|
93
81
|
accelerator_options=pipeline_options.accelerator_options,
|
94
82
|
vlm_options=vlm_options,
|
95
83
|
),
|
@@ -98,7 +86,7 @@ class VlmPipeline(PaginatedPipeline):
|
|
98
86
|
self.build_pipe = [
|
99
87
|
HuggingFaceTransformersVlmModel(
|
100
88
|
enabled=True, # must be always enabled for this pipeline to make sense.
|
101
|
-
artifacts_path=artifacts_path,
|
89
|
+
artifacts_path=self.artifacts_path,
|
102
90
|
accelerator_options=pipeline_options.accelerator_options,
|
103
91
|
vlm_options=vlm_options,
|
104
92
|
),
|
@@ -109,7 +97,7 @@ class VlmPipeline(PaginatedPipeline):
|
|
109
97
|
self.build_pipe = [
|
110
98
|
VllmVlmModel(
|
111
99
|
enabled=True, # must be always enabled for this pipeline to make sense.
|
112
|
-
artifacts_path=artifacts_path,
|
100
|
+
artifacts_path=self.artifacts_path,
|
113
101
|
accelerator_options=pipeline_options.accelerator_options,
|
114
102
|
vlm_options=vlm_options,
|
115
103
|
),
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: docling
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.52.0
|
4
4
|
Summary: SDK and CLI for parsing PDF, DOCX, HTML, and more, to a unified document representation for powering downstream workflows such as gen AI applications.
|
5
5
|
Author-email: Christoph Auer <cau@zurich.ibm.com>, Michele Dolfi <dol@zurich.ibm.com>, Maxim Lysak <mly@zurich.ibm.com>, Nikos Livathinos <nli@zurich.ibm.com>, Ahmed Nassar <ahn@zurich.ibm.com>, Panos Vagenas <pva@zurich.ibm.com>, Peter Staar <taa@zurich.ibm.com>
|
6
6
|
License-Expression: MIT
|
@@ -26,8 +26,8 @@ Requires-Python: <4.0,>=3.9
|
|
26
26
|
Description-Content-Type: text/markdown
|
27
27
|
License-File: LICENSE
|
28
28
|
Requires-Dist: pydantic<3.0.0,>=2.0.0
|
29
|
-
Requires-Dist: docling-core[chunking]<3.0.0,>=2.
|
30
|
-
Requires-Dist: docling-parse<5.0.0,>=4.
|
29
|
+
Requires-Dist: docling-core[chunking]<3.0.0,>=2.48.0
|
30
|
+
Requires-Dist: docling-parse<5.0.0,>=4.4.0
|
31
31
|
Requires-Dist: docling-ibm-models<4,>=3.9.1
|
32
32
|
Requires-Dist: filetype<2.0.0,>=1.2.0
|
33
33
|
Requires-Dist: pypdfium2!=4.30.1,<5.0.0,>=4.30.0
|
@@ -101,22 +101,29 @@ Docling simplifies document processing, parsing diverse formats — including ad
|
|
101
101
|
|
102
102
|
## Features
|
103
103
|
|
104
|
-
* 🗂️
|
104
|
+
* 🗂️ Parsing of [multiple document formats][supported_formats] incl. PDF, DOCX, PPTX, XLSX, HTML, WAV, MP3, images (PNG, TIFF, JPEG, ...), and more
|
105
105
|
* 📑 Advanced PDF understanding incl. page layout, reading order, table structure, code, formulas, image classification, and more
|
106
106
|
* 🧬 Unified, expressive [DoclingDocument][docling_document] representation format
|
107
|
-
* ↪️
|
107
|
+
* ↪️ Various [export formats][supported_formats] and options, including Markdown, HTML, [DocTags](https://arxiv.org/abs/2503.11576) and lossless JSON
|
108
108
|
* 🔒 Local execution capabilities for sensitive data and air-gapped environments
|
109
109
|
* 🤖 Plug-and-play [integrations][integrations] incl. LangChain, LlamaIndex, Crew AI & Haystack for agentic AI
|
110
110
|
* 🔍 Extensive OCR support for scanned PDFs and images
|
111
111
|
* 👓 Support of several Visual Language Models ([SmolDocling](https://huggingface.co/ds4sd/SmolDocling-256M-preview))
|
112
|
-
* 🎙️
|
112
|
+
* 🎙️ Audio support with Automatic Speech Recognition (ASR) models
|
113
|
+
* 🔌 Connect to any agent using the [MCP server](https://docling-project.github.io/docling/usage/mcp/)
|
113
114
|
* 💻 Simple and convenient CLI
|
114
115
|
|
116
|
+
### What's new
|
117
|
+
* 📤 Structured [information extraction][extraction] \[🧪 beta\]
|
118
|
+
* 📑 New layout model (**Heron**) by default, for faster PDF parsing
|
119
|
+
* 🔌 [MCP server](https://docling-project.github.io/docling/usage/mcp/) for agentic applications
|
120
|
+
|
115
121
|
### Coming soon
|
116
122
|
|
117
123
|
* 📝 Metadata extraction, including title, authors, references & language
|
118
124
|
* 📝 Chart understanding (Barchart, Piechart, LinePlot, etc)
|
119
125
|
* 📝 Complex chemistry understanding (Molecular structures)
|
126
|
+
* 📝 Parsing of Web Video Text Tracks (WebVTT) files
|
120
127
|
|
121
128
|
## Installation
|
122
129
|
|
@@ -142,7 +149,7 @@ result = converter.convert(source)
|
|
142
149
|
print(result.document.export_to_markdown()) # output: "## Docling Technical Report[...]"
|
143
150
|
```
|
144
151
|
|
145
|
-
More [advanced usage options](https://docling-project.github.io/docling/usage/) are available in
|
152
|
+
More [advanced usage options](https://docling-project.github.io/docling/usage/advanced_options/) are available in
|
146
153
|
the docs.
|
147
154
|
|
148
155
|
## CLI
|
@@ -222,3 +229,4 @@ The project was started by the AI for knowledge team at IBM Research Zurich.
|
|
222
229
|
[supported_formats]: https://docling-project.github.io/docling/usage/supported_formats/
|
223
230
|
[docling_document]: https://docling-project.github.io/docling/concepts/docling_document/
|
224
231
|
[integrations]: https://docling-project.github.io/docling/integrations/
|
232
|
+
[extraction]: https://docling-project.github.io/docling/examples/extraction/
|
@@ -9,7 +9,7 @@ docling/backend/asciidoc_backend.py,sha256=RDNLrPJHxROiM7-NQdZn3DdvAyiPAndbSWcZo
|
|
9
9
|
docling/backend/csv_backend.py,sha256=2g9famYG2W-ID9jEdZPxc6O8QGv1vWQfjN8pL-QMBE0,4536
|
10
10
|
docling/backend/docling_parse_backend.py,sha256=9rUo1vPxX6QLzGqF-2B2iEYglZg6YQ3Uea00XrLluTg,7918
|
11
11
|
docling/backend/docling_parse_v2_backend.py,sha256=3ckTfke8IICjaImlIzc3TRhG7KDuxDDba0AuCEcjA-M,9500
|
12
|
-
docling/backend/docling_parse_v4_backend.py,sha256=
|
12
|
+
docling/backend/docling_parse_v4_backend.py,sha256=xCBbaaXjNNrOaod9tmBuCbe5mL_ipmTNG2XOxVbGG3w,7891
|
13
13
|
docling/backend/html_backend.py,sha256=7I3BQSmC7P47jpzXHt3OuPNhtVedJiZVEjjLykyx5pY,42245
|
14
14
|
docling/backend/md_backend.py,sha256=qCI7SD9hnWWGrkG_drpzQv2Z7DVBG4Tsq3hhTsYV790,22562
|
15
15
|
docling/backend/mets_gbs_backend.py,sha256=EA8sY6tbmGiysKGYPPZiNlK-i7Adn8bLTo-7Ym15hTU,12774
|
@@ -30,7 +30,7 @@ docling/backend/xml/jats_backend.py,sha256=LPj33EFdi2MRCakkLWrRLlUAc-B-949f8zp5g
|
|
30
30
|
docling/backend/xml/uspto_backend.py,sha256=nyAMr5ht7dclxkVDwsKNeiOhLQrUtRLS8JdscB2AVJg,70924
|
31
31
|
docling/chunking/__init__.py,sha256=h83TDs0AuOV6oEPLAPrn9dpGKiU-2Vg6IRNo4cv6GDA,346
|
32
32
|
docling/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
|
-
docling/cli/main.py,sha256=
|
33
|
+
docling/cli/main.py,sha256=K4m7dtnLUM2gqU8n_Mntpc_ODrwWtrjBPTUZakQ8erg,32111
|
34
34
|
docling/cli/models.py,sha256=5C3CZz3HZXoCrBl92Is62KMCtUqsZK-oygj1hqzJ8vo,6008
|
35
35
|
docling/cli/tools.py,sha256=QhtRxQG0TVrfsMqdv5i7J0_qQy1ZZyWYnHPwJl7b5oY,322
|
36
36
|
docling/datamodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -40,25 +40,25 @@ docling/datamodel/base_models.py,sha256=vOt895z0GsFirHkkI3hM23e9oyUuz9RXfcGFtoIN
|
|
40
40
|
docling/datamodel/document.py,sha256=ElY7G6FYJ6Bayyw433_tbnxyE47fnQRoBG_mygvOBrA,17370
|
41
41
|
docling/datamodel/extraction.py,sha256=7dgvtK5SuvgfB8LHAwS1FwrW1kcMQJuJG0ol8uAQgoQ,1323
|
42
42
|
docling/datamodel/layout_model_specs.py,sha256=GSkJ-Z_0PVgwWGi7C7TsxbzRjlrWS9ZrHJjHumv-Z5U,2339
|
43
|
-
docling/datamodel/pipeline_options.py,sha256=
|
43
|
+
docling/datamodel/pipeline_options.py,sha256=N9g-3FA4hFU8A0uGvPmcy1emBBT4JH6u7CUzl3D-Ta0,11049
|
44
44
|
docling/datamodel/pipeline_options_asr_model.py,sha256=7X068xl-qpbyPxC7-TwX7Q6tLyZXGT5h1osZ_xLNLM0,1454
|
45
45
|
docling/datamodel/pipeline_options_vlm_model.py,sha256=AcqqThSW74hwQ6x7pazzm57LnJiUqB7gQi5wFayGlbk,2628
|
46
46
|
docling/datamodel/settings.py,sha256=c0MTw6pO5be_BKxHKYl4SaBJAw_qL-aapxp-g5HHj1A,2084
|
47
47
|
docling/datamodel/vlm_model_specs.py,sha256=8D-bF95EoaD-Wd29lVX094HPJT1gYN393aFmzv7RipQ,8713
|
48
48
|
docling/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
49
49
|
docling/models/api_vlm_model.py,sha256=-zisU32pgDRbychyG6-neB0qweNbPaYnLXwiGT7SEdI,2859
|
50
|
-
docling/models/base_model.py,sha256=
|
50
|
+
docling/models/base_model.py,sha256=beMGyrpl-yYX3YnLzQkLfxMLxwmDWnbcFhkjbUlWJSU,7146
|
51
51
|
docling/models/base_ocr_model.py,sha256=kT8TylASOpPlY60rIG6VL6_eLVsfg5KvEVnZHzDWtR0,8193
|
52
52
|
docling/models/code_formula_model.py,sha256=XRugm4EwifLRc-TrAk-glKlktJP-nAPneKh2EOovkJU,11308
|
53
53
|
docling/models/document_picture_classifier.py,sha256=9JvoWeH5uQBC7levjM8zptk7UT-b8EQnD-2EnxTjTT4,6202
|
54
|
-
docling/models/easyocr_model.py,sha256=
|
54
|
+
docling/models/easyocr_model.py,sha256=sCWIe2xUYU1uK8g4qkPXh0OkUX-rV6BRd4Deb_na9Y4,7899
|
55
55
|
docling/models/layout_model.py,sha256=2D7Ey2Mvtzyq9KARIFLaUZKzsR661h7Zggwn0IM9R3c,9154
|
56
56
|
docling/models/ocr_mac_model.py,sha256=y-1DSFDbACHpEwNTfQwzN9ab8r5j5rBFNPtQ48BzsrA,5396
|
57
57
|
docling/models/page_assemble_model.py,sha256=TvN1naez7dUodLxpUUBzpuMCpqZBTf6YSpewxgjzmrg,6323
|
58
58
|
docling/models/page_preprocessing_model.py,sha256=EmusNexws5ZmR93js_saVU0BedqZ_HIHQeY7lcf52tI,5284
|
59
59
|
docling/models/picture_description_api_model.py,sha256=o3EkV5aHW_6WzE_fdj_VRnNCrS_btclO_ZCLAUqrfl0,2377
|
60
60
|
docling/models/picture_description_base_model.py,sha256=kLthLhdlgwhootQ4_xhhcAk6A-vso5-qcsFJ3TcYfO0,2991
|
61
|
-
docling/models/picture_description_vlm_model.py,sha256=
|
61
|
+
docling/models/picture_description_vlm_model.py,sha256=Uja_BQSk7F-U1J2hm4yeLguirUzKYv1K8zRyw1IYomY,4150
|
62
62
|
docling/models/rapid_ocr_model.py,sha256=7yZC7I1qoC9xC8xJIjTk2c8VFm89RfB6Vr7IDOnr5gs,7102
|
63
63
|
docling/models/readingorder_model.py,sha256=bZoXHaSwUsa8niSmJrbCuy784ixCeBXT-RQBUfgHJ4A,14925
|
64
64
|
docling/models/table_structure_model.py,sha256=7vO8LisdoqCTsY8X8lsk9d-oD2hVjUtdaWlkMTQxEg0,12518
|
@@ -73,19 +73,19 @@ docling/models/plugins/defaults.py,sha256=OAHWW2tCcUXSyDMFxV_lXVRjSBJ1n6z-Eb3R8c
|
|
73
73
|
docling/models/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
74
74
|
docling/models/utils/hf_model_download.py,sha256=scBEfsM4yl7xPzqe7UtPvDh9RfQZQnuOhqQKilYBHls,984
|
75
75
|
docling/models/vlm_models_inline/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
76
|
-
docling/models/vlm_models_inline/hf_transformers_model.py,sha256=
|
76
|
+
docling/models/vlm_models_inline/hf_transformers_model.py,sha256=wcBsUGHuPNoZn9pfQh4cyyZi1bFGCoF30T_MFVGDyyM,12128
|
77
77
|
docling/models/vlm_models_inline/mlx_model.py,sha256=VP05v97mqzmaG4o9bOpJcxIlEqvNzAapJ15Zz3E3ACI,10169
|
78
|
-
docling/models/vlm_models_inline/nuextract_transformers_model.py,sha256=
|
78
|
+
docling/models/vlm_models_inline/nuextract_transformers_model.py,sha256=jLNtlkMDheUyWot7Oqq-GHQIYzJ0fZrbReq5xCnYb9E,10506
|
79
79
|
docling/models/vlm_models_inline/vllm_model.py,sha256=_EnK1nfpAPJky7aRlyp8SUIghiZOQO8AkDN_hHqXLZg,8615
|
80
80
|
docling/pipeline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
81
|
-
docling/pipeline/asr_pipeline.py,sha256=
|
82
|
-
docling/pipeline/base_extraction_pipeline.py,sha256=
|
83
|
-
docling/pipeline/base_pipeline.py,sha256=
|
84
|
-
docling/pipeline/extraction_vlm_pipeline.py,sha256=
|
85
|
-
docling/pipeline/simple_pipeline.py,sha256=
|
86
|
-
docling/pipeline/standard_pdf_pipeline.py,sha256=
|
87
|
-
docling/pipeline/threaded_standard_pdf_pipeline.py,sha256=
|
88
|
-
docling/pipeline/vlm_pipeline.py,sha256=
|
81
|
+
docling/pipeline/asr_pipeline.py,sha256=S55VHLoX3Mgauen1YP-PSUlI0LA1bgTgTkU-eC4U-dg,8481
|
82
|
+
docling/pipeline/base_extraction_pipeline.py,sha256=GYrEz83IXv-tdIHjtNWxMBNczFwL8SZyf9vnPJ3STaI,2627
|
83
|
+
docling/pipeline/base_pipeline.py,sha256=NPMQDTyis-LgQ4SybY2f5AESZl5PxogF-FRQuCDckXg,12748
|
84
|
+
docling/pipeline/extraction_vlm_pipeline.py,sha256=veUOTe8nGdnduZKaGn1RRb-NfU1H6t_EN4QAsb022Zg,8260
|
85
|
+
docling/pipeline/simple_pipeline.py,sha256=FSL_ucDd9k0D9DjNKMUkyCULIU8a057dvWfLEPmAc2A,2287
|
86
|
+
docling/pipeline/standard_pdf_pipeline.py,sha256=xOge0zP5wli51n_6QLrFHQlwwvsivI7OMt00tht3my4,10479
|
87
|
+
docling/pipeline/threaded_standard_pdf_pipeline.py,sha256=i67G5AOW7PIFCe5JS2sdBmPAKvAH6ScxIBhjwOGZcrI,28183
|
88
|
+
docling/pipeline/vlm_pipeline.py,sha256=oMcdgzym_UQbVN3bajux_hENY40XGOnb6NU6Kwje2Os,15376
|
89
89
|
docling/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
90
90
|
docling/utils/accelerator_utils.py,sha256=DSajLxVx1JEVT0zt5de26llciLNlVfIDfSa2zYCFJzQ,2909
|
91
91
|
docling/utils/api_image_request.py,sha256=_CgdzmPqdsyXmyYUFGLZcXcoH586qC6A1p5vsNbj1Q0,1416
|
@@ -99,9 +99,9 @@ docling/utils/orientation.py,sha256=jTyLxyT31FlOodZoBMlADHNQK2lAWKYVs5z7pXd_6Cg,
|
|
99
99
|
docling/utils/profiling.py,sha256=YaMGoB9MMZpagF9mb5ndoHj8Lpb9aIdb7El-Pl7IcFs,1753
|
100
100
|
docling/utils/utils.py,sha256=kJtIYuzXeOyJHYlxmLAo7dGM5rEsDa1i84qEsUj1nio,1908
|
101
101
|
docling/utils/visualization.py,sha256=tY2ylE2aiQKkmzlSLnFW-HTfFyqUUMguW18ldd1PLfo,2868
|
102
|
-
docling-2.
|
103
|
-
docling-2.
|
104
|
-
docling-2.
|
105
|
-
docling-2.
|
106
|
-
docling-2.
|
107
|
-
docling-2.
|
102
|
+
docling-2.52.0.dist-info/licenses/LICENSE,sha256=mBb7ErEcM8VS9OhiGHnQ2kk75HwPhr54W1Oiz3965MY,1088
|
103
|
+
docling-2.52.0.dist-info/METADATA,sha256=EhUePtqwKQJTgkU9pCtvpWT7wtU-84KXkc48XExkRSQ,11233
|
104
|
+
docling-2.52.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
105
|
+
docling-2.52.0.dist-info/entry_points.txt,sha256=hzVlbeE0aMSTQ9S0-NTYN0Hmgsn6qL_EA2qX4UbkAuY,149
|
106
|
+
docling-2.52.0.dist-info/top_level.txt,sha256=vkIywP-USjFyYo1AIRQbWQQaL3xB5jf8vkCYdTIfNic,8
|
107
|
+
docling-2.52.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|