Spaces:
Paused
Paused
Commit Β·
2b743ed
1
Parent(s): 3cfcf98
fix: voice cloning playback - add status indicator, fallback, debug logging
Browse files- Show 'PLAYING β Cloned Voice' or 'PLAYING β Stock Voice' in status bar
- Add fallback: if cloned synthesis fails, automatically use stock voice
- Add logging to stream_tts to confirm profile_id is received
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
app.py
CHANGED
|
@@ -872,10 +872,14 @@ with gr.Blocks(title="MomsVoice", css=css_code) as demo:
|
|
| 872 |
|
| 873 |
# 5. Play button β streams TTS audio chunk by chunk
|
| 874 |
def stream_tts(tts_chunks, paras, profile_id):
|
| 875 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 876 |
<div style="margin-top: 12px; display: flex; align-items: center; gap: 10px; justify-content: center;">
|
| 877 |
<span style="width: 8px; height: 8px; border-radius: 50%; background: #4ade80; display: inline-block;"></span>
|
| 878 |
-
<span style="font-size: 11px; color: #4ade80; font-family: monospace;">PLAYING</span>
|
| 879 |
</div>
|
| 880 |
"""
|
| 881 |
_status_done = """
|
|
|
|
| 872 |
|
| 873 |
# 5. Play button β streams TTS audio chunk by chunk
|
| 874 |
def stream_tts(tts_chunks, paras, profile_id):
|
| 875 |
+
import logging as _log
|
| 876 |
+
_log.getLogger(__name__).info("stream_tts called with profile_id=%s", profile_id)
|
| 877 |
+
|
| 878 |
+
voice_mode = "ποΈ Cloned Voice" if profile_id else "π Stock Voice"
|
| 879 |
+
_status_playing = f"""
|
| 880 |
<div style="margin-top: 12px; display: flex; align-items: center; gap: 10px; justify-content: center;">
|
| 881 |
<span style="width: 8px; height: 8px; border-radius: 50%; background: #4ade80; display: inline-block;"></span>
|
| 882 |
+
<span style="font-size: 11px; color: #4ade80; font-family: monospace;">PLAYING β {voice_mode}</span>
|
| 883 |
</div>
|
| 884 |
"""
|
| 885 |
_status_done = """
|
tts.py
CHANGED
|
@@ -60,17 +60,33 @@ def generate_audio_stream(
|
|
| 60 |
|
| 61 |
|
| 62 |
def _start_qwen_worker(chunks, profile_id, chunk_q):
|
| 63 |
-
"""Background thread: synthesize chunks with Qwen3-TTS voice clone (Base 1.7B).
|
|
|
|
| 64 |
def _worker():
|
| 65 |
-
from voice_clone import synthesize_cloned
|
|
|
|
| 66 |
for i, stmt in enumerate(chunks):
|
| 67 |
try:
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
| 69 |
chunk_q.put((i, wav, None))
|
| 70 |
except Exception as exc:
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
chunk_q.put(_SENTINEL)
|
| 75 |
|
| 76 |
threading.Thread(target=_worker, daemon=True).start()
|
|
|
|
| 60 |
|
| 61 |
|
| 62 |
def _start_qwen_worker(chunks, profile_id, chunk_q):
|
| 63 |
+
"""Background thread: synthesize chunks with Qwen3-TTS voice clone (Base 1.7B).
|
| 64 |
+
Falls back to stock voice if cloned synthesis fails."""
|
| 65 |
def _worker():
|
| 66 |
+
from voice_clone import synthesize_cloned, synthesize_custom_voice
|
| 67 |
+
use_fallback = False
|
| 68 |
for i, stmt in enumerate(chunks):
|
| 69 |
try:
|
| 70 |
+
if use_fallback:
|
| 71 |
+
wav, _sr = synthesize_custom_voice(stmt)
|
| 72 |
+
else:
|
| 73 |
+
wav, _sr = synthesize_cloned(stmt, profile_id)
|
| 74 |
chunk_q.put((i, wav, None))
|
| 75 |
except Exception as exc:
|
| 76 |
+
if not use_fallback:
|
| 77 |
+
logger.warning("Cloned voice failed (chunk %d): %s β falling back to stock voice", i, exc)
|
| 78 |
+
use_fallback = True
|
| 79 |
+
try:
|
| 80 |
+
wav, _sr = synthesize_custom_voice(stmt)
|
| 81 |
+
chunk_q.put((i, wav, None))
|
| 82 |
+
except Exception as exc2:
|
| 83 |
+
logger.exception("Stock voice also failed on chunk %d", i)
|
| 84 |
+
chunk_q.put((i, None, str(exc2)))
|
| 85 |
+
return
|
| 86 |
+
else:
|
| 87 |
+
logger.exception("Stock voice synthesis failed on chunk %d", i)
|
| 88 |
+
chunk_q.put((i, None, str(exc)))
|
| 89 |
+
return
|
| 90 |
chunk_q.put(_SENTINEL)
|
| 91 |
|
| 92 |
threading.Thread(target=_worker, daemon=True).start()
|