feat(dashboard): 4-way roster (user/bot/voice/role), persistence, TTS all-emotions, layout
- 유저 등록/관리 search now has 4 types: 유저(non-bot members), 봇(bot members), 통화방(current voice-channel members, bot flag enriched), 역할(roles — expandable to the members under each role; register the role OR a member under it). - Persist settings to a JSON state store (WSAI_STATE_FILE, default ~/.config/wsai/state.json) so they survive a service/container restart: per-guild listen lists + bargeIn (BotControl), TTS base/overrides and the chosen STT/LLM models (Dashboard). Applied on voice-server startup before warm. - TTS 감정 선택에 최상단 "전체변경 (모든 감정)" 추가: 적용하면 base를 그 값으로 세팅하고 모든 per-emotion override를 지워 전 감정이 한 번에 그 값으로 말합니다. - Move the component status bar (눈/시각/귀/LLM/입) above the bot bar. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -100,6 +100,28 @@ def _run_stt_test(host: str, port: int) -> None:
|
||||
dash.stop()
|
||||
|
||||
|
||||
def _apply_persisted_state(stt, tts, brain) -> None:
|
||||
"""Apply dashboard settings saved to the state store (STT/LLM model + TTS
|
||||
controls) onto freshly-built backends, so they survive a restart."""
|
||||
from . import state_store
|
||||
st = state_store.load()
|
||||
models = st.get("models") or {}
|
||||
if models.get("stt") and stt is not None:
|
||||
stt.model = str(models["stt"])
|
||||
if models.get("llm") and brain is not None:
|
||||
brain.model = str(models["llm"])
|
||||
tj = st.get("tts") or {}
|
||||
base = tj.get("base") or {}
|
||||
for k in ("speed", "word_gap", "sentence_gap", "pitch"):
|
||||
if base.get(k) is not None and tts is not None:
|
||||
try:
|
||||
setattr(tts, k, float(base[k]))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if tts is not None and isinstance(tj.get("overrides"), dict):
|
||||
tts.emotion_overrides = {k: dict(v) for k, v in tj["overrides"].items() if isinstance(v, dict)}
|
||||
|
||||
|
||||
def _run_voice_server(host: str, port: int) -> None:
|
||||
"""Serve the STT+TTS voice-turn endpoint that the Discord bot (dave/bot.mjs)
|
||||
calls: it POSTs a captured utterance wav and gets back the reply wav to play
|
||||
@@ -129,6 +151,10 @@ def _run_voice_server(host: str, port: int) -> None:
|
||||
monitor = Monitor()
|
||||
stt = WhisperSTT()
|
||||
tts = MeloTTS()
|
||||
# Restore persisted dashboard settings (models + TTS controls) BEFORE warmup
|
||||
# so the worker loads the last-chosen model. Bot lists/toggles are restored
|
||||
# inside BotControl. Applied before dash.warm() so nothing reloads twice.
|
||||
_apply_persisted_state(stt, tts, brain)
|
||||
dash = Dashboard(monitor, host=host, port=port, stt=stt, tts=tts, brain=brain)
|
||||
dash.start()
|
||||
monitor.set_components({"source": "none", "vision": "none", "stt": "whisper",
|
||||
|
||||
Reference in New Issue
Block a user