minhahwang Copilot commited on
Commit
bea718a
·
1 Parent(s): 5ae6bba

feat: show paragraph progress during Play + warmup first paragraphs at startup

Browse files

- Play status shows 'Paragraph X / N' instead of blank
- Background warmup pre-generates first paragraph of all 10 stories (stock voice)
- Uses disk cache directly so cancel_pregeneration() won't clear warmup results

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Files changed (1) hide show
  1. app.py +31 -3
app.py CHANGED
@@ -419,6 +419,33 @@ from inference_lfm import get_lfm_model
419
  get_lfm_model()
420
  print("[MomsVoice] LFM Q&A model ready. All models preloaded.")
421
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
 
423
  # Gradio Application Core setup
424
  with gr.Blocks(title="MomsVoice", css=css_code) as demo:
@@ -933,7 +960,7 @@ with gr.Blocks(title="MomsVoice", css=css_code) as demo:
933
 
934
  n = len(tts_chunks)
935
  yield (gr.update(), _status_playing,
936
- "",
937
  gr.Button(visible=False), gr.Button(visible=True), gr.Button(visible=False),
938
  gr.Slider(value=0), render_story_text(paras, 0) if paras else "",
939
  gr.HTML(visible=False),
@@ -950,13 +977,14 @@ with gr.Blocks(title="MomsVoice", css=css_code) as demo:
950
  return
951
  para_idx = min(int(i * n_paras / total), n_paras - 1) if total > 0 else 0
952
  is_last = (i + 1 >= total)
953
- yield ((sample_rate, wav), _status_playing, "",
 
954
  gr.Button(visible=False), gr.Button(visible=True), gr.Button(visible=True),
955
  gr.Slider(value=para_idx), render_story_text(paras, para_idx),
956
  gr.HTML(visible=is_last),
957
  gr.HTML(visible=False), gr.Group(visible=False), gr.Button(visible=False))
958
 
959
- yield (gr.update(), _status_done, "",
960
  gr.Button(visible=True), gr.Button(visible=False), gr.Button(visible=False),
961
  gr.Slider(value=max(n_paras - 1, 0)), render_story_text(paras, max(n_paras - 1, 0)),
962
  gr.HTML(visible=True),
 
419
  get_lfm_model()
420
  print("[MomsVoice] LFM Q&A model ready. All models preloaded.")
421
 
422
+ # Pre-generate first paragraph audio for all stories (stock voice) for instant start
423
+ import threading
424
+
425
+ def _warmup_first_paragraphs():
426
+ """Background: pre-generate first paragraph of each story with stock voice to disk cache."""
427
+ import logging as _log
428
+ from tts import _get_cached_audio, _save_cached_audio, _synthesize_single
429
+ _logger = _log.getLogger("warmup")
430
+ for book in mock_books:
431
+ try:
432
+ paras = load_paragraphs(book["story_path"])
433
+ if not paras:
434
+ continue
435
+ first_chunks = split_into_chunks(paras[0])
436
+ for chunk in first_chunks:
437
+ if _get_cached_audio(chunk, None) is not None:
438
+ continue # Already cached
439
+ wav, sr = _synthesize_single(chunk, None)
440
+ _save_cached_audio(chunk, None, wav, sr)
441
+ _logger.info("Warmed: %s (%d chunks)", book["title"], len(first_chunks))
442
+ except Exception as e:
443
+ _logger.warning("Warmup failed for %s: %s", book.get("title", "?"), e)
444
+ _logger.info("All first paragraphs warmed.")
445
+
446
+ threading.Thread(target=_warmup_first_paragraphs, daemon=True).start()
447
+ print("[MomsVoice] Background warmup started: pre-generating first paragraph for all stories.")
448
+
449
 
450
  # Gradio Application Core setup
451
  with gr.Blocks(title="MomsVoice", css=css_code) as demo:
 
960
 
961
  n = len(tts_chunks)
962
  yield (gr.update(), _status_playing,
963
+ f"<div style='text-align:center;font-size:10px;color:#4ade80;font-family:monospace;margin-top:8px;'>▶ Paragraph 1 / {n_paras}</div>",
964
  gr.Button(visible=False), gr.Button(visible=True), gr.Button(visible=False),
965
  gr.Slider(value=0), render_story_text(paras, 0) if paras else "",
966
  gr.HTML(visible=False),
 
977
  return
978
  para_idx = min(int(i * n_paras / total), n_paras - 1) if total > 0 else 0
979
  is_last = (i + 1 >= total)
980
+ para_status = f"<div style='text-align:center;font-size:10px;color:#4ade80;font-family:monospace;margin-top:8px;'>▶ Paragraph {para_idx + 1} / {n_paras}</div>"
981
+ yield ((sample_rate, wav), _status_playing, para_status,
982
  gr.Button(visible=False), gr.Button(visible=True), gr.Button(visible=True),
983
  gr.Slider(value=para_idx), render_story_text(paras, para_idx),
984
  gr.HTML(visible=is_last),
985
  gr.HTML(visible=False), gr.Group(visible=False), gr.Button(visible=False))
986
 
987
+ yield (gr.update(), _status_done, f"<div style='text-align:center;font-size:10px;color:#94a3b8;font-family:monospace;margin-top:8px;'>✅ Story complete</div>",
988
  gr.Button(visible=True), gr.Button(visible=False), gr.Button(visible=False),
989
  gr.Slider(value=max(n_paras - 1, 0)), render_story_text(paras, max(n_paras - 1, 0)),
990
  gr.HTML(visible=True),