sous-titres : corriger les légendes Premiere Pro
Configuration unique : voir INSTALL.md à la racine du kit. Avec le plugin, la ligne de configuration est
bash "${CLAUDE_PLUGIN_ROOT}/install.sh" --data "${CLAUDE_PLUGIN_DATA}" ; avec une installation manuelle (les quatre dossiers skills/
copiés côte à côte dans ~/.claude/skills/), exécutez bash install.sh depuis la racine du kit.
Les scripts se trouvent dans le dossier scripts/ de cette compétence. Cette compétence pointe vers l'autre comme ../rough-cut/....
Ce que fait la compétence
Premiere génère une transcription automatique (un export .json) qui est souvent truffée de fautes, surtout sur les
noms propres (le nom d'un photographe transformé en deux mots sans rapport). whisper.cpp transcrit beaucoup mieux.
Cette compétence retranscrit la vidéo localement, puis reconstruit un .json au format exact de Premiere
(réimportable tel quel) : les noms corrigés à l'aide d'un script de référence, la ponctuation et les majuscules rétablies,
les titres d'œuvres entre guillemets. Enfin, elle réaligne les horodatages sur l'audio par alignement forcé (les timings de whisper dérivent).
- OUI : transcription locale, correction des noms, ponctuation et casse, guillemets autour des titres, réalignement temporel sur l'audio (alignement forcé), un format identique à celui de Premiere, prêt à être réimporté.
- NON : couper ou montage brut de la vidéo (c'est
rough-cut), traduire, resynchroniser un fichier de légendes déjà correct, sous-titres.srt/.vtt(le format ici est le JSON natif de Premiere).
Entrées attendues
- La vidéo exportée depuis Premiere (
.mp4/.mov) : elle porte l'audio à transcrire. - Le
.jsondes légendes exporté depuis Premiere : il donne le format cible (clés, UUIDspeaker, langue) à cloner. - Le script de référence de la vidéo, sous toute forme lisible (texte brut, Markdown, un Google Doc, une page Notion, un texte collé) : l'autorité pour l'orthographe des noms propres (personnes, œuvres, lieux, marques). S'il n'y en a pas, demandez-le, ou ne corrigez que les fautes évidentes et gardez l'orthographe de whisper pour tout nom incertain.
Langue
La typographie (espaces autour de la ponctuation), les lettres accentuées, les jeux de ponctuation, les guillemets et les normalisations orthographiques se trouvent dans languages/<code>.json (fr et en sont intégrés), jamais dans le code. La langue est choisie par --lang <code>, sinon la langue du JSON Premiere, sinon celle enregistrée dans la transcription whisper, sinon en. Comment les fichiers fonctionnent et comment ajouter une langue : ../rough-cut/references/languages.md (même mécanisme ; cette compétence a son propre dossier languages/).
Prérequis (une fois par machine)
whisper-cli + ffmpeg + le modèle ~/Models/whisper/ggml-large-v3-turbo.bin. Voir ../rough-cut/references/whisper-setup.md (configuration partagée). Vérifier : which whisper-cli ffmpeg && ls ~/Models/whisper/.
Alignement forcé (réaligner les horodatages sur l'audio, étape 6b) :
pip3 install --break-system-packages ctc-forced-aligner torch torchaudio unidecode
Un modèle ONNX d'environ 1,2 Go est téléchargé lors de la première exécution (cache ~/ctc_forced_aligner/). Vérifier : python3 -c "import ctc_forced_aligner".
Flux de travail
Les commandes
scripts/...ci-dessous supposent que vous êtes dans le dossier de la compétence. Le répertoire de travail peut être réinitialisé entre deux appels shell : soitcddans le dossier de la compétence une fois, soit préfixez chaque script par son chemin absolu. Les fichiers de travail (audio, transcription, corrections) vont dans un dossier temporaire en dehors de tout dossier synchronisé.
1. Renifler la vidéo et le format d'entrée
D'ABORD : prenez un instantané de l'original. Premiere peut RÉÉCRIRE le .json d'entrée lors d'une réexportation, et c'est la seule vérité de synchronisation pour vérifier les horodatages à l'étape 7 :
cp "<Reel.json>" /tmp/subs_original_premiere.json
ffprobe -v error -show_entries format=duration:stream=codec_type,r_frame_rate \
-of default=noprint_wrappers=1 "<video>"
Notez la durée (le dernier mot doit tomber dedans) et le fps. Ensuite, inspectez le JSON Premiere d'entrée pour confirmer le format :
python3 scripts/inspect_format.py "<Reel.json>"
Il imprime les clés (top/segment/word), l'UUID speaker, la langue, le nombre de segments, et le texte actuel segment par segment (= la liste des fautes à corriger). Le format attendu est documenté dans references/premiere-format.md : lisez-le si l'inspection montre des clés inhabituelles.
2. Transcrire localement (whisper.cpp)
python3 scripts/extract_audio.py "<video>" /tmp/subs_audio.wav
python3 scripts/transcribe.py /tmp/subs_audio.wav /tmp/subs_transcript.json --model large-v3-turbo --language <code>
Environ 8 s pour 3 min sur Apple Silicon. La transcription comporte des segments avec text (ponctué, avec casse) et des words horodatés.
2b. Si whisper N'a PAS ponctué (flux continu) : re-ponctuer
Sur les monologues rapides, whisper renvoie parfois un flux sans ponctuation ni majuscules (les segments se coupent au milieu d'une phrase, pas de ./,). Symptôme clair : build_subs.py signale eos: 0. Sans ponctuation, les légendes sont illisibles. Vérification rapide : python3 scripts/words_of.py /tmp/subs_transcript.json 0 1 2 --plain.
Si c'est le cas, re-ponctuez vous-même (c'est un travail de LLM, pas de whisper) : réécrivez le text de chaque segment avec ponctuation et majuscules de phrase, en gardant les mots de whisper textuellement : ajoutez UNIQUEMENT la ponctuation et la casse ; les corrections lexicales (noms, acronymes) restent dans corrections.json. La ponctuation TOUJOURS attachée au mot (so?, pas so ?) : un signe précédé d'un espace devient un jeton isolé que l'alignement supprime silencieusement (114 ?/! ont été perdus d'un coup). build_subs.py remet l'espacement de la langue (pour le français, une espace insécable) tout seul. Mettez le résultat dans un JSON {index: "texte ponctué"}, puis :
python3 scripts/repunctuate.py --transcript /tmp/subs_transcript.json --punct /tmp/punct.json --output /tmp/subs_transcript_punct.json
Le script refuse si vous avez ajouté, supprimé ou modifié un mot (il montre le diff) : c'est ce qui maintient l'alignement mot-à-timing intact. Faites attention à l'enchaînement entre les segments : un segment qui continue une phrase commence par une minuscule, un qui ouvre une phrase prend une majuscule. Utilisez cette transcription ponctuée pour la suite (--transcript à l'étape 6).
Supprimez également toute hallucination de fin de clip : sur le silence final, whisper invente souvent une ligne comme un crédit de sous-titre ou "Merci d'avoir regardé" (les lignes typiques de chaque langue sont listées sous whisper_hallucinations dans languages/<code>.json). Supprimez-la avec une seq_rule N à 0. Autre hallucination : des segments consécutifs avec un texte identique dont les mots ont une durée quasi nulle (start==end), répétitions inventées sur un silence ("c'est parti" x3). Détection : segments i et i+1 avec le même texte et des mots de durée 0. Correction : supprimez-les de la transcription avant la construction (del segs[i:j]).
3. Lire la transcription whisper et le script de référence
Affichez la transcription segment par segment (text) et comparez-la avec le texte Premiere d'entrée (étape 1). whisper corrige déjà beaucoup de choses, mais conserve les fautes sur les noms. Lisez le script de référence pour obtenir l'orthographe canonique des noms propres et des titres d'œuvres cités.
4. Construire corrections.json (le cœur intelligent)
C'est là que la qualité se décide. Construisez un fichier de corrections en comparant ce que whisper a entendu avec les noms du script. Inspectez la découpe mot par mot des segments concernés pour écrire des règles exactes :
python3 scripts/words_of.py /tmp/subs_transcript.json 2 9 38 # jetons indexés des segments à examiner
La sortie indexe chaque mot (9:Smyth 10:Jones) : cela permet d'écrire des règles exactes sans deviner la tokenisation (combien de jetons un nom prend, traits d'union conservés, etc.).
Format de corrections.json (toutes les clés sont facultatives) :
{
"quote_char": "\"",
"normalize_cotes": true,
"seq_rules": [
[["jon","smyth"], ["John","Smith"]],
[["train","park"], ["Trent","Parke"]],
[["arthus","bertrand"], ["Arthus-Bertrand"]]
],
"word_rules": {"macdum": "Magnum", "scholler": "Schoeller"},
"titles": [
{"match": ["the","decisive","moment"], "canonical": ["The","Decisive","Moment"]},
{"match": ["errance"], "canonical": ["Errance"], "sep_comma": true}
]
}
seq_rules: noms multi-mots, ou 1 vers N / N vers 1. La correspondance se fait sur les mots en minuscules, sans ponctuation. Utilisez-le pour tout nom couvrant 2 mots whisper ou plus, ou lorsque le nombre de mots change. Casse : les mots cibles sont utilisés TEXTUELLEMENT : écrivez la casse finale souhaitée, position dans la phrase comprise (["Aujourd'hui","nous",...]si le mot ouvre la phrase, pas["aujourd'hui"...]). Même longueur source/cible : la ponctuation (virgules internes) et les horodatages sont conservés par index ; longueurs différentes : les horodatages sont redistribués et seule la ponctuation du premier/dernier mot subsiste (les virgules internes des mots remplacés sont perdues : relisez ces segments à l'étape 7). Suppression : une cible vide[["uh"], []]supprime le mot (réservez-la aux bruits isolés réels que whisper a doublés ; pour un mot mal transcrit, corrigez-le plutôt que de le supprimer, sinon vous perdez une partie d'une phrase).word_rules: un nom d'un seul mot, casse imposée (clé minuscule vers valeur exacte).titles: œuvres citées (livres, séries, photographies titrées) qui reçoivent automatiquement des guillemets (ouverture sur le premier mot, fermeture sur le dernier) plus uncanonicalpour la casse correcte du titre.sep_comma: trueajoute une virgule après le titre (utile lorsque plusieurs titres se succèdent). Mettez les œuvres entre guillemets, pas les noms de personnes ou les marques.normalize_cotes: applique les normalisations orthographiques du fichier de langue (normalize_words), pour les variantes que whisper écrit de manière incohérente. Désactivé sauf si vous le définissez.french_typography: l'interrupteur pour l'espacement typographique de la langue (le nom est historique ; il s'applique à la langue en cours). Valeur par défaut tirée du fichier de langue : pour le français, une espace insécable (U+00A0) avant les signes de ponctuation double et le guillemet fermant, et après le guillemet ouvrant ; pour l'anglais, rien. Mettezfalseuniquement si vous voulez une ponctuation collée. Lorsque vous re-ponctuez à l'étape 2b, la ponctuation DOIT être attachée (Flop:) ;build_subs.pyremet l'espacement tout seul.
5. Résoudre les incertitudes AVEC l'utilisateur (ne jamais inventer)
whisper produit parfois un mot non-nom ambigu ou inintelligible. Ne devinez pas en silence. Listez ces points avec leur timecode et demandez à l'utilisateur ce qui est réellement dit, en proposant une hypothèse si le contexte ou le script en suggère une. Distinguez :
- Correction directe : noms propres confirmés par le script ; fautes évidentes et certaines.
- Demander d'abord : mots non-noms ambigus, ou toute correction qui change le sens (par exemple whisper "qui se sent" contre le script "sans" : un renversement de sens, signalez-le même si le script le tranche).
Ne réécrivez pas le style parlé (argot, expressions de remplissage, répétitions) : les légendes doivent suivre l'audio.
Ce qu'il faut écrire dans le fichier en attendant la réponse (vous n'êtes pas obligé de bloquer la génération) : produisez une première version qui applique toutes les corrections sûres plus votre meilleure hypothèse pour les mots ambigus courants (et signalez-les), mais gardez l'orthographe brute de whisper pour un NOM incertain absent du script : n'inventez jamais un nom propre. Livrez cette version avec la liste des points à valider (timecodes), puis régénérez après la réponse en mettant à jour corrections.json. C'est le flux normal : générer, présenter avec les questions, affiner.
6. Générer le fichier corrigé
python3 scripts/build_subs.py \
--transcript /tmp/subs_transcript.json \
--original "<Reel.json>" \
--corrections /tmp/corrections.json \
--output "<dossier>/<nom>_corrige.json" [--lang <code>]
Le script clone le format de l'original (UUID speaker, langue, clés triées, UTF-8 minimifié), remet la ponctuation et la casse, applique les corrections, ajoute les guillemets, recalcule eos, et imprime un rapport de validation.
Écrivez <nom>_corrige.json À CÔTÉ de l'original, ne jamais écraser l'export original (c'est la source de l'utilisateur). Le suffixe _corrige est un nom de fichier sur lequel les scripts s'appuient : gardez-le.
6a. Vérifier les 2 pièges récurrents de build_subs.py (à chaque fois)
Deux bugs observés sur de nombreuses vidéos, à vérifier après CHAQUE construction :
- Doublons de nombres décimaux. whisper divise
6.6en 2 jetons (6+.6; de même1,33, ou4 AMen4+AM) ; la réinjection de ponctuation les double dans la sortie (1.4 .4,6.6. .6), etseq_rulesfont une correspondance erronée (la normalisation ne supprime pas un./,interne). Détection : grep la sortie finale pour les motifs\d[.,]?\s+[.,]\d. Correction : chirurgie sur la transcription AVANT la construction : fusionnez les 2 jetons en un seul ({'text':'1.4','start':a.start,'end':b.end,...}; le schéma du mot whisper =text/start/end/confidence, PASduration), puis reconstruisez. - Ponctuation de fin de phrase isolée supprimée. Un
?/!/:présent dans letextdu segment whisper mais sans jeton mot propre disparaît (Comment avons-nous fait ?perd son?). Détection : comparezcount('?')(et!,:) entre le texte whisper et la sortie. Correction : post-éditez le JSON de sortie : rattachez?(avec l'espacement de la langue) au jeton précédent.
Si le piège 1 est détecté, corrigez la transcription et reconstruisez (étape 6). Si le piège 2, corrigez directement la sortie.
6b. Réaligner les horodatages sur l'audio : alignement forcé (TOUJOURS)
Les horodatages des mots de whisper DÉRIVENT (mesuré jusqu'à 7 s d'avance, non linéaire) avec des monologues rapides et multi-prises : whisper écrase les silences entre les prises, donc la voix arrive APRÈS la légende. Plainte typique : "quand le 'Ah' s'affiche, j'entends déjà la phrase suivante". DTW (-dtw) ne change rien (mêmes décalages), et une déformation temporelle sur des ancres éparses déforme les zones qui étaient déjà correctes. Le texte whisper est bon, seuls ses horodatages sont faux. L'alignement forcé corrige cela. Exécutez :
python3 scripts/align_timings.py \
--audio /tmp/subs_audio.wav \
--transcript /tmp/subs_transcript.json \
--output /tmp/subs_transcript_aligné.json
Cette étape réaligne chaque mot en fonction de l'audio et de la transcription re-ponctuée. Elle peut être exécutée après re-ponctuation, puis le transcript aligné est utilisé dans build_subs.py. Notez que cela peut rallonger le temps de traitement (quelques minutes).
7. Vérifier le résultat
python3 scripts/inspect_format.py "<dossier>/<nom>_corrige.json"
Puis comparez avec l'original d'entrée :
python3 scripts/inspect_format.py /tmp/subs_original_premiere.json
Vérifiez :
- Nombre de segments similaire (pas de suppression accidentelle)
- Mots : les noms propres sont corrigés, la ponctuation est cohérente
- Horodatages : le dernier mot doit être dans la durée de la vidéo (vérifiée à l'étape 1)
- Guillemets : les titres d'œuvres sont correctement encadrés
En cas de problème, affinez corrections.json et recommencez à l'étape 6.
Références
- Format JSON Premiere
- Configuration whisper (partagée avec
rough-cut) - Fichiers de langue