Gemini OCR CLI
A command-line tool for OCR processing using Google Gemini's vision capabilities. Process PDFs and images to extract text, tables, equations, and figures.
Choosing an OCR tool
This is one of five OCR CLI tools with a shared design: clean Markdown output, batch processing, and figure extraction. Pick based on your constraints:
| Tool | Engine | Runs | Cost | Best for |
|---|---|---|---|---|
| deepseek-ocr-cli | DeepSeek vision | Local (Ollama / vLLM) | Free | General-purpose local OCR with multi-backend flexibility |
| gemini-ocr-cli (this repo) | Google Gemini | Cloud API | Free tier / Pay-per-use | Fast cloud OCR with concurrent processing |
| marker-ocr-cli | Marker (Surya + Texify) | Local | Free | Academic papers with equations, tables, complex layouts |
| mistral-ocr-cli | Mistral OCR API | Cloud API | ~$1/1k pages | Structured extraction (tables, headers, footers) |
| nougat-ocr-cli | Meta Nougat | Local (GPU) | Free | Academic papers, GPU-accelerated batch processing |
Installation
Requires Python 3.11+ and a Google Gemini API key.
pip install gemini-ocr-cli
Or from source:
git clone https://github.com/r-uben/gemini-ocr-cli.git
cd gemini-ocr-cli
uv sync
Quick start
# Set your API key
export GEMINI_API_KEY="your_key_here"
# Process a single file
gemini-ocr document.pdf
# Process a directory
gemini-ocr ./documents -o ./results
# Preview what would be processed (no API calls)
gemini-ocr ./documents --dry-run
# Process 4 files concurrently
gemini-ocr ./documents -w 4
Options
Usage: gemini-ocr [OPTIONS] INPUT_PATH
Options:
-o, --output-dir PATH Output directory (default: <input_parent>/ocr/)
--api-key TEXT Gemini API key (or set GEMINI_API_KEY env var)
--model TEXT Model to use (default: gemini-3.8-flash)
--task [convert|extract|table|describe_figure]
OCR task type (default: convert)
--prompt TEXT Custom prompt for OCR processing
--per-page Force page-by-page OCR (one call/page).
--whole-pdf Force whole-PDF OCR (one call/document), NO
truncation fallback.
(default: auto = whole-PDF with auto-fallback)
--include-images/--no-images Extract embedded figures (default: True)
-w, --workers N Concurrent workers for batch processing (default: 1)
--reprocess Reprocess already-processed files
--dry-run List files without calling the API
-q, --quiet Print only output .md paths (for scripting)
-v, --verbose Enable verbose/debug output
--info Show configuration and system info
--env-file PATH Path to .env file
--version Show version
--help Show this message
Output structure
gemini-ocr follows the shared OCR-CLI output contract. The default output
root is an ocr/ folder next to the input (-o overrides it). Each source
document gets one aggregated folder that mirrors the input subtree, keyed by
the input-relative path (not the basename), so two intro.pdf files in
different directories never collide:
<input_parent>/ocr/
├── a/
│ └── intro/
│ ├── intro.md # all pages, separated by "## Page N" headers
│ ├── figures/ # figure_<N>_page<P>.png (normalised to PNG)
│ │ └── figure_1_page2.png
│ └── metadata.json # per-document provenance sidecar
├── b/
│ └── intro/ # same basename, different subtree — no collision
│ └── intro.md
└── metadata.json # rolled-up index keyed by input-relative path
The markdown body is clean (no YAML frontmatter); all provenance lives in the
JSON sidecars. Each metadata.json entry records
{status, checksum, model, backend, processing_time, timestamp, output_path, pages, mode, fell_back_from_whole_pdf}. Failures are recorded with
status: "failed", and the process exits non-zero if any file or page fails
(uniform across single-file and batch).
PDF processing modes
PDFs can be processed in three modes; the output structure is identical
across all three (one <stem>.md with ## Page N headers, dual-level metadata,
figures). The mode actually used is recorded per document in metadata (mode),
together with whether an auto run fell back (fell_back_from_whole_pdf):
auto(default). Uploads the whole PDF once and OCRs it in a single call (the model is asked to begin each page with a## Page Nheader, which is split back into pages). If that response looks truncated, the document is automatically re-processed page-by-page and that result is used instead, with a one-line note printed and the fallback recorded in metadata (mode: "per_page",fell_back_from_whole_pdf: true). Truncation is detected from real signals, with no hardcoded page-count threshold: (a) a length-limited finish reason (MAX_TOKENS/LENGTH); (b) fewer## Page Nmarkers recovered than the PDF's actual page count (PyMuPDF, i.e. a dropped tail); (c) a missing end-of-document completeness sentinel (the model is asked to emit a terminal<!-- OCR-END -->line; its absence means the body was cut mid-page even on a cleanSTOP, and the sentinel is stripped from the saved markdown); or (d) a multi-page PDF whose response carries zero## Page Nmarkers (markerless collapse to a single blob). This is the cost/quality-preferred default for academic PDFs: one call per document, full document context, but no silently truncated tails on long papers.--per-page. Forces page-by-page OCR: each page is rendered to an image and OCR'd in its own call (N calls per document). Honest per-page failure tracking (one page can fail without sinking the document) at higher cost.--whole-pdf. Forces a single whole-PDF call with no truncation fallback. Cheapest, but a long document may be silently truncated; use only when you explicitly accept that risk.
gemini-ocr paper.pdf # auto: whole-PDF, auto-fallback on truncation
gemini-ocr paper.pdf --per-page # force page-by-page (N calls, per-page failures)
gemini-ocr paper.pdf --whole-pdf # force single call, no fallback (truncation risk)
API key resolution
Priority order:
--api-keyCLI argumentGEMINI_API_KEYenvironment variableGOOGLE_API_KEYenvironment variable (fallback).envfile in current directory
Configuration
All CLI options can also be set via environment variables or a .env file:
| CLI flag | Environment variable | Default |
|---|---|---|
--api-key |
GEMINI_API_KEY |
(required) |
--model |
GEMINI_MODEL |
gemini-3.8-flash |
--per-page / --whole-pdf |
GEMINI_PDF_MODE (auto|per_page|whole_pdf) |
auto |
--include-images |
GEMINI_INCLUDE_IMAGES |
true |
--workers |
GEMINI_MAX_WORKERS |
1 |
--verbose |
GEMINI_VERBOSE |
false |
GEMINI_MAX_FILE_SIZE_MB |
50 |
|
GEMINI_MAX_RETRIES |
3 |
|
GEMINI_RETRY_BASE_DELAY |
1.0 |
CLI flags override environment variables when explicitly passed.
Development
# Install dev dependencies
uv sync --extra dev
# Run tests
uv run pytest
# Lint
uv run ruff check .
# Format
uv run ruff format .
# Type check
uv run mypy gemini_ocr/ --ignore-missing-imports
Limitations
- Maximum file size: 50 MB (configurable via
GEMINI_MAX_FILE_SIZE_MB) - Supported formats: PDF, JPG, JPEG, PNG, WEBP, GIF, BMP, TIFF
License
MIT License - see LICENSE for details.
Metadata
Release files for gemini-ocr-cli 0.3.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| gemini_ocr_cli-0.3.3.tar.gz | 107.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gemini_ocr_cli-0.3.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 137.5 kB
Release files / gemini_ocr_cli-0.3.3.tar.gz
| Download URL | gemini_ocr_cli-0.3.3.tar.gz |
|---|---|
| Size | 107.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
29502fbcc1a6f549d8e915f26913ef8383dc46a81b0787fd5771324fdbd1e198
|
|
BLAKE2b-256 checksum How to use checksums |
cd174578b0e5464b8fd8ed2399df7df7c025dd83f0f0d407db6fc1dd05c3fea2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|
Release files / gemini_ocr_cli-0.3.3-py3-none-any.whl
| Download URL | gemini_ocr_cli-0.3.3-py3-none-any.whl |
|---|---|
| Size | 30.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
799477286331ddf433d95a48adbc32dadfa2af4280b87a644ec9311c548be6a1
|
|
BLAKE2b-256 checksum How to use checksums |
51f60d90e98ad879966cf06f08b7ae1883a1b78c544582667f494549faebd5ef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|
Security for gemini-ocr-cli 0.3.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.