Files
docling-core/examples/table_annotations.ipynb
Panos Vagenas d8a5256b2c feat: add table annotations (#304)
* feat: add table annotations

Signed-off-by: Panos Vagenas <pva@zurich.ibm.com>

* refactor annotation types

Signed-off-by: Panos Vagenas <pva@zurich.ibm.com>

* expand to HTML

Signed-off-by: Panos Vagenas <pva@zurich.ibm.com>

* introduce annotation serializer

Signed-off-by: Panos Vagenas <pva@zurich.ibm.com>

* Update dummy_doc.yaml

Signed-off-by: Panos Vagenas <35837085+vagenas@users.noreply.github.com>

---------

Signed-off-by: Panos Vagenas <pva@zurich.ibm.com>
Signed-off-by: Panos Vagenas <35837085+vagenas@users.noreply.github.com>
2025-06-05 15:38:46 +02:00

27 KiB

Table annotations

In [1]:
from docling_core.types.doc.document import DoclingDocument

file_path = "2408.09869v3.json"
pages = {5}  # pages to serialize (for output brevity)

doc = DoclingDocument.load_from_json(file_path)
In [2]:
from typing import Optional
from rich.console import Console
from rich.panel import Panel

def print_excerpt(
    txt: str, *, limit: int = 2000, title: Optional[str] = None, min_width: int = 80,
    table_end: str = "--|"
):
    excerpt = txt[:limit]
    width = max(
        max([ln.rfind(table_end) for ln in excerpt.splitlines()]) + len(table_end) + 4,
        min_width,
    )
    console = Console(width=width)
    console.print(Panel(f"{excerpt}{'...' if len(txt)>limit else ''}", title=title))

Adding a table annotation

Below we add a demo table annotation, picking the first table for illustrative purposes.

Note that TableMiscData allows any dict data within the content field.

In [3]:
from docling_core.types.doc.document import DescriptionAnnotation, MiscAnnotation

assert doc.tables, "No table available in this document"
table = doc.tables[0]

table.add_annotation(
    annotation=DescriptionAnnotation(
        text="A typical Docling setup runtime characterization.",
        provenance="model-foo",
    ),
)

table.add_annotation(
    annotation=MiscAnnotation(
        content={
            "type": "performance data",
            "sentiment": 0.85,
            # ...
        },
    ),
)

Default serialization

In [4]:
from docling_core.transforms.serializer.markdown import (
    MarkdownDocSerializer,
    MarkdownParams,
)

ser = MarkdownDocSerializer(
    doc=doc,
    params=MarkdownParams(
        pages=pages,
    ),
)
ser_out = ser.serialize()
ser_txt = ser_out.text

print_excerpt(ser_txt, title=f"{pages=}")
╭────────────────────────────────────────────────────────────────────────────────── pages={5} ───────────────────────────────────────────────────────────────────────────────────╮
│ torch runtimes backing the Docling pipeline. We will deliver updates on this topic at in a future version of this report.                                                      │
│                                                                                                                                                                                │
│ Table 1: Runtime characteristics of Docling with the standard model pipeline and settings, on our test dataset of 225 pages, on two different systems. OCR is disabled. We     │
│ show the time-to-solution (TTS), computed throughput in pages per second, and the peak memory used (resident set size) for both the Docling-native PDF backend and for the     │
│ pypdfium backend, using 4 and 16 threads.                                                                                                                                      │
│                                                                                                                                                                                │
│ A typical Docling setup runtime characterization.                                                                                                                              │
│                                                                                                                                                                                │
│ | CPU                              | Thread budget   | native backend   | native backend   | native backend   | pypdfium backend   | pypdfium backend   | pypdfium backend   | │
│ |----------------------------------|-----------------|------------------|------------------|------------------|--------------------|--------------------|--------------------| │
│ |                                  |                 | TTS              | Pages/s          | Mem              | TTS                | Pages/s            | Mem                | │
│ | Apple M3 Max                     | 4               | 177 s 167 s      | 1.27 1.34        | 6.20 GB          | 103 s 92 s         | 2.18 2.45          | 2.56 GB            | │
│ | (16 cores) Intel(R) Xeon E5-2690 | 16 4 16         | 375 s 244 s      | 0.60 0.92        | 6.16 GB          | 239 s 143 s        | 0.94 1.57          | 2.42 GB            | │
│                                                                                                                                                                                │
│ ## 5 Applications                                                                                                                                                              │
│                                                                                                                                                                                │
│ Thanks to the high-quality, richly structured document conversion achieved by Docling, its output qualifies for numerous downstream applications. For example, Docling can     │
│ provide a base for detailed enterprise document search, passage retrieval or classification use-cases, or support knowledge extraction pipelines, allowing specific treatment  │
│ of different structures in the document, such as tables, figures, section structure or references. For popular generative AI application patterns, such as retrieval-augmented │
│ generation (RAG), we provi...                                                                                                                                                  │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Custom serialization

In [5]:
from typing import Any

from docling_core.transforms.serializer.base import SerializationResult
from docling_core.transforms.serializer.common import create_ser_result
from docling_core.transforms.serializer.markdown import MarkdownAnnotationSerializer
from docling_core.types.doc.document import MiscAnnotation, DocItem

class CustomAnnotationSerializer(MarkdownAnnotationSerializer):
    def serialize(
        self,
        *,
        item: DocItem,
        doc: DoclingDocument,
        **kwargs: Any,
    ) -> SerializationResult:
        text_parts: list[str] = []

        # reusing result from parent serializer:
        parent_res = super().serialize(
            item=item,
            doc=doc,
            **kwargs,
        )
        text_parts.append(parent_res.text)

        # custom serialization logic (appending misc annotation result):
        for ann in item.get_annotations():
            if isinstance(ann, MiscAnnotation):
                out_txt = "".join([f"- {k}: {ann.content[k]}\n" for k in ann.content])
                text_parts.append(out_txt)
        text_res = "\n\n".join(text_parts)
        return create_ser_result(text=text_res, span_source=item)
In [6]:
ser = MarkdownDocSerializer(
    doc=doc,
    annotation_serializer=CustomAnnotationSerializer(),
    params=MarkdownParams(
        pages=pages,
    ),
)
ser_out = ser.serialize()
ser_txt = ser_out.text

print_excerpt(ser_txt, title=f"{pages=}")
╭────────────────────────────────────────────────────────────────────────────────── pages={5} ───────────────────────────────────────────────────────────────────────────────────╮
│ torch runtimes backing the Docling pipeline. We will deliver updates on this topic at in a future version of this report.                                                      │
│                                                                                                                                                                                │
│ Table 1: Runtime characteristics of Docling with the standard model pipeline and settings, on our test dataset of 225 pages, on two different systems. OCR is disabled. We     │
│ show the time-to-solution (TTS), computed throughput in pages per second, and the peak memory used (resident set size) for both the Docling-native PDF backend and for the     │
│ pypdfium backend, using 4 and 16 threads.                                                                                                                                      │
│                                                                                                                                                                                │
│ A typical Docling setup runtime characterization.                                                                                                                              │
│                                                                                                                                                                                │
│ - type: performance data                                                                                                                                                       │
│ - sentiment: 0.85                                                                                                                                                              │
│                                                                                                                                                                                │
│                                                                                                                                                                                │
│ | CPU                              | Thread budget   | native backend   | native backend   | native backend   | pypdfium backend   | pypdfium backend   | pypdfium backend   | │
│ |----------------------------------|-----------------|------------------|------------------|------------------|--------------------|--------------------|--------------------| │
│ |                                  |                 | TTS              | Pages/s          | Mem              | TTS                | Pages/s            | Mem                | │
│ | Apple M3 Max                     | 4               | 177 s 167 s      | 1.27 1.34        | 6.20 GB          | 103 s 92 s         | 2.18 2.45          | 2.56 GB            | │
│ | (16 cores) Intel(R) Xeon E5-2690 | 16 4 16         | 375 s 244 s      | 0.60 0.92        | 6.16 GB          | 239 s 143 s        | 0.94 1.57          | 2.42 GB            | │
│                                                                                                                                                                                │
│ ## 5 Applications                                                                                                                                                              │
│                                                                                                                                                                                │
│ Thanks to the high-quality, richly structured document conversion achieved by Docling, its output qualifies for numerous downstream applications. For example, Docling can     │
│ provide a base for detailed enterprise document search, passage retrieval or classification use-cases, or support knowledge extraction pipelines, allowing specific treatment  │
│ of different structures in the document, such as tables, figures, section structure or references. For popular generative AI application patterns, such as r...                │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
In [ ]: