archivartaunik commited on
Commit
88bcd48
·
verified ·
1 Parent(s): 9d7c77d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +20 -23
app.py CHANGED
@@ -78,7 +78,7 @@ XTTS_MODEL.tokenizer = tokenizer
78
  # =========================================================
79
  # 4) Streaming-міксін у стылі transformers-stream-generator
80
  # =========================================================
81
- MIN_BUFFER_S = 0.06 # 60 мс стабільней для браўзера
82
  FADE_S = 0.008
83
  TOKENS_PER_STEP = 4
84
 
@@ -271,12 +271,10 @@ def text_to_speech(belarusian_story, speaker_audio_file=None):
271
 
272
  full_audio_chunks: List[np.ndarray] = []
273
 
274
- # 1) струменім невялікімі буферамі — толькі ў stream_pipe
275
  for buf in _chunker(gen, sampling_rate, MIN_BUFFER_S):
276
  full_audio_chunks.append(buf)
277
  yield (_pcm_f32_to_b64(buf), None)
278
 
279
- # 2) фінал: запіс у WAV і STOP-сігнал для кліента
280
  if not full_audio_chunks:
281
  yield ("__STOP__", None)
282
  return
@@ -290,7 +288,7 @@ def text_to_speech(belarusian_story, speaker_audio_file=None):
290
  raise gr.Error(f"Памылка пры запісе фінальнага WAV: {e}")
291
 
292
  # ---------------------------------------------------------
293
- # 7) UI: Buttons + схаваны канал + client-side JS
294
  # ---------------------------------------------------------
