Extraire des données de documents avec des modèles de décision
Les modèles de décision permettent d’extraire des données structurées de documents et d’images à faible coût et avec une faible latence. Nous expliquons comment nous avons construit notre API d’extraction de documents avec notre modèle de décision, Strom.
Notre article précédent expliquait comment nous avons construit un pipeline d’extraction de données de factures, avec un modèle de décision en son cœur. Nous avons maintenant généralisé cette approche à tout type de document, comme les CV, les contrats ou les formulaires. Vous pouvez l’essayer ici.
Tout est parti d’un utilisateur qui se sert de Strom pour extraire des champs très précis des plaques signalétiques collées sur des appareils électroniques, comme celle-ci :
Deux champs l’intéressaient : le nom du modèle et le numéro de série. Son processus est le suivant :
- L’utilisateur prend une photo de la plaque avec son application mobile.
- L’application effectue l’OCR sur l’appareil et envoie le texte extrait au modèle de décision, avec une requête comme celle ci-dessous. Les noms de modèles sont connus à l’avance, ce sont donc les options de la première question. Le numéro de série ne l’est pas, donc les options de la seconde question sont les lignes de la plaque reconnues par l’OCR :
POST https://api.uprelic.com/v1/systemone
{
"model": "strom-1.0.7",
"state": "HEWLETT PACKARD\nCOLOR DISPLAY/彩色顯示器/彩色显示器/모니터\nPRODUCT NUMBER: P5303D\nModel No / 型號 / 型号/모델명: PE1165U\nASSEMBLY P/N : 262243-421\n...\nSerial No. 序號/序号:\nCNG34124S0\n...",
"questions": {
"q1": {
"type": "choice",
"criteria": {
"PE1165U": null,
"PE1240": null,
...
},
"instructions": "What is the model name of the device?"
},
"q2": {
"type": "choice",
"criteria": {
"PRODUCT NUMBER: P5303D": null,
"ASSEMBLY P/N : 262243-421": null,
"Serial No. 序號/序号:": null,
"CNG34124S0": null,
...
},
"instructions": "What is the serial number of the device?"
}
}
}
- L’application utilise les réponses du modèle pour afficher à l’utilisateur les informations de l’appareil.
Un modèle de décision convient bien ici, car :
- Il est rapide : ~700 ms aller-retour réseau compris. L’application reste fluide.
- Il est bon marché : ~0,0001 €.
Mais cela ne fonctionne que si :
- L’OCR sur l’appareil est exacte.
- Une simple liste de lignes suffit pour savoir quelle valeur correspond à quel libellé. L’OCR transforme « Serial No. » et « CNG34124S0 » en deux lignes séparées, et leur position sur la plaque est perdue. Sur une plaque simple, le modèle peut quand même les associer. Sur une plaque chargée, avec plusieurs numéros et des libellés en plusieurs langues, il ne le peut pas.
Ces limites ne concernent pas que les plaques signalétiques. Tout document dont le texte est disposé de façon irrégulière peut faire échouer ce processus. Nous avons donc construit un nouvel endpoint, POST /v1/extract, pour répondre à ces deux problèmes.
Quelques détails intéressants sur l’endpoint :
- Strom voit la mise en page, pas seulement le texte. Chaque ligne est envoyée avec sa page et sa position, accompagnée d’une image de la page où chaque ligne est encadrée et marquée de son identifiant. Strom peut alors associer un libellé à la valeur placée à côté ou en dessous, comme le ferait une personne qui lit la page.
- Il effectue l’OCR lui-même si vous envoyez une image ou un PDF scanné. Nous utilisons PP-OCRv6, l’un des meilleurs modèles d’OCR open source, sur nos propres GPU, si bien que le fichier ne quitte jamais notre réseau interne.
- Il enchaîne plusieurs appels au modèle de décision pour améliorer l’extraction. Par exemple, une fois que la première requête Strom a renvoyé les meilleurs candidats pour un champ, nous relançons Strom sur cet ensemble réduit pour départager les candidats à peu près aussi probables.
Vous décrivez les champs souhaités sous forme de JSON Schema, par exemple "serial_number": {"type": "string"}, et vous obtenez pour chaque champ la ligne où il se trouve, une valeur typée, un score de confiance et sa position sur la page. Pour continuer à choisir dans une liste connue, comme pour les noms de modèles ci-dessus, utilisez un enum : "model_name": {"enum": ["PE1165U", "PE1240"]}.
Vous pouvez essayer l’endpoint ici, ou utiliser l’API dans votre configuration existante.
Résultat de l’API, visualisé :