Opera8 commited on
Commit
4daa9fc
·
verified ·
1 Parent(s): e701255

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile (2).txt +36 -0
  2. README (3).md +35 -0
  3. app (3).py +239 -0
  4. requirements (4).txt +35 -0
Dockerfile (2).txt ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use a base image with Python and CUDA support
2
+ FROM nvidia/cuda:12.1.1-cudnn8-devel-ubuntu22.04
3
+
4
+ # Set environment variables to prevent interactive prompts
5
+ ENV DEBIAN_FRONTEND=noninteractive
6
+ ENV TZ=Etc/UTC
7
+
8
+ # Install system dependencies including build-essential for compiling packages
9
+ RUN apt-get update -y && \
10
+ apt-get install -y --no-install-recommends \
11
+ build-essential \
12
+ python3.10 python3-pip python3.10-venv git git-lfs ffmpeg rubberband-cli libsndfile1 && \
13
+ apt-get clean && \
14
+ rm -rf /var/lib/apt/lists/*
15
+
16
+ # Set up git-lfs
17
+ RUN git lfs install
18
+
19
+ # Create a working directory
20
+ WORKDIR /app
21
+
22
+ # Copy the requirements file first to leverage Docker cache
23
+ COPY requirements.txt .
24
+
25
+ # Upgrade pip and install Python dependencies
26
+ RUN python3 -m pip install --no-cache-dir --upgrade pip && \
27
+ python3 -m pip install --no-cache-dir -r requirements.txt
28
+
29
+ # Copy the rest of the application code
30
+ COPY . .
31
+
32
+ # Expose the port Gradio will run on
33
+ EXPOSE 7860
34
+
35
+ # Command to run the Gradio application
36
+ CMD ["python3", "app.py"]
README (3).md ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: AI Video Dubbing Tool
3
+ emoji: 📽️
4
+ colorFrom: red
5
+ colorTo: yellow
6
+ sdk: docker
7
+ app_port: 7860
8
+ ---
9
+
10
+ # 📽️ ابزار دوبله ویدیو با هوش مصنوعی
11
+
12
+ ## ⚠️ نکته مهم برای اجرای اولیه
13
+
14
+ برای استفاده از قابلیت ترجمه، شما نیاز به یک کلید API از **Google AI Studio** دارید.
15
+
16
+ 1. به تب **Settings** در بالای همین صفحه بروید.
17
+ 2. در بخش **Secrets**، یک سکرت جدید با نام `GOOGLE_API_KEY` ایجاد کنید.
18
+ 3. مقدار کلید API خود را در فیلد **Secret value** قرار دهید و ذخیره کنید.
19
+
20
+ ## ✨ قابلیت‌ها
21
+
22
+ - **آپلود مستقیم ویدیو** یا استفاده از **لینک یوتیوب**.
23
+ - **استخراج خودکار متن** از ویدیو با استفاده از مدل WhisperX.
24
+ - **تشخیص گویندگان مختلف** در ویدیو (Diarization).
25
+ - **ترجمه هوشمند** متن به زبان‌های مختلف با Google Gemini.
26
+ - **تولید صدای دوبله** با کیفیت بالا با استفاده از Edge-TTS.
27
+ - **همگام‌سازی دقیق** صدای دوبله با زمان‌بندی اصلی ویدیو.
28
+
29
+ ## ⚙️ نحوه استفاده
30
+
31
+ 1. **ورودی ویدیو:** فایل ویدیویی خود را آپلود کنید یا لینک یک ویدیو از یوتیوب را وارد کنید.
32
+ 2. **تنظیمات دوبله:** زبان اصلی و زبان مقصد را انتخاب کنید. سپس صدای گوینده مورد نظر خود را از لیست انتخاب نمایید.
33
+ 3. **شروع فرآیند:** روی دکمه **"شروع دوبله"** کلیک کنید و منتظر بمانید.
34
+
35
+ **توجه:** فرآیند دوبله، به خصوص مرحله استخراج متن، در پلن رایگان هاگینگ فیس (که از CPU استفاده می‌کند) ممکن است **بسیار زمان‌بر** باشد. برای عملکرد بهتر، استفاده از سخت‌افزار دارای GPU (مانند پلن‌های پولی هاگینگ فیس) توصیه می‌شود.
app (3).py ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import torch
4
+ from soni_translate.logging_setup import logger, set_logging_level, configure_logging_libs
5
+ configure_logging_libs()
6
+ import whisperx
7
+ from soni_translate.preprocessor import audio_video_preprocessor, audio_preprocessor
8
+ from soni_translate.postprocessor import media_out, get_no_ext_filename, sound_separate, get_subtitle_speaker
9
+ from soni_translate.speech_segmentation import transcribe_speech, align_speech, diarize_speech, ASR_MODEL_OPTIONS, find_whisper_models, diarization_models, COMPUTE_TYPE_CPU, COMPUTE_TYPE_GPU
10
+ from soni_translate.translate_segments import translate_text, TRANSLATION_PROCESS_OPTIONS
11
+ from soni_translate.text_to_speech import audio_segmentation_to_voice, edge_tts_voices_list, coqui_xtts_voices_list, piper_tts_voices_list
12
+ from soni_translate.audio_segments import create_translated_audio, accelerate_segments
13
+ from soni_translate.language_configuration import LANGUAGES, LANGUAGES_LIST
14
+ from soni_translate.utils import remove_files, get_link_list, get_valid_files, is_audio_file, is_subtitle_file
15
+ from soni_translate.text_multiformat_processor import process_subtitles, srt_file_to_segments, break_aling_segments
16
+ from soni_translate.languages_gui import language_data
17
+ import hashlib
18
+ import json
19
+ import copy
20
+ from pydub import AudioSegment
21
+
22
+ # Check for API key from Hugging Face Secrets
23
+ if "GOOGLE_API_KEY" in os.environ:
24
+ print("✅ Google API Key found in secrets.")
25
+ else:
26
+ print("⚠️ Google API Key not found. Please set it in the Space secrets.")
27
+
28
+ if "OPENAI_API_KEY" in os.environ:
29
+ print("✅ OpenAI API Key found in secrets.")
30
+ else:
31
+ print("⚠️ OpenAI API Key not found. Please set it in the Space secrets if you use OpenAI models.")
32
+
33
+
34
+ # Create necessary directories
35
+ directories = ["downloads", "logs", "weights", "clean_song_output", "_XTTS_", "audio", "outputs"]
36
+ for directory in directories:
37
+ if not os.path.exists(directory):
38
+ os.makedirs(directory)
39
+
40
+ class SoniTranslate:
41
+ def __init__(self):
42
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
43
+ logger.info(f"Working on device: {self.device}")
44
+ self.result_diarize = None
45
+ self.align_language = None
46
+ self.result_source_lang = None
47
+ self.tts_info = self._get_tts_info()
48
+
49
+ def _get_tts_info(self):
50
+ # Simplified for this example
51
+ class TTS_Info:
52
+ def tts_list(self):
53
+ try:
54
+ return edge_tts_voices_list()
55
+ except Exception as e:
56
+ logger.warning(f"Could not get Edge-TTS voices: {e}")
57
+ return ["en-US-JennyNeural-Female"] # fallback
58
+ return TTS_Info()
59
+
60
+ def multilingual_media_conversion(
61
+ self,
62
+ media_file,
63
+ link_media,
64
+ directory_input,
65
+ origin_language,
66
+ target_language,
67
+ tts_voice,
68
+ transcriber_model,
69
+ max_speakers,
70
+ is_gui=True,
71
+ progress=gr.Progress(),
72
+ ):
73
+ # Simplified function adapted from your notebook
74
+ try:
75
+ progress(0.05, desc="Starting process...")
76
+
77
+ # 1. Handle Input
78
+ input_media = None
79
+ if media_file is not None:
80
+ input_media = media_file.name
81
+ elif link_media:
82
+ input_media = link_media
83
+ elif directory_input and os.path.exists(directory_input):
84
+ input_media = directory_input
85
+
86
+ if not input_media:
87
+ raise ValueError("No input media specified. Please upload a file or provide a URL.")
88
+
89
+ base_audio_wav = "audio.wav"
90
+ base_video_file = "video.mp4"
91
+
92
+ remove_files(base_audio_wav, base_video_file)
93
+
94
+ progress(0.1, desc="Processing input media...")
95
+ if is_audio_file(input_media):
96
+ audio_preprocessor(False, input_media, base_audio_wav)
97
+ else:
98
+ audio_video_preprocessor(False, input_media, base_video_file, base_audio_wav)
99
+
100
+ # 2. Transcription
101
+ progress(0.25, desc="Transcribing audio with WhisperX...")
102
+ source_lang_code = LANGUAGES[origin_language] if origin_language != "Automatic detection" else None
103
+
104
+ # On free CPU hardware, force a smaller model to avoid timeouts
105
+ if self.device == "cpu":
106
+ logger.warning("Running on CPU. Forcing 'medium' Whisper model for better performance.")
107
+ transcriber_model = "medium"
108
+
109
+ audio, result = transcribe_speech(
110
+ base_audio_wav,
111
+ transcriber_model,
112
+ "int8" if self.device == "cpu" else "float16",
113
+ 16,
114
+ source_lang_code
115
+ )
116
+
117
+ progress(0.4, desc="Aligning transcription...")
118
+ self.align_language = result["language"]
119
+ result = align_speech(audio, result)
120
+
121
+ # 3. Diarization
122
+ progress(0.5, desc="Separating speakers...")
123
+ hf_token = os.environ.get("HF_TOKEN") # HF token can be set as a secret too
124
+ if not hf_token:
125
+ logger.warning("Hugging Face token not found. Diarization might fail.")
126
+
127
+ self.result_diarize = diarize_speech(
128
+ base_audio_wav,
129
+ result,
130
+ 1,
131
+ max_speakers,
132
+ hf_token,
133
+ diarization_models["pyannote_3.1"]
134
+ )
135
+ self.result_source_lang = copy.deepcopy(self.result_diarize)
136
+
137
+ # 4. Translation
138
+ progress(0.6, desc="Translating text...")
139
+ translate_to_code = LANGUAGES[target_language]
140
+ self.result_diarize["segments"] = translate_text(
141
+ self.result_diarize["segments"],
142
+ translate_to_code,
143
+ "google_translator_batch", # Using a free translator
144
+ chunk_size=1800,
145
+ source=self.align_language,
146
+ )
147
+
148
+ # 5. Text-to-Speech
149
+ progress(0.75, desc="Generating dubbed audio...")
150
+ valid_speakers = audio_segmentation_to_voice(
151
+ self.result_diarize,
152
+ translate_to_code,
153
+ is_gui,
154
+ tts_voice
155
+ )
156
+
157
+ # 6. Audio Processing & Merging
158
+ progress(0.85, desc="Synchronizing and mixing audio...")
159
+ dub_audio_file = "audio_dub_solo.ogg"
160
+ remove_files(dub_audio_file)
161
+ audio_files, _ = accelerate_segments(self.result_diarize, 1.8, valid_speakers)
162
+ create_translated_audio(self.result_diarize, audio_files, dub_audio_file, False, False)
163
+
164
+ mix_audio_file = "audio_mix.mp3"
165
+ remove_files(mix_audio_file)
166
+ command_volume_mix = f'ffmpeg -y -i {base_audio_wav} -i {dub_audio_file} -filter_complex "[0:0]volume=0.1[a];[1:0]volume=1.5[b];[a][b]amix=inputs=2:duration=longest" -c:a libmp3lame {mix_audio_file}'
167
+ os.system(command_volume_mix)
168
+
169
+ # 7. Final Video Creation
170
+ progress(0.95, desc="Creating final video...")
171
+ output_filename = "video_dub.mp4"
172
+ remove_files(output_filename)
173
+
174
+ if os.path.exists(base_video_file):
175
+ os.system(f"ffmpeg -i {base_video_file} -i {mix_audio_file} -c:v copy -c:a copy -map 0:v -map 1:a -shortest {output_filename}")
176
+ final_output = media_out(input_media, translate_to_code, "", "mp4", file_obj=output_filename)
177
+ else: # Audio only output
178
+ final_output = media_out(input_media, translate_to_code, "", "mp3", file_obj=mix_audio_file)
179
+
180
+ progress(1.0, desc="Done!")
181
+ return final_output
182
+
183
+ except Exception as e:
184
+ logger.error(f"An error occurred: {e}")
185
+ gr.Error(f"An error occurred: {e}")
186
+ return None
187
+
188
+ # Instantiate the class
189
+ SoniTr = SoniTranslate()
190
+
191
+ # Create Gradio Interface
192
+ with gr.Blocks(theme="Taithrah/Minimal") as app:
193
+ gr.Markdown("<center><h1>📽️ ابزار دوبله ویدیو با هوش مصنوعی 🈷️</h1></center>")
194
+ gr.Markdown("ساخته شده توسط [aigolden](https://youtube.com/@aigolden) - بر پایه [SoniTranslate](https://github.com/r3gm/SoniTranslate)")
195
+
196
+ with gr.Row():
197
+ with gr.Column():
198
+ gr.Markdown("### ۱. ورودی ویدیو")
199
+ video_file_input = gr.File(label="آپلود ویدیو")
200
+ link_media_input = gr.Textbox(label="یا لینک یوتیوب", placeholder="https://www.youtube.com/watch?v=...")
201
+
202
+ gr.Markdown("### ۲. تنظیمات دوبله")
203
+ origin_language_input = gr.Dropdown(LANGUAGES_LIST, value="Automatic detection", label="زبان اصلی ویدیو")
204
+ target_language_input = gr.Dropdown(LANGUAGES_LIST[1:], value="Persian (fa)", label="زبان مقصد دوبله")
205
+ tts_voice_input = gr.Dropdown(SoniTr.tts_info.tts_list(), value="fa-IR-FaridNeural", label="صدای گوینده")
206
+
207
+ with gr.Accordion("تنظیمات پیشرفته", open=False):
208
+ transcriber_model_input = gr.Dropdown(
209
+ ASR_MODEL_OPTIONS + find_whisper_models(),
210
+ value="large-v3",
211
+ label="مدل استخراج متن (Whisper)",
212
+ info="مدل‌های بزرگتر دقیق‌تر اما کندتر هستند. در پلن رایگان مدل 'medium' توصیه می‌شود."
213
+ )
214
+ max_speakers_input = gr.Slider(1, 10, value=2, step=1, label="حداکثر تعداد گوینده")
215
+
216
+ process_button = gr.Button("شروع دوبله", variant="primary")
217
+
218
+ with gr.Column():
219
+ gr.Markdown("### ۳. خروجی")
220
+ output_video = gr.Video(label="ویدیوی دوبله شده")
221
+ output_file = gr.File(label="دانلود فای��")
222
+
223
+ process_button.click(
224
+ SoniTr.multilingual_media_conversion,
225
+ inputs=[
226
+ video_file_input,
227
+ link_media_input,
228
+ gr.Textbox(visible=False), # Placeholder for directory input
229
+ origin_language_input,
230
+ target_language_input,
231
+ tts_voice_input,
232
+ transcriber_model_input,
233
+ max_speakers_input,
234
+ ],
235
+ outputs=[output_file]
236
+ )
237
+
238
+ if __name__ == "__main__":
239
+ app.launch(server_name="0.0.0.0", server_port=7860)
requirements (4).txt ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core libraries
2
+ gradio
3
+ torch
4
+ torchvision
5
+ torchaudio
6
+
7
+ # SoniTranslate Core Dependencies
8
+ # Using the specific version of whisperX from the Colab notebook
9
+ git+https://github.com/R3gm/whisperX.git@cuda_12_x
10
+ pyannote.audio==2.1.1
11
+ fairseq
12
+ yt-dlp
13
+ pysrt
14
+ pydub
15
+ faster-whisper
16
+ audiostretchy
17
+
18
+ # Translation and TTS
19
+ google-generativeai
20
+ openai
21
+ edge-tts
22
+ piper-tts==1.2.0
23
+ TTS==0.21.1
24
+
25
+ # Other utilities
26
+ numpy==1.25.2
27
+ soundfile
28
+ librosa
29
+ onnxruntime-gpu
30
+ tqdm
31
+ demucs
32
+ python-multipart
33
+ # Added based on potential dependencies from the code
34
+ tenacity
35
+ youtube-transcript-api