Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -87,7 +87,6 @@ def get_edge_audio(text, v_code, rate_str="+0%", target_sr=None):
|
|
| 87 |
tmp_path = f.name
|
| 88 |
|
| 89 |
async def _generate():
|
| 90 |
-
# Truyền tốc độ trực tiếp vào AI của Microsoft
|
| 91 |
communicate = edge_tts.Communicate(text, v_code, rate=rate_str)
|
| 92 |
await communicate.save(tmp_path)
|
| 93 |
|
|
@@ -110,14 +109,12 @@ def process_single_line(index, text, start_sec, end_sec, provider, v_code, nativ
|
|
| 110 |
srt_duration = end_sec - start_sec
|
| 111 |
if srt_duration <= 0: srt_duration = 0.5
|
| 112 |
|
| 113 |
-
# 1. PHÂN LUỒNG &
|
| 114 |
if provider == "Microsoft Edge (Neural Cao Cấp)":
|
| 115 |
-
# Cộng thêm 15% tốc độ gốc để bù trừ sự "rề rà" mặc định của Edge
|
| 116 |
base_boost = 15
|
| 117 |
user_boost = int((speed_m - 1.0) * 100)
|
| 118 |
total_rate = base_boost + user_boost
|
| 119 |
rate_str = f"+{total_rate}%" if total_rate >= 0 else f"{total_rate}%"
|
| 120 |
-
|
| 121 |
audio_chunk, _ = get_edge_audio(text, v_code, rate_str=rate_str, target_sr=native_sr)
|
| 122 |
else:
|
| 123 |
audio_chunk, _ = get_tiktok_audio(text, v_code, target_sr=native_sr)
|
|
@@ -125,23 +122,34 @@ def process_single_line(index, text, start_sec, end_sec, provider, v_code, nativ
|
|
| 125 |
if audio_chunk is None:
|
| 126 |
return index, None, None, None
|
| 127 |
|
| 128 |
-
# 2. XÉN KHOẢNG LẶNG
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
|
|
|
|
|
|
| 132 |
audio_chunk = safe_normalize(audio_chunk, target_peak=0.90)
|
| 133 |
orig_dur = len(audio_chunk) / native_sr
|
| 134 |
|
| 135 |
-
# 3. TÍNH TOÁN BÙ TRỪ THỜI GIAN
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
-
# 4. ÉP THỜI GIAN/CAO ĐỘ
|
| 141 |
-
if abs(
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
else:
|
| 146 |
processed_chunk = audio_chunk
|
| 147 |
|
|
@@ -149,7 +157,7 @@ def process_single_line(index, text, start_sec, end_sec, provider, v_code, nativ
|
|
| 149 |
processed_chunk = apply_fade(processed_chunk, native_sr, fade_duration=0.015)
|
| 150 |
|
| 151 |
start_sample = int(start_sec * native_sr)
|
| 152 |
-
return index, processed_chunk, start_sample,
|
| 153 |
|
| 154 |
# --- HÀM GIAO TIẾP VỚI GRADIO ---
|
| 155 |
def srt_to_speech_handler(srt_file, provider, chon_giong, toc_do, cao_do, so_luong_luong, progress=gr.Progress(track_tqdm=True)):
|
|
@@ -225,7 +233,7 @@ def srt_to_speech_handler(srt_file, provider, chon_giong, toc_do, cao_do, so_luo
|
|
| 225 |
end_sample = len(final_audio)
|
| 226 |
|
| 227 |
final_audio[start_sample:end_sample] += processed_chunk
|
| 228 |
-
yield None, log(f" [{count}/{len(subs)}] ✅ Dòng {idx+1}: Thành công |
|
| 229 |
else:
|
| 230 |
yield None, log(f" [{count}/{len(subs)}] ❌ Dòng {idx+1}: Thất bại hoàn toàn.")
|
| 231 |
|
|
@@ -273,7 +281,7 @@ with gr.Blocks(title="SRT to Speech (TikTok + Edge)") as demo:
|
|
| 273 |
interactive=True
|
| 274 |
)
|
| 275 |
with gr.Row():
|
| 276 |
-
speed_input = gr.Slider(minimum=1.0, maximum=1.5, value=1.
|
| 277 |
pitch_input = gr.Slider(minimum=-12, maximum=12, value=0, step=1, label="Cao độ (Pitch)")
|
| 278 |
|
| 279 |
threads_input = gr.Slider(minimum=1, maximum=20, value=10, step=1, label="Số lượng luồng tải song song")
|
|
|
|
| 87 |
tmp_path = f.name
|
| 88 |
|
| 89 |
async def _generate():
|
|
|
|
| 90 |
communicate = edge_tts.Communicate(text, v_code, rate=rate_str)
|
| 91 |
await communicate.save(tmp_path)
|
| 92 |
|
|
|
|
| 109 |
srt_duration = end_sec - start_sec
|
| 110 |
if srt_duration <= 0: srt_duration = 0.5
|
| 111 |
|
| 112 |
+
# 1. PHÂN LUỒNG & GỌI API
|
| 113 |
if provider == "Microsoft Edge (Neural Cao Cấp)":
|
|
|
|
| 114 |
base_boost = 15
|
| 115 |
user_boost = int((speed_m - 1.0) * 100)
|
| 116 |
total_rate = base_boost + user_boost
|
| 117 |
rate_str = f"+{total_rate}%" if total_rate >= 0 else f"{total_rate}%"
|
|
|
|
| 118 |
audio_chunk, _ = get_edge_audio(text, v_code, rate_str=rate_str, target_sr=native_sr)
|
| 119 |
else:
|
| 120 |
audio_chunk, _ = get_tiktok_audio(text, v_code, target_sr=native_sr)
|
|
|
|
| 122 |
if audio_chunk is None:
|
| 123 |
return index, None, None, None
|
| 124 |
|
| 125 |
+
# 2. XÉN KHOẢNG LẶNG (Có vòng bảo vệ)
|
| 126 |
+
audio_chunk_trimmed, _ = librosa.effects.trim(audio_chunk, top_db=35)
|
| 127 |
+
# Chỉ trim nếu file sau khi trim còn đủ dài (> 0.2s) để tránh lỗi thư viện sập
|
| 128 |
+
if len(audio_chunk_trimmed) > native_sr * 0.2:
|
| 129 |
+
audio_chunk = audio_chunk_trimmed
|
| 130 |
+
|
| 131 |
audio_chunk = safe_normalize(audio_chunk, target_peak=0.90)
|
| 132 |
orig_dur = len(audio_chunk) / native_sr
|
| 133 |
|
| 134 |
+
# 3. TÍNH TOÁN BÙ TRỪ THỜI GIAN
|
| 135 |
+
if provider == "Microsoft Edge (Neural Cao Cấp)":
|
| 136 |
+
# Tốc độ đã được Microsoft ép trên server, ta chỉ ép thêm nếu nó vẫn dài hơn SRT
|
| 137 |
+
stretch_factor = orig_dur / srt_duration
|
| 138 |
+
stretch_factor = max(1.0, stretch_factor)
|
| 139 |
+
else:
|
| 140 |
+
# TikTok không ép tốc độ trên server, ta phải ép tay
|
| 141 |
+
stretch_factor = max(speed_m, orig_dur / srt_duration)
|
| 142 |
|
| 143 |
+
# 4. ÉP THỜI GIAN/CAO ĐỘ AN TOÀN
|
| 144 |
+
if abs(stretch_factor - 1.0) > 0.01 or pitch_steps != 0:
|
| 145 |
+
try:
|
| 146 |
+
processed_chunk = pyrb.time_stretch(audio_chunk, native_sr, stretch_factor)
|
| 147 |
+
if pitch_steps != 0:
|
| 148 |
+
processed_chunk = pyrb.pitch_shift(processed_chunk, native_sr, pitch_steps)
|
| 149 |
+
except Exception as e:
|
| 150 |
+
# Nếu pyrubberband sập (crash), hoàn tác dùng lại file gốc chứ không để bị khoảng trắng
|
| 151 |
+
processed_chunk = audio_chunk
|
| 152 |
+
print(f"Bỏ qua ép tốc độ dòng {index} do file quá ngắn hoặc lỗi: {e}")
|
| 153 |
else:
|
| 154 |
processed_chunk = audio_chunk
|
| 155 |
|
|
|
|
| 157 |
processed_chunk = apply_fade(processed_chunk, native_sr, fade_duration=0.015)
|
| 158 |
|
| 159 |
start_sample = int(start_sec * native_sr)
|
| 160 |
+
return index, processed_chunk, start_sample, stretch_factor
|
| 161 |
|
| 162 |
# --- HÀM GIAO TIẾP VỚI GRADIO ---
|
| 163 |
def srt_to_speech_handler(srt_file, provider, chon_giong, toc_do, cao_do, so_luong_luong, progress=gr.Progress(track_tqdm=True)):
|
|
|
|
| 233 |
end_sample = len(final_audio)
|
| 234 |
|
| 235 |
final_audio[start_sample:end_sample] += processed_chunk
|
| 236 |
+
yield None, log(f" [{count}/{len(subs)}] ✅ Dòng {idx+1}: Thành công | Biên độ giãn: {speed_applied:.2f}x")
|
| 237 |
else:
|
| 238 |
yield None, log(f" [{count}/{len(subs)}] ❌ Dòng {idx+1}: Thất bại hoàn toàn.")
|
| 239 |
|
|
|
|
| 281 |
interactive=True
|
| 282 |
)
|
| 283 |
with gr.Row():
|
| 284 |
+
speed_input = gr.Slider(minimum=1.0, maximum=1.5, value=1.1, step=0.1, label="Tốc độ mặc định")
|
| 285 |
pitch_input = gr.Slider(minimum=-12, maximum=12, value=0, step=1, label="Cao độ (Pitch)")
|
| 286 |
|
| 287 |
threads_input = gr.Slider(minimum=1, maximum=20, value=10, step=1, label="Số lượng luồng tải song song")
|