voidful commited on
Commit
dd9fd54
·
verified ·
1 Parent(s): 927c1a5

Streaming tab: collect full audio then play smoothly (ZeroGPU is sub-realtime)

Browse files
Files changed (1) hide show
  1. app.py +18 -33
app.py CHANGED
@@ -3,7 +3,7 @@
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 永遠跟著模型走。
@@ -104,17 +104,12 @@ def _to_numpy(audio: torch.Tensor):
104
  return audio.squeeze().float().cpu().numpy()
105
 
106
 
107
- # 串流不支援 retry_badcase(見 model._generate 的警告),故濾掉 retry_* 參數。
108
  STREAM_KWARGS = {k: v for k, v in GEN_KWARGS.items() if not k.startswith("retry_")}
109
 
110
 
111
- def _pcm16(x: np.ndarray) -> np.ndarray:
112
- """把 float 波形轉成 16-bit PCM,供 Gradio 串流播放(格式最穩定)。"""
113
- return (np.clip(x, -1.0, 1.0) * 32767.0).astype(np.int16)
114
-
115
-
116
  # --------------------------------------------------------------------------- #
117
- # 推論:兩種模式都套用 GEN_KWARGS(官方最佳參數)
118
  # --------------------------------------------------------------------------- #
119
  @gpu
120
  def tts_speaker(text):
@@ -144,16 +139,14 @@ def tts_clone(text, reference_audio):
144
  return (SR, _to_numpy(audio))
145
 
146
 
147
- _STREAM_SEG_SEC = 0.6 # 把模型的小 chunk 累積到約 0.6 秒再 yield,減少 Gradio
148
- # 每段 HLS 的封裝開銷,避免播放卡頓(見對話中的量測)。
149
-
150
-
151
  @gpu
152
  def tts_stream(text, reference_audio):
153
- """串流:邊合成邊回傳音訊區塊(不支援自動重試)。
154
 
155
- 有參考音檔走聲音複製,否則用李宏毅語者向量。把模型逐步產生的小 chunk
156
- 累積成約 0.6 秒的片段再 yield,Gradio 依序串流播放。
 
 
157
  """
158
  text = (text or "").strip()
159
  if not text:
@@ -167,19 +160,10 @@ def tts_stream(text, reference_audio):
167
  target_text=text, speaker_centroid=SPK_CENTROID, **STREAM_KWARGS
168
  )
169
 
170
- target = int(SR * _STREAM_SEG_SEC)
171
- buf, nbuf = [], 0
172
- for chunk in gen:
173
- x = chunk.squeeze().float().cpu().numpy()
174
- buf.append(x)
175
- nbuf += x.shape[-1]
176
- if nbuf >= target:
177
- seg = np.concatenate(buf)
178
- buf, nbuf = [], 0
179
- yield (SR, _pcm16(seg))
180
- if buf:
181
- seg = np.concatenate(buf)
182
- yield (SR, _pcm16(seg))
183
 
184
 
185
  # --------------------------------------------------------------------------- #
@@ -248,11 +232,12 @@ with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
248
  c_out = gr.Audio(label="合成結果", type="numpy")
249
  c_btn.click(tts_clone, [c_text, c_ref], c_out)
250
 
251
- with gr.Tab("串流合成 ⚡"):
252
  gr.Markdown(
253
- "**邊合成邊播放**,較快聽到第一段聲音。預設用李宏毅語者向量;"
254
- "若上傳參考音檔則改為聲音複製(請只使用已取得授權的聲音)。\n\n"
255
- "> 串流模式不支援自動重試(`retry_badcase`),偶爾品質可能略低於上面兩個分頁。"
 
256
  )
257
  with gr.Row():
258
  with gr.Column():
@@ -266,7 +251,7 @@ with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
266
  )
267
  t_btn = gr.Button("串流合成", variant="primary")
268
  with gr.Column():
269
- t_out = gr.Audio(label="串流播放", streaming=True, autoplay=True)
270
  gr.Examples(EXAMPLE_TEXTS, inputs=t_text, label="範例文字")
271
  t_btn.click(tts_stream, [t_text, t_ref], t_out)
272
 
 
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 永遠跟著模型走。
 
104
  return audio.squeeze().float().cpu().numpy()
105
 
106
 
107
+ # 串流引擎不支援 retry_badcase(見 model._generate 的警告),故濾掉 retry_* 參數。
108
  STREAM_KWARGS = {k: v for k, v in GEN_KWARGS.items() if not k.startswith("retry_")}
109
 
110
 
 
 
 
 
 
111
  # --------------------------------------------------------------------------- #
112
+ # 推論:三種模式都套用 GEN_KWARGS(官方最佳參數)
113
  # --------------------------------------------------------------------------- #
114
  @gpu
115
  def tts_speaker(text):
 
139
  return (SR, _to_numpy(audio))
140
 
141
 
 
 
 
 
142
  @gpu
143
  def tts_stream(text, reference_audio):
144
+ """用模型的串流生成引擎(generate_streaming)逐段合成,蒐集完整後一次回傳。
145
 
146
+ ZeroGPU 上模型約 0.44x 實時,逐段即時串流播放必然卡頓,故改為「合成完成後
147
+ 順暢播放」:背後仍走串流生成路徑(不支援自動重試),但等所有音訊區塊到齊再
148
+ 合併成完整波形輸出,播放流暢且能正常結束。有參考音檔走聲音複製,否則用李宏毅
149
+ 語者向量。
150
  """
151
  text = (text or "").strip()
152
  if not text:
 
160
  target_text=text, speaker_centroid=SPK_CENTROID, **STREAM_KWARGS
161
  )
162
 
163
+ parts = [chunk.squeeze().float().cpu().numpy() for chunk in gen]
164
+ if not parts:
165
+ raise gr.Error("合成失敗,請再試一次。")
166
+ return (SR, np.concatenate(parts))
 
 
 
 
 
 
 
 
 
167
 
168
 
169
  # --------------------------------------------------------------------------- #
 
232
  c_out = gr.Audio(label="合成結果", type="numpy")
233
  c_btn.click(tts_clone, [c_text, c_ref], c_out)
234
 
235
+ with gr.Tab("串流引擎合成"):
236
  gr.Markdown(
237
+ "使用模型的**串流生成引擎**(`generate_streaming`)合成,完成後一次順暢播放。"
238
+ "預設用李宏毅語者向量;若上傳參考音檔則改為聲音複製(請只使用已取得授權的聲音)。\n\n"
239
+ "> ZeroGPU 上模型約 0.44x 實時,逐段即時播放會卡頓,故改為合成完成後再播放;"
240
+ "串流路徑不支援自動重試(`retry_badcase`)。"
241
  )
242
  with gr.Row():
243
  with gr.Column():
 
251
  )
252
  t_btn = gr.Button("串流合成", variant="primary")
253
  with gr.Column():
254
+ t_out = gr.Audio(label="合成結果", type="numpy", autoplay=True)
255
  gr.Examples(EXAMPLE_TEXTS, inputs=t_text, label="範例文字")
256
  t_btn.click(tts_stream, [t_text, t_ref], t_out)
257