voidful commited on
Commit
5e31159
·
verified ·
1 Parent(s): 7afaa46

Fix voice cloning: use prompt_wav+prompt_text (reference_wav_path produced gibberish); remove debug

Browse files
Files changed (1) hide show
  1. app.py +31 -59
app.py CHANGED
@@ -2,9 +2,12 @@
2
 
3
  提供三種試用情境,並一律套用模型官方建議的最佳生成參數:
4
  1. 指定語者:李宏毅 —— 用模型內附、已取得授權的語者向量控制音色
5
- 2. 聲音複製 —— 上傳一段參考音檔,模仿該語者的音色
6
  3. 長文逐句串流 —— 把長文切句,合成一句播一句,做出串流效果(每句含自動重試)
7
 
 
 
 
8
  最佳參數讀自模型發佈中繼資料 release_metadata.json 的 recommended_generation_defaults
9
  (以 500 句難句 + ASR CER 調出,最佳 trial:cfg=2.8 / steps=9),確保 demo 永遠跟著模型走。
10
  """
@@ -156,28 +159,36 @@ def tts_speaker(text):
156
 
157
 
158
  @gpu
159
- def tts_clone(text, reference_audio):
 
 
 
 
 
160
  text = (text or "").strip()
 
161
  if not text:
162
  raise gr.Error("請先輸入要合成的文字。")
163
  if not reference_audio:
164
  raise gr.Error("請先上傳或錄製一段參考音檔。")
 
 
165
  audio = model.generate(
166
  target_text=text,
167
- reference_wav_path=reference_audio, # gr.Audio(type="filepath") 回傳路徑
 
168
  **GEN_KWARGS,
169
  )
170
  return (SR, _to_numpy(audio))
171
 
172
 
173
  @gpu
174
- def tts_stream(text, reference_audio):
175
- """長文逐句串流:把長文切成句子,逐句合成、合成一句就播一句,做出串流效果。
176
 
177
  逐句串流直到接近單次 GPU 時間配額(約 100s)為止,盡量把整段長文串完,而非固定
178
  句數;真的超過才截斷並提示分批。每句都用一般 generate(含 retry_badcase)產生
