Provider Docling Localhost - thekaveh/atlas GitHub Wiki

5.3.1. Docling Localhost Provider

Run the Atlas Docling provider natively on the host. Atlas containers reach it through host.docker.internal when DOC_PROCESSOR_SOURCE=docling-localhost. It needs Python 3.10 or later and uv.

1. Quick Start

1.1. Install Dependencies

cd services/docling/provider/localhost
uv sync

This installs the locked dependencies, including docling==2.102.1 and torch==2.13.0. The PyPI torch wheel supports CUDA on Linux x86_64 and MPS on Apple Silicon, so no separate torch install is needed. Do not install another torch with uv pip install: uv run restores the locked version.

1.2. Generate the Atlas Credential

From the repository root, start Atlas once so it generates and preserves DOCLING_API_TOKEN in .env before the provider imports its settings:

# Terminal 1: return to the repository root after §1.1
cd ../../../..
./start.sh --doc-processor-source docling-localhost

The provider reads .env once, when it starts. If you started it before Atlas created the token, restart it.

1.3. Start the Server

# Terminal 2, opened at the repository root
cd services/docling/provider/localhost
uv run server.py

The server loads the repository .env (four levels up), then listens on http://127.0.0.1:18159 by default (DOCLING_LOCALHOST_BIND_HOST and DOCLING_LOCALHOST_PORT). Variables exported in the shell override .env.

The first conversion downloads Docling's layout and table models from Hugging Face, so it takes longer. Later runs reuse the cache.

1.4. Test the API

Use Bash from the repository root after §1.1 installs the native dependencies. Use the same shell settings as the running provider. The loader reads repository .env with the server's shell precedence and ignores ATLAS_ENV_FILE. It preserves usable token bytes and refuses absent, empty or whitespace-only credentials before curl. An unset or empty native port uses 18159.

# Terminal 3, opened at the repository root while Atlas and the provider run
if ! docling_values="$(uv run --project services/docling/provider/localhost python - <<'PYTHON'
import os
import shlex
from pathlib import Path
from dotenv import load_dotenv

if Path(".env").exists():
    load_dotenv(Path(".env"))
token = os.getenv("DOCLING_API_TOKEN", "")
if not token.strip():
    raise SystemExit("DOCLING_API_TOKEN must be set in the shell or repository .env.")
port = int(os.getenv("DOCLING_LOCALHOST_PORT") or 18159)
print(f"export DOCLING_API_TOKEN={shlex.quote(token)}")
print(f"export DOCLING_LOCALHOST_PORT={shlex.quote(str(port))}")
print(f"export DOCLING_URL={shlex.quote(f'http://localhost:{port}')}")
PYTHON
)"; then
  exit 1
fi
eval "$docling_values"
curl -X POST "${DOCLING_URL}/v1/document/convert" \
  -H "Authorization: Bearer ${DOCLING_API_TOKEN}" \
  -F "[email protected]" \
  -F "output_format=markdown" \
  -F "table_mode=accurate"

2. Configuration

2.1. Environment Variables

Atlas generates DOCLING_API_TOKEN in repository .env during §1.2. The server loads that file once at startup; exported shell values take precedence, including empty values. It ignores ATLAS_ENV_FILE. With required authentication, an absent or empty token leaves protected routes unavailable.

Run this configuration block from services/docling/provider/localhost before starting the server. Keep the generated token in repository .env, or export a token for the server shell. These exports configure the server:

export DOCLING_LOCALHOST_PORT=18159      # Server port (default: 18159)
export DOCLING_LOCALHOST_BIND_HOST=127.0.0.1  # Listen address (see below)
export DOCLING_AUTH_MODE=required
export DOCLING_MAX_FILE_SIZE=52428800
export DOCLING_UPLOAD_TIMEOUT_SECONDS=120
export DOCLING_INFERENCE_TIMEOUT_SECONDS=900
export DOCLING_DEVICE=cpu                # Device: cpu (default), cuda, mps
export DOCLING_OUTPUT_FORMAT=markdown    # Format: markdown, html, json, doctags
export DOCLING_USE_OCR=auto              # OCR: auto, always, never
export DOCLING_TABLE_MODE=accurate       # Table mode: accurate, fast
export DOCLING_ENABLE_FORMULAS=true      # Formula enrichment: true, false
export DOCLING_ENABLE_CODE_BLOCKS=true   # Code enrichment: true, false
export HF_TOKEN=your_token_here          # Hugging Face token (if needed)

On Linux, containers reach the host through the Docker bridge, not loopback. Bind the bridge IP, or 0.0.0.0 with DOCLING_AUTH_MODE=required.

The request's use_ocr and table_mode values override their environment defaults. Device, formula enrichment and code enrichment are applied through Docling's pinned PdfPipelineOptions API. Request validation rejects an unsupported output format; the server never returns Markdown in its place.

2.2. Custom Port

export DOCLING_LOCALHOST_PORT=55021
uv run server.py

Set the same DOCLING_LOCALHOST_PORT in the repository .env, so Atlas containers use that port.

3. Supported Formats

3.1. Input Formats

The provider uses Docling's converter: PDF, DOCX, PPTX, XLSX, HTML and images (PNG, JPEG, TIFF). Docling does not convert legacy Office files (.doc, .xls, .ppt). The Atlas backend sends those to Tika; see the Document Processor README.

Uploaded Docling JSON retains data:, http: and https: image references. Filesystem paths, file: URIs and other schemes are ignored before enrichment or export, including page images. Embedded images and images from other input formats keep their existing handling. The log reports only the discarded count. The same rule applies to the GPU provider and LightRAG bundle.

