documenta11ist-ocr

Extract text from images and PDF documents using OCR. Fast, accurate, with optional LLM vision fallback for low-confidence results.

REST API v1 Multipart Upload

Authentication

API endpoints require authentication when the server is configured with allowed API keys.

Header X-API-Key
Format Plain string token provided by the service administrator
Scope Applies to /api/* routes when API_KEYS is set. The /health endpoint is public.

Endpoints

POST /api/v1/ocr Auth required

Extract text from an uploaded image or PDF document.

Request

Content-Type multipart/form-data
Body file — the document to process
Formats JPEG, PNG, PDF
Max size 5 MB (configurable)

Response

json 200
{
  "data": "Le texte extrait du document...",
  "metadata": {
    "processing_time_ms": 342,
    "method": "ocr_tesseract"
  }
}

Extraction methods

MethodDescription
ocr_tesseractText extracted via Tesseract OCR engine
text_extractionText extracted directly from a text-based PDF
ocr_tesseract_with_llm_fallbackTesseract result refined by LLM vision (low confidence)
POST /api/v1/analyze Auth required

Analyze an uploaded image or PDF document into useful text, retained blocks with heading levels, removed noise, document language, PDF link annotations, and PDF image metadata (position, caption, nearby text, role, optional AI alt text).

Request

Content-Type multipart/form-data
Body file — the document to process
Optional lang — document language (fr, fr-FR...). When omitted, the language is detected automatically.
Formats JPEG, PNG, PDF
Max size 5 MB (configurable)

Response

json 200
{
  "useful_text": "Titre du document\nParagraphe utile...",
  "blocks": [
    {
      "id": "block-1",
      "kind": "title",
      "text": "Titre du document",
      "page": 1,
      "confidence": 1.0,
      "bbox": null,
      "heading_level": 1
    }
  ],
  "images": [
    {
      "id": "image-1-1",
      "page": 1,
      "width": 640,
      "height": 480,
      "bbox": null,
      "mime_type": "image/jpeg",
      "caption": null,
      "caption_confidence": 0.0,
      "nearby_text": "",
      "alt_text": null,
      "role": "informative"
    }
  ],
  "links": [
    {
      "id": "link-1",
      "page": 1,
      "url": "https://example.org",
      "text": "Texte du lien",
      "bbox": { "x": 72.0, "y": 300.0, "width": 120.0, "height": 14.0 }
    }
  ],
  "language": {
    "code": "fr",
    "source": "detected",
    "confidence": 0.97
  },
  "removed_blocks": [
    {
      "kind": "page_number",
      "text": "Page 1 sur 12",
      "page": 1,
      "reason": "pagination_pattern"
    }
  ],
  "metadata": {
    "processing_time_ms": 512,
    "method": "text_extraction",
    "pages": 1
  }
}

Notes

heading_level comes from PDF outlines, explicit numbering, or typographic ranking (in that priority order). role classifies each image as informative, decorative, or unknown. alt_text is generated only when the LLM alt text feature is enabled. bbox, caption, nearby_text, and language stay empty when no reliable source data is available — values are never guessed.

POST /api/v1/reconstruct Auth required

Full accessibility chain in a single call: analyze the document, rebuild it as semantic accessible HTML, and evaluate it against the automatable RGAA criteria. Returns an atomic JSON envelope with the HTML, the conformity report, and the full analysis.

Request

Content-Type multipart/form-data
Body file — the document to process
Optional lang — document language, same as /api/v1/analyze
Formats JPEG, PNG, PDF
Max size 5 MB (configurable)

Response

json 200
{
  "html": "<!doctype html>\n<html lang=\"fr\">...",
  "report": {
    "criteria": [
      {
        "criterion": "1.1",
        "theme": "images",
        "status": "a_verifier",
        "reason": "Une ou plusieurs images informatives disposent d'un texte alternatif produit automatiquement...",
        "subject_ids": ["image-1-1"],
        "confidence": 0.8
      }
    ],
    "transformations": [
      {
        "kind": "heading_level_adjusted",
        "block_ids": ["block-7"],
        "detail": "Heading level adjusted from 3 to 2 to avoid a hierarchy jump."
      }
    ],
    "summary": {
      "conforme": 7,
      "non_conforme": 0,
      "a_verifier": 6,
      "non_traite": 2
    }
  },
  "analysis": { "...same structure as /api/v1/analyze..." }
}

Notes

The generated HTML is self-contained (JPEG images embedded as data URIs) and every element carries the id of its source block for review highlighting. Report statuses: conforme, non_conforme, a_verifier (human review needed), non_traite (detected but not yet reconstructed — nothing is silently dropped).

GET /health Public

Health check endpoint. Returns service status.

json 200
{
  "status": "ok"
}

Responses

All responses are JSON. Successful responses return the result directly. Error responses use a consistent envelope.

Error format
{
  "error": "Description of what went wrong"
}

Errors

StatusReason
400Unsupported file format, file too large, or invalid PDF
401Missing or invalid API key
422Text extraction failed on a valid file
500Internal server error (OCR engine failure)

Examples

Extract text from an image

curl
$ curl -X POST https://your-domain.com/api/v1/ocr \
  -H "X-API-Key: your-api-key" \
  -F "file=@scan.jpg"

Extract text from a PDF

curl
$ curl -X POST https://your-domain.com/api/v1/ocr \
  -H "X-API-Key: your-api-key" \
  -F "file=@document.pdf"

Analyze a document

curl
$ curl -X POST https://your-domain.com/api/v1/analyze \
  -H "X-API-Key: your-api-key" \
  -F "file=@document.pdf"

Reconstruct an accessible document

curl
$ curl -X POST https://your-domain.com/api/v1/reconstruct \
  -H "X-API-Key: your-api-key" \
  -F "file=@document.pdf" \
  -F "lang=fr"

Health check

curl
$ curl https://your-domain.com/health