Opera8 commited on
Commit
2775a80
·
verified ·
1 Parent(s): 3fbd4a0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -35
app.py CHANGED
@@ -90,7 +90,7 @@ os.makedirs("ckpts/Vevo", exist_ok=True)
90
 
91
  from models.vc.vevo.vevo_utils import VevoInferencePipeline
92
 
93
- # تابع ذخیره سازی اختصاصی برای جلوگیری از ارور TorchCodec
94
  def my_save_audio(waveform, output_path, sample_rate=24000):
95
  try:
96
  if isinstance(waveform, torch.Tensor):
@@ -109,7 +109,7 @@ def setup_configs():
109
  if downloaded_resources["configs"]: return
110
  config_path = "models/vc/vevo/config"
111
  os.makedirs(config_path, exist_ok=True)
112
- config_files = ["Vq8192ToMels.json", "Vocoder.json"] # فقط کانفیگ‌های تیمبر
113
 
114
  for file in config_files:
115
  file_path = f"{config_path}/{file}"
@@ -127,7 +127,6 @@ print(f"Using device: {device}")
127
 
128
  inference_pipelines = {}
129
 
130
- # دانلود منابع (فقط بخش‌های مورد نیاز Timbre)
131
  def preload_all_resources():
132
  print("Preloading Timbre resources...")
133
  setup_configs()
@@ -163,14 +162,12 @@ def get_pipeline():
163
  if "timbre" in inference_pipelines:
164
  return inference_pipelines["timbre"]
165
 
166
- # مسیرها
167
  content_style_tokenizer_ckpt_path = os.path.join(downloaded_content_style_tokenizer_path, "tokenizer/vq8192")
168
  fmt_cfg_path = "./models/vc/vevo/config/Vq8192ToMels.json"
169
  fmt_ckpt_path = os.path.join(downloaded_fmt_path, "acoustic_modeling/Vq8192ToMels")
170
  vocoder_cfg_path = "./models/vc/vevo/config/Vocoder.json"
171
  vocoder_ckpt_path = os.path.join(downloaded_vocoder_path, "acoustic_modeling/Vocoder")
172
 
