OCR Architecture
Docs AI uses a multi-engine OCR strategy to maximize extraction accuracy across different document types and quality levels. The system selects the appropriate engine based on file type and falls back through a chain when the primary engine fails.
Engine Selection by File Type
| File Type | Primary Engine | Notes |
|---|---|---|
| PNG, JPG, JPEG, TIFF, BMP | EasyOCR | Native Arabic + English support with bounding boxes |
| PDF (text-embedded) | PyPDF2 | Extracts embedded text directly — no OCR needed |
| PDF (scanned/image) | Azure OCR -> EasyOCR -> Tesseract | Three-tier failover for scanned PDFs |
| DOCX | python-docx | Parses Word document structure directly |
Failover Chain
For scanned documents where embedded text extraction fails, the OCR pipeline falls through three engines:
1. Azure OCR (Primary)
Azure's Computer Vision OCR service provides the highest accuracy for both Arabic and English text. It handles complex layouts, mixed-language documents, and low-quality scans effectively.
2. EasyOCR (Secondary)
EasyOCR runs locally without cloud dependencies. It provides strong Arabic character-level recognition and returns bounding box coordinates for each detected text block. Used when Azure OCR is unavailable or returns errors.
3. Tesseract (Tertiary)
Tesseract serves as the universal fallback. It supports Arabic through language packs and works across all image formats, though with lower accuracy on complex Arabic layouts compared to EasyOCR.
Local-Only Mode
When running without Azure credentials, the pipeline skips Azure OCR entirely and starts with EasyOCR. This enables fully offline document processing for air-gapped or sovereign environments.
OCR Output
The OCR endpoint returns extracted text along with confidence scores and block-level detail:
curl -X POST "http://localhost:8008/api/v1/docs/ocr?document_id=DOC_ID"
{
"text": "United Arab Emirates\nEmiratesID\n784-1990-1234567-1\nالهوية الإماراتية",
"confidence": 0.92,
"language": "mixed",
"blocks": [
{
"text": "United Arab Emirates",
"confidence": 0.98,
"bbox": [[10, 20], [200, 20], [200, 50], [10, 50]]
},
{
"text": "الهوية الإماراتية",
"confidence": 0.89,
"bbox": [[10, 60], [180, 60], [180, 90], [10, 90]]
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
text | string | Full extracted text concatenated from all blocks |
confidence | float | Overall confidence score (0.0-1.0) |
language | string | Detected language: ar, en, or mixed |
blocks | array | Individual text blocks with per-block confidence and bounding boxes |
Block Fields
| Field | Type | Description |
|---|---|---|
text | string | Text content of this block |
confidence | float | Confidence score for this block |
bbox | array | Bounding box coordinates as four [x, y] corner points |
Arabic-Specific Handling
Arabic text presents unique OCR challenges:
- Right-to-left flow — Text blocks must be ordered RTL, not LTR
- Connected script — Arabic letters connect, requiring ligature-aware recognition
- Diacritical marks — Optional tashkeel marks (harakat) affect meaning but are often omitted in printed text
- Mixed direction — Documents frequently mix Arabic and English (e.g., Emirates IDs have both)
EasyOCR handles these challenges natively, with Arabic as a first-class supported language. The OCR_LANGUAGES environment variable controls which language models are loaded:
OCR_LANGUAGES='["ar", "en"]'
LRU Caching
OCR results are cached using an LRU cache to avoid reprocessing the same document. If a document has already been OCR-processed, subsequent requests return the cached result immediately.
Configuration
| Variable | Default | Description |
|---|---|---|
OCR_LANGUAGES | ["ar", "en"] | Languages to load for OCR |
OCR_GPU | false | Enable GPU acceleration for EasyOCR |
MAX_FILE_SIZE_MB | 50 | Maximum upload file size |
UPLOAD_DIR | ./uploads | Directory for uploaded files |
Batch Processing
For high-volume document processing, upload and OCR documents in sequence:
for file in documents/*.pdf; do
# Upload
doc_id=$(curl -s -X POST http://localhost:8008/api/v1/docs/upload \
-F "file=@$file" | jq -r '.id')
# OCR
curl -X POST "http://localhost:8008/api/v1/docs/ocr?document_id=$doc_id"
done
The OCR engine processes documents sequentially. For parallel processing at scale, run multiple Docs AI instances behind a load balancer.