"""One-off: synthesize a short Korean sample for every canonical emotion and stitch them into a single wav so the delivery of each emotion can be heard. Each clip announces the emotion name at neutral (base) speed, then speaks a sample sentence steered by that emotion's ``[태그]`` — exactly the path the live voice server uses. Run with the orchestrator venv: .venv/bin/python -m tests.gen_emotion_samples /abs/out.wav """ from __future__ import annotations import asyncio import sys import wave from wsai.backends.melo import MeloTTS # (announced Korean name, emotion tag word, sample sentence) SAMPLES: list[tuple[str, str, str]] = [ ("기쁨", "기쁨", "오늘은 정말 기분 좋은 하루예요!"), ("신남", "신남", "우와, 이거 진짜 신난다! 빨리 하자!"), ("희망", "희망", "우리 분명히 잘 해낼 수 있어요!"), ("슬픔", "슬픔", "조금 속상한 일이 있었어요."), ("화남", "화남", "정말 너무하잖아요, 화가 나요."), ("두려움", "두려움", "어떡하지, 너무 무서워요."), ("놀람", "놀람", "어머, 이게 정말이에요?"), ("혐오", "혐오", "으, 이건 좀 별로예요."), ("차분", "차분", "천천히 하나씩 정리해 볼게요."), ("다정", "다정", "언제든지 편하게 말해 주세요."), ("진지", "진지", "이건 정말 중요한 이야기예요."), ("실망", "실망", "조금 아쉬운 결과네요."), ("피곤", "피곤", "아, 오늘 너무 피곤하네요."), ("사랑스럽게", "사랑스럽게", "당신은 정말 소중한 사람이에요."), ("장난스럽게", "장난스럽게", "히히, 한번 맞혀 보세요!"), ("궁금", "궁금", "그건 대체 왜 그런 걸까요?"), ("속삭임", "속삭임", "조용히, 우리끼리만 아는 비밀이에요."), ("외침", "외침", "다 같이 힘내자, 파이팅!"), ("단호", "단호", "이번엔 반드시 해내겠어요."), ("안도", "안도", "휴, 이제야 마음이 놓이네요."), ] def stitch(paths: list[str], out: str, gap_s: float = 0.45) -> None: with wave.open(paths[0], "rb") as w0: nch, sw, fr = w0.getnchannels(), w0.getsampwidth(), w0.getframerate() silence = b"\x00" * (int(fr * gap_s) * sw * nch) with wave.open(out, "wb") as wo: wo.setnchannels(nch) wo.setsampwidth(sw) wo.setframerate(fr) for i, p in enumerate(paths): with wave.open(p, "rb") as w: wo.writeframes(w.readframes(w.getnframes())) if i < len(paths) - 1: wo.writeframes(silence) async def main(out: str) -> None: tts = MeloTTS() # base speed comes from the new WSAI_TTS_SPEED default (1.15) await tts.warmup() print(f"melo ready ({tts.load_ms} ms), base speed {tts.speed}") paths: list[str] = [] for name, tag, sample in SAMPLES: text = f"{name}. [{tag}] {sample}" p = await tts.synth(text) paths.append(p) print(f" {name:8s} -> {p}") await tts.aclose() stitch(paths, out) print(f"stitched {len(paths)} clips -> {out}") if __name__ == "__main__": out = sys.argv[1] if len(sys.argv) > 1 else "/tmp/emotion_samples.wav" asyncio.run(main(out))