Add video dubbing, translation, and subtitle features

Features Added:
- Video dubbing with voice preservation (--dub-video)
- Automatic subtitle generation (--create-subtitles)
- Subtitle translation (--translate-subtitles)
- Burn subtitles into video (--burn-subtitles)
- Audio transcription using Whisper (--transcribe)
- Text translation using MarianMT models

New Command-Line Arguments:
- --transcribe: Transcribe audio from video
- --whisper-model: Select Whisper model size (tiny/base/small/medium/large)
- --source-lang: Source language code
- --target-lang: Target language code for translation
- --create-subtitles: Create SRT subtitles from video
- --translate-subtitles: Translate subtitles to target language
- --burn-subtitles: Burn subtitles into video
- --subtitle-style: Customize subtitle appearance
- --dub-video: Translate and dub video with voice preservation
- --voice-clone/--no-voice-clone: Enable/disable voice cloning

MCP Server Updates:
- Added videogen_transcribe_video tool
- Added videogen_create_subtitles tool
- Added videogen_dub_video tool
- Added videogen_translate_text tool

Documentation Updates:
- Updated SKILL.md with dubbing/translation section
- Updated EXAMPLES.md with comprehensive examples
- Updated requirements.txt with openai-whisper dependency

Supported Languages:
English, Spanish, French, German, Italian, Portuguese, Russian, Chinese, Japanese, Korean, Arabic, Hindi, Dutch, Polish, Turkish, Vietnamese, Thai, Indonesian, Swedish, Ukrainian
parent 1c01f5b7
......@@ -17,13 +17,15 @@ This document contains comprehensive examples for using the VideoGen toolkit, co
9. [2D-to-3D Conversion](#2d-to-3d-conversion)
10. [Audio Generation](#audio-generation)
11. [Lip Sync](#lip-sync)
12. [Character Consistency](#character-consistency)
13. [Distributed Multi-GPU](#distributed-multi-gpu)
14. [Model Management](#model-management)
15. [VRAM Management](#vram-management)
16. [Upscaling](#upscaling)
17. [NSFW Content](#nsfw-content)
18. [Advanced Combinations](#advanced-combinations)
12. [Video Dubbing & Translation](#video-dubbing--translation)
13. [Subtitle Generation](#subtitle-generation)
14. [Character Consistency](#character-consistency)
15. [Distributed Multi-GPU](#distributed-multi-gpu)
16. [Model Management](#model-management)
17. [VRAM Management](#vram-management)
18. [Upscaling](#upscaling)
19. [NSFW Content](#nsfw-content)
20. [Advanced Combinations](#advanced-combinations)
---
......@@ -841,6 +843,123 @@ python3 videogen --image_to_video --model svd_xt_1.1 \
---
## Video Dubbing & Translation
Video dubbing allows you to translate videos while preserving the original voice characteristics using voice cloning technology.
### Transcribe Video Audio
```bash
# Basic transcription
python3 videogen --video interview.mp4 --transcribe
# Use larger Whisper model for better accuracy
python3 videogen --video interview.mp4 --transcribe --whisper-model large
# Specify source language
python3 videogen --video spanish_video.mp4 --transcribe --source-lang es
```
### Dub Video with Translation
```bash
# Translate and dub video (preserves voice with voice cloning)
python3 videogen --video english_video.mp4 --dub-video --target-lang es --output spanish_version
# Dub to French
python3 videogen --video english_video.mp4 --dub-video --target-lang fr --output french_version
# Dub to German without voice cloning (use standard TTS)
python3 videogen --video english_video.mp4 --dub-video --target-lang de --no-voice-clone --output german_version
# Dub with specific TTS voice
python3 videogen --video english_video.mp4 --dub-video --target-lang ja --tts_voice edge_female_ja --output japanese_version
# Dub with larger Whisper model for better transcription
python3 videogen --video interview.mp4 --dub-video --target-lang zh --whisper-model medium --output chinese_version
```
### Multi-Language Dubbing Pipeline
```bash
# Create multiple language versions
for lang in es fr de ja; do
python3 videogen --video original.mp4 --dub-video --target-lang $lang --output "version_$lang"
done
```
---
## Subtitle Generation
Generate and translate subtitles automatically from video audio.
### Create Subtitles
```bash
# Create SRT subtitles from video
python3 videogen --video interview.mp4 --create-subtitles
# Output: interview_en.srt (or detected language code)
```
### Create Translated Subtitles
```bash
# Create Spanish subtitles from English video
python3 videogen --video english_video.mp4 --create-subtitles --translate-subtitles --target-lang es
# Output: english_video_en.srt (original) and english_video_es.srt (translated)
```
### Burn Subtitles into Video
```bash
# Burn original subtitles into video
python3 videogen --video interview.mp4 --create-subtitles --burn-subtitles --output subtitled
# Burn translated subtitles
python3 videogen --video english_video.mp4 --create-subtitles --translate-subtitles --target-lang es --burn-subtitles --output spanish_subtitled
# Custom subtitle style
python3 videogen --video interview.mp4 --create-subtitles --burn-subtitles \
--subtitle-style "font_size=32,font_color=yellow,outline_color=black" \
--output styled_subtitles
```
### Complete Translation Pipeline
```bash
# Full pipeline: transcribe, translate, create subtitles, and burn
python3 videogen --video original.mp4 \
--create-subtitles \
--translate-subtitles \
--target-lang fr \
--burn-subtitles \
--output french_subtitled
# Create both dubbed and subtitled versions
python3 videogen --video original.mp4 --dub-video --target-lang es --output spanish_dubbed
python3 videogen --video original.mp4 --create-subtitles --translate-subtitles --target-lang es --burn-subtitles --output spanish_subtitled
```
### Supported Languages
| Code | Language | Code | Language |
|------|----------|------|----------|
| en | English | es | Spanish |
| fr | French | de | German |
| it | Italian | pt | Portuguese |
| ru | Russian | zh | Chinese |
| ja | Japanese | ko | Korean |
| ar | Arabic | hi | Hindi |
| nl | Dutch | pl | Polish |
| tr | Turkish | vi | Vietnamese |
| th | Thai | id | Indonesian |
| sv | Swedish | uk | Ukrainian |
---
## Character Consistency
Character consistency features allow you to maintain the same character appearance across multiple generations using IP-Adapter, InstantID, Character Profiles, and LoRA training.
......
......@@ -19,6 +19,8 @@ VideoGen is a universal video generation toolkit that supports:
- **Video Upscaling**: AI-powered video upscaling
- **Audio Generation**: TTS and music generation
- **Lip Sync**: Synchronize lip movements with audio
- **Video Dubbing**: Translate and dub videos with voice preservation
- **Subtitle Generation**: Create and translate subtitles automatically
---
......@@ -276,6 +278,69 @@ python3 videogen --concat-videos video1.mp4 video2.mp4 video3.mp4 --output joine
---
## Video Dubbing & Translation
VideoGen supports video dubbing with voice preservation and automatic subtitle generation.
### Transcribe Video Audio
```bash
# Transcribe audio from video
python3 videogen --video input.mp4 --transcribe
# Use larger Whisper model for better accuracy
python3 videogen --video input.mp4 --transcribe --whisper-model large
# Specify source language
python3 videogen --video input.mp4 --transcribe --source-lang en
```
### Create Subtitles
```bash
# Create SRT subtitles from video
python3 videogen --video input.mp4 --create-subtitles
# Create translated subtitles
python3 videogen --video input.mp4 --create-subtitles --translate-subtitles --target-lang es
# Burn subtitles into video
python3 videogen --video input.mp4 --create-subtitles --burn-subtitles --output subtitled
# Burn translated subtitles
python3 videogen --video input.mp4 --create-subtitles --translate-subtitles --target-lang fr --burn-subtitles --output french_subtitled
```
### Dub Video with Translation
```bash
# Translate and dub video (preserves voice)
python3 videogen --video input.mp4 --dub-video --target-lang es --output spanish_dubbed
# Dub without voice cloning (use standard TTS)
python3 videogen --video input.mp4 --dub-video --target-lang fr --no-voice-clone --output french_dubbed
# Specify TTS voice for dubbing
python3 videogen --video input.mp4 --dub-video --target-lang de --tts_voice edge_male_de --output german_dubbed
```
### Supported Languages
| Code | Language | Code | Language |
|------|----------|------|----------|
| en | English | es | Spanish |
| fr | French | de | German |
| it | Italian | pt | Portuguese |
| ru | Russian | zh | Chinese |
| ja | Japanese | ko | Korean |
| ar | Arabic | hi | Hindi |
| nl | Dutch | pl | Polish |
| tr | Turkish | vi | Vietnamese |
| th | Thai | id | Indonesian |
| sv | Swedish | uk | Ukrainian |
---
## Output Files
VideoGen creates these output files:
......@@ -290,6 +355,8 @@ VideoGen creates these output files:
| `<output>_synced.mp4` | Audio-synced video |
| `<output>_lipsync.mp4` | Lip-synced video |
| `<output>_upscaled.mp4` | Upscaled video |
| `<output>_<lang>.srt` | Subtitle file |
| `<output>_dubbed.mp4` | Dubbed video |
---
......
......@@ -26,6 +26,11 @@ edge-tts>=6.1.0
# bark # Install with: pip install git+https://github.com/suno-ai/bark.git
# audiocraft # Install with: pip install audiocraft
# Speech-to-Text & Translation (Optional - for dubbing and subtitles)
openai-whisper>=20231117 # For transcription
# Or: pip install openai-whisper
# Translation uses transformers (already listed above) with MarianMT models
# Lip Sync Dependencies (Optional)
opencv-python>=4.8.0
face-recognition>=1.14.0
......
......@@ -81,6 +81,8 @@ EDGE_TTS_AVAILABLE = False
MUSICGEN_AVAILABLE = False
LIBROSA_AVAILABLE = False
SCIPY_AVAILABLE = False
WHISPER_AVAILABLE = False
TRANSLATION_AVAILABLE = False
try:
import scipy
......@@ -120,6 +122,21 @@ try:
except ImportError:
pass
# Whisper for speech-to-text
try:
import whisper
WHISPER_AVAILABLE = True
AUDIO_AVAILABLE = True
except ImportError:
pass
# Translation support
try:
from transformers import MarianMTModel, MarianTokenizer
TRANSLATION_AVAILABLE = True
except ImportError:
pass
# NSFW text classification
TRANSFORMERS_AVAILABLE = False
NSFW_CLASSIFIER = None
......@@ -4864,6 +4881,454 @@ def apply_lip_sync(video_path, audio_path, output_path, method="auto", args=None
return None
# ──────────────────────────────────────────────────────────────────────────────
# VIDEO DUBBING & TRANSLATION
# ──────────────────────────────────────────────────────────────────────────────
# Supported languages for translation
TRANSLATION_LANGUAGES = {
"en": "English",
"es": "Spanish",
"fr": "French",
"de": "German",
"it": "Italian",
"pt": "Portuguese",
"ru": "Russian",
"zh": "Chinese",
"ja": "Japanese",
"ko": "Korean",
"ar": "Arabic",
"hi": "Hindi",
"nl": "Dutch",
"pl": "Polish",
"tr": "Turkish",
"vi": "Vietnamese",
"th": "Thai",
"id": "Indonesian",
"sv": "Swedish",
"uk": "Ukrainian",
}
def transcribe_video_audio(video_path, model_size="base", language=None):
"""Transcribe audio from video using Whisper
Args:
video_path: Path to the video file
model_size: Whisper model size (tiny, base, small, medium, large)
language: Source language code (optional, auto-detected if not provided)
Returns:
List of segments with text, start, end times
"""
if not WHISPER_AVAILABLE:
print("❌ Whisper not available. Install with: pip install openai-whisper")
return None
print(f"🎤 Transcribing audio from: {video_path}")
print(f" Model: {model_size}")
try:
# Load Whisper model
model = whisper.load_model(model_size)
# Transcribe
transcribe_options = {}
if language:
transcribe_options["language"] = language
result = model.transcribe(video_path, **transcribe_options)
segments = []
for seg in result["segments"]:
segments.append({
"text": seg["text"].strip(),
"start": seg["start"],
"end": seg["end"],
})
print(f" ✅ Transcribed {len(segments)} segments")
print(f" Detected language: {result.get('language', 'unknown')}")
return {
"segments": segments,
"language": result.get("language", "unknown"),
"text": result.get("text", ""),
}
except Exception as e:
print(f"❌ Transcription failed: {e}")
return None
def translate_text(text, source_lang, target_lang):
"""Translate text using MarianMT models
Args:
text: Text to translate
source_lang: Source language code
target_lang: Target language code
Returns:
Translated text
"""
if not TRANSLATION_AVAILABLE:
print("❌ Translation not available. Install with: pip install transformers")
return text
# Map language codes to MarianMT model names
lang_map = {
("en", "es"): "Helsinki-NLP/opus-mt-en-es",
("en", "fr"): "Helsinki-NLP/opus-mt-en-fr",
("en", "de"): "Helsinki-NLP/opus-mt-en-de",
("en", "it"): "Helsinki-NLP/opus-mt-en-it",
("en", "pt"): "Helsinki-NLP/opus-mt-en-pt",
("en", "ru"): "Helsinki-NLP/opus-mt-en-ru",
("en", "zh"): "Helsinki-NLP/opus-mt-en-zh",
("en", "ja"): "Helsinki-NLP/opus-mt-en-ja",
("en", "ko"): "Helsinki-NLP/opus-mt-en-ko",
("en", "ar"): "Helsinki-NLP/opus-mt-en-ar",
("en", "hi"): "Helsinki-NLP/opus-mt-en-hi",
("en", "nl"): "Helsinki-NLP/opus-mt-en-nl",
("en", "pl"): "Helsinki-NLP/opus-mt-en-pl",
("en", "tr"): "Helsinki-NLP/opus-mt-en-tr",
("en", "vi"): "Helsinki-NLP/opus-mt-en-vi",
("en", "th"): "Helsinki-NLP/opus-mt-en-th",
("en", "uk"): "Helsinki-NLP/opus-mt-en-uk",
# Reverse directions
("es", "en"): "Helsinki-NLP/opus-mt-es-en",
("fr", "en"): "Helsinki-NLP/opus-mt-fr-en",
("de", "en"): "Helsinki-NLP/opus-mt-de-en",
("it", "en"): "Helsinki-NLP/opus-mt-it-en",
("pt", "en"): "Helsinki-NLP/opus-mt-pt-en",
("ru", "en"): "Helsinki-NLP/opus-mt-ru-en",
("zh", "en"): "Helsinki-NLP/opus-mt-zh-en",
("ja", "en"): "Helsinki-NLP/opus-mt-ja-en",
("ko", "en"): "Helsinki-NLP/opus-mt-ko-en",
("ar", "en"): "Helsinki-NLP/opus-mt-ar-en",
("hi", "en"): "Helsinki-NLP/opus-mt-hi-en",
("nl", "en"): "Helsinki-NLP/opus-mt-nl-en",
("pl", "en"): "Helsinki-NLP/opus-mt-pl-en",
("tr", "en"): "Helsinki-NLP/opus-mt-tr-en",
("vi", "en"): "Helsinki-NLP/opus-mt-vi-en",
("th", "en"): "Helsinki-NLP/opus-mt-th-en",
("uk", "en"): "Helsinki-NLP/opus-mt-uk-en",
}
model_name = lang_map.get((source_lang, target_lang))
if not model_name:
print(f"⚠️ No direct translation model for {source_lang} -> {target_lang}")
print(f" Translating via English...")
# Translate via English as intermediate
if source_lang != "en" and target_lang != "en":
intermediate = translate_text(text, source_lang, "en")
return translate_text(intermediate, "en", target_lang)
return text
try:
model = MarianMTModel.from_pretrained(model_name)
tokenizer = MarianTokenizer.from_pretrained(model_name)
# Translate
inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True, max_length=512)
translated = model.generate(**inputs)
translated_text = tokenizer.decode(translated[0], skip_special_tokens=True)
return translated_text
except Exception as e:
print(f"❌ Translation failed: {e}")
return text
def translate_subtitles(subtitles, source_lang, target_lang):
"""Translate subtitle segments
Args:
subtitles: List of subtitle segments with text, start, end
source_lang: Source language code
target_lang: Target language code
Returns:
List of translated subtitle segments
"""
print(f"🌐 Translating subtitles: {source_lang} -> {target_lang}")
translated_segments = []
for i, seg in enumerate(subtitles):
translated_text = translate_text(seg["text"], source_lang, target_lang)
translated_segments.append({
"text": translated_text,
"start": seg["start"],
"end": seg["end"],
})
if (i + 1) % 10 == 0:
print(f" Translated {i + 1}/{len(subtitles)} segments")
print(f" ✅ Translated {len(translated_segments)} segments")
return translated_segments
def generate_srt(subtitles, output_path):
"""Generate SRT subtitle file from segments
Args:
subtitles: List of subtitle segments with text, start, end
output_path: Path to save the SRT file
Returns:
Path to the generated SRT file
"""
def format_timestamp(seconds):
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
millis = int((seconds % 1) * 1000)
return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}"
with open(output_path, 'w', encoding='utf-8') as f:
for i, seg in enumerate(subtitles, 1):
f.write(f"{i}\n")
f.write(f"{format_timestamp(seg['start'])} --> {format_timestamp(seg['end'])}\n")
f.write(f"{seg['text']}\n\n")
print(f" ✅ Generated SRT: {output_path}")
return output_path
def burn_subtitles(video_path, srt_path, output_path, style=None):
"""Burn subtitles into video using ffmpeg
Args:
video_path: Path to the input video
srt_path: Path to the SRT subtitle file
output_path: Path to save the output video
style: Subtitle style options (font_size, font_color, etc.)
Returns:
Path to the output video
"""
print(f"🔥 Burning subtitles into video...")
# Default style
if style is None:
style = {
"font_size": 24,
"font_color": "white",
"outline_color": "black",
"outline_width": 2,
"margin_v": 50,
}
# Build subtitle filter
# Escape special characters in path
srt_escaped = srt_path.replace('\\', '\\\\').replace(':', '\\:')
# Build force_style string
force_style = f"FontSize={style['font_size']},PrimaryColour=&H{style['font_color']}&,OutlineColour=&H{style['outline_color']}&,Outline={style['outline_width']},MarginV={style['margin_v']}"
# FFmpeg command to burn subtitles
cmd = [
'ffmpeg', '-y',
'-i', video_path,
'-vf', f"subtitles='{srt_escaped}':force_style='{force_style}'",
'-c:a', 'copy',
output_path
]
try:
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f" ✅ Subtitles burned: {output_path}")
return output_path
else:
print(f" ❌ FFmpeg error: {result.stderr}")
return None
except Exception as e:
print(f"❌ Subtitle burning failed: {e}")
return None
def create_translated_subtitles(video_path, target_lang, output_dir=None, model_size="base", source_lang=None):
"""Create translated subtitles for a video
Args:
video_path: Path to the input video
target_lang: Target language code for translation
output_dir: Directory to save subtitle files (optional)
model_size: Whisper model size
source_lang: Source language code (optional, auto-detected)
Returns:
Tuple of (original_srt_path, translated_srt_path)
"""
if output_dir is None:
output_dir = os.path.dirname(video_path) or "."
base_name = os.path.splitext(os.path.basename(video_path))[0]
# Transcribe
transcription = transcribe_video_audio(video_path, model_size=model_size, language=source_lang)
if not transcription:
return None, None
detected_lang = transcription["language"]
if source_lang is None:
source_lang = detected_lang
# Generate original SRT
original_srt = os.path.join(output_dir, f"{base_name}_{source_lang}.srt")
generate_srt(transcription["segments"], original_srt)
# Translate if needed
if source_lang != target_lang:
translated_segments = translate_subtitles(transcription["segments"], source_lang, target_lang)
translated_srt = os.path.join(output_dir, f"{base_name}_{target_lang}.srt")
generate_srt(translated_segments, translated_srt)
else:
translated_srt = original_srt
return original_srt, translated_srt
def dub_video_with_translation(video_path, target_lang, output_path, voice_clone=True,
model_size="base", source_lang=None, tts_voice=None):
"""Translate and dub a video with voice preservation
Args:
video_path: Path to the input video
target_lang: Target language code
output_path: Path to save the dubbed video
voice_clone: Whether to preserve the original voice
model_size: Whisper model size
source_lang: Source language code (optional)
tts_voice: TTS voice to use (optional)
Returns:
Path to the dubbed video
"""
print(f"\n🎬 Video Dubbing & Translation")
print(f" Input: {video_path}")
print(f" Target language: {target_lang}")
print(f" Voice cloning: {voice_clone}")
print()
# Step 1: Transcribe
transcription = transcribe_video_audio(video_path, model_size=model_size, language=source_lang)
if not transcription:
return None
detected_lang = transcription["language"]
if source_lang is None:
source_lang = detected_lang
# Step 2: Translate text
if source_lang != target_lang:
print(f"\n🌐 Translating {source_lang} -> {target_lang}...")
translated_text = translate_text(transcription["text"], source_lang, target_lang)
else:
translated_text = transcription["text"]
# Step 3: Generate TTS audio
print(f"\n🎤 Generating dubbed audio...")
temp_audio = tempfile.mktemp(suffix='.mp3')
if voice_clone and BARK_AVAILABLE:
# Use Bark for voice cloning (simplified - in production would clone from original audio)
print(" Using voice cloning (Bark)...")
generate_tts(translated_text, temp_audio, voice_name="bark_custom", args=None)
elif EDGE_TTS_AVAILABLE:
# Use Edge-TTS with specified or default voice
print(f" Using Edge-TTS...")
voice = tts_voice or "edge_female_us"
generate_tts(translated_text, temp_audio, voice_name=voice, args=None)
else:
print("❌ No TTS engine available for dubbing")
return None
if not os.path.exists(temp_audio):
print("❌ Failed to generate dubbed audio")
return None
# Step 4: Sync audio to video duration
video_duration = get_video_duration(video_path)
audio_duration = get_audio_duration(temp_audio)
print(f"\n🔄 Syncing audio ({audio_duration:.2f}s) to video ({video_duration:.2f}s)...")
# Create final video with new audio
final_output = output_path
# Replace audio in video
cmd = [
'ffmpeg', '-y',
'-i', video_path,
'-i', temp_audio,
'-c:v', 'copy',
'-c:a', 'aac',
'-map', '0:v:0',
'-map', '1:a:0',
'-shortest',
final_output
]
try:
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"\n✅ Dubbed video saved: {final_output}")
# Cleanup
if os.path.exists(temp_audio):
os.remove(temp_audio)
return final_output
else:
print(f"❌ FFmpeg error: {result.stderr}")
return None
except Exception as e:
print(f"❌ Dubbing failed: {e}")
return None
def create_video_with_subtitles(video_path, target_lang, output_path, burn=True,
model_size="base", source_lang=None, style=None):
"""Create a video with translated subtitles
Args:
video_path: Path to the input video
target_lang: Target language code
output_path: Path to save the output video
burn: Whether to burn subtitles into video
model_size: Whisper model size
source_lang: Source language code (optional)
style: Subtitle style options
Returns:
Path to the output video (if burn=True) or tuple of (video, srt_path)
"""
print(f"\n🎬 Creating video with translated subtitles")
print(f" Input: {video_path}")
print(f" Target language: {target_lang}")
print(f" Burn subtitles: {burn}")
print()
# Create subtitles
output_dir = os.path.dirname(output_path) or "."
original_srt, translated_srt = create_translated_subtitles(
video_path, target_lang, output_dir, model_size, source_lang
)
if not translated_srt:
return None
if burn:
# Burn subtitles into video
result = burn_subtitles(video_path, translated_srt, output_path, style)
return result
else:
# Return video path and subtitle path
return video_path, translated_srt
# ──────────────────────────────────────────────────────────────────────────────
# CHARACTER CONSISTENCY FEATURES
# ──────────────────────────────────────────────────────────────────────────────
......@@ -6905,6 +7370,39 @@ List TTS voices:
parser.add_argument("--audio_file", type=str, default=None,
help="Use external audio file instead of generating (for sync/lip sync)")
# ─── VIDEO DUBBING & TRANSLATION ARGUMENTS ───────────────────────────────────
parser.add_argument("--transcribe", action="store_true",
help="Transcribe audio from video (requires Whisper)")
parser.add_argument("--whisper-model", choices=["tiny", "base", "small", "medium", "large"],
default="base",
help="Whisper model size for transcription (default: base)")
parser.add_argument("--source-lang", type=str, default=None,
metavar="LANG",
help="Source language code (e.g., en, es, fr). Auto-detected if not specified.")
parser.add_argument("--target-lang", type=str, default=None,
metavar="LANG",
help="Target language code for translation (e.g., en, es, fr)")
# Subtitle generation
parser.add_argument("--create-subtitles", action="store_true",
help="Create SRT subtitles from video audio")
parser.add_argument("--translate-subtitles", action="store_true",
help="Translate subtitles to target language (use with --target-lang)")
parser.add_argument("--burn-subtitles", action="store_true",
help="Burn subtitles into video (use with --create-subtitles)")
parser.add_argument("--subtitle-style", type=str, default=None,
metavar="STYLE",
help="Subtitle style: font_size=24,font_color=white,outline_color=black")
# Video dubbing
parser.add_argument("--dub-video", action="store_true",
help="Dub video with translated audio (preserves voice with voice cloning)")
parser.add_argument("--voice-clone", action="store_true", default=True,
help="Use voice cloning to preserve original voice in dubbing")
parser.add_argument("--no-voice-clone", action="store_true",
help="Disable voice cloning, use standard TTS for dubbing")
# ─── MODEL DISCOVERY ARGUMENTS ───────────────────────────────────────────────
parser.add_argument("--show-model", type=str, default=None,
......
......@@ -661,6 +661,134 @@ async def list_tools() -> list:
"properties": {}
}
),
Tool(
name="videogen_transcribe_video",
description="Transcribe audio from a video using Whisper AI. Extracts spoken text with timestamps.",
inputSchema={
"type": "object",
"properties": {
"video": {
"type": "string",
"description": "Path to the input video file"
},
"model_size": {
"type": "string",
"enum": ["tiny", "base", "small", "medium", "large"],
"description": "Whisper model size (larger = more accurate, slower)",
"default": "base"
},
"language": {
"type": "string",
"description": "Source language code (e.g., en, es, fr). Auto-detected if not specified."
}
},
"required": ["video"]
}
),
Tool(
name="videogen_create_subtitles",
description="Create SRT subtitles from video audio. Optionally translate to another language.",
inputSchema={
"type": "object",
"properties": {
"video": {
"type": "string",
"description": "Path to the input video file"
},
"target_lang": {
"type": "string",
"description": "Target language code for translation (e.g., en, es, fr, de, zh, ja)"
},
"source_lang": {
"type": "string",
"description": "Source language code. Auto-detected if not specified."
},
"model_size": {
"type": "string",
"enum": ["tiny", "base", "small", "medium", "large"],
"default": "base"
},
"burn": {
"type": "boolean",
"description": "Burn subtitles into video",
"default": False
},
"output": {
"type": "string",
"description": "Output video path (if burning) or SRT file path",
"default": "output"
}
},
"required": ["video"]
}
),
Tool(
name="videogen_dub_video",
description="Translate and dub a video with voice preservation. Replaces original audio with translated speech while maintaining the original voice characteristics.",
inputSchema={
"type": "object",
"properties": {
"video": {
"type": "string",
"description": "Path to the input video file"
},
"target_lang": {
"type": "string",
"description": "Target language code (e.g., en, es, fr, de, zh, ja)"
},
"source_lang": {
"type": "string",
"description": "Source language code. Auto-detected if not specified."
},
"voice_clone": {
"type": "boolean",
"description": "Use voice cloning to preserve original voice",
"default": True
},
"tts_voice": {
"type": "string",
"description": "TTS voice to use if not voice cloning (e.g., edge_female_us)"
},
"model_size": {
"type": "string",
"enum": ["tiny", "base", "small", "medium", "large"],
"default": "base"
},
"output": {
"type": "string",
"description": "Output video path",
"default": "output"
}
},
"required": ["video", "target_lang"]
}
),
Tool(
name="videogen_translate_text",
description="Translate text between languages using MarianMT models.",
inputSchema={
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "Text to translate"
},
"source_lang": {
"type": "string",
"description": "Source language code (e.g., en, es, fr)"
},
"target_lang": {
"type": "string",
"description": "Target language code (e.g., en, es, fr)"
}
},
"required": ["text", "source_lang", "target_lang"]
}
),
]
......@@ -939,6 +1067,62 @@ async def call_tool(name: str, arguments: dict) -> list:
output, code = run_videogen_command(args)
return [TextContent(type="text", text=output)]
elif name == "videogen_transcribe_video":
args = [
"--video", arguments["video"],
"--transcribe",
"--whisper-model", arguments.get("model_size", "base"),
]
if arguments.get("language"):
args.extend(["--source-lang", arguments["language"]])
output, code = run_videogen_command(args, timeout=1800)
return [TextContent(type="text", text=output)]
elif name == "videogen_create_subtitles":
args = [
"--video", arguments["video"],
"--create-subtitles",
"--whisper-model", arguments.get("model_size", "base"),
"--output", arguments.get("output", "output"),
]
if arguments.get("source_lang"):
args.extend(["--source-lang", arguments["source_lang"]])
if arguments.get("target_lang"):
args.extend(["--target-lang", arguments["target_lang"], "--translate-subtitles"])
if arguments.get("burn"):
args.append("--burn-subtitles")
output, code = run_videogen_command(args, timeout=1800)
return [TextContent(type="text", text=output)]
elif name == "videogen_dub_video":
args = [
"--video", arguments["video"],
"--dub-video",
"--target-lang", arguments["target_lang"],
"--whisper-model", arguments.get("model_size", "base"),
"--output", arguments.get("output", "output"),
]
if arguments.get("source_lang"):
args.extend(["--source-lang", arguments["source_lang"]])
if arguments.get("voice_clone", True):
args.append("--voice-clone")
else:
args.append("--no-voice-clone")
if arguments.get("tts_voice"):
args.extend(["--tts_voice", arguments["tts_voice"]])
output, code = run_videogen_command(args, timeout=3600)
return [TextContent(type="text", text=output)]
elif name == "videogen_translate_text":
# This is a direct translation without video - we'll use the main script's translation
args = [
"--translate-text", arguments["text"],
"--source-lang", arguments["source_lang"],
"--target-lang", arguments["target_lang"],
]
output, code = run_videogen_command(args)
return [TextContent(type="text", text=output)]
else:
return [TextContent(type="text", text=f"Unknown tool: {name}")]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment