This guide provides a complete, step-by-step setup for running this OCR Engine locally on a Windows machine. It covers the required services, Python environment, model downloads, worker-specific prerequisites, and verification steps.
| Software | Version | Purpose |
|---|---|---|
| Python | 3.11+ | Runtime |
| MongoDB | 7.x | Metadata and job storage |
| Redis | 7.x | Background worker orchestration |
| Ollama | Latest | Local LLM inference for Qwen-VL |
| Git | Any | Version control |
| Postman | Optional | API testing |
Recommended minimum hardware:
- 16 GB RAM minimum
- SSD storage preferred
- Internet access for installing dependencies and models
- Download MongoDB Community Server.
- Install it as a Windows service.
- Verify it is running:
mongosh --eval "db.runCommand({ping:1})"Expected output:
{ ok: 1 }
Redis is required for the asynchronous worker pipeline.
Recommended options on Windows:
- Memurai (recommended)
- Redis via WSL2
- Redis Windows build
Verify Redis:
redis-cli pingExpected output:
PONG
Ollama is used by the Qwen-VL OCR worker.
- Install Ollama for Windows.
- Start the service.
- Pull the required models:
ollama pull qwen2.5vl:7b
ollama pull qwen2.5:14bVerify the models are available:
curl http://localhost:11434/api/tagsIf your machine has limited RAM, try smaller models:
ollama pull qwen2.5vl:3b
ollama pull qwen2.5:7bThen update the environment variables accordingly.
cd D:\
mkdir OCR Engine
cd OCR Engine
git clone <your-repo-url> ocr_service
cd ocr_servicepython -m venv venv
.\venv\Scripts\Activate.ps1
python -m pip install --upgrade pipIf PowerShell blocks script execution, run:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserInstall the project requirements:
pip install -r requirements.txtIf install issues occur:
pip install paddlepaddle==2.6.2
pip install paddleocr==2.8.1For CPU-only setup:
pip install torch --index-url https://download.pytorch.org/whl/cpuIf you want GPU acceleration, ensure your machine has a compatible CUDA environment before installing GPU-enabled packages.
The language detection worker depends on fastText.
Create the directory:
mkdir models\fasttextDownload the model:
Invoke-WebRequest -Uri "https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin" -OutFile "models\fasttext\lid.176.bin"The translation worker can use IndicTrans2 when a compatible model is available.
Expected directory:
./models/indictrans2
If the model is not present, the service will gracefully fall back to the original text without translation.
Create the storage structure used by the service:
mkdir storage\incoming
mkdir storage\processed
mkdir storage\failed
mkdir storage\archiveCopy the example configuration:
copy .env.example .envThen update .env with local values such as:
APP_NAME=ocr-service
DEBUG=true
LOG_LEVEL=INFO
MONGO_URI=mongodb://localhost:27017
MONGO_DB=ocr_db
REDIS_URL=redis://localhost:6379
OLLAMA_BASE_URL=http://localhost:11434
QWEN_VL_MODEL=qwen2.5vl:7b
EXTRACTION_MODEL=qwen2.5:14b
PADDLE_USE_GPU=false
PADDLE_CONFIDENCE_THRESHOLD=0.75
PADDLE_LANG=en
FASTTEXT_MODEL_PATH=./models/fasttext/lid.176.bin
INDICTRANS2_MODEL_PATH=./models/indictrans2- Use PADDLE_USE_GPU=false for CPU-only machines.
- If you use smaller Ollama models, update the model names accordingly.
- If IndicTrans2 is unavailable, translation will simply pass through the original text.
Make sure MongoDB, Redis, and Ollama are running before launching the app.
If you use Docker Compose:
docker-compose up -d mongodb redis ollama prometheus grafana lokiOtherwise ensure these endpoints are reachable:
- MongoDB: localhost:27017
- Redis: localhost:6379
- Ollama: localhost:11434
cd "D:\OCR Engine\ocr_service"
.\venv\Scripts\Activate.ps1
python main.pyExpected startup output:
INFO: all_workers_started count=7
INFO: application_started app=ocr-service
INFO: Uvicorn running on http://0.0.0.0:8000
Open the Swagger UI:
http://localhost:8000/api/docs
Test the health endpoint:
curl http://localhost:8000/api/v1/healthExpected response:
{ "status": "ok" }Detailed health check:
curl http://localhost:8000/api/v1/health/detailedThis worker uses:
- PaddleOCR for printed text
- Qwen-VL through Ollama for handwritten or fallback OCR
Required setup:
- PaddleOCR installed
- Ollama running
- Qwen-VL model pulled locally
Required setup:
- fastText model downloaded at the configured path
Required setup:
- IndicTrans2 model if full translation is desired
- If absent, the worker will skip translation and return the source text
This worker uses rule-based extraction for known document types and optional LLM-based extraction behavior through the configured models.
No extra setup is required beyond the main app environment.
Run:
pip install -r requirements.txtCheck that the file exists:
Test-Path .\models\fasttext\lid.176.binVerify with:
curl http://localhost:11434/api/tagsCheck Redis:
redis-cli pingCheck MongoDB:
mongosh --eval "db.runCommand({ping:1})"- Start MongoDB and Redis
- Start Ollama and pull required models
- Activate the virtual environment
- Install dependencies
- Download the fastText model
- Configure .env
- Run the service
- Upload a sample PDF or image via the API
GET http://localhost:8000/api/v1/healthGET http://localhost:8000/api/v1/health/detailedPOST http://localhost:8000/api/v1/upload
Content-Type: multipart/form-dataForm field:
- file: your PDF/image file
GET http://localhost:8000/api/v1/jobs/{job_id}GET http://localhost:8000/api/v1/results/{job_id}To run this project locally, you need:
- Python environment
- MongoDB
- Redis
- Ollama
- PaddleOCR
- fastText model
- Optional IndicTrans2 translation model
Once these are configured, the full OCR pipeline can run end-to-end locally.
POST http://localhost:8000/api/v1/jobs/status
Content-Type: application/json
{
"job_ids": ["JOB-A3F9C2D1E4B7", "JOB-B4E8F1A2C3D6"]
}
POST http://localhost:8000/api/v1/jobs/{job_id}/retry
DELETE http://localhost:8000/api/v1/jobs/{job_id}
POST http://localhost:8000/api/v1/upload/bulk
Postman Setup:
- Method:
POST - Body → form-data
- Add key:
files→ Type: File → Select multiple files - Send
GET http://localhost:8000/metrics
Returns raw Prometheus metrics (counters, histograms, gauges).
Create a new Postman Collection called "OCR Service" and add these requests:
| # | Method | URL | Description |
|---|---|---|---|
| 1 | GET | http://localhost:8000/api/v1/health |
Liveness |
| 2 | GET | http://localhost:8000/api/v1/health/detailed |
Full health |
| 3 | POST | http://localhost:8000/api/v1/upload |
Upload file |
| 4 | POST | http://localhost:8000/api/v1/upload/bulk |
Bulk upload |
| 5 | GET | http://localhost:8000/api/v1/jobs/{{job_id}} |
Job status |
| 6 | POST | http://localhost:8000/api/v1/jobs/status |
Bulk status |
| 7 | GET | http://localhost:8000/api/v1/results/{{job_id}} |
Results |
| 8 | GET | http://localhost:8000/api/v1/pages/{{job_id}} |
All pages |
| 9 | GET | http://localhost:8000/api/v1/pages/{{job_id}}/1 |
Single page |
| 10 | POST | http://localhost:8000/api/v1/jobs/{{job_id}}/retry |
Retry job |
| 11 | DELETE | http://localhost:8000/api/v1/jobs/{{job_id}} |
Delete job |
Tip: Set a Postman variable
{{job_id}}and update it after each upload.
# Make sure you're in the ocr_service directory
cd "D:\OCR Engine\ocr_service"
# Make sure venv is activated
.\venv\Scripts\Activate.ps1# Check if MongoDB service is running
Get-Service MongoDB
# Start it if stopped
Start-Service MongoDB# If using Memurai
Get-Service Memurai
Start-Service Memurai
# If using WSL Redis
wsl sudo service redis-server start# Check if Ollama is running (system tray)
# Or start manually:
ollama serve
# Verify models are downloaded:
ollama listThe .env is set to PADDLE_USE_GPU=false. If you still get CUDA errors:
pip uninstall paddlepaddle-gpu
pip install paddlepaddle# Find what's using port 8000
netstat -ano | findstr :8000
# Kill the process
taskkill /PID <pid> /FThe first OCR request will be slow because:
- PaddleOCR models download on first use (~300 MB)
- Ollama loads models into RAM on first call
Subsequent requests will be fast.
1. Upload file → Saved to ./storage/incoming/{year}/{month}/{job_id}/
2. RendererWorker → Converts PDF pages to PNG (300 DPI)
3. PreprocessorWorker → Grayscale, denoise, deskew, CLAHE, binarize
4. OCRWorker → PaddleOCR (fast) or Qwen-VL (if handwritten/low confidence)
5. LangDetectWorker → Detects language per page (fastText)
6. TranslationWorker → Translates non-English to English (IndicTrans2)
7. ExtractionWorker → Extracts structured fields (Qwen2.5 via Ollama)
8. ValidationWorker → Validates against Pydantic schemas → Job complete!
- MongoDB installed and running on port 27017
- Redis (Memurai) installed and running on port 6379
- Ollama installed with
qwen2.5vl:7bandqwen2.5:14bpulled - Python 3.11+ with virtual environment activated
-
pip install -r requirements.txtcompleted - fastText model at
./models/fasttext/lid.176.bin -
./storage/directories created -
python main.pystarts without errors -
GET /api/v1/healthreturns{"status": "ok"} - Upload a test PDF and check job status