Skip to content

minomgm/docling-glm-ocr

 
 

Repository files navigation

docling-glm-ocr-ollama

A docling OCR plugin that delegates text recognition to a local GLM-OCR model served by Ollama.


GitHub  |  PyPI


PyPI version Python versions License: MIT Ruff

Overview

docling-glm-ocr-ollama is a docling plugin that replaces the built-in OCR stage with a call to a local GLM-OCR model running inside Ollama.

Each page crop is sent to Ollama's OpenAI-compatible chat completion endpoint as a base64-encoded image. The model returns Markdown-formatted text which docling merges back into the document structure.

The plugin registers itself under the "glm-ocr-ollama" OCR engine key so it can be selected per-request through docling or docling-serve without changing application code.

Requirements

  • Python 3.12+
  • A running Ollama instance with the glm-ocr model pulled

Installation

# with uv (recommended)
uv add docling-glm-ocr-ollama

# with pip
pip install docling-glm-ocr-ollama

Usage

Setup Ollama

# Pull the model
ollama pull glm-ocr

# Start the server (if not already running)
ollama serve

Python SDK

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

from docling_glm_ocr_ollama import GlmOcrOllamaOptions

pipeline_options = PdfPipelineOptions(
    allow_external_plugins=True,
    ocr_options=GlmOcrOllamaOptions(
        api_url="http://localhost:11434/v1/chat/completions",
        model_name="glm-ocr",
    ),
)

converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options)
    }
)
result = converter.convert("document.pdf")
print(result.document.export_to_markdown())

docling-serve

Select the engine per-request via the standard API:

curl -X POST http://localhost:5001/v1/convert/source \
  -H 'Content-Type: application/json' \
  -d '{
    "options": {
      "ocr_engine": "glm-ocr-ollama"
    },
    "sources": [{"kind": "http", "url": "https://arxiv.org/pdf/2501.17887"}]
  }'

The server must have DOCLING_SERVE_ALLOW_EXTERNAL_PLUGINS=true set so the plugin is loaded automatically.

Configuration

All options can be set via environment variables (useful for Docker / Compose deployments) or programmatically via GlmOcrOllamaOptions. Explicit constructor arguments always take precedence over environment variables.

Environment variables

Variable Description Default
GLMOCR_OLLAMA_API_URL Ollama chat completion URL http://localhost:11434/v1/chat/completions
GLMOCR_OLLAMA_MODEL_NAME Model tag as shown by ollama list glm-ocr
GLMOCR_OLLAMA_PROMPT Text prompt sent with each image crop see below
GLMOCR_OLLAMA_TIMEOUT HTTP timeout per crop (seconds) 300
GLMOCR_OLLAMA_MAX_TOKENS Max tokens per completion 16384
GLMOCR_OLLAMA_SCALE Image crop rendering scale 3.0
GLMOCR_OLLAMA_MAX_IMAGE_PIXELS Pixel budget per crop 4500000
GLMOCR_OLLAMA_MAX_CONCURRENT_REQUESTS Max concurrent API requests 1
GLMOCR_OLLAMA_MAX_RETRIES Max retry attempts for HTTP errors 3
GLMOCR_OLLAMA_RETRY_BACKOFF_FACTOR Exponential backoff factor for retries 2.0
GLMOCR_OLLAMA_LANG Comma-separated language hint(s) en
GLMOCR_OLLAMA_API_KEY Bearer token for Authorization header unset (no header sent)

GlmOcrOllamaOptions

All options can also be set programmatically:

Option Type Description Default
api_url str OpenAI-compatible chat completion URL GLMOCR_OLLAMA_API_URL env or http://localhost:11434/v1/chat/completions
model_name str Model tag as shown by ollama list GLMOCR_OLLAMA_MODEL_NAME env or glm-ocr
prompt str Text prompt for each image crop GLMOCR_OLLAMA_PROMPT env or default prompt
timeout float HTTP timeout per crop (seconds) GLMOCR_OLLAMA_TIMEOUT env or 300
max_tokens int Max tokens per completion GLMOCR_OLLAMA_MAX_TOKENS env or 16384
scale float Image crop rendering scale GLMOCR_OLLAMA_SCALE env or 3.0
max_image_pixels int Pixel budget per crop GLMOCR_OLLAMA_MAX_IMAGE_PIXELS env or 4500000
max_concurrent_requests int Max concurrent API requests GLMOCR_OLLAMA_MAX_CONCURRENT_REQUESTS env or 1
max_retries int Max retry attempts for HTTP errors GLMOCR_OLLAMA_MAX_RETRIES env or 3
retry_backoff_factor float Exponential backoff factor for retries GLMOCR_OLLAMA_RETRY_BACKOFF_FACTOR env or 2.0
lang list[str] Language hint (passed to docling) GLMOCR_OLLAMA_LANG env (comma-separated) or ["en"]
api_key str | None Bearer token sent in Authorization header GLMOCR_OLLAMA_API_KEY env or None (no header)

