Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -121,7 +121,7 @@ def _crossfade_concat(a: np.ndarray, b: np.ndarray, sr: int, fade_s: float) -> n
|
|
| 121 |
rest = b[fade_n:]
|
| 122 |
return np.concatenate([head, tail, rest], axis=0)
|
| 123 |
|
| 124 |
-
def _bpe_prefixes(text: str, lang: str, step_tokens: int)
|
| 125 |
"""
|
| 126 |
Прэфіксы па BPE/субсловах; калі encode/decode недаступны — псэўда-токены (словы+прабелы).
|
| 127 |
"""
|
|
@@ -308,16 +308,20 @@ def _yield_buffered_chunks_for_gradio(
|
|
| 308 |
time.sleep(buf.size / float(sr))
|
| 309 |
|
| 310 |
# ---------------------------------------------------------
|
| 311 |
-
# 6) Асноўная функцыя TTS для Gradio
|
|
|
|
|
|
|
|
|
|
| 312 |
# ---------------------------------------------------------
|
| 313 |
@spaces.GPU(duration=60)
|
| 314 |
def text_to_speech(belarusian_story, speaker_audio_file=None):
|
| 315 |
"""
|
| 316 |
-
|
| 317 |
-
-
|
| 318 |
-
-
|
| 319 |
"""
|
| 320 |
if not belarusian_story or str(belarusian_story).strip() == "":
|
|
|
|
| 321 |
raise gr.Error("Увядзі хоць нейкі тэкст 🙂")
|
| 322 |
|
| 323 |
# Голас па змаўчанні
|
|
@@ -355,13 +359,17 @@ def text_to_speech(belarusian_story, speaker_audio_file=None):
|
|
| 355 |
|
| 356 |
full_audio_chunks: List[np.ndarray] = []
|
| 357 |
|
|
|
|
| 358 |
for sr, chunk in _yield_buffered_chunks_for_gradio(generator, sampling_rate, MIN_BUFFER_S):
|
| 359 |
full_audio_chunks.append(chunk)
|
| 360 |
-
yield (sr, chunk)
|
| 361 |
|
| 362 |
if not full_audio_chunks:
|
| 363 |
-
|
|
|
|
|
|
|
| 364 |
|
|
|
|
| 365 |
full_audio = full_audio_chunks[0]
|
| 366 |
for i in range(1, len(full_audio_chunks)):
|
| 367 |
full_audio = _crossfade_concat(full_audio, full_audio_chunks[i], sampling_rate, FADE_S)
|
|
@@ -369,7 +377,8 @@ def text_to_speech(belarusian_story, speaker_audio_file=None):
|
|
| 369 |
try:
|
| 370 |
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".wav")
|
| 371 |
write(tmp.name, sampling_rate, full_audio.astype(np.float32))
|
| 372 |
-
|
|
|
|
| 373 |
except Exception as e:
|
| 374 |
raise gr.Error(f"Памылка пры запісе фінальнага WAV: {e}")
|
| 375 |
|
|
@@ -414,7 +423,9 @@ analytics_script = """
|
|
| 414 |
"""
|
| 415 |
|
| 416 |
# ---------------------------------------------------------
|
| 417 |
-
# 8) Gradio UI
|
|
|
|
|
|
|
| 418 |
# ---------------------------------------------------------
|
| 419 |
with gr.Blocks() as demo:
|
| 420 |
gr.HTML(analytics_script)
|
|
@@ -428,15 +439,24 @@ with gr.Blocks() as demo:
|
|
| 428 |
interactive=True,
|
| 429 |
),
|
| 430 |
],
|
| 431 |
-
outputs=
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 437 |
description="""
|
| 438 |
-
<
|
| 439 |
-
|
|
|
|
|
|
|
| 440 |
""",
|
| 441 |
examples=examples,
|
| 442 |
cache_examples=False,
|
|
|
|
| 121 |
rest = b[fade_n:]
|
| 122 |
return np.concatenate([head, tail, rest], axis=0)
|
| 123 |
|
| 124 |
+
def _bpe_prefixes(text: str, lang: str, step_tokens: int):
|
| 125 |
"""
|
| 126 |
Прэфіксы па BPE/субсловах; калі encode/decode недаступны — псэўда-токены (словы+прабелы).
|
| 127 |
"""
|
|
|
|
| 308 |
time.sleep(buf.size / float(sr))
|
| 309 |
|
| 310 |
# ---------------------------------------------------------
|
| 311 |
+
# 6) Асноўная функцыя TTS для Gradio
|
| 312 |
+
# Цяпер ВЫХАД = ДВА элементы:
|
| 313 |
+
# 1) Стрымінг па токенах (грайцеся ўжывую) — gr.Audio(type='numpy')
|
| 314 |
+
# 2) Згенераванае аўдыя (па токенах, мінімальная затрымка) — толькі ФІНАЛЬНЫ файл
|
| 315 |
# ---------------------------------------------------------
|
| 316 |
@spaces.GPU(duration=60)
|
| 317 |
def text_to_speech(belarusian_story, speaker_audio_file=None):
|
| 318 |
"""
|
| 319 |
+
Вяртаем два выхады:
|
| 320 |
+
- (sr, chunk) для стрымінгавага прайгравальніка (на кожным кроку)
|
| 321 |
+
- None / шлях да WAV у ФІНАЛЕ для элемента «Згенераванае аўдыя...»
|
| 322 |
"""
|
| 323 |
if not belarusian_story or str(belarusian_story).strip() == "":
|
| 324 |
+
# Для абодвух выхадаў вяртаем None
|
| 325 |
raise gr.Error("Увядзі хоць нейкі тэкст 🙂")
|
| 326 |
|
| 327 |
# Голас па змаўчанні
|
|
|
|
| 359 |
|
| 360 |
full_audio_chunks: List[np.ndarray] = []
|
| 361 |
|
| 362 |
+
# 1) падчас стриму — аддаем у першы выход (стрымінг), другі — None
|
| 363 |
for sr, chunk in _yield_buffered_chunks_for_gradio(generator, sampling_rate, MIN_BUFFER_S):
|
| 364 |
full_audio_chunks.append(chunk)
|
| 365 |
+
yield ( (sr, chunk), None )
|
| 366 |
|
| 367 |
if not full_audio_chunks:
|
| 368 |
+
# Нічога не назбіралі — абодва выхады None
|
| 369 |
+
yield ( None, None )
|
| 370 |
+
return
|
| 371 |
|
| 372 |
+
# 2) збіраем фінальны WAV і вяртаем яго ў другі выход
|
| 373 |
full_audio = full_audio_chunks[0]
|
| 374 |
for i in range(1, len(full_audio_chunks)):
|
| 375 |
full_audio = _crossfade_concat(full_audio, full_audio_chunks[i], sampling_rate, FADE_S)
|
|
|
|
| 377 |
try:
|
| 378 |
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".wav")
|
| 379 |
write(tmp.name, sampling_rate, full_audio.astype(np.float32))
|
| 380 |
+
# у фінале — першы выход (стрымінг) прыбіраем (None), другі — шлях да файла
|
| 381 |
+
yield ( None, tmp.name )
|
| 382 |
except Exception as e:
|
| 383 |
raise gr.Error(f"Памылка пры запісе фінальнага WAV: {e}")
|
| 384 |
|
|
|
|
| 423 |
"""
|
| 424 |
|
| 425 |
# ---------------------------------------------------------
|
| 426 |
+
# 8) Gradio UI:
|
| 427 |
+
# - Новы ЭЛЕМЕНТ для стрыму: "Стрымінг па токенах (анлайн прайграванне)" — прымае (sr, ndarray)
|
| 428 |
+
# - Стары ЭЛЕМЕНТ "Згенераванае аўдыя (па токенах, мінімальная затрымка)" — цяпер ТОЛЬКІ фінальны файл
|
| 429 |
# ---------------------------------------------------------
|
| 430 |
with gr.Blocks() as demo:
|
| 431 |
gr.HTML(analytics_script)
|
|
|
|
| 439 |
interactive=True,
|
| 440 |
),
|
| 441 |
],
|
| 442 |
+
outputs=[
|
| 443 |
+
gr.Audio(
|
| 444 |
+
type="numpy", # стримінг: (sr, np.ndarray)
|
| 445 |
+
label="Стрымінг па токенах (анлайн прайграванне)",
|
| 446 |
+
autoplay=True,
|
| 447 |
+
),
|
| 448 |
+
gr.Audio(
|
| 449 |
+
type="filepath", # толькі фінальны шлях да WAV
|
| 450 |
+
label="Згенераванае аўдыя (па токенах, мінімальная затрымка)",
|
| 451 |
+
autoplay=False,
|
| 452 |
+
),
|
| 453 |
+
],
|
| 454 |
+
title="Belarusian TTS — Token Streaming (два выхады)",
|
| 455 |
description="""
|
| 456 |
+
<ul>
|
| 457 |
+
<li><b>Стрымінг па токенах</b> — жывы прайгравальнік, атрымлівае маленькія чанкі гуку па меры генерацыі.</li>
|
| 458 |
+
<li><b>Згенераванае аўдыя (па токенах, мінімальная затрымка)</b> — толькі <i>фінальны</i> цэлы WAV-файл для загрузкі/прайгравання.</li>
|
| 459 |
+
</ul>
|
| 460 |
""",
|
| 461 |
examples=examples,
|
| 462 |
cache_examples=False,
|