Communitygithub.com

ThomasHMD/sous-titres

Corrige un export JSON de transcription automatique de Premiere Pro (plein de fautes, surtout sur les noms propres) en retranscrivant la vidéo localement avec whisper.cpp, puis en reconstruisant un JSON au format exact de Premiere (réimportable tel quel) avec les noms corrigés via un script de référence, ponctuation et majuscules rétablies, titres d'œuvres entre guillemets, et synchronisation temporelle réalignée sur l'audio par alignement forcé.

Qu'est-ce que sous-titres ?

Cette compétence corrige les transcriptions automatiques exportées depuis Premiere Pro, qui contiennent souvent de nombreuses fautes de frappe, en particulier sur les noms propres. Elle retranscrit localement la vidéo à l'aide de whisper.cpp pour obtenir un texte de meilleure qualité, puis reconstruit un fichier JSON au format exact de Premiere (réimportable sans modification). Les noms propres sont corrigés via un script de référence, la ponctuation et les majuscules sont rétablies, les titres d'œuvres sont mis entre guillemets, et les horodatages sont réalignés sur l'audio par alignement forcé (corrigeant la dérive des timings de whisper). La compétence est conçue pour les développeurs et utilisateurs avancés de Claude Code ou d'agents similaires, nécessitant whisper.cpp, ffmpeg et un modèle de transcription. Le workflow inclut l'extraction audio, la transcription, la correction des noms via un fichier `corrections.json`, la reconstruction du fichier JSON et l'alignement forcé final. Elle prend en charge les langues via des fichiers de configuration et offre des outils pour détecter les hallucinations de whisper et corriger les bugs récurrents (doublons de nombres décimaux, ponctuation de fin de phrase perdue).

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ThomasHMD/premiere-rough-cut/tree/HEAD/skills/subtitles

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

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

  1. La vidéo exportée depuis Premiere (.mp4/.mov) : elle porte l'audio à transcrire.
  2. Le .json des légendes exporté depuis Premiere : il donne le format cible (clés, UUID speaker, langue) à cloner.
  3. 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 : soit cd dans 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 un canonical pour la casse correcte du titre. sep_comma: true ajoute 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. Mettez false uniquement si vous voulez une ponctuation collée. Lorsque vous re-ponctuez à l'étape 2b, la ponctuation DOIT être attachée (Flop:) ; build_subs.py remet 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 :

  1. Doublons de nombres décimaux. whisper divise 6.6 en 2 jetons (6 + .6 ; de même 1,33, ou 4 AM en 4 + AM) ; la réinjection de ponctuation les double dans la sortie (1.4 .4, 6.6. .6), et seq_rules font 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, PAS duration), puis reconstruisez.
  2. Ponctuation de fin de phrase isolée supprimée. Un ?/!/: présent dans le text du segment whisper mais sans jeton mot propre disparaît (Comment avons-nous fait ? perd son ?). Détection : comparez count('?') (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

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

Skills associés