Default prompt:

Recognize the text in the image and output in Markdown format.
Preserve the original layout (headings/paragraphs/tables/formulas).
Do not fabricate content that does not exist in the image.

Architecture

flowchart LR
    subgraph docling
        Pipeline --> GlmOcrOllamaModel
    end

    subgraph Ollama
        GLMOCR["glm-ocr"]
    end

    GlmOcrOllamaModel -- "POST /v1/chat/completions\n(base64 image)" --> GLMOCR
    GLMOCR -- "Markdown text" --> GlmOcrOllamaModel
Loading

For each page the model:

  1. Collects OCR regions from the docling layout analysis
  2. Renders each region using the page backend (scale configurable, default 3×)
  3. Encodes the crop as a base64 PNG data URI
  4. POSTs chat completion requests to the Ollama endpoint (with retry logic)
  5. Returns the recognised text as TextCell objects for docling to merge

Parallel inference

By default max_concurrent_requests=1 because Ollama processes one request at a time (single GPU, single generation). If you need higher throughput, start Ollama with OLLAMA_NUM_PARALLEL and raise max_concurrent_requests to match:

OLLAMA_NUM_PARALLEL=4 ollama serve
GlmOcrOllamaOptions(max_concurrent_requests=4)

Note: Setting max_concurrent_requests above OLLAMA_NUM_PARALLEL will cause excess requests to queue on the server and may trigger timeouts on large documents.

Remote Ollama / reverse proxy

Point api_url at your remote host and set api_key if the proxy requires authentication:

GlmOcrOllamaOptions(
    api_url="https://ollama.my-server.com/v1/chat/completions",
    api_key="my-secret-token",
)

Or via environment variables:

GLMOCR_OLLAMA_API_URL=https://ollama.my-server.com/v1/chat/completions
GLMOCR_OLLAMA_API_KEY=my-secret-token

Context window and image size

Ollama returns HTTP 400 with "context length" in the body when an image crop produces more tokens than the model's context window allows. The plugin detects this automatically and retries at 2/3 scale before recording a conversion error.

To avoid this entirely, reduce scale or max_image_pixels:

GlmOcrOllamaOptions(
    scale=2.0,
    max_image_pixels=2_000_000,
)

Development

Setup

git clone https://github.com/your-org/docling-glm-ocr-ollama.git
cd docling-glm-ocr-ollama
make install

Available commands

make install     Install dependencies and pre-commit hooks
make check       Run all quality checks (ruff lint, format, ty type check)
make test        Run tests with coverage report
make build       Build distribution packages
make publish     Publish to PyPI

Running tests

make test

Tests are in tests/ and use pytest. Coverage reports are generated at coverage.xml and printed to the terminal.

End-to-end tests

The e2e tests hit a real Ollama server and are skipped by default. To run them, ensure Ollama is running with glm-ocr pulled and use the e2e marker:

GLMOCR_OLLAMA_API_URL=http://localhost:11434/v1/chat/completions pytest -m e2e

Code quality

This project uses:

  • ruff – linting and formatting
  • ty – type checking
  • pre-commit – pre-commit hooks

Run all checks:

make check

Releasing

Releases are published to PyPI automatically. Update the version in pyproject.toml, then trigger the Publish workflow from GitHub Actions:

GitHub → Actions → Publish to PyPI → Run workflow

The workflow tags the commit, builds the package, and publishes to PyPI via trusted publishing.

License

MIT

About

A docling plugin to integrate a remote hosted GLM-OCR OCR model into docling

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 97.3%
  • Makefile 2.7%