docling-core 2.97.2__tar.gz → 2.98.0__tar.gz
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_core-2.97.2 → docling_core-2.98.0}/PKG-INFO +1 -1
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/markdown.py +82 -3
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/__init__.py +1 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/base.py +7 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/document.py +11 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core.egg-info/PKG-INFO +1 -1
- {docling_core-2.97.2 → docling_core-2.98.0}/pyproject.toml +1 -1
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_serialization.py +123 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/LICENSE +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/README.md +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/cli/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/cli/serialize.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/cli/view.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/compat.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/experimental/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/experimental/serializer/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/experimental/serializer/outline.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/py.typed +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/search/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/search/package.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/base.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/chunk_expander.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/code_chunking/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/code_chunking/_language_code_chunkers.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/code_chunking/_utils.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/code_chunking/base_code_chunking_strategy.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/code_chunking/code_chunk.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/code_chunking/standard_code_chunking_strategy.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/doc_chunk.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/hierarchical_chunker.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/hybrid_chunker.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/line_chunker.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/page_chunker.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/tokenizer/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/tokenizer/base.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/tokenizer/huggingface.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/tokenizer/openai.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/deserializer/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/deserializer/base.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/deserializer/doclang.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/deserializer/doclang_source_mapping.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/profiler/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/profiler/doc_profiler.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/_doclang_utils.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/azure.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/base.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/common.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/doclang.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/doctags.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/html.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/html_styles.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/latex.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/markdown_excel.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/plain_text.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/webvtt.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/visualizer/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/visualizer/base.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/visualizer/key_value_visualizer.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/visualizer/layout_visualizer.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/visualizer/reading_order_visualizer.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/visualizer/table_visualizer.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/base.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/annotations.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/constants.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/content_layer.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/formatting.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/meta.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/origin.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/reference.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/scalars.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/common/source.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/doctags.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/code.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/content.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/form.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/group.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/key_value.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/node.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/picture/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/picture/charts.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/picture/classification.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/picture/meta.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/picture/molecule.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/picture/picture.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/table/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/table/table.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/table/table_data.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/text.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/labels.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/page.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/tokens.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/utils.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/webvtt.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/io/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/legacy_doc/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/legacy_doc/base.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/legacy_doc/document.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/utils/__init__.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/utils/alias.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/utils/file.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/utils/generate_docs.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/utils/generate_jsonschema.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/utils/legacy.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/utils/settings.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core/utils/validators.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core.egg-info/SOURCES.txt +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core.egg-info/dependency_links.txt +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core.egg-info/entry_points.txt +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core.egg-info/requires.txt +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/docling_core.egg-info/top_level.txt +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/setup.cfg +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_azure_serializer.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_base.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_chunk_expander.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_cli_serialize.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_code_chunker.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_code_chunking_strategy.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_compat.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_data_gen_flag.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_deserializer_doclang.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_deserializer_doclang_source_mapping.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_doc_base.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_doclang_archive.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_docling_doc.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_doctags_load.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_hierarchical_chunker.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_hierarchy.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_hybrid_chunker.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_latex_serialization.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_line_chunker.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_metadata.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_otsl_table_export.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_page.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_page_chunker.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_plain_text_serialization.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_profiler.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_regions_to_table.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_serialization_doclang.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_serialization_doctag.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_serialization_outline.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_tokens.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_upath_support.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_utils.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_visualization.py +0 -0
- {docling_core-2.97.2 → docling_core-2.98.0}/tests/test_webvtt.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docling-core
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.98.0
|
|
4
4
|
Summary: A python library to define and validate data types in Docling.
|
|
5
5
|
Author-email: Cesar Berrospi Ramis <ceb@zurich.ibm.com>, Panos Vagenas <pva@zurich.ibm.com>, Michele Dolfi <dol@zurich.ibm.com>, Christoph Auer <cau@zurich.ibm.com>, Peter Staar <taa@zurich.ibm.com>
|
|
6
6
|
Maintainer-email: Panos Vagenas <pva@zurich.ibm.com>, Michele Dolfi <dol@zurich.ibm.com>, Christoph Auer <cau@zurich.ibm.com>, Peter Staar <taa@zurich.ibm.com>, Cesar Berrospi Ramis <ceb@zurich.ibm.com>
|
|
@@ -37,8 +37,10 @@ from docling_core.transforms.serializer.common import (
|
|
|
37
37
|
)
|
|
38
38
|
from docling_core.types.doc import (
|
|
39
39
|
BaseMeta,
|
|
40
|
+
CaptionPlacement,
|
|
40
41
|
CodeItem,
|
|
41
42
|
ContentLayer,
|
|
43
|
+
CoordOrigin,
|
|
42
44
|
DescriptionAnnotation,
|
|
43
45
|
DescriptionMetaField,
|
|
44
46
|
DocItem,
|
|
@@ -65,6 +67,7 @@ from docling_core.types.doc import (
|
|
|
65
67
|
PictureItem,
|
|
66
68
|
PictureMoleculeData,
|
|
67
69
|
PictureTabularChartData,
|
|
70
|
+
ProvenanceItem,
|
|
68
71
|
RichTableCell,
|
|
69
72
|
SectionHeaderItem,
|
|
70
73
|
SummaryMetaField,
|
|
@@ -89,6 +92,61 @@ def _cell_content_has_table(item: NodeItem, doc: DoclingDocument) -> bool:
|
|
|
89
92
|
return False
|
|
90
93
|
|
|
91
94
|
|
|
95
|
+
def _captions_below_item(item: FloatingItem, doc: DoclingDocument) -> bool | None:
|
|
96
|
+
"""Tell whether the item's captions sit below the item, judging by bbox centers.
|
|
97
|
+
|
|
98
|
+
Returns ``True`` if every caption is centered lower than the item on the page,
|
|
99
|
+
``False`` if the item has captions located at or above it, and ``None`` if the
|
|
100
|
+
position cannot be determined (no captions, missing provenance, different pages
|
|
101
|
+
or unresolvable page height), in which case the caller keeps its default order.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
def center_y(prov: ProvenanceItem) -> float | None:
|
|
105
|
+
bbox = prov.bbox
|
|
106
|
+
if bbox.coord_origin != CoordOrigin.TOPLEFT:
|
|
107
|
+
page = doc.pages.get(prov.page_no)
|
|
108
|
+
if page is None:
|
|
109
|
+
return None
|
|
110
|
+
bbox = bbox.to_top_left_origin(page_height=page.size.height)
|
|
111
|
+
return (bbox.t + bbox.b) / 2
|
|
112
|
+
|
|
113
|
+
if not item.prov or not item.captions:
|
|
114
|
+
return None
|
|
115
|
+
item_prov = item.prov[0]
|
|
116
|
+
item_y = center_y(item_prov)
|
|
117
|
+
if item_y is None:
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
below: list[bool] = []
|
|
121
|
+
for cap_ref in item.captions:
|
|
122
|
+
cap = cap_ref.resolve(doc)
|
|
123
|
+
if not isinstance(cap, DocItem):
|
|
124
|
+
continue
|
|
125
|
+
cap_prov = next((p for p in cap.prov if p.page_no == item_prov.page_no), None)
|
|
126
|
+
if cap_prov is None or (cap_y := center_y(cap_prov)) is None:
|
|
127
|
+
return None
|
|
128
|
+
below.append(cap_y > item_y)
|
|
129
|
+
return all(below) if below else None
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _caption_goes_after(
|
|
133
|
+
item: FloatingItem,
|
|
134
|
+
doc: DoclingDocument,
|
|
135
|
+
params: "MarkdownParams",
|
|
136
|
+
standard_after: bool,
|
|
137
|
+
) -> bool:
|
|
138
|
+
"""Decide whether the item's captions are serialized after the item.
|
|
139
|
+
|
|
140
|
+
``standard_after`` is the item type's default order, used for ``STANDARD``
|
|
141
|
+
placement and whenever ``LAYOUT`` placement cannot determine the position.
|
|
142
|
+
"""
|
|
143
|
+
if params.caption_placement == CaptionPlacement.LAYOUT:
|
|
144
|
+
below = _captions_below_item(item, doc)
|
|
145
|
+
if below is not None:
|
|
146
|
+
return below
|
|
147
|
+
return standard_after
|
|
148
|
+
|
|
149
|
+
|
|
92
150
|
def _mark_subtree_visited(
|
|
93
151
|
item: NodeItem,
|
|
94
152
|
doc: DoclingDocument,
|
|
@@ -197,6 +255,15 @@ class MarkdownParams(CommonParams):
|
|
|
197
255
|
default=True,
|
|
198
256
|
description="Include the picture classification prediction (the image's predicted class).",
|
|
199
257
|
)
|
|
258
|
+
caption_placement: CaptionPlacement = Field(
|
|
259
|
+
default=CaptionPlacement.STANDARD,
|
|
260
|
+
description=(
|
|
261
|
+
"Where captions go relative to their item. 'standard' keeps the per-type order "
|
|
262
|
+
"(before tables and pictures, after code and formulas); 'layout' places a caption "
|
|
263
|
+
"after its item if the caption's bbox center is lower on the page, else before, "
|
|
264
|
+
"falling back to 'standard' when positions are unavailable."
|
|
265
|
+
),
|
|
266
|
+
)
|
|
200
267
|
|
|
201
268
|
|
|
202
269
|
class MarkdownTextSerializer(BaseModel, BaseTextSerializer):
|
|
@@ -373,7 +440,10 @@ class MarkdownTextSerializer(BaseModel, BaseTextSerializer):
|
|
|
373
440
|
if isinstance(item, FloatingItem):
|
|
374
441
|
cap_res = doc_serializer.serialize_captions(item=item, **kwargs)
|
|
375
442
|
if cap_res.text:
|
|
376
|
-
|
|
443
|
+
if _caption_goes_after(item, doc, params, standard_after=True):
|
|
444
|
+
res_parts.append(cap_res)
|
|
445
|
+
else:
|
|
446
|
+
res_parts.insert(0, cap_res)
|
|
377
447
|
|
|
378
448
|
text = (" " if is_inline_scope else "\n\n").join([r.text for r in res_parts])
|
|
379
449
|
if processing_pending:
|
|
@@ -732,7 +802,8 @@ class MarkdownTableSerializer(BaseTableSerializer):
|
|
|
732
802
|
item=item,
|
|
733
803
|
**kwargs,
|
|
734
804
|
)
|
|
735
|
-
|
|
805
|
+
cap_after = _caption_goes_after(item, doc, params, standard_after=False)
|
|
806
|
+
if cap_res.text and not cap_after:
|
|
736
807
|
res_parts.append(cap_res)
|
|
737
808
|
|
|
738
809
|
if item.self_ref not in doc_serializer.get_excluded_refs(**kwargs):
|
|
@@ -790,6 +861,9 @@ class MarkdownTableSerializer(BaseTableSerializer):
|
|
|
790
861
|
if table_text:
|
|
791
862
|
res_parts.append(create_ser_result(text=table_text, span_source=item))
|
|
792
863
|
|
|
864
|
+
if cap_res.text and cap_after:
|
|
865
|
+
res_parts.append(cap_res)
|
|
866
|
+
|
|
793
867
|
text_res = "\n\n".join([r.text for r in res_parts])
|
|
794
868
|
|
|
795
869
|
return create_ser_result(text=text_res, span_source=res_parts)
|
|
@@ -828,7 +902,8 @@ class MarkdownPictureSerializer(BasePictureSerializer):
|
|
|
828
902
|
item=item,
|
|
829
903
|
**kwargs,
|
|
830
904
|
)
|
|
831
|
-
|
|
905
|
+
cap_after = _caption_goes_after(item, doc, params, standard_after=False)
|
|
906
|
+
if cap_res.text and not cap_after:
|
|
832
907
|
res_parts.append(cap_res)
|
|
833
908
|
|
|
834
909
|
if item.self_ref not in doc_serializer.get_excluded_refs(**kwargs):
|
|
@@ -862,6 +937,10 @@ class MarkdownPictureSerializer(BasePictureSerializer):
|
|
|
862
937
|
md_table_content = temp_table.export_to_markdown(temp_doc)
|
|
863
938
|
if len(md_table_content) > 0:
|
|
864
939
|
res_parts.append(create_ser_result(text=md_table_content, span_source=item))
|
|
940
|
+
|
|
941
|
+
if cap_res.text and cap_after:
|
|
942
|
+
res_parts.append(cap_res)
|
|
943
|
+
|
|
865
944
|
text_res = "\n\n".join([r.text for r in res_parts if r.text])
|
|
866
945
|
|
|
867
946
|
return create_ser_result(text=text_res, span_source=res_parts)
|
|
@@ -14,6 +14,13 @@ class ImageRefMode(str, Enum):
|
|
|
14
14
|
REFERENCED = "referenced" # reference the image via uri
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
class CaptionPlacement(str, Enum):
|
|
18
|
+
"""Placement of captions relative to the item they caption."""
|
|
19
|
+
|
|
20
|
+
STANDARD = "standard" # per item type: before tables and pictures, after code and formulas
|
|
21
|
+
LAYOUT = "layout" # by bbox: after the item if the caption is centered lower on the page, else before
|
|
22
|
+
|
|
23
|
+
|
|
17
24
|
class CoordOrigin(str, Enum):
|
|
18
25
|
"""CoordOrigin."""
|
|
19
26
|
|
|
@@ -52,6 +52,7 @@ from typing_extensions import Self, deprecated, override
|
|
|
52
52
|
from docling_core.types.base import _JSON_POINTER_REGEX, VERSION_PATTERN, UniqueList
|
|
53
53
|
from docling_core.types.doc import BoundingBox, Size
|
|
54
54
|
from docling_core.types.doc.base import (
|
|
55
|
+
CaptionPlacement,
|
|
55
56
|
CoordOrigin,
|
|
56
57
|
ImageRefMode,
|
|
57
58
|
PydanticSerCtxKey,
|
|
@@ -3722,6 +3723,7 @@ class DoclingDocument(BaseModel):
|
|
|
3722
3723
|
mark_meta: bool = False,
|
|
3723
3724
|
use_legacy_annotations: bool | None = None, # deprecated
|
|
3724
3725
|
include_picture_classification: bool = True,
|
|
3726
|
+
caption_placement: CaptionPlacement = CaptionPlacement.STANDARD,
|
|
3725
3727
|
):
|
|
3726
3728
|
"""Save to markdown."""
|
|
3727
3729
|
if isinstance(filename, str):
|
|
@@ -3755,6 +3757,7 @@ class DoclingDocument(BaseModel):
|
|
|
3755
3757
|
use_legacy_annotations=use_legacy_annotations,
|
|
3756
3758
|
mark_meta=mark_meta,
|
|
3757
3759
|
include_picture_classification=include_picture_classification,
|
|
3760
|
+
caption_placement=caption_placement,
|
|
3758
3761
|
)
|
|
3759
3762
|
|
|
3760
3763
|
filename.write_text(md_out, encoding="utf-8")
|
|
@@ -3788,6 +3791,7 @@ class DoclingDocument(BaseModel):
|
|
|
3788
3791
|
blocked_meta_names: set[str] | None = None,
|
|
3789
3792
|
mark_meta: bool = False,
|
|
3790
3793
|
include_picture_classification: bool = True,
|
|
3794
|
+
caption_placement: CaptionPlacement = CaptionPlacement.STANDARD,
|
|
3791
3795
|
) -> str:
|
|
3792
3796
|
r"""Serialize to Markdown.
|
|
3793
3797
|
|
|
@@ -3863,6 +3867,12 @@ class DoclingDocument(BaseModel):
|
|
|
3863
3867
|
classification prediction (the image's predicted class) in the export.
|
|
3864
3868
|
(Default value = True).
|
|
3865
3869
|
:type include_picture_classification: bool = True
|
|
3870
|
+
:param caption_placement: Where captions go relative to their item: "standard" keeps
|
|
3871
|
+
the per-type order (before tables and pictures, after code and formulas); "layout"
|
|
3872
|
+
places a caption after its item if the caption's bbox center is lower on the page,
|
|
3873
|
+
else before, falling back to "standard" when positions are unavailable.
|
|
3874
|
+
(Default value = CaptionPlacement.STANDARD).
|
|
3875
|
+
:type caption_placement: CaptionPlacement = CaptionPlacement.STANDARD
|
|
3866
3876
|
"""
|
|
3867
3877
|
from docling_core.transforms.serializer.markdown import (
|
|
3868
3878
|
MarkdownDocSerializer,
|
|
@@ -3915,6 +3925,7 @@ class DoclingDocument(BaseModel):
|
|
|
3915
3925
|
compact_tables=compact_tables,
|
|
3916
3926
|
traverse_pictures=traverse_pictures,
|
|
3917
3927
|
include_picture_classification=include_picture_classification,
|
|
3928
|
+
caption_placement=caption_placement,
|
|
3918
3929
|
),
|
|
3919
3930
|
)
|
|
3920
3931
|
ser_res = serializer.serialize()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docling-core
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.98.0
|
|
4
4
|
Summary: A python library to define and validate data types in Docling.
|
|
5
5
|
Author-email: Cesar Berrospi Ramis <ceb@zurich.ibm.com>, Panos Vagenas <pva@zurich.ibm.com>, Michele Dolfi <dol@zurich.ibm.com>, Christoph Auer <cau@zurich.ibm.com>, Peter Staar <taa@zurich.ibm.com>
|
|
6
6
|
Maintainer-email: Panos Vagenas <pva@zurich.ibm.com>, Michele Dolfi <dol@zurich.ibm.com>, Christoph Auer <cau@zurich.ibm.com>, Peter Staar <taa@zurich.ibm.com>, Cesar Berrospi Ramis <ceb@zurich.ibm.com>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "docling-core"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.98.0" # DO NOT EDIT, updated automatically
|
|
4
4
|
description = "A python library to define and validate data types in Docling."
|
|
5
5
|
license = "MIT"
|
|
6
6
|
license-files = ["LICENSE"]
|
|
@@ -18,6 +18,7 @@ from docling_core.transforms.serializer.html import (
|
|
|
18
18
|
HTMLTableSerializer,
|
|
19
19
|
)
|
|
20
20
|
from docling_core.transforms.serializer.markdown import (
|
|
21
|
+
CaptionPlacement,
|
|
21
22
|
MarkdownDocSerializer,
|
|
22
23
|
MarkdownParams,
|
|
23
24
|
MarkdownPictureSerializer,
|
|
@@ -1747,3 +1748,125 @@ def test_export_to_html_image_dir_without_referenced_raises(sample_doc, tmp_path
|
|
|
1747
1748
|
"""Passing image_dir without REFERENCED mode raises ValueError."""
|
|
1748
1749
|
with pytest.raises(ValueError, match=r"ImageRefMode\.REFERENCED"):
|
|
1749
1750
|
sample_doc.export_to_html(image_dir=tmp_path / "images")
|
|
1751
|
+
|
|
1752
|
+
|
|
1753
|
+
def _make_captioned_doc(
|
|
1754
|
+
*,
|
|
1755
|
+
kind: str,
|
|
1756
|
+
cap_bbox: BoundingBox | None,
|
|
1757
|
+
obj_bbox: BoundingBox | None,
|
|
1758
|
+
page_no: int = 1,
|
|
1759
|
+
) -> DoclingDocument:
|
|
1760
|
+
doc = DoclingDocument(name="cap_order")
|
|
1761
|
+
doc.add_page(page_no=1, size=Size(width=100, height=200))
|
|
1762
|
+
|
|
1763
|
+
def prov(bbox: BoundingBox | None) -> ProvenanceItem | None:
|
|
1764
|
+
if bbox is None:
|
|
1765
|
+
return None
|
|
1766
|
+
return ProvenanceItem(page_no=page_no, bbox=bbox, charspan=(0, 0))
|
|
1767
|
+
|
|
1768
|
+
caption = doc.add_text(label=DocItemLabel.CAPTION, text="THE CAPTION", prov=prov(cap_bbox))
|
|
1769
|
+
if kind == "table":
|
|
1770
|
+
table_data = TableData(num_rows=1, num_cols=1)
|
|
1771
|
+
table_data.add_row(["cell"])
|
|
1772
|
+
table_data.num_rows = 1
|
|
1773
|
+
doc.add_table(data=table_data, caption=caption, prov=prov(obj_bbox))
|
|
1774
|
+
else:
|
|
1775
|
+
doc.add_picture(caption=caption, prov=prov(obj_bbox))
|
|
1776
|
+
return doc
|
|
1777
|
+
|
|
1778
|
+
|
|
1779
|
+
def _tl(t: float, b: float) -> BoundingBox:
|
|
1780
|
+
return BoundingBox(l=0, r=10, t=t, b=b, coord_origin=CoordOrigin.TOPLEFT)
|
|
1781
|
+
|
|
1782
|
+
|
|
1783
|
+
def _bl(t: float, b: float) -> BoundingBox:
|
|
1784
|
+
return BoundingBox(l=0, r=10, t=t, b=b, coord_origin=CoordOrigin.BOTTOMLEFT)
|
|
1785
|
+
|
|
1786
|
+
|
|
1787
|
+
def _serialize_md(doc: DoclingDocument, placement: CaptionPlacement) -> str:
|
|
1788
|
+
return MarkdownDocSerializer(doc=doc, params=MarkdownParams(caption_placement=placement)).serialize().text
|
|
1789
|
+
|
|
1790
|
+
|
|
1791
|
+
@pytest.mark.parametrize("kind, marker", [("table", "cell"), ("picture", "<!-- image -->")])
|
|
1792
|
+
@pytest.mark.parametrize(
|
|
1793
|
+
"cap_bbox, obj_bbox, layout_caption_first",
|
|
1794
|
+
[
|
|
1795
|
+
(None, None, True), # no bboxes: falls back to standard order (caption first)
|
|
1796
|
+
(_tl(150, 170), None, True), # object without bbox: falls back to standard order
|
|
1797
|
+
(_tl(10, 30), _tl(50, 100), True), # caption above
|
|
1798
|
+
(_tl(150, 170), _tl(50, 100), False), # caption below
|
|
1799
|
+
(_bl(190, 170), _bl(150, 100), True), # caption above, BOTTOMLEFT origin
|
|
1800
|
+
(_bl(50, 30), _bl(150, 100), False), # caption below, BOTTOMLEFT origin
|
|
1801
|
+
(_tl(150, 170), _bl(150, 100), False), # mixed origins: caption (y=160) below object (y=75)
|
|
1802
|
+
(_tl(10, 30), _bl(150, 100), True), # mixed origins: caption (y=20) above object (y=75)
|
|
1803
|
+
],
|
|
1804
|
+
)
|
|
1805
|
+
def test_markdown_caption_placement(kind, marker, cap_bbox, obj_bbox, layout_caption_first):
|
|
1806
|
+
doc = _make_captioned_doc(kind=kind, cap_bbox=cap_bbox, obj_bbox=obj_bbox)
|
|
1807
|
+
|
|
1808
|
+
# standard ignores bboxes: tables and pictures always have the caption first
|
|
1809
|
+
md = _serialize_md(doc, CaptionPlacement.STANDARD)
|
|
1810
|
+
assert md.index("THE CAPTION") < md.index(marker)
|
|
1811
|
+
assert md == doc.export_to_markdown()
|
|
1812
|
+
|
|
1813
|
+
md = _serialize_md(doc, CaptionPlacement.LAYOUT)
|
|
1814
|
+
if layout_caption_first:
|
|
1815
|
+
assert md.index("THE CAPTION") < md.index(marker)
|
|
1816
|
+
else:
|
|
1817
|
+
assert md.index("THE CAPTION") > md.index(marker)
|
|
1818
|
+
|
|
1819
|
+
|
|
1820
|
+
def test_markdown_caption_placement_layout_other_page_falls_back_to_standard():
|
|
1821
|
+
doc = DoclingDocument(name="cap_pages")
|
|
1822
|
+
doc.add_page(page_no=1, size=Size(width=100, height=200))
|
|
1823
|
+
doc.add_page(page_no=2, size=Size(width=100, height=200))
|
|
1824
|
+
caption = doc.add_text(
|
|
1825
|
+
label=DocItemLabel.CAPTION,
|
|
1826
|
+
text="THE CAPTION",
|
|
1827
|
+
prov=ProvenanceItem(page_no=2, bbox=_tl(150, 170), charspan=(0, 0)),
|
|
1828
|
+
)
|
|
1829
|
+
doc.add_picture(caption=caption, prov=ProvenanceItem(page_no=1, bbox=_tl(50, 100), charspan=(0, 0)))
|
|
1830
|
+
md = _serialize_md(doc, CaptionPlacement.LAYOUT)
|
|
1831
|
+
assert md.index("THE CAPTION") < md.index("<!-- image -->")
|
|
1832
|
+
|
|
1833
|
+
|
|
1834
|
+
@pytest.mark.parametrize(
|
|
1835
|
+
"cap_bbox, placement, caption_first",
|
|
1836
|
+
[
|
|
1837
|
+
(None, CaptionPlacement.STANDARD, False), # standard: code captions come after
|
|
1838
|
+
(_tl(10, 30), CaptionPlacement.STANDARD, False), # standard ignores bboxes
|
|
1839
|
+
(None, CaptionPlacement.LAYOUT, False), # no bboxes: falls back to standard
|
|
1840
|
+
(_tl(10, 30), CaptionPlacement.LAYOUT, True), # caption above the code
|
|
1841
|
+
(_tl(150, 170), CaptionPlacement.LAYOUT, False), # caption below the code
|
|
1842
|
+
],
|
|
1843
|
+
)
|
|
1844
|
+
def test_markdown_caption_placement_code(cap_bbox, placement, caption_first):
|
|
1845
|
+
doc = DoclingDocument(name="cap_code")
|
|
1846
|
+
doc.add_page(page_no=1, size=Size(width=100, height=200))
|
|
1847
|
+
|
|
1848
|
+
def prov(bbox):
|
|
1849
|
+
return None if bbox is None else ProvenanceItem(page_no=1, bbox=bbox, charspan=(0, 0))
|
|
1850
|
+
|
|
1851
|
+
caption = doc.add_text(label=DocItemLabel.CAPTION, text="THE CAPTION", prov=prov(cap_bbox))
|
|
1852
|
+
code = doc.add_code(text="print(1)", prov=prov(_tl(50, 100) if cap_bbox else None))
|
|
1853
|
+
code.captions.append(caption.get_ref())
|
|
1854
|
+
|
|
1855
|
+
md = _serialize_md(doc, placement)
|
|
1856
|
+
assert (md.index("THE CAPTION") < md.index("print(1)")) == caption_first
|
|
1857
|
+
|
|
1858
|
+
|
|
1859
|
+
@pytest.mark.parametrize("placement", [CaptionPlacement.LAYOUT, "layout"])
|
|
1860
|
+
def test_export_and_save_markdown_caption_placement(tmp_path, placement):
|
|
1861
|
+
doc = _make_captioned_doc(kind="picture", cap_bbox=_tl(150, 170), obj_bbox=_tl(50, 100))
|
|
1862
|
+
|
|
1863
|
+
md = doc.export_to_markdown(caption_placement=placement)
|
|
1864
|
+
assert md.index("THE CAPTION") > md.index("<!-- image -->")
|
|
1865
|
+
|
|
1866
|
+
out = tmp_path / "out.md"
|
|
1867
|
+
doc.save_as_markdown(out, caption_placement=placement)
|
|
1868
|
+
assert out.read_text(encoding="utf-8") == md
|
|
1869
|
+
|
|
1870
|
+
# default is unchanged
|
|
1871
|
+
assert doc.export_to_markdown().index("THE CAPTION") < doc.export_to_markdown().index("<!-- image -->")
|
|
1872
|
+
assert doc.export_to_markdown() == doc.export_to_markdown(caption_placement="standard")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/experimental/serializer/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/chunk_expander.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/code_chunking/_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/hierarchical_chunker.py
RENAMED
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/hybrid_chunker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/tokenizer/__init__.py
RENAMED
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/tokenizer/base.py
RENAMED
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/tokenizer/huggingface.py
RENAMED
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/chunker/tokenizer/openai.py
RENAMED
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/deserializer/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/profiler/doc_profiler.py
RENAMED
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/_doclang_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/html_styles.py
RENAMED
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/markdown_excel.py
RENAMED
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/serializer/plain_text.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/visualizer/layout_visualizer.py
RENAMED
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/transforms/visualizer/table_visualizer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/picture/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/picture/classification.py
RENAMED
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/picture/molecule.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/docling_core/types/doc/items/table/table_data.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docling_core-2.97.2 → docling_core-2.98.0}/tests/test_deserializer_doclang_source_mapping.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|