Imaginez. Vous avez un outil de partage de fichiers avec une jolie grille de posters façon Netflix. Vous partagez votre collection de Looney Tunes avec un ami. Il ouvre la page et voit... le poster de Kill Bill sur le Volume 1. Les Gardiens de la Galaxie sur le Volume 2. Un anime japonais obscur sur le Volume 5. Classe.
C'est exactement ce qui m'est arrivé avec ShareBox, mon side project de partage de fichiers. L'idée de base était simple : prendre le nom du dossier, chercher sur TMDB (la base de données de films/séries), afficher le poster. Sauf que les noms de dossiers ressemblent à ça :
Naruto.INTEGRALE.MULTI.VFF.1080p.BluRay.x264-AMB3R
Moi.Moche.Et.Mechant.COLLECTION.(2010-2024).MULTI.VFF.2160.4KLight.HDR10
Vol 1
S01
Le regex de nettoyage que j'avais écrit (extract_title_year()) faisait
le boulot dans 80% des cas. Mais les 20% restants, c'était le chaos. "Vol 1" matchait
Kill Bill. "S01" matchait une série chinoise au hasard. "Moi.Moche.Et.Mechant.COLLECTION"
matchait le 4e film au lieu de la saga. Et "Naruto" retournait systématiquement
Naruto Shippuden — parce que Shippuden est plus populaire sur TMDB.
L'idée : empiler des couches d'IA comme des filets de sécurité
Plutôt que d'écrire un regex surhumain, j'ai décidé de traiter le problème en couches. Le principe : le truc gratuit fait le gros du travail, l'IA ne corrige que ce qui passe entre les mailles. Trois passes, du moins cher au plus cher :
- Regex + TMDB : nettoyage basique du nom, recherche TMDB, premier résultat. Gratuit, instantané.
- Pass 1 — "C'est quoi ce titre ?" : quand le regex rate, envoyer le nom brut à Claude Haiku pour qu'il devine le vrai titre.
- Pass 2 — "C'est le bon match ?" : envoyer toutes les paires {nom du dossier, titre TMDB trouvé} à l'IA pour qu'elle détecte les erreurs évidentes.
- Pass 3 — "Lequel tu choisis ?" : quand l'IA dit "c'est faux", chercher 15 candidats sur TMDB et demander à l'IA de choisir le bon.
Un cron tourne toutes les 30 minutes pour faire les passes 1 et 2 sur les nouvelles entrées. La passe 3 ne se déclenche que quand la passe 2 trouve un faux positif. En pratique, sur 290 dossiers, la passe 3 n'a tourné que 9 fois.
Les fails mémorables : un bestiaire du faux positif
Avant de parler d'optimisation, quelques perles. Voici ce que TMDB retournait quand on lui envoyait les noms tels quels :
| Nom du dossier | Ce que TMDB a matché | Réaction |
|---|---|---|
| Vol 1 | Kill Bill : Volume 1 | ... |
| Vol 2 | Les Gardiens de la Galaxie Vol. 2 | Ah. |
| Covers | Alien : Covenant | Pardon ? |
| CIA | CIA (le film) | Techniquement correct. |
| PLAYLIST | Zoey et son incroyable playlist | Non. |
| Movie | Scary Movie | J'aurais dû m'en douter. |
| STREAM | Stream (le film) | Il y a un film qui s'appelle Stream ??? |
| Wii | Wii_ja! | Je ne veux même pas savoir. |
La première leçon : TMDB trouve toujours quelque chose. Même pour "CLIPINF" (un dossier technique de Blu-ray), il retournait un résultat avec un poster. Il faut donc aussi savoir ne pas chercher.
Étape zéro : la liste noire des mots génériques
Avant même l'IA, j'ai dû écrire un skipPattern — un regex qui
filtre les noms qui ne seront jamais des titres de films :
vol\s*\d+, movie, films?, série, covers?, wii, nds, switch, 3ds, xbox,
bdmv, clipinf, playlist, stream$, meta, backup, samples?, nfo...
30+ patterns. Le piège : "stream" doit matcher "STREAM" (le dossier Blu-ray) mais pas
"Streaming Wars" (un film South Park). D'où le stream$ ancré en fin de chaîne.
Même chose pour "movie" vs "The Movie Database". Les regex, c'est jamais fini.
Pass 1 : le prompt qui skip trop
Le prompt initial était raisonnable : "extrais le titre propre du film ou de la série à partir de ce nom de fichier". Testé sur 290 noms réels, résultat : 72 faux skips.
L'IA voyait "Naruto.INTEGRALE" et se disait : "INTEGRALE, c'est pas un titre, c'est un descripteur. Skip." Pareil pour "Pokemon La Series" — "La Series" n'est pas un titre. Et les courts-métrages Pikachu ? "Les Vacances De Pikachu", skip, c'est un bonus.
Le fix tenait en trois règles ajoutées au prompt :
- "En cas de doute, skip=false" — le filet de sécurité. Un faux positif sera corrigé par le pass 2. Un faux skip est perdu pour toujours.
- "GARDE les collections et intégrales" — INTEGRALE, COLLECTION, COMPLETE sont des indicateurs de série, pas des raisons de skipper.
- "Traduis les titres connus" — "Despicable Me" doit devenir "Moi, moche et méchant" pour que TMDB trouve le résultat français.
Résultat v2 : 72 → 41 skips. Naruto, Pokemon, Batman, les Looney Tunes, les courts-métrages Pikachu — tous récupérés. Et surtout : zéro régression. Aucun dossier qui marchait avant ne s'est cassé.
Pass 2 : quand l'IA ne connaît pas le contexte
La passe 2 envoyait des paires comme {"S01", "Saison 1"} et demandait :
"est-ce que c'est le bon match ?" Sur 247 paires, l'IA a signalé
55 erreurs. Problème : 46 d'entre elles étaient fausses.
Pourquoi ? L'IA ne savait pas que mon système avait un mécanisme dédié pour
les saisons. Quand elle voyait "S01" matché à "Saison 1", elle se disait :
"S01 tout seul, ça ne veut rien dire, c'est sûrement un mauvais match."
Alors qu'en réalité, c'est le poster de la saison 1 récupéré via l'API TMDB
/tv/{id}/season/1 à partir de la série parente. C'est correct.
34 saisons des Simpsons. 11 saisons de Walking Dead. 4 saisons de Batman. Toutes signalées comme "faux positif" alors qu'elles étaient parfaitement correctes.
Le fix : expliquer le contexte à l'IA. Une section "cas spéciaux" dans le prompt qui dit explicitement : les saisons matchées à leur numéro, c'est normal. Les traductions, c'est normal. Les collections, c'est normal.
Résultat : 55 → 9. Les 9 restants ? Tous de vrais problèmes. Kill Bill, Gundam ZZ, Demon Slayer — des matchs objectivement foireux.
Pass 3 : TMDB et le piège de la popularité
La passe 2 a détecté que "Naruto" était mal matché et a suggéré de chercher "Naruto" sur TMDB. Super. Sauf que TMDB retourne les résultats par popularité. Et Naruto Shippuden est plus populaire que le Naruto original. Prendre le premier résultat, c'est refaire exactement la même erreur.
La solution : ne pas choisir automatiquement. Récupérer les 15 premiers candidats (séries, films, tous mélangés), et demander à l'IA de choisir le bon en lui donnant le contexte du nom de fichier. "INTEGRALE" dans le nom → c'est la série complète, pas un film dérivé. "S01" → c'est une série TV, pas un film.
L'IA reçoit la liste et répond juste {"idx": 1} — l'index du bon
candidat. Pour Naruto, elle choisit correctement la série originale de 2002
plutôt que Shippuden ou le film. Le mot "INTEGRALE" dans le nom du fichier
fait toute la différence.
Petit piège technique : parfois l'IA ajoute une explication après le JSON.
{"idx": 1} parce que INTEGRALE indique la série complète...
Ce qui casse le parsing JSON classique. Le fix : extraire le {"idx": N}
par regex plutôt que de parser tout le texte.
Les chiffres
| Passe | Avant optimisation | Après | Gain |
|---|---|---|---|
| Extraction (deviner le titre) | 72 faux skips | 41 | -43% |
| Vérification (détecter les erreurs) | 55 faux négatifs | 9 vrais problèmes | -84% |
| Choix du candidat | 4 échecs de parsing | 0 | -100% |
Le tout testé sur 290 entrées réelles. Pas des exemples choisis — toute la base, y compris les cas tordus genre "N° 057 - 2000 Walt Disney - Les Aventures de Tigrou et de Winnie l'Ourson.avi".
Ce que j'en retiens
Le 80/20 s'applique aux prompts. 46 faux négatifs sur 55 venaient d'un seul pattern : les dossiers de saison. Une ligne dans le prompt a éliminé 84% des erreurs. Pas besoin de réécrire le prompt entier — identifier le pattern dominant et le traiter.
"En cas de doute, ne fais rien" est souvent le meilleur choix. Pour la passe 1 : "en cas de doute, skip=false". Pour la passe 2 : "en cas de doute, correct=true". L'idée : les couches suivantes rattraperont. Mieux vaut un faux positif qu'on corrigera qu'un faux négatif qu'on perd.
L'IA ne connaît pas votre architecture. Quand le prompt de vérification voyait "S01 → Saison 1", il ne savait pas que c'était un match légitime via un mécanisme de saisons dédié. Il faut expliquer le contexte métier à l'IA, pas juste lui demander de vérifier.
Le parsing compte autant que le prompt. Le prompt peut être
parfait — si l'IA ajoute un paragraphe d'explication après le JSON et que
votre json_decode() plante, c'est pareil. Parsez de manière défensive.
Comme dans l'article sur la boucle d'itération : le prompt qui marche le mieux n'est pas celui qui donne le plus d'instructions. C'est celui qui décrit les cas limites avec précision. "Les saisons sont CORRECTES" vaut plus que 20 lignes de règles génériques.