Spaces:
Running on Zero
Running on Zero
Download app.py from artificialguybr/video-dubbing: direct link, hf CLI and curl.
- Browser
- Download file 2.91 kB
-
https://huggingface.co/spaces/artificialguybr/video-dubbing/resolve/refs%2Fpr%2F45/app.py
- Command line
-
hf download hf://spaces/artificialguybr/video-dubbing@refs/pr/45/app.py
-
curl -L -o app.py https://huggingface.co/spaces/artificialguybr/video-dubbing/resolve/refs%2Fpr%2F45/app.py
2.91 kB
| import os | |
| import uuid | |
| import asyncio | |
| import subprocess | |
| import shutil | |
| import gradio as gr | |
| import edge_tts | |
| from deep_translator import GoogleTranslator | |
| from faster_whisper import WhisperModel | |
| import spaces | |
| MAX_VIDEO_DURATION = 60 | |
| model = WhisperModel("small", device="cpu", compute_type="int8") | |
| language_mapping = { | |
| "English": ("en", "en-US-EricNeural"), | |
| "Spanish": ("es", "es-ES-AlvaroNeural"), | |
| "French": ("fr", "fr-FR-HenriNeural"), | |
| "German": ("de", "de-DE-ConradNeural"), | |
| "Italian": ("it", "it-IT-DiegoNeural"), | |
| "Portuguese": ("pt", "pt-PT-DuarteNeural"), | |
| "Polish": ("pl", "pl-PL-MarekNeural"), | |
| "Turkish": ("tr", "tr-TR-AhmetNeural"), | |
| "Russian": ("ru", "ru-RU-DmitryNeural"), | |
| } | |
| def unique(ext): | |
| return f"{uuid.uuid4().hex}{ext}" | |
| def transcribe(audio): | |
| segments, _ = model.transcribe(audio) | |
| text = "" | |
| for seg in segments: | |
| text += seg.text + " " | |
| return text.strip() | |
| async def tts(text, voice, out): | |
| communicate = edge_tts.Communicate(text, voice) | |
| await communicate.save(out) | |
| def process(video, target_language): | |
| video = video.name if hasattr(video, "name") else video | |
| try: | |
| uid = uuid.uuid4().hex[:6] | |
| # безопасное имя файла | |
| safe_video = f"{uid}_input.mp4" | |
| shutil.copy(video, safe_video) | |
| resized = f"{uid}_720.mp4" | |
| subprocess.run( | |
| f'ffmpeg -y -i "{safe_video}" -vf scale=-2:720 "{resized}"', | |
| shell=True, | |
| check=True | |
| ) | |
| audio = f"{uid}.wav" | |
| subprocess.run( | |
| f'ffmpeg -y -i "{resized}" -vn -ac 1 -ar 16000 "{audio}"', | |
| shell=True, | |
| check=True | |
| ) | |
| text = transcribe(audio) | |
| lang, voice = language_mapping[target_language] | |
| translated = GoogleTranslator( | |
| source="auto", | |
| target=lang | |
| ).translate(text) | |
| speech = f"{uid}_tts.wav" | |
| asyncio.run(tts(translated, voice, speech)) | |
| out = f"{uid}_dubbed.mp4" | |
| subprocess.run( | |
| f'ffmpeg -y -i "{resized}" -i "{speech}" -c:v copy -c:a aac -map 0:v -map 1:a "{out}"', | |
| shell=True, | |
| check=True | |
| ) | |
| # cleanup | |
| for f in [safe_video, resized, audio, speech]: | |
| if os.path.exists(f): | |
| os.remove(f) | |
| return out, "" | |
| except Exception as e: | |
| return None, str(e) | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# AI Video Dubbing") | |
| video = gr.File(file_types=["video"]) | |
| lang = gr.Dropdown( | |
| list(language_mapping.keys()), | |
| value="Spanish" | |
| ) | |
| run = gr.Button("Process") | |
| out = gr.Video() | |
| status = gr.Textbox() | |
| run.click( | |
| process, | |
| inputs=[video, lang], | |
| outputs=[out, status] | |
| ) | |
| demo.queue() | |
| demo.launch(server_name="0.0.0.0", server_port=7860) |