"""Voice = Simlish babble + emoticon + browser-TTS params. No model, no GPU, no server cost — the frontend speaks `simlish` via the Web Speech API and shows `emoticon` in the bubble. Rage register uses a harsher syllable pool + lower, faster voice.""" from __future__ import annotations import random from app.appearance import _face _WORD = { "content": "cheerful", "excited": "excited", "sad": "sad", "angry": "angry", "neutral": "calm", } _EMOTICON = { "content": "(◕‿◕)", "excited": "(★▽★)", "sad": "(╥﹏╥)", "angry": "(╬ಠ益ಠ)", "neutral": "(・_・)", } _SOFT = ["ba", "bo", "doo", "la", "lee", "mee", "na", "no", "wa", "yu", "pi", "to"] _RAGE = ["grr", "kah", "ztt", "brk", "gnak", "rrg", "tzk", "drr", "skuh", "vrr"] # region -> (syllable pool, word count, exclaim, pitch, rate) _VOICE = { "content": (_SOFT, 3, False, 1.4, 1.0), "excited": (_SOFT, 4, True, 1.7, 1.25), "sad": (_SOFT, 2, False, 1.1, 0.8), "angry": (_RAGE, 4, True, 0.7, 1.35), "neutral": (_SOFT, 3, False, 1.3, 1.0), } def _region(mood: list[int]) -> str: return _face(mood[0], mood[1]) def mood_word(mood: list[int]) -> str: return _WORD[_region(mood)] def emoticon(mood: list[int]) -> str: return _EMOTICON[_region(mood)] def simlish(mood: list[int], *, rng: random.Random | None = None) -> str: pool, nwords, exclaim, _pitch, _rate = _VOICE[_region(mood)] rng = rng or random.Random() words = ["".join(rng.choice(pool) for _ in range(rng.randint(1, 3))) for _ in range(nwords)] return " ".join(words) + ("!" if exclaim else "") def voice_params(mood: list[int]) -> dict: _pool, _n, _ex, pitch, rate = _VOICE[_region(mood)] return {"pitch": pitch, "rate": rate}