295
  examples = [
296
  ["Прывітанне! Гэта праверка жывога струменя беларускага TTS.", "Nestarka.wav"],
@@ -303,28 +301,27 @@ with gr.Blocks() as demo:
303
  inp_text = gr.Textbox(lines=5, label="Тэкст на беларускай мове")
304
  inp_voice = gr.Audio(type="filepath", label="Прыклад голасу (7+ сек)", interactive=True)
305
 
 
306
  with gr.Row():
307
  play_btn = gr.Button("▶️ Play")
308
  stop_btn = gr.Button("⏹ Stop")
309
- gr.Markdown(
310
- f"**Sample rate:** {sampling_rate} Hz • Націсні *Play* перад генерацыяй або падчас — для запуску аўдыя."
311
- )
312
 
313
- # Схаваны канал для стриму base64-чанкаў
314
  stream_pipe = gr.Textbox(value="", visible=False, label="stream_pipe")
315
  final_file = gr.Audio(type="filepath", label="Згенераванае аўдыя (фінальны файл)", autoplay=False)
316
 
317
  run_btn = gr.Button("Згенераваць")
318
 
319
- # --- JS-код (чысцей і надзейней за HTML-ін'екцыю) ---
320
- PLAY_JS = f"""
321
  () => {{
322
  const sampleRate = {sampling_rate};
323
  const AC = window.AudioContext || window.webkitAudioContext;
324
  if (!AC) return;
325
  if (!window.__wa) {{
326
  const ctx = new AC({{ sampleRate }});
327
- const bufferSize = 2048; // ≈40–90мс у залежнасці ад SR
328
  const node = ctx.createScriptProcessor(bufferSize, 0, 1);
329
  let queue = [];
330
  let playing = false;
@@ -351,21 +348,21 @@ with gr.Blocks() as demo:
351
  stop: () => {{ playing = false; }},
352
  reset: () => {{ playing = false; queue = []; }},
353
  }};
 
 
354
  }}
355
- window.__wa.start();
356
  }}
357
  """
358
 
359
  STOP_JS = "() => { if (window.__wa) window.__wa.stop(); }"
 
360
 
361
- RESET_JS = "() => { if (window.__wa) window.__wa.reset(); }"
362
-
363
- # Base64 -> Float32 + push/stop
364
  PUSH_JS = """
365
  (b64) => {
366
  if (!window.__wa || !b64) return;
367
  if (b64 === "__STOP__") { window.__wa.stop(); return; }
368
- // b64 PCM Float32 -> Float32Array
369
  const bin = atob(b64);
370
  const len = bin.length;
371
  const buf = new ArrayBuffer(len);
@@ -376,28 +373,28 @@ with gr.Blocks() as demo:
376
  }
377
  """
378
 
379
- # Прывязкі падзей:
380
  play_btn.click(fn=None, inputs=[], outputs=[], js=PLAY_JS)
381
  stop_btn.click(fn=None, inputs=[], outputs=[], js=STOP_JS)
382
 
383
- # Перад пачаткам новай генерацыі — ачышчаем чаргу на кліенце
384
- run_btn.click(fn=None, inputs=[], outputs=[], js=RESET_JS)
385
 
386
- # Сам стримінг: Python -> (stream_pipe, final_file)
387
  run_btn.click(
388
  fn=text_to_speech,
389
  inputs=[inp_text, inp_voice],
390
  outputs=[stream_pipe, final_file]
391
  )
392
 
393
- # На кожнае абнаўленне stream_pipe — пуш у WebAudio (кліент)
394
  stream_pipe.change(fn=None, inputs=[stream_pipe], outputs=[], js=PUSH_JS)
395
 
 
396
  gr.Examples(
397
  examples=examples,
398
  inputs=[inp_text, inp_voice],
399
- outputs=[stream_pipe, final_file],
400
- fn=text_to_speech,
401
  cache_examples=False,
402
  )
403
 
 
78
  # =========================================================
79
  # 4) Streaming-міксін у стылі transformers-stream-generator
80
  # =========================================================
81
+ MIN_BUFFER_S = 0.06 # ~60 мс для гладкага плыннага прайгравання
82
  FADE_S = 0.008
83
  TOKENS_PER_STEP = 4
84
 
 
271
 
272
  full_audio_chunks: List[np.ndarray] = []
273
 
 
274
  for buf in _chunker(gen, sampling_rate, MIN_BUFFER_S):
275
  full_audio_chunks.append(buf)
276
  yield (_pcm_f32_to_b64(buf), None)
277
 
 
278
  if not full_audio_chunks:
279
  yield ("__STOP__", None)
280
  return
 
288
  raise gr.Error(f"Памылка пры запісе фінальнага WAV: {e}")
289
 
290
  # ---------------------------------------------------------
291
+ # 7) UI: аўта-Play пры "Згенераваць" ніт + reset + start у адным JS)
292
  # ---------------------------------------------------------
293
  examples = [
294
  ["Прывітанне! Гэта праверка жывога струменя беларускага TTS.", "Nestarka.wav"],
 
301
  inp_text = gr.Textbox(lines=5, label="Тэкст на беларускай мове")
302
  inp_voice = gr.Audio(type="filepath", label="Прыклад голасу (7+ сек)", interactive=True)
303
 
304
+ # Кастомныя кнопкі (Play/Stop пакідаю на ўсялякі выпадак)
305
  with gr.Row():
306
  play_btn = gr.Button("▶️ Play")
307
  stop_btn = gr.Button("⏹ Stop")
308
+ gr.Markdown(f"**Sample rate:** {sampling_rate} Hz")
 
 
309
 
310
+ # Схаваны канал для стриму base64-чанкаў і фінальны файл
311
  stream_pipe = gr.Textbox(value="", visible=False, label="stream_pipe")
312
  final_file = gr.Audio(type="filepath", label="Згенераванае аўдыя (фінальны файл)", autoplay=False)
313
 
314
  run_btn = gr.Button("Згенераваць")
315
 
316
+ # --- JS: ініт + reset + start (аўтаматычны Play на кнопку Згенераваць) ---
317
+ INIT_RESET_AND_PLAY_JS = f"""
318
  () => {{
319
  const sampleRate = {sampling_rate};
320
  const AC = window.AudioContext || window.webkitAudioContext;
321
  if (!AC) return;
322
  if (!window.__wa) {{
323
  const ctx = new AC({{ sampleRate }});
324
+ const bufferSize = 2048;
325
  const node = ctx.createScriptProcessor(bufferSize, 0, 1);
326
  let queue = [];
327
  let playing = false;
 
348
  stop: () => {{ playing = false; }},
349
  reset: () => {{ playing = false; queue = []; }},
350
  }};
351
+ }} else {{
352
+ window.__wa.reset();
353
  }}
354
+ window.__wa.start(); // Аўта-Play
355
  }}
356
  """
357
 
358
  STOP_JS = "() => { if (window.__wa) window.__wa.stop(); }"
359
+ PLAY_JS = "() => { if (window.__wa) window.__wa.start(); }"
360
 
361
+ # Base64 -> Float32 + push/stop у канцы
 
 
362
  PUSH_JS = """
363
  (b64) => {
364
  if (!window.__wa || !b64) return;
365
  if (b64 === "__STOP__") { window.__wa.stop(); return; }
 
366
  const bin = atob(b64);
367
  const len = bin.length;
368
  const buf = new ArrayBuffer(len);
 
373
  }
374
  """
375
 
376
+ # Ручныя кнопкі
377
  play_btn.click(fn=None, inputs=[], outputs=[], js=PLAY_JS)
378
  stop_btn.click(fn=None, inputs=[], outputs=[], js=STOP_JS)
379
 
380
+ # Аўта-ініт+reset+play ПЕРАД стартам сервэрнай генерацыі
381
+ run_btn.click(fn=None, inputs=[], outputs=[], js=INIT_RESET_AND_PLAY_JS)
382
 
383
+ # Стрымінг (сервер)
384
  run_btn.click(
385
  fn=text_to_speech,
386
  inputs=[inp_text, inp_voice],
387
  outputs=[stream_pipe, final_file]
388
  )
389
 
390
+ # Пуш чанкаў у WebAudio пры кожным абнаўленні схаванага канала
391
  stream_pipe.change(fn=None, inputs=[stream_pipe], outputs=[], js=PUSH_JS)
392
 
393
+ # Прыклады: толькі запаўняем палі (не запускаем), каб аўта-Play быў праз «Згенераваць»
394
  gr.Examples(
395
  examples=examples,
396
  inputs=[inp_text, inp_voice],
397
+ fn=None,
 
398
  cache_examples=False,
399
  )
400