179
- 完整音檔再 yield;句與句之間可能有短暫間隔(ZeroGPU 約 0.44x 實時所致)。預設用
180
- 李宏毅語者向量,上傳參考音檔則改為聲音複製。
181
  """
182
  text = (text or "").strip()
183
  if not text:
@@ -193,14 +204,9 @@ def tts_stream(text, reference_audio):
193
  # 至少先產出第一句;之後一旦逼近 GPU 時間配額就停,避免配額被回收而報錯
194
  if done and time.time() - start > _GPU_BUDGET_S:
195
  break
196
- if reference_audio:
197
- audio = model.generate(
198
- target_text=sent, reference_wav_path=reference_audio, **GEN_KWARGS
199
- )
200
- else:
201
- audio = model.generate(
202
- target_text=sent, speaker_centroid=SPK_CENTROID, **GEN_KWARGS
203
- )
204
  yield (SR, _pcm16(_to_numpy(audio)))
205
  done += 1
206
  if done < total:
@@ -210,30 +216,6 @@ def tts_stream(text, reference_audio):
210
  )
211
 
212
 
213
- # --- TEMP diagnostic endpoint (remove after voice-clone debugging) ----------- #
214
- @gpu
215
- def tts_debug(target_text, audio_path, prompt_text, mode, cfg, use_null):
216
- target_text = (target_text or "").strip()
217
- if not target_text:
218
- raise gr.Error("請輸入 target_text。")
219
- base = {k: v for k, v in GEN_KWARGS.items() if k != "cfg_value"}
220
- kw = dict(base, cfg_value=float(cfg), use_null_speaker=bool(use_null))
221
- if mode == "prompt":
222
- audio = model.generate(
223
- target_text=target_text,
224
- prompt_wav_path=audio_path or "",
225
- prompt_text=(prompt_text or ""),
226
- **kw,
227
- )
228
- else:
229
- audio = model.generate(
230
- target_text=target_text,
231
- reference_wav_path=audio_path or "",
232
- **kw,
233
- )
234
- return (SR, _to_numpy(audio))
235
-
236
-
237
  # --------------------------------------------------------------------------- #
238
  # 介面
239
  # --------------------------------------------------------------------------- #
@@ -289,7 +271,9 @@ with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
289
 
290
  with gr.Tab("聲音複製"):
291
  gr.Markdown(
292
- "上傳一段參考音檔,輸出會模仿該語者的音色。\n\n"
 
 
293
  "⚠️ **請只使用你已取得授權的聲音**,請勿在未經本人同意下複製他人聲音。"
294
  )
295
  with gr.Row():
@@ -302,16 +286,19 @@ with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
302
  label="參考音檔(上傳或錄製)", type="filepath",
303
  sources=["upload", "microphone"],
304
  )
 
 
 
 
305
  c_btn = gr.Button("複製音色合成", variant="primary")
306
  with gr.Column():
307
  c_out = gr.Audio(label="合成結果", type="numpy")
308
- c_btn.click(tts_clone, [c_text, c_ref], c_out)
309
 
310
  with gr.Tab("長文逐句串流"):
311
  gr.Markdown(
312
  "**長文逐句串流**:把長文切成句子,合成一句就播一句,做出串流(邊聽邊等)效果。"
313
- "第一句很快就能聽到,後面邊播邊合成。\n\n"
314
- "預設用李宏毅語者向量;若上傳參考音檔則改為聲音複製(請只使用已取得授權的聲音)。\n"
315
  "> ZeroGPU 約 0.44x 實時,句與句之間可能有短暫間隔;每句都套用最佳參數(含自動重試)。"
316
  "單次串流以 ZeroGPU 時間配額為限(約可串數十句),超長會自動截斷並提示分批。"
317
  )
@@ -321,26 +308,11 @@ with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
321
  label="要合成的長文", lines=5,
322
  placeholder="貼上一段多句的文字,會逐句合成、逐句播放…",
323
  )
324
- t_ref = gr.Audio(
325
- label="參考音檔(選填;留空則用李宏毅音色)", type="filepath",
326
- sources=["upload", "microphone"],
327
- )
328
  t_btn = gr.Button("逐句串流合成", variant="primary")
329
  with gr.Column():
330
  t_out = gr.Audio(label="逐句串流播放", streaming=True, autoplay=True)
331
  gr.Examples(STREAM_EXAMPLES, inputs=t_text, label="長文範例")
332
- t_btn.click(tts_stream, [t_text, t_ref], t_out)
333
-
334
- with gr.Tab("debug"):
335
- d_text = gr.Textbox(label="target_text", value="今天天氣真好,我們一起去公園散步看花。")
336
- d_audio = gr.Audio(label="audio", type="filepath", sources=["upload", "microphone"])
337
- d_prompt = gr.Textbox(label="prompt_text (for prompt mode)")
338
- d_mode = gr.Radio(["reference", "prompt"], value="prompt", label="mode")
339
- d_cfg = gr.Slider(1.0, 4.0, value=2.8, step=0.1, label="cfg")
340
- d_null = gr.Checkbox(value=True, label="use_null_speaker")
341
- d_btn = gr.Button("debug gen")
342
- d_out = gr.Audio(label="out", type="numpy")
343
- d_btn.click(tts_debug, [d_text, d_audio, d_prompt, d_mode, d_cfg, d_null], d_out)
344
 
345
  gr.Markdown(
346
  "---\n"
 
2
 
3
  提供三種試用情境,並一律套用模型官方建議的最佳生成參數:
4
  1. 指定語者:李宏毅 —— 用模型內附、已取得授權的語者向量控制音色
5
+ 2. 聲音複製 —— 參考音檔 + 其逐字稿(prompt 模式)做 zero-shot 複製
6
  3. 長文逐句串流 —— 把長文切句,合成一句播一句,做出串流效果(每句含自動重試)
7
 
8
+ 註:transcript-free 的 reference_wav_path 路徑在此 checkpoint 會吐出亂掉內容(實測
9
+ CER≈3),故複製改用可靠的 prompt_wav_path + prompt_text(語音接續)路徑(實測 CER 0)。
10
+
11
  最佳參數讀自模型發佈中繼資料 release_metadata.json 的 recommended_generation_defaults
12
  (以 500 句難句 + ASR CER 調出,最佳 trial:cfg=2.8 / steps=9),確保 demo 永遠跟著模型走。
13
  """
 
159
 
160
 
161
  @gpu
162
+ def tts_clone(text, reference_audio, prompt_text):
163
+ """聲音複製:以「參考語音 + 其逐字稿」做 zero-shot 複製。
164
+
165
+ 用 prompt_wav_path + prompt_text(語音接續)路徑 —— 這是此模型可靠的複製方式;
166
+ transcript-free 的 reference_wav_path 路徑在本 checkpoint 會吐出亂掉的內容,故不用。
167
+ """
168
  text = (text or "").strip()
