██╗ ██╗███╗ ██╗██╗ ██████╗ ██████╗██████╗ ██║ ██║████╗ ██║██║ ██╔═══██╗██╔════╝██╔══██╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██████╔╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██╔══██╗ ╚██████╔╝██║ ╚████║███████╗╚██████╔╝╚██████╗██║ ██║ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝GUI/CLI for unlimited-ocr
English | 简体中文
Not affiliated with Unlimited OCR but a wrapper/GUI around Unlimited OCR
A fast, lightweight tool to OCR PDFs into clean Markdown. It is powered by the Unlimited-OCR model (DeepSeek-OCR 3B VLM) running locally via llama.cpp (GGUF).
Currently, a WIP and has pretty tough system requirements. Do not expect it to work on low end devices. This was created to use unlimited-ocr on local computer and it is not affiliated with the original unlimited-ocr.
This is vibe coded so don't expect everything to be perfect. Feel free to submit PR's. UI was done in Claude Design.
- Local & Secure: Runs entirely offline on your CPU or GPU.
- Auto-cached: Model weights download automatically from Hugging Face on first run.
- High Performance: Uses a single persistent
llama-serverbackground process to avoid reloading overhead across pages. - Flexible Engines: Supports GGUF (default, via llama.cpp) or the full unquantized model on GPU (via vLLM/SGLang).
- Multi-Platform: Available for macOS, Linux, and Windows as both a CLI and a Desktop GUI application.
To run unlocr, you need:
- poppler (provides
pdftoppmfor rasterizing PDF pages to images). - llama-server — a patched
llama.cppbuild carrying the Unlimited-OCR R-SWA support from PR #24975. That PR is not yet merged upstream, so stock/Homebrew/apt builds do not work. unlocr downloads its own patched build for you (CLI and GUI) on first run — you do not install it manually. See the note below. - pandoc (optional) — only for the GUI's "export to DOCX/ODT/RTF/HTML/TXT" feature. OCR works without it.
- Rust Toolchain (only if building from source or installing via cargo).
Both the CLI and the Desktop GUI auto-download the sha256-pinned patched llama-server into the app cache on first run (macOS arm64/x64, Linux x64, Windows x64; CPU build, macOS with Metal). You only supply pdftoppm:
| OS | poppler (pdftoppm) |
llama-server (patched R-SWA build) | pandoc (export) |
|---|---|---|---|
| Windows | GUI downloads it for you | auto-downloaded (CLI + GUI) | GUI downloads it for you |
| Linux | installed by the .deb/.rpm (declared dep) |
auto-downloaded (CLI + GUI, x86_64) | installed by the .deb/.rpm (recommended dep) |
| macOS | brew install poppler (cask dep) |
auto-downloaded (CLI + GUI) | GUI downloads it, or brew install pandoc |
Note
The patched llama-server is built by unlocr's own CI (build-llama.yml) and hosted on a dedicated llama-rswa-* GitHub release. In the GUI, Settings → Dependencies shows what is found/missing and can (re)download it. If you point unlocr at your OWN llama-server (--llama-bin, or one on PATH/Homebrew), it is used but you get a warning that it cannot be verified for R-SWA support; silence it with UNLOCR_ALLOW_EXTERNAL_LLAMA=1. GPU users (CUDA/Vulkan) should build llama.cpp from PR #24975 themselves and pass --llama-bin.
By default, unlocr runs a quantized GGUF on llama.cpp (CPU or GPU-offloaded). You can also run the full, unquantized model on a dedicated GPU via vLLM.
| Mode | Variant | Download Size | RAM/VRAM Required | Engine | Quality Flag |
|---|---|---|---|---|---|
| GGUF | Q4_K_M |
1.82 GB | ~4 GB RAM | llama.cpp | --quality less |
| GGUF | Q8_0 (Default) |
2.91 GB | ~6 GB RAM | llama.cpp | --quality good |
| GGUF | BF16 |
5.47 GB | ~8 GB RAM | llama.cpp | --quality best |
| Full Model | DeepSeek-OCR |
~6.7 GB | 16 GB+ VRAM | vLLM | --gpu |
All installation files (pre-built binaries, desktop installers, and packages) are available on the GitHub Releases page.
- macOS (Apple Silicon & Intel):
- GUI (Desktop App): Download the
.dmginstaller from Releases (or install via Homebrew Cask:brew install --cask whit3rabbit/tap/unlocr) - CLI:
brew install whit3rabbit/tap/unlocr
- GUI (Desktop App): Download the
- Windows:
- Linux:
Homebrew is required for poppler (unlocr auto-downloads the patched llama-server itself; do NOT brew install llama.cpp — the Homebrew build lacks R-SWA). Install the prerequisite:
brew install poppler # pandoc optional, only for GUI export: brew install pandocThen install unlocr using Homebrew:
# Install the CLI tool
brew install whit3rabbit/tap/unlocr
# Or install the GUI Desktop App
brew install --cask whit3rabbit/tap/unlocrNote
For the unsigned macOS GUI app, Homebrew handles quarantine flags automatically. If downloading manually, run:
xattr -dr com.apple.quarantine "/Applications/unlocr.app"
- Download the pre-built CLI binary or GUI installer (
.AppImage,.deb,.rpm) from GitHub Releases. - The
.deb/.rpmdeclares poppler (and pandoc for GUI export) as dependencies, so your package manager pulls them in automatically. llama-serveris auto-downloaded (x86_64) — unlocr fetches its patched R-SWA build (PR #24975) into the app cache on first run; you do not installllama.cppmanually. (Other arches, e.g. arm64, have no pinned download: build llama.cpp from PR #24975 and pass--llama-bin.)
- Download the CLI executable or the Windows GUI Installer (
.msi) from GitHub Releases. - GUI: no manual setup — open Settings → Dependencies and click Download for any missing tool. The GUI fetches sha256-pinned
pdftoppm, the patchedllama-server, andpandocinto its cache (GPU users should build llama.cpp from PR #24975 and pass--llama-bin). - CLI: the patched
llama-serverauto-downloads on first run; just ensurepdftoppmis on yourPATH, then run the installer or script:powershell -ExecutionPolicy Bypass -File packaging\windows\install.ps1
If you have the Rust toolchain installed:
cargo install unlocr# Clone the repository and run the install script (macOS/Linux)
./install.sh(For Windows source installation details, see packaging/README.md.)
Simply launch the installed unlocr application from your OS Applications folder (or Start Menu). The GUI provides an intuitive interface to load PDFs, select quality presets, customize prompts, and start the OCR process.
Run unlocr by passing one or more PDFs:
unlocr <input.pdf> [more.pdf ...] [options]Example:
unlocr report.pdf --out ./out --quality best
# Generates ./out/report.md with page-delimited <!-- page N --> markersFor a complete, in-depth guide on all CLI arguments, sampling configurations, and advanced setups, see docs/CLI.md.
| Option | Default | Description |
|---|---|---|
--out DIR |
. |
Output directory for the converted Markdown files. |
-o, --output FILE |
(from input name) | Single output file path (single-input only). .md appended when no extension; joined under --out when relative. |
--recursive |
false |
Recurse into subdirectories when an input is a folder. |
--from-list FILE |
(none) | Read extra PDF paths from a text file (one per line; # comments and blank lines skipped). |
--password PW |
UNLOCR_PDF_PASSWORD |
User/open password for encrypted PDFs. --password overrides the env var. Prefer the UNLOCR_PDF_PASSWORD env var or --password-file to keep the secret out of your shell history and unlocr's own argv. (Poppler still receives it as -upw, so it appears in the process list while pdfinfo/pdftoppm run, whichever source you use.) |
--password-file FILE |
(none) | Text file of candidate PDF passwords (one per line; # comments and blank lines skipped). Each PDF is tried against every password until one unlocks it, so a batch with different passwords works. A PDF no password unlocks is skipped (reported), and the rest of the batch continues. |
--quality TIER |
good |
Quality preset. Options: best (BF16), good (Q8_0), less (Q4_K_M). |
--quant TAG |
(from quality) | Exact Hugging Face model quant tag (e.g. Q6_K, IQ4_XS). Overrides --quality. |
--model PATH |
(HF download) | Use this GGUF directly, skipping the HF download and naming convention. Disables --quant/--quality/--model-dir selection. |
--mmproj PATH |
(cached projector) | Projector (mmproj) GGUF override. Requires --model. |
--max-tokens N |
4096 |
Max tokens generated per page (prevents infinite loop/runaways on dense pages). |
--pages RANGE |
(all) | Pages to OCR: a single page (5) or inclusive 1-based range (5-9). Applies to every input. |
--task PRESET |
markdown |
Prompt preset: markdown (clean md), grounding (md + layout coordinates), free (plain text), figure (parses charts/figures). |
--prompt TEXT |
(from task) | Custom OCR prompt. Overrides --task. Use `< |
--dpi N |
144 |
PDF page rendering DPI (higher DPI gives larger/clearer source images). |
--image-max-tokens N |
(model default) | Vision-token budget for llama-server (local mode only). Higher means finer detail recognition but slower/more VRAM. |
--chat-template NAME |
(model default) | Forwarded to llama-server --chat-template (e.g., deepseek-ocr); local mode only. |
--repeat-penalty F |
1.3 (local GGUF) / (server default) (--endpoint/--gpu) |
Sampling repeat penalty; helps break generation loops in smaller quants. |
--llama-bin PATH |
Auto-detected | Path to the llama-server binary. |
--model-dir PATH |
OS Cache | Custom cache directory for GGUF model downloads. |
--port N |
0 (Auto) |
Port for the spawned llama-server. |
--keep-images |
false |
Retain the intermediate page PNGs generated during processing. |
--gpu |
false |
Run the full DeepSeek-OCR model via local vLLM. Shortcut for --endpoint http://localhost:8000 --endpoint-model deepseek-ai/DeepSeek-OCR. |
--endpoint URL |
Local spawn | Route requests to a remote OpenAI-compatible server (vLLM, SGLang, etc.) and skip local spawn. |
--endpoint-key KEY |
UNLOCR_API_KEY |
Bearer API token for --endpoint (or set via UNLOCR_API_KEY env var). |
--endpoint-model M |
(none) | Model name sent in endpoint request body (required by vLLM/LiteLLM gateways). |
Subcommands: unlocr doctor (alias preflight) validates system deps, model files, RAM, and disk space without running OCR. Accepts --llama-bin, --model-dir, --quant.
- Preflight: Resolves
llama-server(preferring unlocr's cached patched R-SWA build, auto-downloading it if absent) and locatespdftoppm. An externalllama-server(--llama-bin/PATH) is used with a warning that it cannot be verified for R-SWA support (silence viaUNLOCR_ALLOW_EXTERNAL_LLAMA=1). - Model Cache: Checks for
Unlimited-OCR-<quant>.ggufandmmproj-Unlimited-OCR-F16.ggufin the cache directory, downloading them from HF if missing. - Spawn Server: Starts a single background
llama-serverinstance and polls/healthuntil active. - OCR Processing: For each PDF, runs
pdftoppmto extract pages as PNGs, POSTs them sequentially (base64 encoded) to/v1/chat/completions, and appends the markdown output.
GGUFs are cached locally. They can be quite large (~1.8 GB to ~8.0 GB total depending on quants downloaded).
| OS | Default Cache Path |
|---|---|
| macOS | ~/Library/Caches/unlocr |
| Linux | $XDG_CACHE_HOME/unlocr (or ~/.cache/unlocr) |
| Windows | %LOCALAPPDATA%\unlocr |
Override the path using --model-dir PATH or the $XDG_CACHE_HOME env var.
To remove the application binary and purge downloaded model weights, run:
- macOS/Linux:
./uninstall.sh - Windows:
powershell -ExecutionPolicy Bypass -File packaging\windows\uninstall.ps1
For high-performance GPU serving of the unquantized model:
- Install vLLM (pre-release recommended for DeepSeek-OCR support):
pip install -U vllm --pre --extra-index-url https://wheels.vllm.ai/nightly
- Serve the model:
vllm serve deepseek-ai/DeepSeek-OCR \ --no-enable-prefix-caching \ --mm-processor-cache-gb 0 \ --logits-processors vllm.model_executor.models.deepseek_ocr:NGramPerReqLogitsProcessor
- Run
unlocrtargeting this endpoint:(In the GUI, select the GPU full model (vLLM · DeepSeek-OCR) engine preset.)unlocr report.pdf --gpu
Tip
Google Colab: Check out the Google Colab notebooks to run the full GPU pipeline on a free Colab T4 cloud instance:
- Hardware: macOS (Apple Silicon, Metal)
- llama.cpp: build b9770
- Model: BF16 (
--quality best, 5.47GB) - Document: 355-page book PDF (~12.4MB), 144 DPI
| Metric | Result |
|---|---|
| Cold Start (Model Loaded) | ~15 seconds |
| Total Processing Time | 42 min 44 s (~7.2s/page) |
| Output size | 1.2 MB markdown (~192k words) |
Smaller quants (--quality good / less) trade off accuracy for much faster speeds and smaller downloads.
- Ctrl-C (SIGINT): Interrupting CLI does not clean up the background server process, which might orphan
llama-server. - Abnormal exit (macOS): If the app is force-killed (
SIGKILL/segfault) or panics (panic=abort), cleanup is skipped. Linux (PR_SET_PDEATHSIG) and Windows (Job Objects) killllama-serverwith the parent; macOS has no equivalent, so a warm server can be orphaned. Recover withpkill llama-server. - Port Race: Free-port allocation may occasionally conflict; pin using
--port N. - Authentication: The local
llama-serverbinds to127.0.0.1without auth. On multi-user machines, other local users could access the server port during execution. Single-user environments are recommended. - Repetition loops on blank/ruled/low-content pages: The underlying Unlimited-OCR/DeepSeek-OCR model can degenerate into repetitive or hallucinated output (e.g. rambling about "the Ground Truth image" instead of transcribing) on blank regions, ruled/underscore lines, or other low-content input. This is an open, currently unresolved upstream model issue (deepseek-ai/DeepSeek-OCR#151), not a bug in unlocr's prompt: upstream's vLLM/SGLang serving suppresses it with a custom n-gram-repetition logits processor that has no llama.cpp/GGUF equivalent. If you hit this, first confirm you are on unlocr's managed R-SWA build, not a stock/PATH/Homebrew
llama-server: an unpatched build cannot load the vision tower and is the most common cause ofocr-ocr-style loops (the GUI pipeline shows an amber "external" flag when it is; the CLIdoctorprints the provenance). Then try the anti-loop DRY knobs the community found for dense/math pages:--dry-allowed-length 2 --dry-penalty-last-n -1(the GUI's Anti-loop (dense pages) toggle sets both), raising--repeat-penalty(e.g.1.5), raising--dry-multiplier, or using a higher-precision quant (--quality best/goodoverless). A page whose generation hits--max-tokenswithout a natural stop is flagged with a warning (likely a repetition loop) rather than silently written out as if it were real text.
The unlocr codebase is released under the MIT License. Note that model weights downloaded automatically from Hugging Face are governed by their respective licenses (see HF model card).