File size: 3,540 Bytes
b510add
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# Architecture du module IA

## Vue d'ensemble

```
Photo du terminal
      │
      ▼
┌─────────────────────┐
│ preprocessing.py     │  détection de l'écran LCD (contours) puis
│                      │  découpage en 3 lignes (prix / volume / prix_litre)
└─────────┬────────────┘
          ▼
┌─────────────────────┐
│ recognizer.py         │  CRNN fine-tuné : lit chaque ligne, renvoie
│ (models/*.pt)         │  {field, text, confidence} par valeur
└─────────┬────────────┘
          ▼
┌─────────────────────┐
│ postprocess.py        │  normalise les nombres (virgule/point),
│                       │  calcule la valeur manquante, vérifie
│                       │  montant = litres × prix
└─────────┬────────────┘
          ▼
┌─────────────────────┐        ┌─────────────────┐
│ rules.py              │◄──────│ quality.py        │ flou / luminosité
│ décide success/blocage │       └─────────────────┘
└─────────┬────────────┘
          ▼
     réponse API (main.py)
```

## Pourquoi ce découpage en modules séparés

Chaque étage a une responsabilité et une durée de vie différentes :

- **preprocessing** et **quality** : de la vision par ordinateur classique
  (OpenCV), aucune dépendance au modèle de reconnaissance. Réutilisable même
  si on change de modèle IA demain.
- **recognizer** : la seule brique qui dépend du modèle entraîné. Isolée
  pour pouvoir la remplacer (nouvelle version du CRNN, ou un autre modèle)
  sans toucher au reste.
- **postprocess** : logique métier pure (aucune I/O, aucun modèle) — donc
  entièrement testable sans charger le CRNN (voir `tests/test_postprocess.py`,
  instantané).
- **rules** : la décision finale (bloquer/valider) séparée du calcul, pour
  pouvoir ajuster les seuils (`config.py`/`config.yaml`) sans toucher à la
  logique de calcul.

## Différence avec le prototype précédent (OCR générique)

L'ancienne version du projet (racine du dépôt, `src/`, `api/`) utilisait
PaddleOCR/EasyOCR : des modèles pré-entraînés génériques, avec toute une
mécanique de variantes d'image et de repli entre moteurs pour compenser
leur manque de spécialisation. Ce module utilise à la place un modèle
**entraîné sur nos propres données** (voir `train/`), ce qui simplifie le
post-traitement : le CRNN sait déjà quelle ligne correspond à quel champ
(par position), il n'y a donc plus besoin d'heuristique de proximité de
libellé ni de deviner "quel nombre est le montant" par magnitude — la
principale source d'erreur du prototype précédent.

## Fichiers clés

| Fichier | Rôle |
|---|---|
| `app/preprocessing.py` | détection écran + découpage lignes |
| `app/recognizer.py` | chargement CRNN + inférence |
| `app/postprocess.py` | normalisation, calculs, cohérence |
| `app/rules.py` | porte de décision succès/blocage |
| `app/config.py` | seuils configurables |
| `app/main.py` | API FastAPI |
| `train/finetune_doctr.py` | entraînement du CRNN |
| `docs/LIMITATIONS.md` | limites connues du modèle actuel |