fix(voice): stop dashboard from mangling the leading [감정] tag

The dashboard voice-turn path ran _speech_text() before MeloTTS.synth, which
rewrote a leading "[힘차게] 안녕!" into "힘차게, 안녕!" — reading the first
emotion aloud and destroying the tag before the TTS emotion parser could use it.
Make _speech_text() a pass-through so every emotion tag (including the first)
reaches synth intact and shapes pitch/speed instead of being spoken. Adds a
regression test covering the leading-tag case.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-08-22 10:18:54 +09:00
parent 4db73bf69f
commit 87b77f9997
2 changed files with 20 additions and 13 deletions

View File

@@ -18,7 +18,6 @@ from __future__ import annotations
import json
import logging
import queue
import re
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
@@ -26,20 +25,14 @@ from .monitor import Monitor
log = logging.getLogger("wsai.dashboard")
_EMOTION_RE = re.compile(r"^\s*\[([^\]]+)\]\s*(.*)", re.S)
def _speech_text(reply: str) -> str:
"""Turn a reply like ``[힘차게] 안녕!`` into what the TTS should actually say.
"""Return reply text exactly as authored for the TTS backend.
The bracketed emotion is spoken too (per user request), so the leading tag
becomes a natural spoken word: ``[힘차게] 안녕!`` -> ``힘차게, 안녕!``. Replies
without a tag are spoken as-is."""
m = _EMOTION_RE.match(reply or "")
if not m:
return reply
emotion, rest = m.group(1).strip(), m.group(2).strip()
return f"{emotion}, {rest}" if rest else emotion
The TTS backend itself understands bracketed emotion tags: known emotion
tags steer delivery and are not spoken; non-emotion brackets are spoken.
Do not rewrite a leading tag here, or the first emotion would be read aloud
and lost before ``MeloTTS.synth`` can parse it."""
return reply
def _make_handler(dash: "Dashboard"):