Opera8 commited on
Commit
72c8333
·
verified ·
1 Parent(s): cd57ce8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -25
app.py CHANGED
@@ -14,7 +14,7 @@ import shutil
14
  import re
15
  import gradio as gr
16
 
17
- # --- 1. نصب و تنظیمات اولیه ---
18
 
19
  def install_espeak():
20
  try:
@@ -204,6 +204,84 @@ def get_pipeline():
204
  inference_pipelines["timbre"] = pipeline
205
  return pipeline
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  # =========================================================================
208
  # سیستم استنتاج مستقیم بر روی Zero-GPU با رابط کاربری Gradio
209
  # =========================================================================
@@ -218,10 +296,10 @@ def predict_voice_conversion(source_audio_path, ref_audio_path):
218
  SR = 24000
219
 
220
  try:
221
- # پردازش و بارگذاری صوت اصلی
222
  content_data, _ = librosa.load(source_audio_path, sr=SR)
223
 
224
- # پردازش و بارگذاری صوت مرجع
225
  ref_data, _ = librosa.load(ref_audio_path, sr=SR)
226
  ref_tensor = torch.FloatTensor(ref_data).unsqueeze(0)
227
  ref_tensor = ref_tensor / (torch.max(torch.abs(ref_tensor)) + 1e-6) * 0.95
@@ -229,26 +307,13 @@ def predict_voice_conversion(source_audio_path, ref_audio_path):
229
  temp_r = f"wav/{task_id}_temp_r.wav"
230
  save_audio_pcm16(ref_tensor, temp_r, SR)
231
 
232
- # تقسیم فایل صوتی اصلی به ب��ش‌های حداکثر ۶ ثانیه‌ای
233
- chunk_duration = 6 # ثانیه
234
- min_chunk_duration = 1.5 # حداقل طول مجاز برای آخرین قطعه (جهت جلوگیری از خطا)
235
- chunk_samples = int(chunk_duration * SR)
236
- min_samples = int(min_chunk_duration * SR)
237
- total_samples = len(content_data)
238
-
239
- chunks = []
240
- for i in range(0, total_samples, chunk_samples):
241
- chunks.append(content_data[i:i + chunk_samples])
242
-
243
- # در صورتی که قطعه آخر بسیار کوتاه باشد، آن را با قطعه قبلی ترکیب می‌کنیم
244
- if len(chunks) > 1 and len(chunks[-1]) < min_samples:
245
- last_chunk = chunks.pop()
246
- chunks[-1] = np.concatenate([chunks[-1], last_chunk])
247
 
248
  generated_chunks = []
249
  pipeline = get_pipeline()
250
 
251
- # پردازش نوبتی هر یک از قطعات صدا
252
  for idx, chunk in enumerate(chunks):
253
  chunk_tensor = torch.FloatTensor(chunk).unsqueeze(0)
254
  chunk_tensor = chunk_tensor / (torch.max(torch.abs(chunk_tensor)) + 1e-6) * 0.95
@@ -256,7 +321,6 @@ def predict_voice_conversion(source_audio_path, ref_audio_path):
256
  temp_c_chunk = f"wav/{task_id}_temp_c_{idx}.wav"
257
  save_audio_pcm16(chunk_tensor, temp_c_chunk, SR)
258
 
