# Un plugin IA de légendes qui doublait la charge à chaque import de média

> Symptôme d'un temps d'upload multiplié par trois, diagnostic d'un appel synchrone à un modèle de vision à chaque média, correctif par traitement différé.

- Auteur : Clément Hadrot
- Publié le : 2024-07-06
- Mis à jour le : 2024-07-06
- Catégorie : Performance
- URL : https://wpmoderne.dev.wordpress-developpement.fr/performance/plugin-ia-legendes-charge-import-doublee/

## L’essentiel

- Un appel synchrone à un modèle de vision bloque l'upload jusqu'à sa réponse
- Le temps de réponse d'une API IA externe varie fortement et reste hors du contrôle du site
- Différer le traitement rend l'upload instantané sans perdre la fonctionnalité

Trois fois plus long : c'est devenu le temps d'upload d'une image dans la médiathèque, le jour où un plugin de génération automatique de légendes via un modèle de vision par IA a été activé pour accélérer le travail de la rédaction. Un utilisateur n'accepte pas d'attendre aussi longtemps avant qu'une image n'apparaisse enfin dans la grille.

Avant l'activation du plugin, l'upload d'une image de taille standard prenait environ deux secondes, le temps de générer les différentes tailles de miniatures. Après activation, ce temps est passé à six secondes en moyenne, avec des pointes à plus de dix secondes selon les images, rendant l'expérience d'ajout de média nettement plus pénible pour la rédaction.

## Symptôme : un upload qui semble figé

Le navigateur affichait une barre de progression complète très rapidement — l'envoi du fichier lui-même vers le serveur ne posait aucun problème — mais l'interface restait ensuite bloquée sur un indicateur de traitement pendant plusieurs secondes supplémentaires, avant que la miniature et la légende générée n'apparaissent enfin dans la médiathèque.

## Diagnostic : un appel bloquant au modèle de vision

> L'essentiel à retenir : Un appel synchrone à un modèle de vision bloque l'upload jusqu'à sa réponse ; Le temps de réponse d'une API IA externe varie fortement et reste hors du contrôle du site ; Différer le traitement rend l'upload instantané sans perdre la fonctionnalité

Le code du plugin accrochait sa logique au hook `add_attachment`, avec un appel HTTP synchrone vers une API de description d'image par IA, dont la réponse conditionnait directement la fin du traitement d'upload perçu par l'utilisateur :

```
add_action( 'add_attachment', function ( $attachment_id ) {
    $chemin = get_attached_file( $attachment_id );
    $reponse = wp_remote_post( 'https://api.vision-ia.example/decrire', [
        'timeout' => 15,
        'body'    => [ 'image' => base64_encode( file_get_contents( $chemin ) ) ],
    ] );

    if ( ! is_wp_error( $reponse ) ) {
        $legende = json_decode( wp_remote_retrieve_body( $reponse ), true )['legende'];
        update_post_meta( $attachment_id, '_wp_attachment_image_alt', $legende );
    }
});
```

Le `timeout` de 15 secondes, fixé côté `wp_remote_post()`, dessinait déjà le pire scénario possible : chaque upload d'image restait suspendu jusqu'à 15 secondes en cas de lenteur de l'API externe, sans possibilité pour WordPress de continuer son traitement pendant ce temps. Le hook `add_attachment` se déclenche en effet de façon synchrone, dans le même cycle de requête que l'upload lui-même, ce qui rendait ce blocage inévitable avec cette implémentation.

## Correctif : différer l'appel à l'API de vision

Le traitement a été extrait du cycle de requête d'upload et confié à Action Scheduler, avec un état intermédiaire affiché à l'utilisateur pendant le traitement en arrière-plan :

```
add_action( 'add_attachment', function ( $attachment_id ) {
    update_post_meta( $attachment_id, '_legende_ia_statut', 'en_attente' );
    as_enqueue_async_action( 'generer_legende_ia', [ $attachment_id ] );
});

add_action( 'generer_legende_ia', function ( $attachment_id ) {
    $chemin = get_attached_file( $attachment_id );
    $reponse = wp_remote_post( 'https://api.vision-ia.example/decrire', [
        'timeout' => 30,
        'body'    => [ 'image' => base64_encode( file_get_contents( $chemin ) ) ],
    ] );

    if ( ! is_wp_error( $reponse ) ) {
        $legende = json_decode( wp_remote_retrieve_body( $reponse ), true )['legende'];
        update_post_meta( $attachment_id, '_wp_attachment_image_alt', $legende );
    }
    update_post_meta( $attachment_id, '_legende_ia_statut', 'termine' );
});
```

L'interface de la médiathèque a été complétée d'un badge « légende en cours de génération », interrogé toutes les quelques secondes via un appel Ajax léger, plutôt que de faire attendre l'utilisateur sur l'appel lui-même.

## Résultat mesuré

| Mesure | Appel synchrone | Traitement différé |
| --- | --- | --- |
| Temps d'upload perçu | 6 s en moyenne, pics à 10 s+ | 2 s, identique à avant activation du plugin |
| Délai d'apparition de la légende | Immédiat (bloquant) | 3 à 8 s en arrière-plan, sans blocage |

### Prévention pour tout appel à une API IA externe

- Aucun appel réseau vers un service externe dont le temps de réponse n'est pas garanti ne devrait rester sur le chemin critique d'une action utilisateur directe comme un upload.
- Un traitement différé avec état visible (badge, notification) offre une meilleure expérience qu'un traitement synchrone rapide mais fragile face aux lenteurs occasionnelles du service tiers.
- Un `timeout` généreux (30 secondes) devient acceptable une fois le traitement sorti du cycle de requête utilisateur, puisqu'il ne bloque plus personne.

> La qualité d'une légende générée par IA n'a d'intérêt que si son obtention ne dégrade pas l'expérience qu'elle est censée enrichir.

## En résumé

Ce billet ne juge pas la pertinence des légendes produites par le modèle de vision, uniquement l'architecture technique de leur génération. Déplacer un appel à une API externe hors du cycle de requête synchrone reste, sur ce type de fonctionnalité enrichie par IA, un réflexe à appliquer systématiquement plutôt qu'après avoir constaté la dégradation en production.
