CoolFace
Apppublic

Rootoor/doctr-ocr-service

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
App README

docTR OCR Service

Self-hosted REST microservice for text extraction from images. Used in the Webhook: Verify Student Card workflow.

Based on docTR (Apache 2.0) — no data sent to any external service.

Requirements

  • Docker
  • Docker Compose v2 (docker compose, not docker-compose)

Setup

bash
cp .env.example .env
# Edit .env: set API_KEY to a strong secret
docker compose up -d --build

The first start downloads docTR models (~130 MB) and caches them in a persistent Docker volume. Subsequent restarts are fast.

Endpoints

GET /health

Returns service status. No auth required.

bash
curl http://localhost:8001/health
json
{ "ok": true, "message": "OCR service is running", "data": {} }

POST /extract/student-card

Main endpoint for the student card verification workflow. Extracts the student number and academic year from a card photo.

Handles automatically:

  • Any orientation (portrait, landscape, 90°, 270°) — tries 4 rotations
  • EXIF correction — compensates for phone orientation metadata
  • Blur detection — rejects unreadable photos before OCR processing

Body: multipart/form-data with a file field (JPEG, PNG, or WebP). Max 10 MB.

bash
curl -X POST http://localhost:8001/extract/student-card \
  -F "file=@/path/to/card.jpg"

Success response:

json
{
  "ok": true,
  "message": "Carte lue avec succès",
  "data": {
    "student_number": "645102",
    "academic_year": "2024-2025"
  }
}

Blurry photo:

json
{
  "ok": false,
  "message": "Photo trop floue",
  "data": {
    "error": "La photo est trop floue pour être lue. Prends une photo plus nette, bien éclairée et sans bouger.",
    "traceback": null
  }
}

Unreadable card (sharp photo but fields not found):

json
{
  "ok": false,
  "message": "Carte illisible",
  "data": {
    "error": "Impossible d'extraire le numéro étudiant ou l'année académique. Envoie une photo plus nette de ta carte.",
    "traceback": null
  }
}

POST /extract

Extracts raw text from any image. Requires X-API-Key header if API_KEY is set.

Body: multipart/form-data with a file field (JPEG, PNG, or WebP). Max 10 MB.

bash
curl -X POST http://localhost:8001/extract \
  -H "X-API-Key: your_api_key" \
  -F "file=@/path/to/image.jpg"

Success response:

json
{
  "ok": true,
  "message": "Text extracted successfully",
  "data": {
    "full_text": "UNIVERSITE DE LOME\nNuméro: 645102\n...",
    "blocks": ["block 1", "block 2"],
    "page_count": 1
  }
}

Configuration

VariableDefaultDescription
PORT8001Host port the service listens on
API_KEY(empty)Required X-API-Key header value. Leave empty to disable auth

EC2 Deployment

Prerequisites

Ensure the EC2 instance has a swap file (critical on 2 GB RAM instances):

bash
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Start the service

bash
cp .env.example .env
# Set a strong API_KEY in .env
docker compose up -d

The service binds to 127.0.0.1:8001 only — it is not directly reachable from the internet.

Nginx configuration

Add the following to your existing Nginx config (inside the appropriate server block):

nginx
location /ocr/ {
    proxy_pass http://127.0.0.1:8001/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    client_max_body_size 10m;
    proxy_read_timeout 120s;
}

Then reload Nginx:

bash
sudo nginx -t && sudo systemctl reload nginx

Management

bash
# Start
docker compose up -d

# Stop
docker compose down

# Logs
docker logs doctr-ocr -f

# Rebuild after code changes
docker compose up -d --build

Structure

doctr/
├── app/
│   ├── main.py           # FastAPI app
│   └── requirements.txt  # Python dependencies
├── Dockerfile
├── docker-compose.yml
├── .env.example
└── README.md

Notes

  • Models are cached in the doctr_models Docker volume — they survive restarts.
  • Uses PyTorch CPU backend (no GPU required).
  • Memory capped at 1400 MB in docker-compose to protect the host.
  • Uses docker compose (v2) — docker-compose (v1) is not supported.
  • Student number accepted: 5–7 digits, anchored to the Numéro: label on the card.