Aller au contenu principal

Extraction de Données Structurées depuis des Images

Transformer des images en données exploitables

L’une des applications les plus puissantes de la Vision API est l’extraction de données structurées : transformer le contenu visuel d’une image (tableaux, formulaires, cartes de visite, étiquettes) en JSON, CSV ou tout autre format exploitable par votre code.

Dans cette leçon, vous apprendrez à utiliser des prompts précis et le mode JSON de l’API pour obtenir des données fiables et parsables.

Le mode JSON de l’API

Mistral propose un paramètre response_format qui force le modèle à retourner du JSON valide :

from mistralai import Mistral
import os
import json

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

response = client.chat.complete(
    model="mistral-large-latest",
    response_format={"type": "json_object"},
    messages=[
        {
            "role": "system",
            "content": "Retournez toujours un objet JSON valide avec les données extraites de l'image."
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "Extrayez les données de cette carte de visite en JSON : nom, titre, entreprise, email, telephone, adresse."
                },
                {"type": "image_url", "image_url": data_uri_carte}
            ]
        }
    ]
)

# Le résultat est directement parsable
donnees = json.loads(response.choices[0].message.content)
print(json.dumps(donnees, indent=2, ensure_ascii=False))

Le response_format={"type": "json_object"} garantit un JSON valide en sortie, ce qui élimine les problèmes de parsing.

Extraire un tableau depuis une image

Les tableaux photographiés ou capturés en screenshot sont un cas d’usage fréquent :

prompt_tableau = """Extrayez le contenu de ce tableau en JSON.
Format attendu :
{
  "colonnes": ["Colonne1", "Colonne2", ...],
  "lignes": [
    {"Colonne1": "valeur", "Colonne2": "valeur"},
    ...
  ]
}
Lisez toutes les lignes visibles. Si une cellule est vide, utilisez null."""

response = client.chat.complete(
    model="mistral-large-latest",
    response_format={"type": "json_object"},
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": prompt_tableau},
                {"type": "image_url", "image_url": encoder_image("captures/tableau-excel.png")}
            ]
        }
    ]
)

donnees = json.loads(response.choices[0].message.content)
print(f"Colonnes : {donnees['colonnes']}")
print(f"Nombre de lignes : {len(donnees['lignes'])}")

Formulaires et documents administratifs

Pour extraire les champs d’un formulaire rempli :

prompt_formulaire = """Analysez ce formulaire rempli et extrayez tous les champs et leurs valeurs.
Format JSON attendu :
{
  "type_formulaire": "...",
  "champs": {
    "nom_du_champ": "valeur_renseignee",
    ...
  },
  "cases_cochees": ["champ1", "champ2"],
  "signature_presente": true/false
}
Si un champ est vide ou illisible, utilisez null."""

response = client.chat.complete(
    model="mistral-large-latest",
    response_format={"type": "json_object"},
    messages=[
        {
            "role": "system",
            "content": "Vous êtes un extracteur de formulaires précis. Retournez du JSON structuré."
        },
        {
            "role": "user",
            "content": [
                {"type": "text", "text": prompt_formulaire},
                {"type": "image_url", "image_url": encoder_image("formulaires/cerfa-12345.jpg")}
            ]
        }
    ]
)

Extraire des données d’étiquettes produit

prompt_etiquette = """Extrayez les informations nutritionnelles de cette étiquette.
Format JSON :
{
  "nom_produit": "...",
  "poids_net": "...",
  "valeurs_nutritionnelles_pour_100g": {
    "energie_kcal": ...,
    "matieres_grasses_g": ...,
    "dont_satures_g": ...,
    "glucides_g": ...,
    "dont_sucres_g": ...,
    "proteines_g": ...,
    "sel_g": ...
  },
  "ingredients": "...",
  "allergenes": ["..."]
}"""

response = client.chat.complete(
    model="mistral-large-latest",
    response_format={"type": "json_object"},
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": prompt_etiquette},
                {"type": "image_url", "image_url": encoder_image("produits/etiquette.jpg")}
            ]
        }
    ]
)

produit = json.loads(response.choices[0].message.content)

Pipeline d’extraction avec validation

Pour la production, ajoutez une couche de validation :

from pydantic import BaseModel, Field
from typing import Optional
import json

class CarteDeVisite(BaseModel):
    nom: str
    prenom: str
    titre: Optional[str] = None
    entreprise: Optional[str] = None
    email: Optional[str] = None
    telephone: Optional[str] = None
    adresse: Optional[str] = None
    site_web: Optional[str] = None

def extraire_carte_visite(chemin_image):
    """Extrait et valide les données d'une carte de visite."""
    response = client.chat.complete(
        model="mistral-large-latest",
        response_format={"type": "json_object"},
        messages=[
            {
                "role": "system",
                "content": "Extrayez les données de cette carte de visite. Champs : nom, prenom, titre, entreprise, email, telephone, adresse, site_web. Retournez du JSON."
            },
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "Extrayez les informations de cette carte de visite."},
                    {"type": "image_url", "image_url": encoder_image(chemin_image)}
                ]
            }
        ]
    )

    # Parser et valider avec Pydantic
    donnees_brutes = json.loads(response.choices[0].message.content)
    carte = CarteDeVisite(**donnees_brutes)
    return carte

# Utilisation
carte = extraire_carte_visite("cartes/contact-dupont.jpg")
print(f"Contact : {carte.prenom} {carte.nom} - {carte.email}")

Pydantic valide les types et les champs obligatoires, ce qui sécurise votre pipeline.

Convertir en CSV ou DataFrame

Pour intégrer les données extraites dans un workflow data :

import pandas as pd

# Depuis un tableau extrait
donnees = json.loads(response.choices[0].message.content)

# Créer un DataFrame pandas
df = pd.DataFrame(donnees["lignes"])
print(df.to_string())

# Exporter en CSV
df.to_csv("export/tableau_extrait.csv", index=False, encoding="utf-8")

Points clés à retenir

  • Le paramètre response_format={"type": "json_object"} garantit un JSON valide en sortie
  • Fournissez toujours un schéma JSON attendu dans votre prompt pour guider l’extraction
  • Utilisez Pydantic pour valider les données extraites en production
  • Les tableaux, formulaires, étiquettes et cartes de visite sont des cibles idéales
  • Combinez l’extraction avec pandas pour une intégration directe dans vos workflows data