diff --git a/ttstoy/ttstoy.py b/ttstoy/ttstoy.py index 1a8a176..b3c9761 100644 --- a/ttstoy/ttstoy.py +++ b/ttstoy/ttstoy.py @@ -122,7 +122,7 @@ def _save_emoji_sfx_map(mapping: dict): json.dump(mapping, f, ensure_ascii=False, indent=2) -# Live reference — all code reads from this dict; _reload_emoji_sfx_map() refreshes it. +# Live reference - all code reads from this dict; _reload_emoji_sfx_map() refreshes it. EMOJI_SFX_FOLDERS: dict = _load_emoji_sfx_map() @@ -457,7 +457,7 @@ class TtsToy(Cog): def _kill_leftover_webui(self): """Terminate any web UI subprocess left over from before the web UI moved out of the bot. It ran from /webui/app.py, which no - longer exists — so a matching process is guaranteed stale.""" + longer exists - so a matching process is guaranteed stale.""" try: pattern = str(Path(__file__).resolve().parent / "webui" / "app.py") result = subprocess.run( @@ -830,7 +830,7 @@ class TtsToy(Cog): voice_segments = _split_voice_segments(text) has_voice_switches = len(voice_segments) > 1 or voice_segments[0][0] is not None - # Fast path: no voice switches — use the legacy single-engine path + # Fast path: no voice switches - use the legacy single-engine path if not has_voice_switches: return self._render_single_mode( api_key, model, voice_id, text, output_path, sfx_volume, @@ -1032,7 +1032,7 @@ class TtsToy(Cog): @commands.group(name="chatterbox", invoke_without_command=True) async def chatterbox_group(self, ctx: commands.Context): - """Chatterbox TTS voice management — upload, tune, and share cloned voices. + """Chatterbox TTS voice management - upload, tune, and share cloned voices. Use `[p]help chatterbox` to see all subcommands. """ @@ -1049,13 +1049,13 @@ class TtsToy(Cog): "", "**── Voice Cloning ──**", "Upload a voice clip and Chatterbox will clone it for TTS.", - f"• `{prefix}chatterbox addvoice ` — attach a .wav or .mp3 (5+ sec)", - f"• `{prefix}chatterbox addvoice ` — or paste a direct link", - f"• `{prefix}chatterbox removevoice ` — delete a voice", - f"• `{prefix}chatterbox myvoices` — see your uploaded voices", - f"• `{prefix}ttstoy myvoice ` — switch your active voice", + f"• `{prefix}chatterbox addvoice ` - attach a .wav or .mp3 (5+ sec)", + f"• `{prefix}chatterbox addvoice ` - or paste a direct link", + f"• `{prefix}chatterbox removevoice ` - delete a voice", + f"• `{prefix}chatterbox myvoices` - see your uploaded voices", + f"• `{prefix}ttstoy myvoice ` - switch your active voice", "", - "Tips: 5–15s of clear speech, one speaker, no background noise.", + "Tips: 5-15s of clear speech, one speaker, no background noise.", ".wav works best, .mp3 accepted. Short clips auto-loop to 5s.", "", "**── Special Tokens (Turbo model) ──**", @@ -1068,9 +1068,9 @@ class TtsToy(Cog): "**── Voice Settings ──**", "All saved per voice per user. Each voice keeps its own tuning.", "", - f"• `{prefix}chatterbox temp [0.0–1.5]` — randomness", - f"• `{prefix}chatterbox exag [0.25–2.0]` — expressiveness", - f"• `{prefix}chatterbox volume [-20–20]` — dB loudness offset", + f"• `{prefix}chatterbox temp [0.0-1.5]` - randomness", + f"• `{prefix}chatterbox exag [0.25-2.0]` - expressiveness", + f"• `{prefix}chatterbox volume [-20-20]` - dB loudness offset", "Append `reset` to any of the above to clear it.", "", "**── Voice Sharing ──**", @@ -1116,8 +1116,8 @@ class TtsToy(Cog): f"**Loaded:** {'✅' if loaded else '❌'}", "", "Available models:", - "• `turbo` — fast, 350M params, supports [laugh]/[cough]/etc tags", - "• `original` — better voice cloning, 0.5B params, stronger emotion control", + "• `turbo` - fast, 350M params, supports [laugh]/[cough]/etc tags", + "• `original` - better voice cloning, 0.5B params, stronger emotion control", "", f"Switch: `{ctx.clean_prefix}chatterbox model turbo` or `{ctx.clean_prefix}chatterbox model original`", ] @@ -1232,11 +1232,11 @@ class TtsToy(Cog): f"**Current TTS Mode: {mode_emoji} {current.upper()}**", "", "Available modes:", - "- `minimax` – Use MiniMax cloud API (requires API key)", - "- `chatterbox` – Use local Chatterbox TTS server (AI voice cloning)", - "- `dectalk` – Use DECTalk API (classic robotic voice)", - f"- `morshu` – Use MorshuTalk ({'available' if MORSHU_AVAILABLE else 'not installed'})", - f"- `vox` – Black Mesa VOX announcer ({'available' if VOX_AVAILABLE else 'not installed'})", + "- `minimax` - Use MiniMax cloud API (requires API key)", + "- `chatterbox` - Use local Chatterbox TTS server (AI voice cloning)", + "- `dectalk` - Use DECTalk API (classic robotic voice)", + f"- `morshu` - Use MorshuTalk ({'available' if MORSHU_AVAILABLE else 'not installed'})", + f"- `vox` - Black Mesa VOX announcer ({'available' if VOX_AVAILABLE else 'not installed'})", "", ] @@ -1593,9 +1593,9 @@ class TtsToy(Cog): @chatterbox_group.command(name="temp") async def chatterbox_temperature(self, ctx: commands.Context, value: Optional[float] = None): """ - Show or set Chatterbox temperature for your current voice (0.0–1.5). + Show or set Chatterbox temperature for your current voice (0.0-1.5). - Saved per voice per user — each voice remembers its own setting. + Saved per voice per user - each voice remembers its own setting. Lower = more consistent, higher = more varied. - `[p]chatterbox temp` → show current - `[p]chatterbox temp 0.8` → set value @@ -1640,14 +1640,14 @@ class TtsToy(Cog): await self.config.user(ctx.author).chatterbox_temperature_offsets.set(offsets) await ctx.send(f"✅ Temperature for `{voice}` reset to server default.") else: - await ctx.send("❌ Value must be a number (0.0–1.5) or `reset`.") + await ctx.send("❌ Value must be a number (0.0-1.5) or `reset`.") @chatterbox_group.command(name="exag") async def chatterbox_exaggeration(self, ctx: commands.Context, value: Optional[float] = None): """ - Show or set Chatterbox exaggeration for your current voice (0.25–2.0). + Show or set Chatterbox exaggeration for your current voice (0.25-2.0). - Saved per voice per user — each voice remembers its own setting. + Saved per voice per user - each voice remembers its own setting. Higher = more expressive/dramatic delivery. - `[p]chatterbox exag` → show current - `[p]chatterbox exag 1.5` → set value @@ -1692,7 +1692,7 @@ class TtsToy(Cog): await self.config.user(ctx.author).chatterbox_exaggeration_offsets.set(offsets) await ctx.send(f"✅ Exaggeration for `{voice}` reset to server default.") else: - await ctx.send("❌ Value must be a number (0.25–2.0) or `reset`.") + await ctx.send("❌ Value must be a number (0.25-2.0) or `reset`.") @chatterbox_group.command(name="volume") async def chatterbox_volume(self, ctx: commands.Context, value: Optional[float] = None): @@ -1744,9 +1744,9 @@ class TtsToy(Cog): @chatterbox_group.command(name="speed") async def chatterbox_speed(self, ctx: commands.Context, value: Optional[float] = None): """ - Show or set speed for your current voice (0.25–4.0). + Show or set speed for your current voice (0.25-4.0). - Saved per-voice — each voice remembers its own speed. + Saved per-voice - each voice remembers its own speed. - `[p]chatterbox speed` → show current voice's speed - `[p]chatterbox speed 1.2` → set speed (1.0 = normal) - `[p]chatterbox speed reset` → remove speed override @@ -1790,7 +1790,7 @@ class TtsToy(Cog): display = parts[1].rsplit(".", 1)[0] if len(parts) > 1 and parts[0].isdigit() else voice.rsplit(".", 1)[0] await ctx.send(f"✅ Speed for `{display}` reset to default.") else: - await ctx.send("❌ Value must be a number (0.25–4.0) or `reset`.") + await ctx.send("❌ Value must be a number (0.25-4.0) or `reset`.") @chatterbox_group.command(name="sharevoice") async def share_voice(self, ctx: commands.Context, name: str, target: discord.Member): @@ -1979,7 +1979,7 @@ class TtsToy(Cog): return await ctx.send(f"No words found in VOX pack `{pack}`.") # Split into chunks to avoid message length limits - header = f"**VOX Words ({pack}) — {len(words)} words:**\n" + header = f"**VOX Words ({pack}) - {len(words)} words:**\n" chunk = header for w in words: entry = f"`{w}` " @@ -2020,7 +2020,7 @@ class TtsToy(Cog): f"- Run `{prefix}ttstoy myvoice` to see all voice commands.", "", "**For Morshu mode:**", - f"- Just switch to morshu mode — no setup needed.", + f"- Just switch to morshu mode - no setup needed.", f"- All text is spoken in Morshu's voice from the CD-i Zelda games.", "", "**For VOX mode:**", @@ -2084,10 +2084,10 @@ class TtsToy(Cog): "**MiniMax TTS Models**", "", "These are example model names you can use (subject to your MiniMax account):", - "- `speech-01-turbo` – fast & cheap", - "- `speech-01-hd` – higher quality, slower", - "- `speech-02-turbo` – newer fast model", - "- `speech-02-hd` – newer high quality model", + "- `speech-01-turbo` - fast & cheap", + "- `speech-01-hd` - higher quality, slower", + "- `speech-02-turbo` - newer fast model", + "- `speech-02-hd` - newer high quality model", "", f"Current configured model: `{current}`", "", @@ -2431,7 +2431,7 @@ class TtsToy(Cog): Generate TTS audio and upload the MP3. Also plays in voice chat if you're in one. """ async with ctx.typing(): - # Check if user is in a VC — we'll play there if so, but it's not required + # Check if user is in a VC - we'll play there if so, but it's not required user_in_vc = ctx.author.voice and ctx.author.voice.channel audio: Optional[Audio] = self.bot.get_cog("Audio") @@ -2586,7 +2586,7 @@ class TtsToy(Cog): await ctx.react_quietly("🗣") # ========================================================================= - # WEB UI — login, webui commands, and shared-state processor + # WEB UI - login, webui commands, and shared-state processor # ========================================================================= WEBUI_SHARED_STATE = Path(os.environ.get("TTSTOY_SHARED_STATE", "/tmp/ttstoy_webui_state.json")) @@ -2630,7 +2630,7 @@ class TtsToy(Cog): ephemeral=True, ) - # Register token with ttstoy webui — it writes to shared_auth.json. + # Register token with ttstoy webui - it writes to shared_auth.json. # The user logs in once on the Homepage; the session cookie is shared # across all *.kingstons-scrapyard.net subdomains. avatar_url = str(ctx.author.display_avatar.url) if ctx.author.display_avatar else "" @@ -2657,7 +2657,7 @@ class TtsToy(Cog): try: await ctx.author.send( - f"**Kingston's Scrapyard — Login**\n\n" + f"**Kingston's Scrapyard - Login**\n\n" f"Go to: https://homepage.kingstons-scrapyard.net/login\n\n" f"Your key (valid for 5 minutes):\n```\n{token}\n```\n" f"Log in once and you'll be signed in across all Scrapyard sites." @@ -2707,7 +2707,7 @@ class TtsToy(Cog): await ctx.send("🔄 The web UI is now a scrapyard service.\nRestart it with: `sudo systemctl restart scrapyard`") # ------------------------------------------------------------------------- - # Background task — poll shared state for pending commands and posts + # Background task - poll shared state for pending commands and posts # ------------------------------------------------------------------------- @tasks.loop(seconds=3) @@ -2731,7 +2731,7 @@ class TtsToy(Cog): def _take_pending_state_updates(self): """Under a cross-process lock: pop pending commands/posts and refresh user info. - Returns (pending_cmds, pending_posts). Runs in a worker thread — the + Returns (pending_cmds, pending_posts). Runs in a worker thread - the lock matches the one the web UI uses when appending, so no updates are lost between the read and the write. """ @@ -2899,13 +2899,13 @@ class TtsToy(Cog): break if not member_vc or not member_guild: - log.info(f"[WebUI] {user_id} is not in a VC — skipping playback") + log.info(f"[WebUI] {user_id} is not in a VC - skipping playback") return member = member_guild.get_member(user_id) audio_cog: Optional[Audio] = self.bot.get_cog("Audio") if not audio_cog: - log.warning("[WebUI] Audio cog not loaded — skipping VC playback") + log.warning("[WebUI] Audio cog not loaded - skipping VC playback") return text_channel = member_guild.system_channel or next( (c for c in member_guild.text_channels @@ -2964,7 +2964,7 @@ class TtsToy(Cog): if ch.name.lower() in ("tts", "ttstoy", "tts-toy"): return ch - # No guild specified — search all guilds + # No guild specified - search all guilds for guild in self.bot.guilds: for ch in guild.text_channels: if ch.name.lower() in ("tts", "ttstoy", "tts-toy"): @@ -2978,8 +2978,8 @@ class TtsToy(Cog): """Set or show the channel where web UI TTS audio is posted in this server. Usage: - [p]ttstoy webuichannel — show current channel - [p]ttstoy webuichannel #channel — set channel for this server + [p]ttstoy webuichannel - show current channel + [p]ttstoy webuichannel #channel - set channel for this server """ if channel is None: guild_channel_id = await self.config.guild(ctx.guild).webui_tts_channel_id()