- Dockerfile 60.1%
- Shell 30.2%
- Python 9.7%
|
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
hatchling raises 'Unable to determine which files to ship inside the wheel' when packages = [] is set. The wheel builder needs at least one package directory. Create an empty marker_ocr/__init__.py with a docstring explaining the wrapper nature of the project, and point packages = ["marker_ocr"]. |
||
|---|---|---|
| marker_ocr | ||
| .env.example | ||
| .gitignore | ||
| .woodpecker.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| marker-ocr-llm | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
Marker OCR
Thin wrapper around marker-pdf v2.0.0+
that makes it easy to run via uv (native, with Apple Silicon MPS support) or
Docker / apple-container (CPU, portable).
The package itself contributes almost nothing: a single script entry point that
re-exports marker.scripts.convert_single:convert_single_cli as marker-ocr,
plus a small marker-ocr-llm wrapper that injects OpenAI-compatible LLM-boost
flags from environment variables.
Why
marker-pdfCLI does not readOPENAI_*env vars — only CLI flags. Themarker-ocr-llmwrapper bridges that for.env/ shell workflows.uvxmakes one-off native runs trivial (no venv management, no Docker).- The published image is multi-arch (
linux/amd64+linux/arm64). - Models are NOT bundled in the image; the recommended pattern is a persistent
HF cache volume (see
docker-compose.yml).
Quickstart
1. uvx one-off (native, MPS on Apple Silicon)
# macOS only — system deps for marker-pdf[full] (WeasyPrint).
brew install cairo pango gdk-pixbuf libffi
# Run from a git ref (latest commit on default branch):
uvx --from git+https://git.ppvn.ru/wailorman/marker-ocr marker-ocr \
/path/to/book.pdf --output_dir ./out
# Or pinned to a tag/SHA:
uvx --from git+https://git.ppvn.ru/wailorman/marker-ocr@<commit-sha> marker-ocr ...
MPS is auto-detected on Apple Silicon. Verify:
uvx --from marker-pdf python -c "import torch; print('mps' if torch.backends.mps.is_available() else 'cpu')"
2. uv tool install (persistent binary on PATH)
uv tool install git+https://git.ppvn.ru/wailorman/marker-ocr
marker-ocr /path/to/book.pdf --output_dir ./out
Upgrade with uv tool upgrade marker-ocr.
3. docker run one-off (CPU, portable)
docker run --rm \
-v "$PWD:/work" \
-v marker-ocr-hf-cache:/root/.cache/huggingface \
cr.ppvn.ru/marker-ocr/marker-ocr:latest \
/work/book.pdf --output_dir /work/out
4. docker compose run (env_file + volume management)
git clone https://git.ppvn.ru/wailorman/marker-ocr
cd marker-ocr
cp .env.example .env # fill in OPENAI_*
mkdir -p data && cp ~/Downloads/book.pdf data/
docker compose run --rm marker-ocr \
/work/data/book.pdf --output_dir /work/data/out
For pure-OCR (no LLM-boost), override the entrypoint:
docker compose run --rm --entrypoint marker-ocr marker-ocr \
/work/data/book.pdf --output_dir /work/data/out
LLM-boost (OpenAI-compatible endpoint)
LLM-boost sends page images to a vision-capable model to clean up OCR output.
The OpenAIService client speaks the OpenAI Chat Completions protocol and works
with any compatible endpoint: OpenAI, Azure OpenAI, OpenRouter, vLLM, Ollama,
routerai.ru, LocalAI, etc.
Required CLI flags (when calling marker-ocr directly)
marker-ocr book.pdf --output_dir ./out \
--use_llm \
--llm_service marker.services.openai.OpenAIService \
--openai_base_url "https://api.openai.com/v1" \
--openai_api_key "sk-..." \
--openai_model "gpt-4o-mini"
Or use marker-ocr-llm wrapper (reads env vars)
export OPENAI_BASE_URL=https://api.openai.com/v1 # NO trailing slash
export OPENAI_API_KEY=sk-...
export OPENAI_MODEL=gpt-4o-mini
marker-ocr-llm book.pdf --output_dir ./out
The same wrapper is the default entrypoint in docker-compose.yml.
Caveats
- Model must be vision-capable (gpt-4o, gpt-4o-mini, claude-sonnet, gemini-flash, qwen2.5-vl). marker sends page images to the LLM.
- NO trailing slash in
--openai_base_url(known bug in theopenaiPython client — request URLs become//chat/completions). OPENAI_API_KEYenv var is ignored by marker-pdf CLI. It only reads the--openai_api_keyflag. Themarker-ocr-llmwrapper exists for this reason.
Modes (marker-pdf v2.0.0)
| Mode | CLI | Use case |
|---|---|---|
balanced |
--mode balanced |
VLM layout + full-page OCR. Highest quality. Default on GPU. |
fast |
--mode fast |
Lightweight rf-detr layout + pdftext. Default on CPU/MPS. |
| no OCR | --disable_ocr |
Text-layer only, no VLM. Fastest. |
Defaults are device-aware: balanced on CUDA GPU, fast on CPU/MPS.
# Fast on the laptop
marker-ocr book.pdf --output_dir ./out --mode fast
# Best quality, no OCR (text-based PDF)
marker-ocr book.pdf --output_dir ./out --disable_ocr
Apple Silicon MPS vs Docker CPU
| Path | Device | Speed | Portability |
|---|---|---|---|
uvx / uv tool install native |
MPS (Metal) | ~5-8× faster than CPU | macOS only |
docker run / docker compose |
CPU | baseline | any Linux/macOS |
| apple-container | CPU | baseline | macOS only |
Metal/MPS is macOS-only — Virtualization.framework (which backs both Docker
Desktop and apple-container) does not expose Metal to Linux guests. Use native
uvx on Apple Silicon when speed matters.
Model cache
marker-pdf v2.0.0 spins up a separate surya inference server lazily on first OCR call. Model weights (~2-5 GB) are downloaded to the HuggingFace cache:
- Native (
uvx):~/.cache/huggingface/ - Docker / apple-container:
/root/.cache/huggingface/inside the container (mount as a volume — seedocker-compose.yml).
The Docker image intentionally does NOT pre-cache weights: doing so would bloat
the image to 5+ GB and complicate multi-arch builds. The persistent volume
pattern in docker-compose.yml achieves the same effect across runs.
Output layout
<output_dir>/
└── <input-basename>/
├── <input-basename>.md # (or .json / .html per --output_format)
└── images/
├── image_0.jpg
└── ...
Versions
marker-pdf:>=2.0.0(pinned viapyproject.toml).- Python:
>=3.10, <4. - Image tags:
cr.ppvn.ru/marker-ocr/marker-ocr:latestandcr.ppvn.ru/marker-ocr/marker-ocr:<commit-sha>.
Development
git clone https://git.ppvn.ru/wailorman/marker-ocr
cd marker-ocr
uv sync
uv run marker-ocr --help
The CI pipeline (.woodpecker.yml) builds and publishes multi-arch images on
push to main/master.