File size: 3,763 Bytes
e4e6ceb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4124165
 
e4e6ceb
4124165
 
 
 
 
 
 
 
e4e6ceb
 
 
 
 
 
 
4124165
e4e6ceb
 
 
 
 
4124165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e4e6ceb
 
 
 
 
 
 
 
 
 
 
 
 
 
4124165
e4e6ceb
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Delivery Note OCR API Specification

Base URL: `https://<backend-host>`

The API is frontend-agnostic. Web apps, mobile apps, CLI tools, automations, and
the Hugging Face Space all consume the same HTTP contract.

## Authentication and Secrets

This backend currently protects the upstream Mistral credential by keeping it on
the server side as `MISTRAL_API_KEY`. Clients never send the provider key.

Add caller authentication at the API gateway or with a FastAPI dependency before
public internet exposure.

## Endpoints

| Method | Path | Purpose |
| --- | --- | --- |
| `GET` | `/health` | Liveness and provider configuration status |
| `GET` | `/v1/schema` | JSON schema used for structured extraction |
| `POST` | `/v1/ocr` | Multipart image upload OCR/inference |
| `POST` | `/v1/ocr/base64` | JSON base64 OCR/inference for non-browser clients |

Interactive OpenAPI docs are available at `/docs` when the backend is running.

## `POST /v1/ocr`

Request: `multipart/form-data`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `file` | file | yes | `.jpg`, `.jpeg`, `.png`, or `.webp` image |
| `repair` | query bool | no | Defaults to `true`; applies deterministic repair |
| `validate` | query bool | no | Defaults to `true`; returns validation warnings |

Example:

```bash
curl -X POST \
  -F "file=@scan.jpg" \
  "http://localhost:8000/v1/ocr?repair=true&validate=true"
```

## `POST /v1/ocr/base64`

Request body:

```json
{
  "filename": "scan.jpg",
  "content_type": "image/jpeg",
  "image_base64": "<base64-or-data-url>",
  "repair": true,
  "validate": true
}
```

## Response Shape

```json
{
  "filename": "scan.jpg",
  "content_type": "image/jpeg",
  "checksum_md5": "string",
  "annotation": {
    "delivery_note_full": {"value": "111565/2026", "confidence": 0.99},
    "products": []
  },
  "schema_valid": true,
  "schema_errors": [],
  "validation_warnings": [],
  "repairs": [
    {
      "path": "products[0].pharmacist_price_ttc",
      "original": 7.89,
      "value": 5.35,
      "reason": "derived from line_total_ttc / quantity"
    }
  ],
  "raw_provider_response": {},
  "parse_error": null,
  "metadata": {
    "provider": "mistral",
    "model": "mistral-ocr-latest",
    "retry_count": 0,
    "critical_retry_reasons": [],
    "retry_reasons": [],
    "duration_ms": 1234
  }
}
```

Field notes:

- `annotation` is the frontend-friendly structured extraction. Every leaf is a
  `{value, confidence}` object; `value` may be `null` when a field is absent. The
  annotation is always schema-clean — repair provenance never appears inside it.
- `schema_valid` / `schema_errors` report whether the (post-repair) annotation
  validates against `/v1/schema`. Each error carries `path`, `message`, and
  `validator`.
- `repairs` are structured, deterministic corrections applied server-side. Each
  record carries `path`, `original` (the OCR reading), `value` (the corrected
  number), and `reason` (the accounting identity used).
- `validation_warnings` are non-blocking consistency notes (row-count, line
  arithmetic, total reconciliation) for human review.
- `raw_provider_response` preserves the original OCR provider response for
  debugging and replay.

Entity resolution against a client database (supplier / pharmacy / product
matching) is **not** performed here; it is the CRM's responsibility. See
`docs/client-integration-guide.md`.

## Deployment

Backend:

```bash
cp .env.example .env
# edit MISTRAL_API_KEY in .env
docker compose up --build
```

Hugging Face Space:

1. Create a Gradio Space.
2. Deploy the Gradio UI (`app.py`) with its dependencies.
3. Set `BACKEND_API_URL` to the deployed backend URL.

No backend code changes are required when the frontend URL or hosting platform
changes.