use crate::Data; use crate::error::Error; use crate::lang; type Context<'a> = poise::Context<'a, Data, Error>; /// Query the AI senator via OpenRouter or local LLM #[poise::command(slash_command)] pub async fn senator( ctx: Context<'_>, #[description = "Wiadomość do wysłania"] text: String, #[description = "Przemówić w kanale głosowym?"] tts_vc: Option, ) -> crate::error::Result<()> { ctx.defer().await?; let (api_url, api_key, model) = ctx.data().config.resolve_llm(); let client = crate::openrouter::OpenRouterClient::new(api_url, api_key, model); let response = client.chat(lang::SENATOR_SYSTEM_PROMPT, &text).await?; if tts_vc.unwrap_or(false) { let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; let channel_id = ctx .serenity_context() .cache .guild(guild_id) .and_then(|g| { g.voice_states .get(&ctx.author().id) .and_then(|vs| vs.channel_id) }) .ok_or_else(lang::err_not_in_voice)?; let audio_data = ctx.data().tts.synthesize(&response).await?; let call = ctx .data() .voice_manager .connect(guild_id, channel_id) .await?; let input = crate::tts::pcm_bytes_to_input(audio_data); let mut call_lock = call.lock().await; if call_lock.current_channel().is_some() { call_lock.play_input(input); } } ctx.say(response).await?; Ok(()) } pub fn commands() -> Vec> { vec![senator()] }