169
+ prompt_text = (prompt_text or "").strip()
170
  if not text:
171
  raise gr.Error("請先輸入要合成的文字。")
172
  if not reference_audio:
173
  raise gr.Error("請先上傳或錄製一段參考音檔。")
174
+ if not prompt_text:
175
+ raise gr.Error("請填寫參考音檔的逐字稿(這段參考語音實際說的內容)。")
176
  audio = model.generate(
177
  target_text=text,
178
+ prompt_wav_path=reference_audio, # gr.Audio(type="filepath") 回傳路徑
179
+ prompt_text=prompt_text,
180
  **GEN_KWARGS,
181
  )
182
  return (SR, _to_numpy(audio))
183
 
184
 
185
  @gpu
186
+ def tts_stream(text):
187
+ """長文逐句串流(李宏毅語者向量):把長文切成句子,逐句合成、合成一句就播一句。
188
 
189
  逐句串流直到接近單次 GPU 時間配額(約 100s)為止,盡量把整段長文串完,而非固定
190
  句數;真的超過才截斷並提示分批。每句都用一般 generate(含 retry_badcase)產生
191
+ 完整音檔再 yield;句與句之間可能有短暫間隔(ZeroGPU 約 0.44x 實時所致)。
 
192
  """
193
  text = (text or "").strip()
194
  if not text:
 
204
  # 至少先產出第一句;之後一旦逼近 GPU 時間配額就停,避免配額被回收而報錯
205
  if done and time.time() - start > _GPU_BUDGET_S:
206
  break
207
+ audio = model.generate(
208
+ target_text=sent, speaker_centroid=SPK_CENTROID, **GEN_KWARGS
209
+ )
 
 
 
 
 
210
  yield (SR, _pcm16(_to_numpy(audio)))
211
  done += 1
212
  if done < total:
 
216
  )
217
 
218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  # --------------------------------------------------------------------------- #
220
  # 介面
221
  # --------------------------------------------------------------------------- #
 
271
 
272
  with gr.Tab("聲音複製"):
273
  gr.Markdown(
274
+ "上傳一段參考音檔**並填寫它的逐字稿**,輸出會模仿該語者的音色。\n\n"
275
+ "為什麼要逐字稿?本模型靠「參考語音+逐字稿」做複製最穩定;少了逐字稿的純參考"
276
+ "模式在目前 checkpoint 會吐出亂掉的內容。建議參考音檔約 3–10 秒、乾淨單一語者。\n\n"
277
  "⚠️ **請只使用你已取得授權的聲音**,請勿在未經本人同意下複製他人聲音。"
278
  )
279
  with gr.Row():
 
286
  label="參考音檔(上傳或錄製)", type="filepath",
287
  sources=["upload", "microphone"],
288
  )
289
+ c_prompt = gr.Textbox(
290
+ label="參考音檔的逐字稿", lines=2,
291
+ placeholder="輸入這段參考語音實際說的內容…",
292
+ )
293
  c_btn = gr.Button("複製音色合成", variant="primary")
294
  with gr.Column():
295
  c_out = gr.Audio(label="合成結果", type="numpy")
296
+ c_btn.click(tts_clone, [c_text, c_ref, c_prompt], c_out)
297
 
298
  with gr.Tab("長文逐句串流"):
299
  gr.Markdown(
300
  "**長文逐句串流**:把長文切成句子,合成一句就播一句,做出串流(邊聽邊等)效果。"
301
+ "第一句很快就能聽到,後面邊播邊合成。用**李宏毅語者向量**。\n\n"
 
302
  "> ZeroGPU 約 0.44x 實時,句與句之間可能有短暫間隔;每句都套用最佳參數(含自動重試)。"
303
  "單次串流以 ZeroGPU 時間配額為限(約可串數十句),超長會自動截斷並提示分批。"
304
  )
 
308
  label="要合成的長文", lines=5,
309
  placeholder="貼上一段多句的文字,會逐句合成、逐句播放…",
310
  )
 
 
 
 
311
  t_btn = gr.Button("逐句串流合成", variant="primary")
312
  with gr.Column():
313
  t_out = gr.Audio(label="逐句串流播放", streaming=True, autoplay=True)
314
  gr.Examples(STREAM_EXAMPLES, inputs=t_text, label="長文範例")
315
+ t_btn.click(tts_stream, t_text, t_out)
 
 
 
 
 
 
 
 
 
 
 
316
 
317
  gr.Markdown(
318
  "---\n"