diff --git a/src/commands/audio/play.rs b/src/commands/audio/play.rs index b0a4fe1..386e6a2 100644 --- a/src/commands/audio/play.rs +++ b/src/commands/audio/play.rs @@ -73,8 +73,8 @@ pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) { match add_song(handler_lock.clone(), &track_url, is_queue_empty, ac.get(&guild_id)).await { Ok(added_song) => { let track_title = added_song.title.unwrap(); - debug!("Added song: {}", track_title); - if let Err(why) = edit_response(&ctx, &command, format!("Added song to queue: {}", track_title)).await { + debug!("Added track: {}", track_title); + if let Err(why) = edit_response(&ctx, &command, format!("Added track to queue: {}", track_title)).await { error!("Failed to edit response message: {}", why); } let mut handler = handler_lock.lock().await; diff --git a/src/commands/audio/volume.rs b/src/commands/audio/volume.rs index 202894b..4ef8501 100644 --- a/src/commands/audio/volume.rs +++ b/src/commands/audio/volume.rs @@ -1,19 +1,19 @@ -use log::{debug, error, warn}; +use log::{error, warn}; use serenity::prelude::*; use serenity::builder::CreateApplicationCommand; use serenity::model::application::interaction::application_command::ApplicationCommandInteraction; -use super::{get_songbird, create_response, edit_response}; +use super::{get_songbird, create_response, edit_response, AudioConfigs, AudioConfig}; pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) { // Get the volume let volume = match command.data.options.get(0) { Some(t) => match &t.value { - Some(v) => match v.as_str() { - Some(s) => s.to_owned(), + Some(v) => match v.as_i64() { + Some(p) => std::cmp::min(100, std::cmp::max(0, p)), None => { - warn!("Missing volume option"); + warn!("Unable to get volume option as a string"); if let Err(why) = create_response(&ctx, &command, format!("Volume option is missing")).await { error!("Failed to create response message: {}", why); } @@ -21,7 +21,7 @@ pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) { } } None => { - warn!("Missing volume option"); + warn!("Missing volume option value"); if let Err(why) = create_response(&ctx, &command, format!("Volume option is missing")).await { error!("Failed to create response message: {}", why); } @@ -37,6 +37,9 @@ pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) { } }; + // Format volume to f32 bound between 0.0 and 1.0 + let bound_volume = volume as f32 / 100.0; + // Create the initial response if let Err(why) = create_response(&ctx, &command, "Processing command...".to_string()).await { error!("Failed to create response message: {}", why); @@ -52,27 +55,31 @@ pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) { return; } }; + let audio_config_lock = { + let data_read = ctx.data.read().await; + data_read.get::().expect("Expected AudioConfigs in TypeMap.").clone() + }; + { + let mut audio_configs = audio_config_lock.write().await; + *audio_configs.entry(guild_id).or_insert(AudioConfig { volume: 1.0 }) = AudioConfig { volume: bound_volume }; + } let manager = get_songbird(ctx).await; if let Some(handler_lock) = manager.get(guild_id) { let handler = handler_lock.lock().await; - if let Err(err) = handler.queue().skip() { - if let Err(why) = edit_response(&ctx, &command, format!("Failed to change volume: {}", err)).await { - error!("Failed to edit response message: {}", why); - } - } else { - debug!("Setting the volume to {}", volume); - if let Err(why) = edit_response(&ctx, &command, format!("Setting volume to {}", volume)).await { - error!("Failed to edit response message: {}", why); - } + for (_, track_handle) in handler.queue().current_queue().iter().enumerate() { + let _ = track_handle.set_volume(bound_volume); } } + if let Err(why) = edit_response(&ctx, &command, format!("Setting the volume to {}", volume)).await { + error!("Failed to set the volume: {}", why); + } } pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand { command.name("volume").description("Set the audio player volume").create_option(|option| { option .name("volume") - .description("The new volume level") - .kind(serenity::model::prelude::command::CommandOptionType::Number) + .description("Volume between 0 and 100") + .kind(serenity::model::prelude::command::CommandOptionType::Integer) .required(true) }) } \ No newline at end of file diff --git a/src/commands/oai.rs b/src/commands/oai.rs index c93a357..fbc55b9 100644 --- a/src/commands/oai.rs +++ b/src/commands/oai.rs @@ -8,8 +8,9 @@ use log::{error, debug, trace, warn}; use serde::{Serialize, Deserialize}; use serde_json::Value; +use serenity::model::Permissions; use serenity::model::channel::Message; -use serenity::model::prelude::ChannelType; +use serenity::model::prelude::{ChannelType, PermissionOverwrite, PermissionOverwriteType}; use serenity::prelude::*; use crate::database::models::{NewMessageDB, MessageDB}; @@ -214,7 +215,7 @@ pub async fn generate_response(ctx: &Context, msg: &Message, oai: &OAI, pool: &P Ok(r) => { let mut previous_message = "".to_string(); for message in r { - previous_message = format!("{}\nYou: {}\n Siren: {}", previous_message, message.request, message.response); + previous_message = format!("{}You: {}\n Siren: {}\n", previous_message, message.request, message.response); } Some(ChatCompletionMessage { role: GPTRole::User, content: previous_message }) } @@ -232,7 +233,7 @@ pub async fn generate_response(ctx: &Context, msg: &Message, oai: &OAI, pool: &P ]; if let Some(mut previous) = previous_messages { - previous.content = format!("{}\nYou: {}\nSiren: ", previous.content, parsed_content); + previous.content = format!("{}You: {}\nSiren: ", previous.content, parsed_content); messages.push(previous); } else { messages.push(ChatCompletionMessage { @@ -254,16 +255,38 @@ pub async fn generate_response(ctx: &Context, msg: &Message, oai: &OAI, pool: &P frequency_penalty: Some(0.0), user: Some(msg.author.name.clone()) }; + + // Get the thread channel ID + let response_channel = match msg.channel_id.create_private_thread(&ctx.http, |thread| { + thread.name(truncate(&parsed_content, 99)).kind(ChannelType::PublicThread) + }).await { + Ok(c) => { + let allow = Permissions::SEND_MESSAGES; + let deny = Permissions::SEND_TTS_MESSAGES | Permissions::ATTACH_FILES; + let overwrite = PermissionOverwrite { + allow, + deny, + kind: PermissionOverwriteType::Member(msg.author.id), + }; + let _ = c.create_permission(&ctx.http, &overwrite).await; + c.id + } + Err(_) => { + channel_id + } + }; + + // Get the OAI response and store message/response into the database let response = match oai.get_request(request).await { Ok(r) => { debug!("Processing response received from OpenAI"); if !r.choices.is_empty() { - // Insert the message into the messages database table let res = r.choices[0].message.content.clone(); + // Insert the message into the messages database table if let Err(err) = insert_into(crate::database::schema::messages::table).values(NewMessageDB { id: &r.id, guild_id: guild_id.0 as i64, - channel_id: channel_id.0 as i64, + channel_id: response_channel.0 as i64, user_id: author_id.0 as i64, created: r.created, model: &model, @@ -287,22 +310,25 @@ pub async fn generate_response(ctx: &Context, msg: &Message, oai: &OAI, pool: &P }; debug!("Writing response: \"{}\"", response); - // Stop the typing indicator and send the response typing.stop(); - match msg.channel_id.create_public_thread(&ctx.http, msg.id, |thread| { - thread.name(truncate(&parsed_content, 99)).kind(ChannelType::PublicThread) - }).await { - Ok(c) => { - if let Err(why) = c.say(&ctx.http, response).await { - error!("Cannot send message: {}", why); - } - } - Err(_) => { - if let Err(why) = channel_id.say(&ctx.http, response).await { - error!("Cannot send message: {}", why); - } - } - }; + if let Err(why) = response_channel.say(&ctx.http, response).await { + error!("Cannot send message: {}", why); + } + + // match msg.channel_id.create_public_thread(&ctx.http, msg.id, |thread| { + // thread.name(truncate(&parsed_content, 99)).kind(ChannelType::PublicThread) + // }).await { + // Ok(c) => { + // if let Err(why) = c.say(&ctx.http, response).await { + // error!("Cannot send message: {}", why); + // } + // } + // Err(_) => { + // if let Err(why) = channel_id.say(&ctx.http, response).await { + // error!("Cannot send message: {}", why); + // } + // } + // }; } fn truncate(s: &str, max_chars: usize) -> &str { diff --git a/src/main.rs b/src/main.rs index 71e3616..4d1c851 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,7 +36,17 @@ impl EventHandler for Handler { Some(oai) => { match msg.mentions_me(&ctx.http).await { Ok(mentioned) => { - if mentioned { + let bot_in_thread = match msg.channel_id.get_thread_members(&ctx.http).await { + Ok(t) => { + match t.iter().find(|t| t.user_id.unwrap().0 == ctx.cache.current_user_id().0) { + Some(_) => true, + None => false + } + } + Err(_) => false + }; + // let has_bot = msg.channel_id.get_thread_members(&ctx.http).await.unwrap().contains(ctx.cache.current_user_id().0); + if mentioned || bot_in_thread { commands::oai::generate_response(&ctx, &msg, oai, &self.pool).await; } }