A high-performance RESTful API service for document OCR processing with modular engine architecture using datenzar OCR Bridge packages.
- Modular Engine Architecture: Plugin-based OCR engines via PyPI packages
- Multi-format Support: Process JPEG, PNG, PDF, and TIFF documents
- HOCR Output: Industry-standard HTML-based OCR with bounding boxes and text hierarchy
- Multiple OCR Engines: Tesseract, EasyOCR, and ocrmac (macOS only)
- Dynamic Engine Discovery: Automatically detects installed engine packages
- Engine-agnostic API: Unified endpoint works with any installed engine
- No Authentication: Public API for easy integration
This service uses a modular plugin architecture powered by the datenzar OCR Bridge packages:
- Core Framework: FastAPI with async/await
- Base Package:
ocrbridge-core- Base classes and utilities - Engine Packages (optional, installed separately):
ocrbridge-tesseract- Tesseract OCR (100+ languages)ocrbridge-easyocr- EasyOCR deep learning (80+ languages, GPU support)ocrbridge-ocrmac- Apple Vision framework (macOS only)
- Engine Discovery: Python entry points for automatic detection
- Logging: structlog (JSON format)
- Metrics: Prometheus client
- OCR engine packages register themselves via Python entry points (
ocrbridge.engines) - On startup, the service discovers all installed engines dynamically
- API endpoints work with any engine - no code changes needed
- Add new engines by installing packages, no service modification required
- mise
Install the core service (no engines):
# Clone the repository
git clone <repository-url>
cd ocr-service
# Install pinned tools and base dependencies
mise install
mise run install:baseChoose which engines to install:
# Option 1: Install Tesseract engine
mise run install:tesseract
# System requirement: tesseract binary must be installed
# Ubuntu/Debian: sudo apt-get install tesseract-ocr
# macOS: brew install tesseract
# Option 2: Install EasyOCR engine (includes PyTorch, ~2GB)
mise run install:easyocr
# Option 3: Install ocrmac engine (macOS only)
mise run install:ocrmac
# Option 4: Install all engines
mise run install:all
# Optional: Install pdfocr for searchable PDF output from PDF uploads
# Requires Go toolchain (https://go.dev/dl/)
go install github.com/gardar/ocrchestra/cmd/pdfocr@latestpdfocr is used when output_format=pdf and the uploaded file is a PDF. For image uploads, PDF output still uses pytesseract.
| Engine | Package | Accuracy | Speed | GPU Support | Languages | Size Impact |
|---|---|---|---|---|---|---|
| Tesseract | ocrbridge-tesseract |
Good | Fast | No | 100+ | ~500MB |
| EasyOCR | ocrbridge-easyocr |
Excellent | Medium | Yes | 80+ | +2GB (PyTorch) |
| ocrmac | ocrbridge-ocrmac |
Excellent | Very Fast | Yes (Apple Neural Engine) | 30+ | +10MB (macOS only) |
# Install Tesseract engine (lightest option)
mise run install:tesseract
# Make sure tesseract binary is installed
# macOS: brew install tesseract
# Ubuntu: sudo apt-get install tesseract-ocrmise run devThe API will be available at http://localhost:8000.
# Health check
curl http://localhost:8000/health
# List available engines
curl http://localhost:8000/v2/ocr/engines
# Check engine parameter schema
curl http://localhost:8000/v2/ocr/engines/tesseract/schemaThe unified /v2/ocr/process endpoint works with any installed engine:
# Process with Tesseract
curl -X POST http://localhost:8000/v2/ocr/process \
-F "file=@document.pdf" \
-F "engine=tesseract"
# Process with custom parameters (Individual form fields)
curl -X POST http://localhost:8000/v2/ocr/process \
-F "file=@document.pdf" \
-F "engine=tesseract" \
-F "lang=eng+fra" \
-F "psm=3" \
-F "dpi=300"
# Process with EasyOCR (if installed)
# List parameters can be passed by repeating the field
curl -X POST http://localhost:8000/v2/ocr/process \
-F "file=@document.pdf" \
-F "engine=easyocr" \
-F "languages=en" \
-F "languages=ch_sim" \
-F "text_threshold=0.7"
# Process with ocrmac (macOS only, if installed)
curl -X POST http://localhost:8000/v2/ocr/process \
-F "file=@document.pdf" \
-F "engine=ocrmac" \
-F "languages=en-US" \
-F "recognition_level=accurate"Response:
{
"hocr": "<?xml version='1.0' encoding='UTF-8'?>...",
"processing_duration_seconds": 2.456,
"engine": "tesseract",
"pages": 1
}curl http://localhost:8000/v2/ocr/enginesResponse:
{
"engines": ["tesseract", "easyocr"],
"count": 2,
"details": [
{
"name": "tesseract",
"class": "TesseractEngine",
"supported_formats": [".jpg", ".jpeg", ".png", ".tiff", ".tif", ".pdf"],
"has_param_model": true
}
]
}curl http://localhost:8000/v2/ocr/engines/tesseract/schemaResponse:
{
"engine": "tesseract",
"schema": {
"properties": {
"lang": {
"type": "string",
"description": "Language code(s): 'eng', 'fra', 'eng+fra' (max 5)",
"pattern": "^[a-z_]{3,7}(\\+[a-z_]{3,7})*$"
},
"psm": {
"type": "integer",
"minimum": 0,
"maximum": 13,
"description": "Page segmentation mode (0-13)"
},
"oem": {
"type": "integer",
"minimum": 0,
"maximum": 3,
"description": "OCR Engine mode: 0=Legacy, 1=LSTM, 2=Both, 3=Default"
},
"dpi": {
"type": "integer",
"minimum": 70,
"maximum": 2400,
"description": "Image DPI (70-2400, typical: 300)"
}
}
}
}# Health check
curl http://localhost:8000/health
# Prometheus metrics
curl http://localhost:8000/metricsConfiguration via environment variables:
# API Configuration
API_HOST=0.0.0.0
API_PORT=8000
API_WORKERS=4
# File Storage
UPLOAD_DIR=/tmp/uploads
RESULTS_DIR=/tmp/results
MAX_UPLOAD_SIZE_MB=25
# Job Configuration
JOB_EXPIRATION_HOURS=48
# Synchronous Processing
SYNC_TIMEOUT_SECONDS=30
SYNC_MAX_FILE_SIZE_MB=5
# Searchable PDF tool (used for PDF uploads with output_format=pdf)
PDFOCR_COMMAND=pdfocr
# Logging
LOG_LEVEL=INFO
LOG_FORMAT=jsonFrom ocrbridge-tesseract:
lang(string): Language codes, e.g., "eng", "eng+fra" (max 5 languages)psm(integer 0-13): Page segmentation modeoem(integer 0-3): OCR engine mode (0=Legacy, 1=LSTM, 2=Both, 3=Default)dpi(integer 70-2400): DPI for PDF conversion (default: 300)
From ocrbridge-easyocr:
languages(list of strings): Language codes, e.g., ["en", "ch_sim"] (max 5)text_threshold(float 0.0-1.0): Confidence threshold for text detection (default: 0.7)link_threshold(float 0.0-1.0): Threshold for linking text regions (default: 0.7)
From ocrbridge-ocrmac (macOS only):
languages(list of strings): IETF BCP 47 codes, e.g., ["en-US", "fr-FR"] (max 5)recognition_level(string): "fast", "balanced" (default), "accurate", or "livetext"
To create a custom OCR engine:
- Create a Python package that depends on
ocrbridge-core>=1.0.0 - Implement
OCREnginebase class fromocrbridge.core - Register via entry point in
pyproject.toml:
[project.entry-points."ocrbridge.engines"]
my_engine = "my_package:MyEngine"- Install your package - the service will automatically discover it!
No code changes to the service required.
# Install pinned tools
mise install
# Install dependencies (dev + all engines)
mise run install:all
# Or install only Tesseract for a lighter setup
mise run install:tesseractmise run lint:format
mise run lint:lint
mise run lint:typecheck
# Run all quality tasks
mise run lint:allocr-service/
├── src/
│ ├── api/
│ │ └── routes/
│ │ └── v2/
│ │ └── dynamic_routes.py # V2 unified OCR endpoints
│ ├── services/
│ │ └── ocr/
│ │ └── registry_v2.py # Entry point discovery registry
│ ├── models/
│ │ └── responses.py # API response models
│ └── main.py # FastAPI application
├── pyproject.toml # Dependencies and entry points
└── README.md
# Build the full runtime image
docker build --target full -t ocr-service:full -t ocr-service:latest .
# Start the API stack
docker compose -f docker-compose.base.yml -f docker-compose.yml up -d- Horizontal Scaling: Service is fully stateless
- Engine Installation: Install only needed engines to minimize image size
- GPU Support: Use GPU-enabled base image for EasyOCR
- Health Monitoring: Use
/healthendpoint for liveness/readiness probes - Metrics: Scrape
/metricswith Prometheus
# Check discovered engine entry points
uv run python -c "import importlib.metadata as m; print([ep.name for ep in m.entry_points(group='ocrbridge.engines')])"
# Check logs for engine discovery
# Look for: "ocr_engines_discovered"# For Tesseract: Ensure tesseract binary is installed
which tesseract
# For ocrmac: Only works on macOS, not in Docker
uname -s # Should return "Darwin"
# For searchable PDF output from PDF uploads: Ensure pdfocr is installed
which pdfocrDefault: 100 requests/minute per IP. Configure with RATE_LIMIT_REQUESTS.
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
This project is licensed under the GNU General Public License v3.0.
Built with:
- FastAPI - Web framework
- datenzar OCR Bridge - Modular OCR engines
- structlog - Structured logging
GET /v2/ocr/engines: Lists discovered engines with metadata.- Includes
name,class,supported_formats,has_param_model, andparams_schema(JSON Schema for engine params when available).
- Includes
GET /v2/ocr/{engine}/info: Returns metadata for a specific engine, includingparams_schema.POST /v2/ocr/{engine}/process:multipart/form-datawithfileand engine-specific parameters as individual form fields.- Parameters are dynamically registered in the OpenAPI schema and validated against the engine's Pydantic model.
Example:
{
"name": "tesseract",
"class": "TesseractEngine",
"supported_formats": ["image/png", "image/jpeg", "application/pdf"],
"has_param_model": true,
"params_schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "TesseractParams",
"type": "object",
"properties": {
"psm": {"type": "integer"},
"oem": {"type": "integer"}
}
}
}