Add standalone morshu-server, update webui to support morshu/dectalk generate

This commit is contained in:
2026-06-05 19:05:00 -05:00
parent 27b24701e8
commit 7d9c6c0edb
4 changed files with 117 additions and 70 deletions
+21 -11
View File
@@ -621,14 +621,26 @@ class TtsToy(Cog):
def _save_morshu_tts(self, text: str, audio_path: str):
"""
Generate TTS audio using MorshuTalk.
Generate TTS audio using MorshuTalk server (HTTP).
Falls back to in-process engine if server is unavailable.
Args:
text: Text to synthesize
audio_path: Output file path
"""
morshu_url = "http://127.0.0.1:3002"
try:
r = requests.get(f"{morshu_url}/say", params={"text": text}, timeout=60)
r.raise_for_status()
with open(audio_path, "wb") as f:
f.write(r.content)
return
except Exception as e:
log.warning(f"[Morshu] Server unavailable ({e}), falling back to in-process engine")
# Fallback to in-process
if not self.morshu:
raise RuntimeError("MorshuTalk engine is not available. Check that g2p_en, numpy, and pydub are installed.")
raise RuntimeError("MorshuTalk engine is not available. Start the morshu-server or install g2p_en, numpy, pydub.")
audio = self.morshu.load_text(text)
if audio is False or audio is None:
@@ -2972,9 +2984,8 @@ class TtsToy(Cog):
mode_override = payload.get("mode_override") # per-request mode from web UI
voice_override = payload.get("voice_override") # per-request voice from web UI
skip_vc = payload.get("skip_vc", False)
skip_post = payload.get("skip_post", False)
guild_id_str = payload.get("guild_id", "")
log.info(f"[WebUI] speak_in_vc: user={user} job={job_id} guild={guild_id_str} mode_override={mode_override} voice_override={voice_override} skip_vc={skip_vc} skip_post={skip_post} text={text[:60]!r}")
log.info(f"[WebUI] speak_in_vc: user={user} job={job_id} guild={guild_id_str} mode_override={mode_override} voice_override={voice_override} skip_vc={skip_vc} text={text[:60]!r}")
webui_url = self._get_webui_url()
secret = self._get_internal_secret()
@@ -3086,14 +3097,13 @@ class TtsToy(Cog):
log.exception(f"[WebUI] VC playback failed for job {job_id}: {e}")
# Post transcript to Discord channel and mark job done
# Post transcript to Discord channel (unless skip_post)
# Resolve the best guild ID for posting: login guild > VC guild > empty
post_guild_id = guild_id_str or (str(member_guild.id) if member_guild else "")
if not skip_post:
await self._handle_webui_post({
"job_id": job_id, "path": audio_path,
"text": text, "user": discord_name, "engine": mode,
"guild_id": post_guild_id,
})
await self._handle_webui_post({
"job_id": job_id, "path": audio_path,
"text": text, "user": discord_name, "engine": mode,
"guild_id": post_guild_id,
})
await asyncio.to_thread(_update_job, "done", path=audio_path)
async def _handle_webui_post(self, post: dict):