diff --git a/tests/test_emotion.py b/tests/test_emotion.py index 1130244..083c5c4 100644 --- a/tests/test_emotion.py +++ b/tests/test_emotion.py @@ -7,6 +7,7 @@ from wsai.backends.emotion import ( match_emotion, parse_segments, ) +from wsai.dashboard import _speech_text BASE = 1.3 @@ -74,3 +75,16 @@ def test_persona_examples_are_all_recognised(): # read aloud instead of shaping the voice. for word in ["힘차게", "궁금", "반가움", "차분하게", "웃으며", "속상함"]: assert match_emotion(word) is not None, word + + +def test_voice_turn_keeps_leading_emotion_tag_for_tts_parser(): + text = "[속상함] 정말 힘들었겠다. [힘차게] 하지만 넌 할 수 있어!" + + spoken = _speech_text(text) + segs = parse_segments(spoken, BASE) + + assert spoken == text + assert segs[0].text == "정말 힘들었겠다." + assert segs[0].pitch == EMOTION_PARAMS["sad"][1] + assert segs[1].text == "하지만 넌 할 수 있어!" + assert segs[1].pitch == EMOTION_PARAMS["hopeful"][1] diff --git a/wsai/dashboard.py b/wsai/dashboard.py index e2397a4..5476999 100644 --- a/wsai/dashboard.py +++ b/wsai/dashboard.py @@ -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"):