3.2. Output Formats

  • markdown - Markdown (default)
  • html - HTML
  • json - Docling document as JSON
  • doctags - Docling's native DocTags format

4. API Examples

Run §1.4 first in the same shell to export the usable token and native URL. Before repeating §1.4, update or unset client-shell token and port exports to match the running provider. The loader preserves existing exports, so changing repository .env alone does not replace them.

4.1. Basic Conversion

curl -X POST "${DOCLING_URL}/v1/document/convert" \
  -H "Authorization: Bearer ${DOCLING_API_TOKEN}" \
  -F "[email protected]" \
  -F "output_format=markdown"

4.2. With OCR and Table Extraction

curl -X POST "${DOCLING_URL}/v1/document/convert" \
  -H "Authorization: Bearer ${DOCLING_API_TOKEN}" \
  -F "[email protected]" \
  -F "use_ocr=always" \
  -F "table_mode=accurate"

4.3. RAG Chunking

curl -X POST "${DOCLING_URL}/v1/document/convert" \
  -H "Authorization: Bearer ${DOCLING_API_TOKEN}" \
  -F "[email protected]" \
  -F "enable_chunking=true" \
  -F "chunk_size=512" \
  -F "chunk_overlap=50"

5. Features

5.1. Table Extraction

  • accurate: the accurate TableFormer model (default).
  • fast: the fast TableFormer model; quicker, with lower table quality.

5.2. OCR Support

  • auto: OCR only where the document needs it, for example scanned pages.
  • always: full-page OCR on every page.
  • never: no OCR.

5.3. Advanced Extraction

  • Mathematical formulas (DOCLING_ENABLE_FORMULAS)
  • Code blocks (DOCLING_ENABLE_CODE_BLOCKS)
  • Document structure: headings, paragraphs, lists and tables

6. Integration with Atlas

6.1. Method 1: Localhost Mode (Recommended)

# Terminal 1, repository root: generate/preserve .env credentials and run Atlas
./start.sh --doc-processor-source docling-localhost

# Terminal 2, after Atlas has generated .env: start the provider
cd services/docling/provider/localhost
uv run server.py

Atlas remains in the foreground in Terminal 1; use the separate Terminal 2 for the native provider.

6.2. Method 2: With Custom Base Port

# Terminal 1, repository root: start Atlas first
./start.sh --base-port 55000 --doc-processor-source docling-localhost

# Terminal 2, repository root: the provider reads the port and token from .env
cd services/docling/provider/localhost
uv run server.py

6.3. Method 3: Permanent Configuration

Edit .env file:

DOC_PROCESSOR_SOURCE=docling-localhost

Then start stack:

# Terminal 1, repository root
./start.sh

# Terminal 2, after Atlas has generated/preserved the credential
cd services/docling/provider/localhost
uv run server.py

For long-lived use, run the provider under a service manager (systemd or launchd) with restart-on-failure. After a conversion timeout the provider exits with status 70, and a bare uv run server.py stays stopped.

7. Performance

Conversion time and memory depend on the device, the page count, tables, OCR and table_mode. Atlas publishes no per-page figures. Benchmark representative documents on the host before capacity planning.

8. Troubleshooting

8.1. Port Already in Use

# Use a different port, then set the same value in the repository .env
export DOCLING_LOCALHOST_PORT=18160
uv run server.py

8.2. GPU Not Used

DOCLING_DEVICE defaults to cpu; the server does not detect a GPU. Set DOCLING_DEVICE=cuda or DOCLING_DEVICE=mps, then check that torch can see the device:

uv run python -c "import torch; print(torch.cuda.is_available(), torch.backends.mps.is_available())"

8.3. Model Download Fails

# Set a Hugging Face token if the download needs one
export HF_TOKEN=your_token_here
uv run server.py

# Check free disk space for the Hugging Face cache
df -h

8.4. Import Errors

# Reinstall dependencies
uv sync --reinstall

# Or use fresh environment
rm -rf .venv
uv sync

8.5. Slow Processing

  • Use table_mode=fast for faster, less accurate table extraction.
  • Use use_ocr=never when the documents have a text layer.
  • Set DOCLING_DEVICE to an available GPU device (§8.2).

9. Technical Details

9.1. Model Downloads

Docling downloads its layout and table models on first use and caches them in the Hugging Face cache (~/.cache/huggingface/ by default).

9.2. Device Selection

The device comes from DOCLING_DEVICE only: cpu (default), cuda or mps. An invalid device makes /health report unavailable.

10. Advanced Usage

10.1. Python Integration

Run §1.4 in the same shell first to export DOCLING_API_TOKEN and DOCLING_URL. Use those settings for the Python and batch examples below.

import requests
import os

with open("document.pdf", "rb") as f:
    response = requests.post(
        f"{os.environ['DOCLING_URL']}/v1/document/convert",
        headers={"Authorization": f"Bearer {os.environ['DOCLING_API_TOKEN']}"},
        files={"file": f},
        data={
            "output_format": "markdown",
            "table_mode": "accurate",
            "enable_chunking": True,
            "chunk_size": 512
        }
    )

result = response.json()
print(result["content"])
print(f"Processed {result['metadata']['pages']} pages")
print(f"Found {result['metadata']['tables']} tables")

10.2. Batch Processing

# Process multiple files; the response is JSON with the text in "content"
for file in *.pdf; do
  curl -X POST "${DOCLING_URL}/v1/document/convert" \
    -H "Authorization: Bearer ${DOCLING_API_TOKEN}" \
    -F "file=@$file" \
    -F "output_format=markdown" \
    > "${file%.pdf}.json"
done

11. References