Spaces:
Running on Zero
Running on Zero
Add adjustable cfg_value / inference_timesteps sliders (shared across tabs, defaults = model-card recommendation)
Browse files
README.md
CHANGED
|
@@ -40,9 +40,11 @@ CER=合成語音用 ASR 轉寫回文字後,與原文不一致的字元比例
|
|
| 40 |
|
| 41 |
## 參數說明
|
| 42 |
|
|
|
|
|
|
|
| 43 |
| 參數 | 說明 |
|
| 44 |
|---|---|
|
| 45 |
-
| `cfg_value` | 引導強度,數值越大越貼合條件、但可能較不自然(
|
| 46 |
-
| `inference_timesteps` | 取樣步數,越多通常品質越好、速度越慢(
|
| 47 |
|
| 48 |
> 合成的語音僅供研究與評估展示用途,正式使用前請人工檢視。授權:Apache-2.0。
|
|
|
|
| 40 |
|
| 41 |
## 參數說明
|
| 42 |
|
| 43 |
+
兩個生成參數可在頁面上方的「⚙️ 生成參數」區調整(三個分頁共用),預設為模型卡建議值:
|
| 44 |
+
|
| 45 |
| 參數 | 說明 |
|
| 46 |
|---|---|
|
| 47 |
+
| `cfg_value` | 引導強度,數值越大越貼合條件、但可能較不自然(預設 2.0,可調 1.0–4.0) |
|
| 48 |
+
| `inference_timesteps` | 取樣步數,越多通常品質越好、速度越慢(預設 10,可調 4–20) |
|
| 49 |
|
| 50 |
> 合成的語音僅供研究與評估展示用途,正式使用前請人工檢視。授權:Apache-2.0。
|
app.py
CHANGED
|
@@ -91,6 +91,20 @@ except Exception as e: # 任何讀取/解析問題都退回安全的建議值
|
|
| 91 |
|
| 92 |
print(f"[BlueMagpie] checkpoint={CHECKPOINT}, generation params: {GEN_KWARGS}")
|
| 93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
# 語者向量:載入多語者表(優先 speaker_centroids.pt),建成「顯示名稱 -> 向量」。
|
| 95 |
# 內附的李宏毅向量已取得本人授權;其餘為通用語者向量。
|
| 96 |
_DISPLAY = {"hung_yi_lee": "李宏毅", "female_voice": "女聲"}
|
|
@@ -170,25 +184,27 @@ def _split_sentences(text):
|
|
| 170 |
# 推論:三種模式都套用 GEN_KWARGS(官方建議參數)
|
| 171 |
# --------------------------------------------------------------------------- #
|
| 172 |
@gpu
|
| 173 |
-
def tts_speaker(text, speaker=DEFAULT_SPEAKER):
|
| 174 |
text = (text or "").strip()
|
| 175 |
if not text:
|
| 176 |
raise gr.Error("請先輸入要合成的文字。")
|
| 177 |
audio = model.generate(
|
| 178 |
target_text=text,
|
| 179 |
speaker_centroid=SPEAKERS.get(speaker, SPK_CENTROID),
|
| 180 |
-
**
|
| 181 |
)
|
| 182 |
return (SR, _to_numpy(audio))
|
| 183 |
|
| 184 |
|
| 185 |
@gpu
|
| 186 |
-
def _clone_gpu(text, ref_path):
|
| 187 |
-
audio = model.generate(
|
|
|
|
|
|
|
| 188 |
return (SR, _to_numpy(audio))
|
| 189 |
|
| 190 |
|
| 191 |
-
def tts_clone(text, recording):
|
| 192 |
"""聲音複製(免逐字稿):把參考音檔直接交給模型(reference_wav_path 路徑,
|
| 193 |
checkpoint step_0006000 起正式支援)。一段 3 秒以上的乾淨語音即可。"""
|
| 194 |
text = (text or "").strip()
|
|
@@ -199,11 +215,11 @@ def tts_clone(text, recording):
|
|
| 199 |
dur = _audio_seconds(recording)
|
| 200 |
if 0 < dur < 3:
|
| 201 |
gr.Warning(f"參考音檔只有約 {dur:.0f} 秒,建議 3 秒以上會更穩定。")
|
| 202 |
-
return _clone_gpu(text, recording)
|
| 203 |
|
| 204 |
|
| 205 |
@gpu
|
| 206 |
-
def tts_stream(text, speaker=DEFAULT_SPEAKER):
|
| 207 |
"""長文逐句串流(指定語者向量):把長文切成句子,逐句合成、合成一句就播一句。
|
| 208 |
|
| 209 |
逐句串流直到接近單次 GPU 時間配額(約 100s)為止,盡量把整段長文串完,而非固定
|
|
@@ -219,6 +235,7 @@ def tts_stream(text, speaker=DEFAULT_SPEAKER):
|
|
| 219 |
centroid = SPEAKERS.get(speaker, SPK_CENTROID)
|
| 220 |
total = len(sentences)
|
| 221 |
sentences = sentences[:_MAX_STREAM_SENTENCES]
|
|
|
|
| 222 |
start = time.time()
|
| 223 |
done = 0
|
| 224 |
for sent in sentences:
|
|
@@ -226,7 +243,7 @@ def tts_stream(text, speaker=DEFAULT_SPEAKER):
|
|
| 226 |
if done and time.time() - start > _GPU_BUDGET_S:
|
| 227 |
break
|
| 228 |
audio = model.generate(
|
| 229 |
-
target_text=sent, speaker_centroid=centroid, **
|
| 230 |
)
|
| 231 |
yield (SR, _pcm16(_to_numpy(audio)))
|
| 232 |
done += 1
|
|
@@ -254,10 +271,11 @@ STREAM_EXAMPLES = [
|
|
| 254 |
]
|
| 255 |
|
| 256 |
_PARAMS_NOTE = (
|
| 257 |
-
f"模型 checkpoint:`{CHECKPOINT}`,
|
| 258 |
-
f"`cfg_value={
|
| 259 |
-
f"`inference_timesteps={
|
| 260 |
-
f"`retry_badcase={'on' if GEN_KWARGS.get('retry_badcase') else 'off'}`
|
|
|
|
| 261 |
)
|
| 262 |
|
| 263 |
HEADER = f"""
|
|
@@ -274,6 +292,19 @@ HEADER = f"""
|
|
| 274 |
with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
|
| 275 |
gr.Markdown(HEADER)
|
| 276 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
with gr.Tab("指定語者"):
|
| 278 |
gr.Markdown(
|
| 279 |
"用模型內附的**語者向量**控制音色。**李宏毅**老師的向量已取得本人授權;"
|
|
@@ -292,7 +323,7 @@ with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
|
|
| 292 |
with gr.Column():
|
| 293 |
s_out = gr.Audio(label="合成結果", type="numpy")
|
| 294 |
gr.Examples(EXAMPLE_TEXTS, inputs=s_text, label="範例文字")
|
| 295 |
-
s_btn.click(tts_speaker, [s_text, s_spk], s_out)
|
| 296 |
|
| 297 |
with gr.Tab("聲音複製"):
|
| 298 |
gr.Markdown(
|
|
@@ -313,13 +344,13 @@ with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
|
|
| 313 |
c_btn = gr.Button("複製音色合成", variant="primary")
|
| 314 |
with gr.Column():
|
| 315 |
c_out = gr.Audio(label="合成結果", type="numpy")
|
| 316 |
-
c_btn.click(tts_clone, [c_text, c_rec], c_out)
|
| 317 |
|
| 318 |
with gr.Tab("長文逐句串流"):
|
| 319 |
gr.Markdown(
|
| 320 |
"**長文逐句串流**:把長文切成句子,合成一句就播一句,做出串流(邊聽邊等)效果。"
|
| 321 |
"第一句很快就能聽到,後面邊播邊合成。用**所選語者向量**。\n\n"
|
| 322 |
-
"> ZeroGPU 約 0.44x 即時,句與句之間可能有短暫間隔;每句都套用
|
| 323 |
"單次串流以 ZeroGPU 時間配額為限(約可串數十句),超長會自動截斷並提示分批。"
|
| 324 |
)
|
| 325 |
with gr.Row():
|
|
@@ -335,7 +366,7 @@ with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
|
|
| 335 |
with gr.Column():
|
| 336 |
t_out = gr.Audio(label="逐句串流播放", streaming=True, autoplay=True)
|
| 337 |
gr.Examples(STREAM_EXAMPLES, inputs=t_text, label="長文範例")
|
| 338 |
-
t_btn.click(tts_stream, [t_text, t_spk], t_out)
|
| 339 |
|
| 340 |
gr.Markdown(
|
| 341 |
"---\n"
|
|
|
|
| 91 |
|
| 92 |
print(f"[BlueMagpie] checkpoint={CHECKPOINT}, generation params: {GEN_KWARGS}")
|
| 93 |
|
| 94 |
+
# 介面上可調整的兩個生成參數;預設即官方建議值。
|
| 95 |
+
DEFAULT_CFG = float(GEN_KWARGS.get("cfg_value", 2.0))
|
| 96 |
+
DEFAULT_STEPS = int(GEN_KWARGS.get("inference_timesteps", 10))
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def _gen_kwargs(cfg_value=None, inference_timesteps=None):
|
| 100 |
+
"""以官方建議參數為底,套用使用者在介面上調整的 cfg / 取樣步數。"""
|
| 101 |
+
kw = dict(GEN_KWARGS)
|
| 102 |
+
if cfg_value is not None:
|
| 103 |
+
kw["cfg_value"] = float(cfg_value)
|
| 104 |
+
if inference_timesteps is not None:
|
| 105 |
+
kw["inference_timesteps"] = int(inference_timesteps)
|
| 106 |
+
return kw
|
| 107 |
+
|
| 108 |
# 語者向量:載入多語者表(優先 speaker_centroids.pt),建成「顯示名稱 -> 向量」。
|
| 109 |
# 內附的李宏毅向量已取得本人授權;其餘為通用語者向量。
|
| 110 |
_DISPLAY = {"hung_yi_lee": "李宏毅", "female_voice": "女聲"}
|
|
|
|
| 184 |
# 推論:三種模式都套用 GEN_KWARGS(官方建議參數)
|
| 185 |
# --------------------------------------------------------------------------- #
|
| 186 |
@gpu
|
| 187 |
+
def tts_speaker(text, speaker=DEFAULT_SPEAKER, cfg=DEFAULT_CFG, steps=DEFAULT_STEPS):
|
| 188 |
text = (text or "").strip()
|
| 189 |
if not text:
|
| 190 |
raise gr.Error("請先輸入要合成的文字。")
|
| 191 |
audio = model.generate(
|
| 192 |
target_text=text,
|
| 193 |
speaker_centroid=SPEAKERS.get(speaker, SPK_CENTROID),
|
| 194 |
+
**_gen_kwargs(cfg, steps),
|
| 195 |
)
|
| 196 |
return (SR, _to_numpy(audio))
|
| 197 |
|
| 198 |
|
| 199 |
@gpu
|
| 200 |
+
def _clone_gpu(text, ref_path, cfg, steps):
|
| 201 |
+
audio = model.generate(
|
| 202 |
+
target_text=text, reference_wav_path=ref_path, **_gen_kwargs(cfg, steps)
|
| 203 |
+
)
|
| 204 |
return (SR, _to_numpy(audio))
|
| 205 |
|
| 206 |
|
| 207 |
+
def tts_clone(text, recording, cfg=DEFAULT_CFG, steps=DEFAULT_STEPS):
|
| 208 |
"""聲音複製(免逐字稿):把參考音檔直接交給模型(reference_wav_path 路徑,
|
| 209 |
checkpoint step_0006000 起正式支援)。一段 3 秒以上的乾淨語音即可。"""
|
| 210 |
text = (text or "").strip()
|
|
|
|
| 215 |
dur = _audio_seconds(recording)
|
| 216 |
if 0 < dur < 3:
|
| 217 |
gr.Warning(f"參考音檔只有約 {dur:.0f} 秒,建議 3 秒以上會更穩定。")
|
| 218 |
+
return _clone_gpu(text, recording, cfg, steps)
|
| 219 |
|
| 220 |
|
| 221 |
@gpu
|
| 222 |
+
def tts_stream(text, speaker=DEFAULT_SPEAKER, cfg=DEFAULT_CFG, steps=DEFAULT_STEPS):
|
| 223 |
"""長文逐句串流(指定語者向量):把長文切成句子,逐句合成、合成一句就播一句。
|
| 224 |
|
| 225 |
逐句串流直到接近單次 GPU 時間配額(約 100s)為止,盡量把整段長文串完,而非固定
|
|
|
|
| 235 |
centroid = SPEAKERS.get(speaker, SPK_CENTROID)
|
| 236 |
total = len(sentences)
|
| 237 |
sentences = sentences[:_MAX_STREAM_SENTENCES]
|
| 238 |
+
gen_kw = _gen_kwargs(cfg, steps)
|
| 239 |
start = time.time()
|
| 240 |
done = 0
|
| 241 |
for sent in sentences:
|
|
|
|
| 243 |
if done and time.time() - start > _GPU_BUDGET_S:
|
| 244 |
break
|
| 245 |
audio = model.generate(
|
| 246 |
+
target_text=sent, speaker_centroid=centroid, **gen_kw
|
| 247 |
)
|
| 248 |
yield (SR, _pcm16(_to_numpy(audio)))
|
| 249 |
done += 1
|
|
|
|
| 271 |
]
|
| 272 |
|
| 273 |
_PARAMS_NOTE = (
|
| 274 |
+
f"模型 checkpoint:`{CHECKPOINT}`,預設套用官方建議參數:"
|
| 275 |
+
f"`cfg_value={DEFAULT_CFG}`、"
|
| 276 |
+
f"`inference_timesteps={DEFAULT_STEPS}`、"
|
| 277 |
+
f"`retry_badcase={'on' if GEN_KWARGS.get('retry_badcase') else 'off'}`;"
|
| 278 |
+
f"可展開下方「⚙️ 生成參數」自行調整。"
|
| 279 |
)
|
| 280 |
|
| 281 |
HEADER = f"""
|
|
|
|
| 292 |
with gr.Blocks(title="BlueMagpie-TTS Demo", theme=gr.themes.Soft()) as demo:
|
| 293 |
gr.Markdown(HEADER)
|
| 294 |
|
| 295 |
+
with gr.Accordion("⚙️ 生成參數(預設為官方建議值,三個分頁共用)", open=False):
|
| 296 |
+
with gr.Row():
|
| 297 |
+
g_cfg = gr.Slider(
|
| 298 |
+
1.0, 4.0, value=DEFAULT_CFG, step=0.1,
|
| 299 |
+
label="cfg_value(引導強度)",
|
| 300 |
+
info="越大越貼合語者條件、但可能較不自然(建議 2.0)",
|
| 301 |
+
)
|
| 302 |
+
g_steps = gr.Slider(
|
| 303 |
+
4, 20, value=DEFAULT_STEPS, step=1,
|
| 304 |
+
label="inference_timesteps(取樣步數)",
|
| 305 |
+
info="���多通常品質越好、速度越慢(建議 10)",
|
| 306 |
+
)
|
| 307 |
+
|
| 308 |
with gr.Tab("指定語者"):
|
| 309 |
gr.Markdown(
|
| 310 |
"用模型內附的**語者向量**控制音色。**李宏毅**老師的向量已取得本人授權;"
|
|
|
|
| 323 |
with gr.Column():
|
| 324 |
s_out = gr.Audio(label="合成結果", type="numpy")
|
| 325 |
gr.Examples(EXAMPLE_TEXTS, inputs=s_text, label="範例文字")
|
| 326 |
+
s_btn.click(tts_speaker, [s_text, s_spk, g_cfg, g_steps], s_out)
|
| 327 |
|
| 328 |
with gr.Tab("聲音複製"):
|
| 329 |
gr.Markdown(
|
|
|
|
| 344 |
c_btn = gr.Button("複製音色合成", variant="primary")
|
| 345 |
with gr.Column():
|
| 346 |
c_out = gr.Audio(label="合成結果", type="numpy")
|
| 347 |
+
c_btn.click(tts_clone, [c_text, c_rec, g_cfg, g_steps], c_out)
|
| 348 |
|
| 349 |
with gr.Tab("長文逐句串流"):
|
| 350 |
gr.Markdown(
|
| 351 |
"**長文逐句串流**:把長文切成句子,合成一句就播一句,做出串流(邊聽邊等)效果。"
|
| 352 |
"第一句很快就能聽到,後面邊播邊合成。用**所選語者向量**。\n\n"
|
| 353 |
+
"> ZeroGPU 約 0.44x 即時,句與句之間可能有短暫間隔;每句都套用所選的生成參數(含自動重試)。"
|
| 354 |
"單次串流以 ZeroGPU 時間配額為限(約可串數十句),超長會自動截斷並提示分批。"
|
| 355 |
)
|
| 356 |
with gr.Row():
|
|
|
|
| 366 |
with gr.Column():
|
| 367 |
t_out = gr.Audio(label="逐句串流播放", streaming=True, autoplay=True)
|
| 368 |
gr.Examples(STREAM_EXAMPLES, inputs=t_text, label="長文範例")
|
| 369 |
+
t_btn.click(tts_stream, [t_text, t_spk, g_cfg, g_steps], t_out)
|
| 370 |
|
| 371 |
gr.Markdown(
|
| 372 |
"---\n"
|