LocalDub.NET : bâtir un pipeline de doublage vidéo local avec C#, .NET et Agent Framewor disponible en open source sur GitHub...
Lien GitHub : odahan/VideoDubbing: Video dubbing from French to English, 100% locally produced using AI (fully automated pipeline in C#)
Le doublage automatique de vidéos est souvent présenté comme un simple enchaînement : transcrire, traduire, synthétiser une voix, puis remonter la piste audio. En pratique, c’est un problème beaucoup plus exigeant. Il faut conserver les durées, préserver les termes techniques, gérer la mémoire GPU, produire des fichiers exploitables en postproduction et, surtout, ne pas transformer une vidéo source en artefact fragile.
C’est l’objectif de LocalDub.NET : un pipeline de doublage français vers anglais américain, pensé pour les vidéos à un seul locuteur et exécuté localement sur Windows. Le projet s’appuie sur C# et .NET 10 pour orchestrer les outils spécialisés : FFmpeg pour l’audio et le muxing, whisper.cpp pour la transcription, Ollama pour la traduction locale et Chatterbox-Turbo pour la synthèse vocale.
L’idée est simple : utiliser chaque outil là où il est le meilleur, tout en confiant à .NET le rôle de colonne vertébrale fiable, testable et maintenable.
Pourquoi .NET pour orchestrer de l’IA audio ?
Dans ce type de projet, la tentation est forte de tout écrire dans un script Python. C’est rapide pour un prototype, mais l’orchestration devient vite difficile à faire évoluer : paramètres dispersés, gestion des erreurs partielle, processus externes difficiles à superviser, peu de tests et logique métier mélangée aux appels système.
C# apporte ici plusieurs avantages très concrets :
-
une structure de projet claire et fortement typée ;
-
l’injection de dépendances de Microsoft.Extensions.DependencyInjection ;
-
une configuration centralisée avec appsettings.json ;
-
des logs cohérents via Microsoft.Extensions.Logging ;
-
une gestion native de l’asynchronisme et de l’annulation ;
-
des tests unitaires pour la ligne de commande, les sous-titres et les politiques de sortie.
Le pipeline est composé de services spécialisés : extraction audio, séparation des sources, transcription, traduction, gestion des glossaires, synthèse, construction de timeline audio, génération de sous-titres et remux vidéo. Cette découpe évite que la classe principale ne devienne un script géant impossible à relire.
Le résultat est une application console qui reste simple à utiliser, mais dont les étapes sont clairement isolées et remplaçables.
Une contrainte essentielle : la vidéo originale reste intacte
LocalDub.NET n’écrase jamais la vidéo source. Pour une entrée demo.mp4, l’application produit, à côté :
demo-EN.mp4 vidéo doublée
demo-EN.wav piste anglaise synchronisée
demo-EN.srt sous-titres anglais
demo-EN.json manifeste du traitement
Ce manifeste contient notamment les segments, traductions, timings, modèle de traduction et paramètres vocaux employés. C’est important pour la traçabilité : un doublage n’est pas seulement un fichier final, c’est aussi un ensemble de décisions qu’il doit rester possible d’auditer ou de reproduire.
Par défaut, une sortie existante bloque également le traitement. Il faut choisir explicitement --overwrite pour la remplacer.
Un pipeline local, étape par étape
Le flux de traitement suit une logique volontairement pragmatique.
D’abord, FFmpeg extrait un master audio à fréquence fixe. Selon le mode choisi, Demucs peut ensuite séparer la voix de l’accompagnement. Cette étape permet de conserver une musique de fond tout en retirant la voix française avant d’ajouter la narration anglaise.
La parole est ensuite convertie dans un format adapté à whisper.cpp, qui produit une transcription découpée en segments temporels. Ces segments sont la pièce centrale du système : ils portent le texte source, les timestamps, la traduction et, plus tard, les informations nécessaires à la synthèse.
La traduction est effectuée localement avec Ollama. Chatterbox-Turbo génère alors les segments anglais. Enfin, LocalDub.NET reconstruit une piste audio complète, alignée depuis 00:00:00, avant de produire les sous-titres et la vidéo finale.
Cette séparation des responsabilités est essentielle : FFmpeg n’a pas besoin de connaître la logique de traduction, le traducteur n’a pas besoin de manipuler les fichiers vidéo, et le code métier C# garde la maîtrise du déroulement global.
Agent Framework : un agent local, pas un argument marketing
Oui, Microsoft Agent Framework est réellement utilisé dans le projet, au travers du package Microsoft.Agents.AI.
Mais il est important de préciser son rôle. LocalDub.NET n’utilise pas une chorégraphie complexe de dizaines d’agents autonomes. Ce serait inutile ici. Agent Framework sert plutôt d’abstraction propre entre un client de conversation IA et les tâches linguistiques du pipeline.
Le client Ollama, exposé via IChatClient, est converti en AIAgent :
IChatClient chatClient = ollama;
AIAgent agent = chatClient.AsAIAgent(
name: "LocalDubTranslator",
instructions: TranslationInstructions);
L’intérêt est de formaliser l’intention de l’agent : il ne s’agit pas d’un chat généraliste, mais d’un traducteur audiovisuel spécialisé. Ses instructions précisent qu’il doit produire une narration américaine naturelle, concise, adaptée au doublage, et respecter un schéma JSON strict.
La traduction est ensuite exécutée par lots avec une sortie typée :
var response = await agent.RunAsync<TranslationEnvelope>(
prompt,
options: runOptions,
cancellationToken: cancellationToken);
Cette approche apporte un cadre plus robuste qu’un simple appel texte-à-texte. La réponse attendue est un objet TranslationEnvelope, contenant les traductions associées aux identifiants de segment. Le programme peut alors vérifier qu’aucun segment n’a été oublié avant de poursuivre.
Agent Framework est aussi utilisé pour une seconde tâche : raccourcir une phrase anglaise lorsque sa durée ne permet pas de la prononcer naturellement dans la fenêtre temporelle disponible.
C’est une distinction importante. Traduire et adapter au timing sont deux opérations différentes. Une traduction correcte peut être trop longue pour être doublée. LocalDub.NET appelle donc un agent éditeur dédié, avec une instruction très stricte : préserver le sens essentiel, respecter un nombre maximal de mots et ne renvoyer que la phrase reformulée.
Traduire pour une voix, pas pour un document
Le projet ne cherche pas une traduction littérale. Le prompt de traduction contient plusieurs contraintes adaptées au doublage :
-
respecter les identifiants de segments ;
-
conserver le sens ;
-
préférer une formulation orale naturelle ;
-
ne pas dépasser le nombre de mots autorisé ;
-
préserver les noms de produits, acronymes et termes techniques ;
-
appliquer un glossaire éventuel.
Chaque segment reçoit un maxWords, calculé à partir de sa durée et d’un débit cible. Ainsi, la contrainte temporelle est intégrée avant la synthèse, pas découverte trop tard au montage.
Le glossaire est tout aussi important. Dans une vidéo technique, un modèle de synthétiseur, un nom de produit, un sigle ou une API ne doivent pas être « traduits » de façon créative. LocalDub.NET fournit des glossaires JSON et permet aussi d’ajouter ponctuellement des termes à préserver.
Gérer le timing sans maltraiter la voix
Une erreur fréquente consiste à accélérer brutalement une voix synthétique dès qu’une phrase dépasse son créneau. Le résultat est rarement agréable.
LocalDub.NET privilégie une stratégie plus progressive :
-
traduire de manière concise dès le départ ;
-
synthétiser le segment ;
-
si nécessaire, reformuler la phrase pour la raccourcir ;
-
limiter l’accélération habituelle à 1,15×.
Ce choix place l’intelligibilité et le naturel au-dessus de l’obsession du timing parfait. Pour les cas réellement contraints, une accélération limitée est préférable à une voix artificiellement compressée ou à une dérive temporelle qui casse le montage.
Penser à la VRAM comme une ressource partagée
Le pipeline peut faire cohabiter plusieurs charges lourdes : modèle de traduction Ollama, transcription accélérée CUDA et synthèse vocale. Sur une machine locale, la mémoire GPU est une ressource finie.
C’est pourquoi LocalDub.NET peut décharger le modèle Ollama avant de lancer les étapes de synthèse. Cette décision est représentative de l’approche du projet : l’orchestrateur C# ne se contente pas d’appeler des outils, il gère les ressources et l’ordre des opérations.
Le modèle principal peut donc traiter la traduction, être arrêté pour libérer la VRAM, puis laisser la place à Chatterbox-Turbo. Une éventuelle reformulation courte peut s’appuyer sur un modèle plus léger.
Réutiliser le travail déjà fait
Une vidéo longue peut demander du temps. Recommencer une transcription ou une séparation audio après une interruption est frustrant et coûteux.
LocalDub.NET conserve les artefacts intermédiaires dans output/work/. Le répertoire de travail est déterminé par une signature qui tient notamment compte du fichier source, du mode audio, du modèle Ollama, du glossaire et des termes préservés.
Cela permet de réutiliser les transcriptions, stems et traductions lorsque le traitement est relancé avec les mêmes paramètres, tout en évitant de mélanger les résultats de deux configurations différentes.
C’est un détail d’architecture qui fait une grande différence à l’usage : l’IA locale devient plus pratique lorsqu’elle est aussi capable de reprendre intelligemment.
Une base .NET pour faire évoluer le projet
LocalDub.NET n’est pas un démonstrateur isolé. Son architecture permet d’envisager plusieurs évolutions sans réécrire le pipeline :
-
prise en charge de plusieurs locuteurs ;
-
nouveaux moteurs de transcription ou de synthèse ;
-
détection automatique de la langue source ;
-
synchronisation labiale en post-traitement ;
-
interface graphique ;
-
exports adaptés à des outils de montage spécifiques.
La vidéo -EN et son WAV parfaitement aligné constituent déjà une base solide pour une future étape de lip-sync, sans modifier le cœur du flux existant.
Conclusion
Le point fort de LocalDub.NET n’est pas seulement de relier whisper.cpp, Ollama, Chatterbox et FFmpeg. C’est de les intégrer dans une application .NET cohérente, locale et contrôlable.
L'absence de synchro sur les lèvres ou la contrainte mono-locuteur ne sont pas pénalisantes pour ce projet destiné surtout à traduire automatiquement en anglais des vidéos de démos ou de formation dans lesquelles il y a peu ou pas de facecam et où il n'y a qu'un locuteur en général.
C# gère l’orchestration, les fichiers, la configuration, les erreurs et les tests. Agent Framework structure les interactions avec le modèle de langage en agents spécialisés et en réponses typées. Les outils IA et audio restent locaux, tandis que la vidéo source demeure protégée.
C’est une vision de l’IA appliquée qui me paraît particulièrement intéressante : ne pas déléguer aveuglément un processus à un modèle, mais construire autour de lui un système logiciel fiable, observable et adapté à une vraie chaîne de production.
Et puis, tout en local, sans API couteuse, sans abonnement, rien que votre PC et votre carte graphique. Le processus complet pour une vidéo est relativement rapide. Essayez, vous verrez ! (enfin, vous entendrez votre vidéo en anglais avec votre voix si vous le souhaitez !).
Stay Tuned !