173
- # ساخت پایپ‌لاین فقط برای Timbre
174
  pipeline = VevoInferencePipeline(
175
  content_style_tokenizer_ckpt_path=content_style_tokenizer_ckpt_path,
176
  fmt_cfg_path=fmt_cfg_path,
@@ -192,7 +189,7 @@ def vevo_timbre(content_wav, reference_wav):
192
  if content_wav is None or reference_wav is None:
193
  raise ValueError("Please upload audio files")
194
 
195
- # پردازش صدای اصلی
196
  if isinstance(content_wav, tuple):
197
  content_sr, content_data = content_wav if isinstance(content_wav[0], int) else (content_wav[1], content_wav[0])
198
  else:
@@ -201,7 +198,6 @@ def vevo_timbre(content_wav, reference_wav):
201
  if len(content_data.shape) > 1 and content_data.shape[1] > 1:
202
  content_data = np.mean(content_data, axis=1)
203
 
204
- # ریسمپل به 24k
205
  content_tensor = torch.FloatTensor(content_data).unsqueeze(0)
206
  if content_sr != 24000:
207
  content_tensor = torchaudio.functional.resample(content_tensor, content_sr, 24000)
@@ -209,7 +205,7 @@ def vevo_timbre(content_wav, reference_wav):
209
 
210
  content_tensor = content_tensor / (torch.max(torch.abs(content_tensor)) + 1e-6) * 0.95
211
 
212
- # پردازش صدای رفرنس (Timbre)
213
  if isinstance(reference_wav, tuple):
214
  ref_sr, ref_data = reference_wav if isinstance(reference_wav[0], int) else (reference_wav[1], reference_wav[0])
215
  else:
@@ -225,45 +221,83 @@ def vevo_timbre(content_wav, reference_wav):
225
 
226
  ref_tensor = ref_tensor / (torch.max(torch.abs(ref_tensor)) + 1e-6) * 0.95
227
 
228
- print(f"Processing Timbre Swap... Content Length: {content_tensor.shape[-1]/24000:.2f}s")
229
-
230
- # ذخیره موقت فایل‌ها
231
- sf.write(temp_content_path, content_tensor.squeeze().cpu().numpy(), content_sr)
 
 
232
  sf.write(temp_reference_path, ref_tensor.squeeze().cpu().numpy(), ref_sr)
233
 
234
- try:
235
- pipeline = get_pipeline()
 
 
 
 
 
 
 
 
 
 
 
 
 
236
 
237
- gen_audio = pipeline.inference_fm(
238
- src_wav_path=temp_content_path,
239
- timbre_ref_wav_path=temp_reference_path,
240
- flow_matching_steps=32,
241
- )
242
 
243
- if torch.isnan(gen_audio).any() or torch.isinf(gen_audio).any():
244
- print("Warning: NaN detected, fixing...")
245
- gen_audio = torch.nan_to_num(gen_audio, nan=0.0, posinf=0.95, neginf=-0.95)
246
 
247
- # ذخیره خروجی
248
- my_save_audio(gen_audio, output_path=output_path)
249
- return output_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
 
251
- except Exception as e:
252
- print(f"Error: {e}")
253
- raise e
 
 
 
 
 
 
 
 
254
 
255
- # رابط کاربری ساده فقط برای Vevo-Timbre
256
- with gr.Blocks(title="Vevo-Timbre Only") as demo:
257
- gr.Markdown("## Vevo-Timbre: Zero-Shot Voice Conversion")
258
- gr.Markdown("**نکته:** برای بهترین کیفیت، از فایل‌های صوتی زیر ۲۰ ثانیه استفاده کنید. فایل‌های طولانی ممکن است دچار افت کیفیت شوند.")
259
 
260
  with gr.Row():
261
  with gr.Column():
262
- timbre_content = gr.Audio(label="Source Audio (صدای اصلی)", type="numpy")
263
- timbre_reference = gr.Audio(label="Target Timbre (صدای هدف)", type="numpy")
264
  timbre_button = gr.Button("Generate (ساخت صدا)", variant="primary")
265
  with gr.Column():
266
- timbre_output = gr.Audio(label="Result (خروجی)")
267
 
268
  timbre_button.click(vevo_timbre, inputs=[timbre_content, timbre_reference], outputs=timbre_output)
269
 
 
90
 
91
  from models.vc.vevo.vevo_utils import VevoInferencePipeline
92
 
93
+ # تابع ذخیره سازی اختصاصی
94
  def my_save_audio(waveform, output_path, sample_rate=24000):
95
  try:
96
  if isinstance(waveform, torch.Tensor):
 
109
  if downloaded_resources["configs"]: return
110
  config_path = "models/vc/vevo/config"
111
  os.makedirs(config_path, exist_ok=True)
112
+ config_files = ["Vq8192ToMels.json", "Vocoder.json"]
113
 
114
  for file in config_files:
115
  file_path = f"{config_path}/{file}"
 
127
 
128
  inference_pipelines = {}
129
 
 
130
  def preload_all_resources():
131
  print("Preloading Timbre resources...")
132
  setup_configs()
 
162
  if "timbre" in inference_pipelines:
163
  return inference_pipelines["timbre"]
164
 
 
165
  content_style_tokenizer_ckpt_path = os.path.join(downloaded_content_style_tokenizer_path, "tokenizer/vq8192")
166
  fmt_cfg_path = "./models/vc/vevo/config/Vq8192ToMels.json"
167
  fmt_ckpt_path = os.path.join(downloaded_fmt_path, "acoustic_modeling/Vq8192ToMels")
168
  vocoder_cfg_path = "./models/vc/vevo/config/Vocoder.json"
169
  vocoder_ckpt_path = os.path.join(downloaded_vocoder_path, "acoustic_modeling/Vocoder")
170
 
 
171
  pipeline = VevoInferencePipeline(
172
  content_style_tokenizer_ckpt_path=content_style_tokenizer_ckpt_path,
173
  fmt_cfg_path=fmt_cfg_path,
 
189
  if content_wav is None or reference_wav is None:
190
  raise ValueError("Please upload audio files")
191
 
192
+ # --- بارگذاری و پردازش صدای اصلی (Content) ---
193
  if isinstance(content_wav, tuple):
194
  content_sr, content_data = content_wav if isinstance(content_wav[0], int) else (content_wav[1], content_wav[0])
195
  else:
 
198
  if len(content_data.shape) > 1 and content_data.shape[1] > 1:
199
  content_data = np.mean(content_data, axis=1)
200
 
 
201
  content_tensor = torch.FloatTensor(content_data).unsqueeze(0)
202
  if content_sr != 24000:
203
  content_tensor = torchaudio.functional.resample(content_tensor, content_sr, 24000)
 
205
 
206
  content_tensor = content_tensor / (torch.max(torch.abs(content_tensor)) + 1e-6) * 0.95
207
 
208
+ # --- بارگذاری و پردازش صدای رفرنس (Reference) ---
209
  if isinstance(reference_wav, tuple):
210
  ref_sr, ref_data = reference_wav if isinstance(reference_wav[0], int) else (reference_wav[1], reference_wav[0])
211
  else:
 
221
 
222
  ref_tensor = ref_tensor / (torch.max(torch.abs(ref_tensor)) + 1e-6) * 0.95
223
 
224
+ # برش زدن صدای رفرنس به 20 ثانیه اول (برای جلوگیری از گیج شدن مدل)
225
+ # صدای رفرنس فقط برای برداشتن "رنگ صدا" استفاده میشه و 20 ثانیه کافیه
226
+ if ref_tensor.shape[1] > 24000 * 20:
227
+ ref_tensor = ref_tensor[:, :24000 * 20]
228
+
229
+ # ذخیره موقت صدای رفرنس
230
  sf.write(temp_reference_path, ref_tensor.squeeze().cpu().numpy(), ref_sr)
231
 
232
+ print(f"Total Duration: {content_tensor.shape[1]/24000:.2f}s")
233
+
234
+ # --- تکه تکه کردن صدای اصلی (Chunking Logic) ---
235
+ pipeline = get_pipeline()
236
+
237
+ CHUNK_DURATION = 15 # ثانیه (اندازه هر تکه)
238
+ CHUNK_SAMPLES = CHUNK_DURATION * 24000
239
+ total_samples = content_tensor.shape[1]
240
+
241
+ generated_chunks = []
242
+
243
+ # حلقه برای پردازش تکه تکه
244
+ for i in range(0, total_samples, CHUNK_SAMPLES):
245
+ end = min(i + CHUNK_SAMPLES, total_samples)
246
+ chunk = content_tensor[:, i:end]
247
 
248
+ print(f"Processing Chunk: {i/24000:.1f}s to {end/24000:.1f}s")
 
 
 
 
249
 
250
+ # ذخیره تکه جاری
251
+ sf.write(temp_content_path, chunk.squeeze().cpu().numpy(), 24000)
 
252
 
253
+ try:
254
+ # پردازش تکه
255
+ gen_chunk = pipeline.inference_fm(
256
+ src_wav_path=temp_content_path,
257
+ timbre_ref_wav_path=temp_reference_path,
258
+ flow_matching_steps=32,
259
+ )
260
+
261
+ # بررسی خرابی احتمالی
262
+ if torch.isnan(gen_chunk).any() or torch.isinf(gen_chunk).any():
263
+ print("Warning: NaN in chunk, fixing...")
264
+ gen_chunk = torch.nan_to_num(gen_chunk, nan=0.0, posinf=0.95, neginf=-0.95)
265
+
266
+ # اضافه کردن به لیست خروجی‌ها (مطمئن میشیم دوبعدی باشه [1, T])
267
+ if gen_chunk.dim() == 1:
268
+ gen_chunk = gen_chunk.unsqueeze(0)
269
+ generated_chunks.append(gen_chunk.cpu())
270
+
271
+ except Exception as e:
272
+ print(f"Error processing chunk starting at {i}: {e}")
273
+ # در صورت خطا در یک تکه، سکوت جایگزین میکنیم تا کل فایل خراب نشه
274
+ silence = torch.zeros_like(chunk)
275
+ generated_chunks.append(silence)
276
 
277
+ # --- چسباندن تکه‌ها به هم ---
278
+ if not generated_chunks:
279
+ raise ValueError("No audio generated")
280
+
281
+ final_audio = torch.cat(generated_chunks, dim=1)
282
+
283
+ print(f"Final Audio Duration: {final_audio.shape[1]/24000:.2f}s")
284
+
285
+ # ذخیره خروجی نهایی
286
+ my_save_audio(final_audio, output_path=output_path)
287
+ return output_path
288
 
289
+ # رابط کاربری
290
+ with gr.Blocks(title="Vevo-Timbre (Long Audio Fix)") as demo:
291
+ gr.Markdown("## Vevo-Timbre: Zero-Shot Voice Conversion (Unlimited Length)")
292
+ gr.Markdown("این نسخه فایل‌های طولانی را به صورت اتوماتیک به تکه‌های ۱۵ ثانیه‌ای تقسیم کرده و پردازش می‌کند تا صدا خراب نشود.")
293
 
294
  with gr.Row():
295
  with gr.Column():
296
+ timbre_content = gr.Audio(label="Source Audio (صدای اصلی - هر چقدر طولانی باشد مشکلی نیست)", type="numpy")
297
+ timbre_reference = gr.Audio(label="Target Timbre (صدای هدف - ۲۰ ثانیه اول استفاده میشود)", type="numpy")
298
  timbre_button = gr.Button("Generate (ساخت صدا)", variant="primary")
299
  with gr.Column():
300
+ timbre_output = gr.Audio(label="Result (خروجی نهایی)")
301
 
302
  timbre_button.click(vevo_timbre, inputs=[timbre_content, timbre_reference], outputs=timbre_output)
303