Feature #1296
openCorriger la prise en charge des PDF pour l'extraction des factures
100%
conversation:92
Description
### Problème
Dans la modale *"Factures extraites - À valider"*, l'application **n'accepte que les images** (PNG, JPEG, GIF, WEBP) pour extraire les données des factures. Lorsqu'un utilisateur tente de charger un **PDF** (scanné ou natif), une erreur s'affiche :
> *"Erreur: OpenAI - 400 [...] Format d’image non supporté. Veuillez utiliser PNG, JPEG, GIF ou WEBP."*
De plus, même si le PDF était accepté, **l'extraction des données (montant, date, fournisseur, etc.) ne fonctionne pas correctement**, contrairement aux images.
### Contexte
- **Impact** : Bloquant pour les utilisateurs, qui ne peuvent pas valider leurs factures en PDF.
- **Formats concernés** : PDF scannés (comme une image) ou natifs (texte sélectionnable).
- **Comportement attendu** : Les PDF doivent être traités **de la même manière que les images**, avec une extraction fiable des données pour pré-remplir les champs de la facture.
### Comportement proposé
- Accepter les **PDF** en plus des images dans la modale de chargement.
- Extraire les données des PDF **avec la même précision** que pour les images (ex. : montant, date, numéro de facture).
- Afficher les champs pré-remplis **sans erreur** pour permettre la validation.
## Acceptance criteria
['- [ ] Un utilisateur peut charger un **PDF** (scanné ou natif) dans la modale *"Factures extraites - À valider"* **sans erreur**.', '- [ ] Les données de la facture (montant, date, fournisseur, etc.) sont **extraites et affichées correctement** dans les champs correspondants, **quel que soit le format** (PDF ou image).', "- [ ] La validation d'une facture en PDF **fonctionne sans blocage**, comme pour une image.", "- [ ] Les tests incluent des **PDF variés** (scannés, natifs, avec tableaux/logos) pour valider la robustesse de l'extraction."]
## Classification
- bug
## Complexity
- 7/10 — La complexité est élevée car elle nécessite des modifications au niveau du backend (gestion des PDF) et du frontend (affichage des données extraites), ainsi que des tests approfondis pour garantir la compatibilité avec différents types de PDF.
Files
RA Updated by Redmine Admin 28 days ago
- Status changed from Submitted to Preprod
- % Done changed from 0 to 100
- deployed_at set to 07/08/2026
- branch set to fix/invoice-pdf-extraction
- pr_url set to https://github.com/Scobby-organisation/scobby/pull/113
Corrigé et déployé sur **preprod** (2026-07-08).
**Cause racine** — `OpenAiAdapter.invoke` (server/) envoyait *toute* URL de fichier à OpenAI en content-part `image_url`. La vision de gpt-4o n'accepte en `image_url` que PNG/JPEG/GIF/WEBP → un PDF renvoie un `400 unsupported image`, remonté tel quel dans le toast « Erreur : OpenAI - 400 … Format d'image non supporté ». Même classe de bug que #80. **Le front n'était pas en cause** : l'upload accepte déjà tous les formats (la modale n'a jamais bloqué les PDF).
**Correctif** (`server/src/infrastructure/llm/openai.adapter.ts`) — détection d'un PDF (extension `.pdf`), téléchargement côté serveur via le `safeFetch` anti-SSRF existant, puis envoi en content-part `file` base64. gpt-4o lit alors le PDF page par page (texte + rendu) → **PDF scanné comme natif** (AC #1, #2, #3 couverts). Les images continuent de passer en `image_url` (aucune régression). Correctif centralisé dans l'adaptateur → bénéficie aussi à l'extraction billetterie / ingrédients-facture / étiquette-viande.
**Vérification**
- Test unitaire TDD `server/test/openai-invoke-files.test.ts` (RED → GREEN).
- Suite unitaire serveur : 252 passés (dont architecture hexagonale) ; typecheck OK ; Jenkins vert.
- PR #113 → `dev` (mergée) ; PR #114 `dev` → `preprod` (mergée) ; déploiement preprod Jenkins #50 ✅.
**Reste à faire (AC #4)** — smoke-test manuel sur preprod avec des PDF variés (scannés, natifs, avec tableaux/logos) pour valider la qualité d'extraction, non couverte par la CI headless. Passage en prod = gate humain (statut restera Preprod jusque-là).
RA Updated by Redmine Admin 28 days ago
- Status changed from Preprod to Ready to ship
Promu jusqu'à **master** (2026-07-08).
- PR #113 → dev, #114 dev→preprod, #116 dev→preprod (docs), **#117 preprod→master (mergée, commit 7b196c70)**. Jenkins master #13 vert (build+test+push images prod).
- **Vérifié en réel sur preprod** : l'`OpenAiAdapter` exécuté contre une vraie facture PDF hébergée sur preprod + OpenAI réel a extrait correctement les champs (fournisseur, n°, date, montant). Le chemin qui renvoyait `400 unsupported image` fonctionne désormais.
- **Prérequis prod** : `OPENAI_API_KEY` posée dans `/opt/omdev/scobby/prod/.env` (les fonctions LLM prod étaient jusque-là en 503 faute de clé).
**Reste = gate humain** : approuver/dérouler le déploiement prod (flux omdev « master → gate manuel → prod »). Le rollout prod rechargera l'env + la nouvelle image api. Statut passera à *Shipped* une fois le prod déployé et confirmé.