259
- # فراخوانی خط لوله مدل برای قطعه فعلی
260
  gen = pipeline.inference_fm(
261
  src_wav_path=temp_c_chunk,
262
  timbre_ref_wav_path=temp_r,
@@ -269,17 +333,15 @@ def predict_voice_conversion(source_audio_path, ref_audio_path):
269
 
270
  generated_chunks.append(gen_np)
271
 
272
- # پاکسازی قطعه موقت فعلی
273
  if os.path.exists(temp_c_chunk):
274
  os.remove(temp_c_chunk)
275
 
276
- # ادغام تمام قطعات خروجی شبیه‌سازی شده
277
  final_gen = np.concatenate(generated_chunks, axis=0)
278
 
279
- # ذخیره‌سازی نهایی فایل صوتی ادغام شده
280
  save_audio_pcm16(final_gen, out_path, SR)
281
 
282
- # پاکسازی فایل مرجع موقت
283
  if os.path.exists(temp_r):
284
  os.remove(temp_r)
285
 
@@ -288,7 +350,7 @@ def predict_voice_conversion(source_audio_path, ref_audio_path):
288
  except Exception as e:
289
  raise gr.Error(f"خطایی در حین پردازش رخ داد: {str(e)}")
290
 
291
- # طراحی ساختار وب با استفاده از Gradio (تم سازگار با نسخه جدید)
292
  with gr.Blocks() as demo:
293
  gr.Markdown("# سامانه تبدیل صدا (Vevo Voice Conversion) - نسخه Zero-GPU PRO")
294
 
 
14
  import re
15
  import gradio as gr
16
 
17
+ # --- 1. نصب و تنظیمات اولیه (بدون تغییر) ---
18
 
19
  def install_espeak():
20
  try:
 
204
  inference_pipelines["timbre"] = pipeline
205
  return pipeline
206
 
207
+
208
+ # --- تابع جدید برش هوشمند با قابلیت افزایش داینامیک بازه جستجو ---
209
+ def smart_split_audio_vevo(y, sr, min_segment=4):
210
+ total_samples = len(y)
211
+ current_sample = 0
212
+ chunks = []
213
+
214
+ # اگر طول کل فایل کمتر از حد مجاز اولیه (8 ثانیه) باشد، نیازی به برش نیست
215
+ if total_samples <= 8 * sr:
216
+ return [y]
217
+
218
+ while current_sample < total_samples:
219
+ # اگر حجم نمونه‌های باقی‌مانده کمتر از حداقل زمان قطعه (4 ثانیه) باشد، بقیه فایل را یکجا بردار
220
+ if total_samples - current_sample <= min_segment * sr:
221
+ chunks.append(y[current_sample:])
222
+ break
223
+
224
+ # بازه‌های گام‌به‌گام برای جستجوی سکوت: ابتدا ۸، سپس ۱۲، ۱۵ و نهایتاً ۲۰ ثانیه
225
+ steps = [8, 12, 15, 20]
226
+ silence_threshold = 0.015 # آستانه شدت انرژی سیگنال برای پذیرش به عنوان سکوت واقعی
227
+
228
+ best_split_point = None
229
+ best_rms_val = float('inf')
230
+
231
+ for max_sec in steps:
232
+ start_search = current_sample + int(min_segment * sr)
233
+ end_search = current_sample + int(max_sec * sr)
234
+
235
+ if start_search >= total_samples:
236
+ best_split_point = total_samples
237
+ break
238
+
239
+ if end_search > total_samples:
240
+ end_search = total_samples
241
+
242
+ search_region = y[start_search:end_search]
243
+ if len(search_region) == 0:
244
+ best_split_point = total_samples
245
+ break
246
+
247
+ # محاسبه میزان انرژی (RMS) قطعه
248
+ rms = librosa.feature.rms(y=search_region, frame_length=2048, hop_length=512)[0]
249
+ if len(rms) == 0:
250
+ continue
251
+
252
+ min_rms_idx = np.argmin(rms)
253
+ min_rms_val = rms[min_rms_idx]
254
+ candidate_point = start_search + (min_rms_idx * 512)
255
+
256
+ # ذخیره بهترین نقطه کم‌صدا (در صورتی که سکوت مطلق پیدا نشود، کم‌صدا‌ترین نقطه انتخاب می‌شود)
257
+ if min_rms_val < best_rms_val:
258
+ best_rms_val = min_rms_val
259
+ best_split_point = candidate_point
260
+
261
+ # اگر شدت صدای نقطه پیدا شده پایین‌تر از آستانه سکوت بود، فرآیند جستجو را متوقف کرده و برش بزن
262
+ if min_rms_val < silence_threshold:
263
+ break
264
+
265
+ if best_split_point is None:
266
+ best_split_point = min(current_sample + int(8 * sr), total_samples)
267
+
268
+ chunk_audio = y[current_sample:best_split_point]
269
+ chunks.append(chunk_audio)
270
+ current_sample = best_split_point
271
+
272
+ # بررسی قطعه آخر: اگر بیش از حد کوتاه باشد، آن را با بخش قبلی ادغام می‌کنیم
273
+ if len(chunks) > 1 and len(chunks[-1]) < int(1.5 * sr):
274
+ last_chunk = chunks.pop()
275
+ combined_len = len(chunks[-1]) + len(last_chunk)
276
+ # تا سقف حداکثر ۲۰ ثانیه ادغام قطعه آخر مجاز است
277
+ if combined_len <= int(20 * sr):
278
+ chunks[-1] = np.concatenate([chunks[-1], last_chunk])
279
+ else:
280
+ chunks.append(last_chunk)
281
+
282
+ return chunks
283
+
284
+
285
  # =========================================================================
286
  # سیستم استنتاج مستقیم بر روی Zero-GPU با رابط کاربری Gradio
287
  # =========================================================================
 
296
  SR = 24000
297
 
298
  try:
299
+ # پردازش صوت اصلی
300
  content_data, _ = librosa.load(source_audio_path, sr=SR)
301
 
302
+ # پردازش صوت مرجع
303
  ref_data, _ = librosa.load(ref_audio_path, sr=SR)
304
  ref_tensor = torch.FloatTensor(ref_data).unsqueeze(0)
305
  ref_tensor = ref_tensor / (torch.max(torch.abs(ref_tensor)) + 1e-6) * 0.95
 
307
  temp_r = f"wav/{task_id}_temp_r.wav"
308
  save_audio_pcm16(ref_tensor, temp_r, SR)
309
 
310
+ # اعمال تقسیمکننده هوشمند چندمرحله‌ای
311
+ chunks = smart_split_audio_vevo(content_data, SR, min_segment=4)
 
 
 
 
 
 
 
 
 
 
 
 
 
312
 
313
  generated_chunks = []
314
  pipeline = get_pipeline()
315
 
316
+ # شبیه‌سازی قطعه به قطعه
317
  for idx, chunk in enumerate(chunks):
318
  chunk_tensor = torch.FloatTensor(chunk).unsqueeze(0)
319
  chunk_tensor = chunk_tensor / (torch.max(torch.abs(chunk_tensor)) + 1e-6) * 0.95
 
321
  temp_c_chunk = f"wav/{task_id}_temp_c_{idx}.wav"
322
  save_audio_pcm16(chunk_tensor, temp_c_chunk, SR)
323
 
 
324
  gen = pipeline.inference_fm(
325
  src_wav_path=temp_c_chunk,
326
  timbre_ref_wav_path=temp_r,
 
333
 
334
  generated_chunks.append(gen_np)
335
 
 
336
  if os.path.exists(temp_c_chunk):
337
  os.remove(temp_c_chunk)
338
 
339
+ # ادغام قطعات خروجی
340
  final_gen = np.concatenate(generated_chunks, axis=0)
341
 
342
+ # ذخیره نهایی
343
  save_audio_pcm16(final_gen, out_path, SR)
344
 
 
345
  if os.path.exists(temp_r):
346
  os.remove(temp_r)
347
 
 
350
  except Exception as e:
351
  raise gr.Error(f"خطایی در حین پردازش رخ داد: {str(e)}")
352
 
353
+ # طراحی ساختار وب با استفاده از Gradio
354
  with gr.Blocks() as demo:
355
  gr.Markdown("# سامانه تبدیل صدا (Vevo Voice Conversion) - نسخه Zero-GPU PRO")
356