docling-project / docling-project/docling

How to make the dockling uses less hardware resources?

Open
#2,877 1 comment 0 reactions 0 assignees View on GitHub
question triage/close-stale
Dominant language
Python
Stars
66.4k
Forks
4.8k
Avg merge
2d 21h
Merged PRs (30d)
84

Description

### Question
I have noticed that, regardless of the hardware spec, the processing of the PDF takes a lot of RAM and CPU. 3-4GB RAM spike and CPU hits 100% until completion. Any thoughts? I can wait, but I need the server resources to do other stuff. Any chance I can run this on low priority, it will not consume this much server resources. (A fair amount of less accuracy is also acceptable if the resource consumption can be lower.)

I use a .NET 10 web api project and [PythonNet NuGet](https://github.com/pythonnet/pythonnet) to call this script.

My code for reference:

```
import io
import os
from typing import List

--- CRITICAL: Force lightweight backend BEFORE any Docling import ---
os.environ["DOCFLOW_PDF_BACKEND"] = "pypdfium2" # fixes 90% of OOM issues

--- Import Docling ---
from docling.document_converter import DocumentConverter, PdfFormatOption
from docling.datamodel.pipeline_options import PdfPipelineOptions
from docling.datamodel.base_models import InputFormat

CHUNK_SIZE = 20 # Number of pages per chunk for large PDFs

--- Convert .NET byte[] → real Python bytes ---
def _to_python_bytes(net_bytes) -> bytes:
if isinstance(net_bytes, (bytes, bytearray)):
return bytes(net_bytes)
elif hasattr(net_bytes, "__iter__"):
return bytes(net_bytes)
else:
raise TypeError(f"Unsupported input type: {type(net_bytes)}")

--- Safe chunk splitter (PyMuPDF) ---
def _split_into_chunks(pdf_bytes: bytes, chunk_size: int = CHUNK_SIZE) -> List[bytes]:
import fitz # PyMuPDF - lazy import only when needed
doc = fitz.open(stream=pdf_bytes, filetype="pdf")
total = len(doc)
chunks = []
for start in range(0, total, chunk_size):
end = min(start + chunk_size, total)
new_doc = fitz.open()
new_doc.insert_pdf(doc, from_page=start, to_page=end - 1)
chunks.append(new_doc.write())
new_doc.close()
doc.close()
return chunks

--- Helper: Create pipeline options (removes duplication) ---
def _create_pipeline_options(artifacts_path: str = r"C:\inetpub\wwwroot\cache\docling\models") -> PdfPipelineOptions:
"""Creates and configures PDF pipeline options for document conversion."""
pipeline_options = PdfPipelineOptions(
artifacts_path=artifacts_path,
do_clean=False, # Cleans unnecessary elements (headers, footers)
do_dereference=False, # Resolves references inside the document
do_table_structure=False, # Enables table extraction
do_figures=False, # Disables figure/image extraction
do_ocr=False, # Enables OCR for scanned PDFs
do_picture_description=False,
images_scale=1.0,
)
pipeline_options.table_structure_options.do_cell_matching = False
pipeline_options.generate_page_images = False # No picture enrichment
return pipeline_options

def convert_pdf_to_markdown(file_bytes: bytes) -> bytes:
"""Converts a PDF file (given as bytes) to Markdown and returns as a string."""

try:
file_bytes = _to_python_bytes(file_bytes)

import fitz
temp_doc = fitz.open(stream=file_bytes, filetype="pdf")
page_count = len(temp_doc)
temp_doc.close()

# Create converter once (reused for efficiency)
pipeline_options = _create_pipeline_options()
converter = DocumentConverter(
format_options={InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options)}
)

if page_count > CHUNK_SIZE:
chunks = _split_into_chunks(file_bytes, chunk_size=CHUNK_SIZE)
all_markdown_parts = []

for i, chunk in enumerate(chunks, 1):
stream = io.BytesIO(chunk)
source = {"name": f"chunk_{i}", "stream": stream}

# Convert the document
result = converter.convert(source)

# Extract markdown content
all_markdown_parts.append(result.document.export_to_markdown())
all_markdown_parts.append("\n\n---\n\n")

final_markdown = "".join(all_markdown_parts)
return final_markdown
else:
# Create a byte stream from the input bytes
stream_str = io.BytesIO(file_bytes)

# Prepare input document stream
docstream = {
'name': 'converted_document',
'stream': stream_str
}

result = converter.convert(docstream)
return result.document.export_to_markdown()

except Exception as e:
error_msg = f"[Docling Error] {type(e).__name__}: {str(e)}"
print(error_msg)
return error_msg.encode('utf-8')
# return ""
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.