Sous-titres
C'est une tâche, pas une étape d'un processus. L'utilisateur l'appelle quand il en a besoin — juste après un montage, ou après avoir supprimé deux phrases et souhaitant refaire les sous-titres.
Il n'y a qu'un seul prérequis : le registre de montage doit exister. Non pas parce que ça vient après le montage, mais parce que sans lui, le script ne sait pas quelles phrases sont conservées et à quelle seconde elles apparaissent dans le montage final.
Nécessite edit-list.json (registre), transcript.json (transcription mot-à-mot)
Produit subtitles.json
La tâche s'arrête là, ne dirige pas l'utilisateur vers l'étape suivante.
Lire et exécuter d'abord le Contrat de phase du skill métier, les critères sont dans Règles de correction des sous-titres, et les écritures des noms propres dans le Dictionnaire de termes AI.
Qui décide de quoi
C'est le fondement de cette section, tout le reste en découle.
Montage vocal décide « quelles phrases garder et à quel moment » ← source unique de vérité temporelle
Sous-titres décident « quel texte afficher à l'écran » ← source unique de vérité d'affichage
Un sous-titre stocke une liste d'IDs de mots + le texte affiché, pas de secondes. Le temps est recalculé à chaque fois à partir du registre. Ainsi, il n'y a pas de deuxième source de temps qui pourrait dériver. Les sous-titres obsolètes peuvent être détectés avec précision : « Les mots des sous-titres 7 et 12 ont été coupés », plutôt qu'un vague « les sous-titres sont peut-être obsolètes ».
Le sous-titre stocke son propre texte intentionnellement. La transcription répond à « ce qu'il a dit », le sous-titre répond à « ce qu'on montre aux spectateurs » — la ponctuation, les tics de langage supprimés, l'écriture formelle des noms propres, tout ça doit être différent. Forcer une seule chaîne de caractères à faire les deux empêcherait à jamais d'ajouter des virgules.
0. Prêt
Exécuter d'abord la « vérification de prêt » de Vérification des mises à jour — les skills sont-ils à jour, le Runtime est-il compatible ; le répertoire racine du plugin y est aussi localisé (dans les commandes de ce document, <racine-plugin> est remplacé par ce chemin littéral). Continuer seulement si « prêt » ; si « nouvelle session nécessaire » ou « stop », exécuter ses instructions (y compris l'interdiction de créer une interface de substitution). Le skill métier n'a pas sa propre logique d'environnement.
Si le résultat du prêt est runtime.kind=desktop-managed, réutiliser directement le CLI stable déjà installé par l'application de bureau et le même service launchd/tâche windows ; ne pas analyser le chemin d'Electron, installer des dépendances supplémentaires ni lancer un second Runtime.
1. Assertions d'entrée
node "<racine-plugin>/scripts/ensure-running.cjs" --json
node "<racine-plugin>/scripts/videocut-cli.cjs" inspect "<répertoire-projet>" --json
| Assertion | Si non vérifiée |
|---|---|
edit-list.json existe et contient des segments | Dire clairement que le registre manque, demander à l'utilisateur d'appeler d'abord le montage vocal. Ne pas faire le montage soi-même. |
transcript.json existe | Le projet n'est pas prêt, s'arrêter. Ne pas en créer un soi-même. |
Ne pas vérifier l'existence de source_cut.mp4, ni faire de transcription. Les sous-titres n'ont besoin ni de l'un ni de l'autre — voir la section suivante.
2. Correction du texte : d'abord le dictionnaire, puis le script
Pas besoin de retranscrire. La transcription mot-à-mot existante contient déjà les timestamps, et le registre sait quels segments sont conservés — la position de chaque mot dans la vidéo finale est calculée, pas obtenue en réécoutant :
La seconde du mot dans la vidéo source la transcription la donne
Quels segments sont conservés le registre le donne
La seconde du mot dans la vidéo finale le calcul des deux le donne
Renvoyer l'audio à un ASR ne ferait que réécouter la même chose, coûter du temps et de l'argent, et en plus mal — il faudrait à nouveau corriger les noms propres. (transcript retranscribe est un vestige de l'ancien design, où les sous-titres utilisaient la transcription de la vidéo montée pour obtenir la timeline. Maintenant que les sous-titres sont ancrés par IDs de mots, ce problème n'existe plus. Ne pas l'utiliser pour les sous-titres.)
Deux outils différents, tous deux à utiliser.
# Dictionnaire : écriture fixe de ce locuteur, sans besoin de preuve
node "<racine-plugin>/scripts/videocut-cli.cjs" transcript dictionary "<répertoire-projet>" --dictionary "<racine-plugin>/references/ai-term-dictionary.md" --json
# Script : seulement si l'auteur a un script, chaque correction nécessite une preuve
node "<racine-plugin>/scripts/videocut-cli.cjs" transcript align "<répertoire-projet>" --script "<fichier-script>" --json
Dictionnaire toujours écrire ainsi sans regarder le contexte, corriger directement, lister les modifications
Script seulement si le contexte correspond preuve exigée pour chaque modification, signaler « incertain » sinon, ne pas deviner
Pourquoi le dictionnaire est indispensable, le script seul ne suffit pas : les enregistrements vocaux sont ré-enregistrés. Dans un projet réel, la même phrase a été enregistrée quatre fois, donc des contextes comme « connect叉 » et « 叉is » apparaissent plusieurs fois. L'alignement ne peut que signaler « incertain », car il ne devine pas par règle — un nom mal écrit est pire qu'un mot mal entendu. Sur trois occurrences de « 叉 », il n'en corrige qu'une seule. Le dictionnaire n'a pas ce problème : dans les œuvres de ce locuteur, « 叉 » est bien « X ».
Il n'y a qu'un seul dictionnaire, dans references/ai-term-dictionary.md au niveau du plugin : il corrige la transcription, et le montage vocal et les sous-titres utilisent la même transcription. Ne pas en créer un autre dans ce skill.
Après la correction, il faut examiner la liste. Le dictionnaire ne regarde pas le contexte, donc il peut aussi faire des erreurs — par exemple normaliser « Skills » (Claude Skills, nom propre pluriel) en « Skill ». Si c'est faux, corriger le dictionnaire, ne pas patcher la commande.
transcript align ne fait que signaler, n'applique pas. Pour appliquer ses propositions, convertir les corrections en [{wordId, text}] puis exécuter :
node "<racine-plugin>/scripts/videocut-cli.cjs" transcript correct "<répertoire-projet>" --file "<fichier-correction>" --json
Après avoir corrigé la transcription, les sous-titres qui référencent ces mots sont mis à jour dans la même étape et renvoient subtitles.updated. Ceux qui ne peuvent pas être modifiés (une ligne réécrite manuellement) sont listés dans needsAttention, signalés pour examen, sans deviner.
Quand aucune écriture ne peut être confirmée comme correcte ni par le dictionnaire ni par le script, ne pas deviner. Signaler pour que l'utilisateur complète le dictionnaire — une fois ajouté, la vidéo suivante sera correcte automatiquement. Deviner aujourd'hui, c'est deviner à nouveau la prochaine fois.
3. Segmentation
node "<racine-plugin>/scripts/videocut-cli.cjs" subtitle build "<répertoire-projet>" --json
Quatre règles, dans l'ordre :
① Du contenu a été supprimé ici Les deux côtés de la coupe sont adjacents dans la timeline mais n'ont aucun rapport sémantique.
Supprimer du « silence » ne compte pas — couper une pause au milieu d'une phrase ne doit pas briser la phrase.
② Tout signe de ponctuation Ceux donnés par Volcengine, points et virgules sont inclus — **c'est la même granularité que la segmentation du montage vocal**,
les deux coupent au même endroit. La ponctuation est plus forte que toute preuve temporelle : un locuteur peut enchaîner deux phrases sans respirer,
ou faire une pause au milieu d'une phrase.
③ Limite de paragraphe + pause **Utilisé seulement quand le mot n'a pas de ponctuation.** C'est « quand il n'y a pas de ponctuation, deviner que la phrase se termine par un paragraphe ».
Si la ponctuation existe, la règle ② et la règle de la virgule doivent s'appliquer — elles tiennent compte de la longueur de l'écran, la règle ③ non.
(Déclencher ③ sur une limite avec ponctuation : dans un projet réel, on passe de 40 à 43 écrans, créant plus d'écrans fragmentés.)
④ Longue pause perçue par le public Pour couper à l'intérieur d'une phrase, un silence plus long est nécessaire.
Montage vocal et sous-titres utilisent la même ponctuation et la même granularité : une virgule = un segment / un écran.
Les fragments (un ou deux caractères) sont fusionnés, mais pas à travers un point — « 你看 » commence une nouvelle phrase, ce n'est pas la queue de la phrase précédente. Le fusionner en arrière donnerait « …utiliser Grok CLI你看 », deux phrases collées ensemble.
Les phrases courtes dites rapidement par le locuteur restent (dans un projet réel, « 每天早上 » et « 执行任务 » font 0,6 seconde chacune). C'est comme ça qu'il parle, pas d'alerte. Un écran par virgule produit forcément ce genre d'écrans. Donner une alerte pour ça reviendrait à alerter pour une parole normale — avec trop d'alertes, personne ne les regarde.
Ce qui dépasse la durée d'un écran est réparti équitablement, un écran par ligne. Si la division crée un fragment d'un ou deux caractères, cela signifie que la limite ② n'était en fait pas un point ; fusionner le fragment avec l'écran précédent.
La commande rapporte quatre choses, toutes à vérifier :
stale Écrans modifiés par le montage — écran précis, mots perdus
tooFast Trop de mots, pas assez de temps pour lire
transcriptMoved La transcription a changé depuis la dernière fois
Quand des sous-titres existent déjà — s'arrêter ici et demander
Sans --replace, la commande refuse. C'est le seul moment dans ce skill où il faut demander le consentement de l'utilisateur, car --replace efface le travail manuel de segmentation et de formulation, que le produit lui-même ne peut pas restaurer.
L'utilisateur veut modifier quelques mots Ne pas utiliser build. Le laisser modifier directement dans Studio, ou vous dire quels écrans modifier.
L'utilisateur veut tout recommencer Confirmer puis ajouter --replace.
4. Vérification : écran par écran dans Studio
node "<racine-plugin>/scripts/videocut-cli.cjs" open "<répertoire-projet>" --json
Une fois ouvert, aller à l'onglet « Sous-titres » de la colonne de gauche. Un écran par ligne : à gauche le numéro et le temps, à droite le texte, cliquer pour modifier directement.
- Entrée = créer un nouvel écran à partir du curseur
- Retour arrière en début de ligne = fusionner avec l'écran précédent
- Paramètres → Sous-titres dans la colonne de droite : quatre préréglages au choix, un style pour toute la vidéo
- Les sous-titres sont visibles directement sur l'image, leur position et leur taille sont proportionnelles à l'image — l'aperçu et la version finale utilisent les mêmes données
Lors de la vérification, demander au moins à l'utilisateur de confirmer : les noms propres sont-ils corrects, aucun mot manquant, la coupe se lit-elle bien, l'écran reste-t-il assez longtemps pour la lecture.
5. Jusqu'à subtitles.json
Cette section est terminée. Pas de coupe physique, pas de storyboard, pas d'animations, pas de rendu vidéo, et ne pas pousser l'utilisateur à l'étape suivante.
Le rapport doit être distinct : le readback structuré Product est API/readback PASS ; la vérification visuelle avec des images réelles du même projet est visual frame PASS ; quand personne n'a réellement vérifié que les sous-titres correspondent à l'image, le rapport doit être human listening UNVERIFIED, sans utiliser de DOM, de captures d'écran ou de sondes de fichiers comme substitut.
Limite : l'incrustation dans l'image n'est pas de cette section
La méthode de sortie prévue est l'incrustation dans l'image, et l'image est dessinée par l'étape d'export. Le produit des sous-titres est subtitles.json — toutes les dimensions sont des pourcentages de l'image, l'export les convertit en pixels selon la résolution de sortie, les deux utilisent les mêmes données.
Aujourd'hui, le mp4 exporté ne contient pas de sous-titres, cette étape n'est pas encore faite. Le rapport doit indiquer clairement cette conséquence, ne pas dire « les sous-titres sont prêts » — l'utilisateur penserait que la vidéo finale en contient.
Récupération et échec
subtitles_exist: Des sous-titres existent déjà. Demander d'abord, ne pas utiliser--replacedirectement.revision_conflict: Un autre processus écrit aussi. Relire, ne pas écraser automatiquement.- Le dictionnaire signale « ligne N illisible » : une ligne de tableau mal formatée. Seules les lignes de tableau (
| écriture correcte | erreur courante |) sont reconnues ; le texte brut et les listes sont ignorés silencieusement. transcript correctsignale « must not change any word id, time or gap flag » : la proposition de modification contient des changements de temps. Modifier uniquement le texte.runtime_unhealthy: Ne pas réinstaller en boucle.- En cas d'échec, ne jamais dire « la transcription est terminée » comme « les sous-titres sont prêts ». L'ASR produit la matière première, pas le résultat final.