openclaw-voice/discord_bot/commands.py
Jezza Hehn a2099e9d81 Strip Jarvis/Sage personas, simplify to MoltMic pipe
- Replace /jarvis and /sage command groups with /moltmic join|leave|status
- Remove AgentVoiceConfig, AgentsConfig now just has default agent
- Remove voice file checks from run.py (cloud TTS doesn't need them)
- Remove agent-to-voice mapping in bot.py on_speech_complete
- Rename from 'Jarvis Voice Bot' to 'MoltMic' throughout
2026-04-10 01:43:02 +00:00

103 lines
4.2 KiB
Python

"""Discord slash commands for MoltMic voice bot."""
from typing import Optional
import discord
from discord import app_commands
from utils.logging import get_logger
try:
from discord.ext import voice_recv
HAS_VOICE_RECV = True
except ImportError:
voice_recv = None
HAS_VOICE_RECV = False
logger = get_logger(__name__)
class MoltMicCommands(app_commands.Group):
"""Slash commands for MoltMic voice bot."""
def __init__(self, bot):
super().__init__(name="moltmic", description="MoltMic voice commands")
self.bot = bot
@app_commands.command(name="join", description="Join your voice channel and start listening")
@app_commands.describe(channel="Voice channel to join (defaults to your current channel)")
async def join(self, interaction: discord.Interaction, channel: Optional[discord.VoiceChannel] = None):
await interaction.response.defer(thinking=True)
try:
target = channel or (interaction.user.voice and interaction.user.voice.channel)
if not target:
await interaction.followup.send("❌ You're not in a voice channel.", ephemeral=True)
return
# Already in this channel?
if interaction.guild.voice_client and interaction.guild.voice_client.channel.id == target.id:
await interaction.followup.send(f"Already in {target.mention}", ephemeral=True)
return
# Move or connect
if interaction.guild.voice_client:
await interaction.guild.voice_client.move_to(target)
voice_client = interaction.guild.voice_client
else:
connect_cls = voice_recv.VoiceRecvClient if HAS_VOICE_RECV else discord.VoiceClient
voice_client = await target.connect(cls=connect_cls, self_deaf=False, timeout=60.0)
await self.bot.on_voice_join(interaction.guild, target, voice_client)
await interaction.followup.send(f"🎙️ Joined {target.mention} and listening...")
except discord.errors.ClientException as e:
logger.error(f"Failed to join: {e}")
await interaction.followup.send(f"❌ Failed to join: {e}", ephemeral=True)
except Exception as e:
logger.exception(f"Join error: {e}")
await interaction.followup.send("❌ Unexpected error", ephemeral=True)
@app_commands.command(name="leave", description="Leave the voice channel")
async def leave(self, interaction: discord.Interaction):
await interaction.response.defer(thinking=True)
try:
if not interaction.guild.voice_client:
await interaction.followup.send("❌ Not in a voice channel.", ephemeral=True)
return
await self.bot.on_voice_leave(interaction.guild)
await interaction.followup.send("👋 Left voice channel.")
except Exception as e:
logger.exception(f"Leave error: {e}")
await interaction.followup.send("❌ Error leaving.", ephemeral=True)
@app_commands.command(name="status", description="Show bot status")
async def status(self, interaction: discord.Interaction):
await interaction.response.defer(thinking=True)
try:
session = self.bot.session_manager.get_session(interaction.guild.id)
if not session:
await interaction.followup.send("❌ Not in a voice channel.", ephemeral=True)
return
embed = discord.Embed(title="🎙️ MoltMic Status", color=discord.Color.green())
embed.add_field(name="Channel", value=f"<#{session.channel_id}>", inline=True)
embed.add_field(name="Duration", value=f"{session.duration:.0f}s", inline=True)
embed.add_field(name="Users", value=str(session.get_user_count()), inline=True)
await interaction.followup.send(embed=embed)
except Exception as e:
logger.exception(f"Status error: {e}")
await interaction.followup.send("❌ Error.", ephemeral=True)
async def setup_commands(bot):
"""Register slash commands."""
cmds = MoltMicCommands(bot)
bot.tree.add_command(cmds)
logger.info("Slash commands registered (moltmic: join, leave, status)")
return cmds