auto-subtitle — Transcription automatique audio/vidéo en SubtitleCue
Une seule commande pour obtenir les sous-titres : fichier audio/vidéo en entrée, deux fichiers en sortie : <nom>.cues.json + <nom>.srt. Le contrat de données est aligné mot à mot avec SubtitleCue de video-motion : {start, end, text}, en secondes, 3 décimales, texte sur une seule ligne (les longues phrases sont découpées). Le tableau subtitles peut être directement inséré dans la timeline de video-motion.
Étape 1 · Vérifier le média et la langue
- Formats acceptés : mp4 / wav / flac (décodage direct via PyAV). En cas d'erreur de décodage, effectuer d'abord une conversion :
ffmpeg -i in.mp4 -vn -ac 1 -ar 16000 out.wav - Préciser la langue via
--lang:zh(par défaut) /enou tout code de langue Whisper - Ne pas exécuter sur des fichiers purement musicaux ou sonores : VAD peut produire des sorties vides ou très courtes (ce n'est pas un bug, mais une fonctionnalité)
- Si une transcription de référence (script, dialogue) est disponible, la conserver en UTF-8 — Elle servira de base pour la vérification de l'étape 3 L2 (évite la dérive de référence)
Étape 2 · Exécuter la transcription
L'environnement virtuel n'est pas stocké dans le dépôt (artefact de construction de 284 Mo, déjà couvert par .gitignore pour .venv/). Par convention, ce skill n'inclut pas les artefacts de construction (comme node_modules pour un template). L'environnement virtuel est donc créé en dehors du dépôt, pour être réutilisé par tous les projets :
python -m venv "$env:USERPROFILE\.cache\vibe-studio\asr-venv"
& "$env:USERPROFILE\.cache\vibe-studio\asr-venv\Scripts\python.exe" -m pip install -r skills/auto-subtitle/templates/asr/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
cd skills/auto-subtitle/templates/asr
& "$env:USERPROFILE\.cache\vibe-studio\asr-venv\Scripts\python.exe" transcribe.py <input.mp4|wav> --outdir <output-directory>
- Modèle par défaut :
large-v3-turbo(≈1,6 Go, téléchargé automatiquement à la première utilisation, qualité pour le chinois). Pour une validation rapide, ajouter--model small(≈484 Mo). Le cache des modèles se trouve dans~/.cache/huggingface, téléchargé une fois pour toutes. - En cas d'échec du téléchargement du modèle, définir
HF_ENDPOINTpour changer de source : connexion directe officielle par défaut (testée en août 2026) ; alternative :$env:HF_ENDPOINT="https://hf-mirror.com"(attention : le miroir peut avoir des problèmes de redirection 308 avec hub 1.x, privilégier la source officielle). - Sortie standard : un résumé en anglais sur une ligne :
segments=N cues=M total_audio=... model=... lang=... out=...; exit 0 pour succès, 1 pour échec.
Étape 3 · Vérification en trois niveaux (obligatoire, ne pas sauter)
L1 structure : Le JSON peut être chargé avec json.load ; subtitles est un tableau et chaque élément possède exactement les trois champs start/end/text ; start < end et monotone non décroissante entre les lignes ; valeurs numériques avec 3 décimales ; la dernière end ≤ durée ffprobe + 1s. Les lignes de temps SRT correspondent au format HH:MM:SS,mmm --> HH:MM:SS,mmm, numérotation continue à partir de 1.
L2 précision : Si un texte de référence existe → utiliser difflib.SequenceMatcher (supprimer la ponctuation et normaliser les espaces des deux côtés), similarité globale ≥0,85, par phrase ≥0,70 (prendre le max de la fenêtre de concaténation des cues consécutives pour couvrir les divisions/fusions). Si aucun texte de référence → écouter le début, le milieu et la fin pour vérifier.
L2.5 Chronométrage (vérification régulière) : La fenêtre du sous-titre doit être alignée sur la fenêtre temporelle du mot, aucun sous-titre ne doit apparaître pendant un silence entre les phrases — Vérifier les écarts entre les cues adjacents : un écart de silence réel >1s doit apparaître entre les phrases (les écarts de coupure à l'intérieur d'une phrase = 0 sont normaux) ; aucun fragment flash <0,3s ; le premier start aligné sur le début de la parole, le dernier end ne doit pas couper la fin du silence. Le script utilise déjà les horodatages au niveau du mot (premier mot start / dernier mot end) pour définir la fenêtre ; cette étape est une validation de l'artefact.
L3 Conclusion : Si tout est OK = ALL GREEN ; en cas de rouge → ajuster la coupure / rejouer avec des paramètres VAD modifiés, puis revérifier. Si deux tours consécutifs sont rouges → s'arrêter et signaler, ne pas faire d'ajustement aveugle.
Étape 4 · Livraison
- Rapport : chemin absolu du
cues.json+ nombre de cues + durée audio + modèle/langue + conclusion de la vérification en trois niveaux - Intégration video-motion : Le tableau
subtitlespeut être collé directement danssrc/cues.tsdu projet video-motion, danscues.subtitles, sans conversion de champs. - Ce qui n'est pas fait (pour une version ultérieure) : diarisation (séparation des locuteurs), export des horodatages au niveau du mot, traduction, TTS (synthèse vocale)
Étape 5 · Archivage de la commande pour relecture
À la fin du rapport de livraison, joindre la commande complète permettant de rejouer la transcription (chemin d'entrée / --lang / --outdir / --model), afin de garantir une reproductibilité exacte pour la session suivante ou un autre utilisateur. Les artefacts (cues.json / srt) sont placés dans la zone de sortie (products/ de ce dépôt, ou output/ à la racine du projet pour un autre dépôt), et ne sont pas inclus dans git ; la commande est l'actif.
Limites et pièges
- Console GBK : les
printdu script sont en anglais ; les fichiers sont toujours écrits avecencoding="utf-8"explicite, JSON avecensure_ascii=False - Règle de découpage : si une ligne dépasse 20 caractères, la couper aux signes de ponctuation (。!?;,、). Si la fenêtre n'a pas de ponctuation, couper de force et garantir au moins 3 caractères pour le dernier fragment (pour éviter les fragments d'un seul caractère). Les fragments <0,3s fusionnent avec la ligne précédente, sans dépasser la limite de 20 caractères.
- Les horodatages au niveau du mot sont la seule source correcte pour la fenêtre du sous-titre. Les horodatages au niveau du segment peuvent absorber le silence entre les phrases, ce qui fait apparaître les sous-titres en avance d'environ une période de silence (corrigé, ne pas revenir à
word_timestamps=False) - Inférence CPU int8 : 28 secondes d'audio donnent un résultat en moins d'une minute ; pour les longues durées, estimer proportionnellement. Le premier lancement avec
large-v3-turboinclut le téléchargement, prévoir un délai suffisant. - En reconnaissance chinoise, les nombres sont souvent convertis en chiffres arabes (« deux cents millisecondes » → « 200 millisecondes »). C'est une différence normale lors de la comparaison L2, pas une erreur de reconnaissance.
Branchement de livraison
Le SRT/cues final est archivé avec la source de la piste audio originale et la version du modèle ; ne pas conserver uniquement la vidéo intégrée avec les sous-titres. Lors de la livraison de la vidéo, utiliser media-qc pour vérifier la fenêtre des sous-titres par rapport à la durée réelle ; la précision est toujours vérifiée par rapport au script connu ou par écoute. Le téléchargement du modèle par défaut et l'inférence locale ne remplacent pas un doublage humain.