style: remove em/en dashes from command help and log text

This commit is contained in:
2026-09-14 18:00:24 -05:00
parent 6ed69bc686
commit 164b195c2f
+46 -46
View File
@@ -122,7 +122,7 @@ def _save_emoji_sfx_map(mapping: dict):
json.dump(mapping, f, ensure_ascii=False, indent=2) 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() EMOJI_SFX_FOLDERS: dict = _load_emoji_sfx_map()
@@ -457,7 +457,7 @@ class TtsToy(Cog):
def _kill_leftover_webui(self): def _kill_leftover_webui(self):
"""Terminate any web UI subprocess left over from before the web UI """Terminate any web UI subprocess left over from before the web UI
moved out of the bot. It ran from <cog_dir>/webui/app.py, which no moved out of the bot. It ran from <cog_dir>/webui/app.py, which no
longer exists — so a matching process is guaranteed stale.""" longer exists - so a matching process is guaranteed stale."""
try: try:
pattern = str(Path(__file__).resolve().parent / "webui" / "app.py") pattern = str(Path(__file__).resolve().parent / "webui" / "app.py")
result = subprocess.run( result = subprocess.run(
@@ -830,7 +830,7 @@ class TtsToy(Cog):
voice_segments = _split_voice_segments(text) voice_segments = _split_voice_segments(text)
has_voice_switches = len(voice_segments) > 1 or voice_segments[0][0] is not None 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: if not has_voice_switches:
return self._render_single_mode( return self._render_single_mode(
api_key, model, voice_id, text, output_path, sfx_volume, 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) @commands.group(name="chatterbox", invoke_without_command=True)
async def chatterbox_group(self, ctx: commands.Context): 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. Use `[p]help chatterbox` to see all subcommands.
""" """
@@ -1049,13 +1049,13 @@ class TtsToy(Cog):
"", "",
"**── Voice Cloning ──**", "**── Voice Cloning ──**",
"Upload a voice clip and Chatterbox will clone it for TTS.", "Upload a voice clip and Chatterbox will clone it for TTS.",
f"• `{prefix}chatterbox addvoice <name>` — attach a .wav or .mp3 (5+ sec)", f"• `{prefix}chatterbox addvoice <name>` - attach a .wav or .mp3 (5+ sec)",
f"• `{prefix}chatterbox addvoice <name> <url>` — or paste a direct link", f"• `{prefix}chatterbox addvoice <name> <url>` - or paste a direct link",
f"• `{prefix}chatterbox removevoice <name>` — delete a voice", f"• `{prefix}chatterbox removevoice <name>` - delete a voice",
f"• `{prefix}chatterbox myvoices` — see your uploaded voices", f"• `{prefix}chatterbox myvoices` - see your uploaded voices",
f"• `{prefix}ttstoy myvoice <name>` — switch your active voice", f"• `{prefix}ttstoy myvoice <name>` - 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.", ".wav works best, .mp3 accepted. Short clips auto-loop to 5s.",
"", "",
"**── Special Tokens (Turbo model) ──**", "**── Special Tokens (Turbo model) ──**",
@@ -1068,9 +1068,9 @@ class TtsToy(Cog):
"**── Voice Settings ──**", "**── Voice Settings ──**",
"All saved per voice per user. Each voice keeps its own tuning.", "All saved per voice per user. Each voice keeps its own tuning.",
"", "",
f"• `{prefix}chatterbox temp [0.0–1.5]` — randomness", f"• `{prefix}chatterbox temp [0.0-1.5]` - randomness",
f"• `{prefix}chatterbox exag [0.25–2.0]` — expressiveness", f"• `{prefix}chatterbox exag [0.25-2.0]` - expressiveness",
f"• `{prefix}chatterbox volume [-20–20]` — dB loudness offset", f"• `{prefix}chatterbox volume [-20-20]` - dB loudness offset",
"Append `reset` to any of the above to clear it.", "Append `reset` to any of the above to clear it.",
"", "",
"**── Voice Sharing ──**", "**── Voice Sharing ──**",
@@ -1116,8 +1116,8 @@ class TtsToy(Cog):
f"**Loaded:** {'✅' if loaded else '❌'}", f"**Loaded:** {'✅' if loaded else '❌'}",
"", "",
"Available models:", "Available models:",
"• `turbo` — fast, 350M params, supports [laugh]/[cough]/etc tags", "• `turbo` - fast, 350M params, supports [laugh]/[cough]/etc tags",
"• `original` — better voice cloning, 0.5B params, stronger emotion control", "• `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`", 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()}**", f"**Current TTS Mode: {mode_emoji} {current.upper()}**",
"", "",
"Available modes:", "Available modes:",
"- `minimax` – Use MiniMax cloud API (requires API key)", "- `minimax` - Use MiniMax cloud API (requires API key)",
"- `chatterbox` – Use local Chatterbox TTS server (AI voice cloning)", "- `chatterbox` - Use local Chatterbox TTS server (AI voice cloning)",
"- `dectalk` – Use DECTalk API (classic robotic voice)", "- `dectalk` - Use DECTalk API (classic robotic voice)",
f"- `morshu` – Use MorshuTalk ({'available' if MORSHU_AVAILABLE else 'not installed'})", f"- `morshu` - Use MorshuTalk ({'available' if MORSHU_AVAILABLE else 'not installed'})",
f"- `vox` – Black Mesa VOX announcer ({'available' if VOX_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") @chatterbox_group.command(name="temp")
async def chatterbox_temperature(self, ctx: commands.Context, value: Optional[float] = None): 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. Lower = more consistent, higher = more varied.
- `[p]chatterbox temp` → show current - `[p]chatterbox temp` → show current
- `[p]chatterbox temp 0.8` → set value - `[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 self.config.user(ctx.author).chatterbox_temperature_offsets.set(offsets)
await ctx.send(f"✅ Temperature for `{voice}` reset to server default.") await ctx.send(f"✅ Temperature for `{voice}` reset to server default.")
else: 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") @chatterbox_group.command(name="exag")
async def chatterbox_exaggeration(self, ctx: commands.Context, value: Optional[float] = None): 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. Higher = more expressive/dramatic delivery.
- `[p]chatterbox exag` → show current - `[p]chatterbox exag` → show current
- `[p]chatterbox exag 1.5` → set value - `[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 self.config.user(ctx.author).chatterbox_exaggeration_offsets.set(offsets)
await ctx.send(f"✅ Exaggeration for `{voice}` reset to server default.") await ctx.send(f"✅ Exaggeration for `{voice}` reset to server default.")
else: 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") @chatterbox_group.command(name="volume")
async def chatterbox_volume(self, ctx: commands.Context, value: Optional[float] = None): async def chatterbox_volume(self, ctx: commands.Context, value: Optional[float] = None):
@@ -1744,9 +1744,9 @@ class TtsToy(Cog):
@chatterbox_group.command(name="speed") @chatterbox_group.command(name="speed")
async def chatterbox_speed(self, ctx: commands.Context, value: Optional[float] = None): 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` → show current voice's speed
- `[p]chatterbox speed 1.2` → set speed (1.0 = normal) - `[p]chatterbox speed 1.2` → set speed (1.0 = normal)
- `[p]chatterbox speed reset` → remove speed override - `[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] 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.") await ctx.send(f"✅ Speed for `{display}` reset to default.")
else: 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") @chatterbox_group.command(name="sharevoice")
async def share_voice(self, ctx: commands.Context, name: str, target: discord.Member): 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}`.") return await ctx.send(f"No words found in VOX pack `{pack}`.")
# Split into chunks to avoid message length limits # 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 chunk = header
for w in words: for w in words:
entry = f"`{w}` " entry = f"`{w}` "
@@ -2020,7 +2020,7 @@ class TtsToy(Cog):
f"- Run `{prefix}ttstoy myvoice` to see all voice commands.", f"- Run `{prefix}ttstoy myvoice` to see all voice commands.",
"", "",
"**For Morshu mode:**", "**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.", f"- All text is spoken in Morshu's voice from the CD-i Zelda games.",
"", "",
"**For VOX mode:**", "**For VOX mode:**",
@@ -2084,10 +2084,10 @@ class TtsToy(Cog):
"**MiniMax TTS Models**", "**MiniMax TTS Models**",
"", "",
"These are example model names you can use (subject to your MiniMax account):", "These are example model names you can use (subject to your MiniMax account):",
"- `speech-01-turbo` – fast & cheap", "- `speech-01-turbo` - fast & cheap",
"- `speech-01-hd` – higher quality, slower", "- `speech-01-hd` - higher quality, slower",
"- `speech-02-turbo` – newer fast model", "- `speech-02-turbo` - newer fast model",
"- `speech-02-hd` – newer high quality model", "- `speech-02-hd` - newer high quality model",
"", "",
f"Current configured model: `{current}`", 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. Generate TTS audio and upload the MP3. Also plays in voice chat if you're in one.
""" """
async with ctx.typing(): 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 user_in_vc = ctx.author.voice and ctx.author.voice.channel
audio: Optional[Audio] = self.bot.get_cog("Audio") audio: Optional[Audio] = self.bot.get_cog("Audio")
@@ -2586,7 +2586,7 @@ class TtsToy(Cog):
await ctx.react_quietly("🗣") 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")) WEBUI_SHARED_STATE = Path(os.environ.get("TTSTOY_SHARED_STATE", "/tmp/ttstoy_webui_state.json"))
@@ -2630,7 +2630,7 @@ class TtsToy(Cog):
ephemeral=True, 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 # The user logs in once on the Homepage; the session cookie is shared
# across all *.kingstons-scrapyard.net subdomains. # across all *.kingstons-scrapyard.net subdomains.
avatar_url = str(ctx.author.display_avatar.url) if ctx.author.display_avatar else "" avatar_url = str(ctx.author.display_avatar.url) if ctx.author.display_avatar else ""
@@ -2657,7 +2657,7 @@ class TtsToy(Cog):
try: try:
await ctx.author.send( 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"Go to: https://homepage.kingstons-scrapyard.net/login\n\n"
f"Your key (valid for 5 minutes):\n```\n{token}\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." 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`") 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) @tasks.loop(seconds=3)
@@ -2731,7 +2731,7 @@ class TtsToy(Cog):
def _take_pending_state_updates(self): def _take_pending_state_updates(self):
"""Under a cross-process lock: pop pending commands/posts and refresh user info. """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 lock matches the one the web UI uses when appending, so no updates are
lost between the read and the write. lost between the read and the write.
""" """
@@ -2899,13 +2899,13 @@ class TtsToy(Cog):
break break
if not member_vc or not member_guild: 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 return
member = member_guild.get_member(user_id) member = member_guild.get_member(user_id)
audio_cog: Optional[Audio] = self.bot.get_cog("Audio") audio_cog: Optional[Audio] = self.bot.get_cog("Audio")
if not audio_cog: 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 return
text_channel = member_guild.system_channel or next( text_channel = member_guild.system_channel or next(
(c for c in member_guild.text_channels (c for c in member_guild.text_channels
@@ -2964,7 +2964,7 @@ class TtsToy(Cog):
if ch.name.lower() in ("tts", "ttstoy", "tts-toy"): if ch.name.lower() in ("tts", "ttstoy", "tts-toy"):
return ch return ch
# No guild specified — search all guilds # No guild specified - search all guilds
for guild in self.bot.guilds: for guild in self.bot.guilds:
for ch in guild.text_channels: for ch in guild.text_channels:
if ch.name.lower() in ("tts", "ttstoy", "tts-toy"): 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. """Set or show the channel where web UI TTS audio is posted in this server.
Usage: Usage:
[p]ttstoy webuichannel — show current channel [p]ttstoy webuichannel - show current channel
[p]ttstoy webuichannel #channel — set channel for this server [p]ttstoy webuichannel #channel - set channel for this server
""" """
if channel is None: if channel is None:
guild_channel_id = await self.config.guild(ctx.guild).webui_tts_channel_id() guild_channel_id = await self.config.guild(ctx.guild).webui_tts_channel_id()