311 lines
9.3 KiB
Rust
311 lines
9.3 KiB
Rust
use crate::commands::fun::AiChatKey;
|
|
use crate::{Context, Error};
|
|
use poise::serenity_prelude as serenity;
|
|
use serde::{Deserialize, Serialize};
|
|
use serenity::prelude::TypeMapKey;
|
|
use std::collections::HashMap;
|
|
use surrealdb::Surreal;
|
|
use surrealdb::engine::remote::ws::Client;
|
|
|
|
pub struct DbKey;
|
|
|
|
impl TypeMapKey for DbKey {
|
|
type Value = Surreal<Client>;
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct AutoResponse {
|
|
pub response: String,
|
|
pub mention_reply: bool,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct GuildRecord {
|
|
auto_responses: Option<HashMap<String, AutoResponse>>,
|
|
}
|
|
|
|
#[poise::command(
|
|
slash_command,
|
|
prefix_command,
|
|
guild_only,
|
|
default_member_permissions = "MANAGE_MESSAGES",
|
|
required_permissions = "MANAGE_MESSAGES"
|
|
)]
|
|
pub async fn auto_response(
|
|
ctx: Context<'_>,
|
|
#[description = "The trigger message"] msg: String,
|
|
#[description = "The response message"] response: String,
|
|
#[description = "Reply to the user? (default: false)"] mention_reply: Option<bool>,
|
|
) -> Result<(), Error> {
|
|
let guild_id = ctx
|
|
.guild_id()
|
|
.ok_or_else(|| Error::msg("Guild only command"))?;
|
|
let db = &ctx.data().db;
|
|
|
|
let mention_reply = mention_reply.unwrap_or(false);
|
|
let auto_response = AutoResponse {
|
|
response: response.clone(),
|
|
mention_reply,
|
|
};
|
|
|
|
let _: Option<serde::de::IgnoredAny> = db
|
|
.update(("guilds", guild_id.to_string()))
|
|
.merge(serde_json::json!({
|
|
"auto_responses": {
|
|
msg.clone(): auto_response
|
|
}
|
|
}))
|
|
.await?;
|
|
|
|
ctx.say(format!(
|
|
"Auto-response configured: `{}` -> `{}` (Reply: {})",
|
|
msg, response, mention_reply
|
|
))
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(
|
|
slash_command,
|
|
prefix_command,
|
|
guild_only,
|
|
default_member_permissions = "MANAGE_MESSAGES",
|
|
required_permissions = "MANAGE_MESSAGES"
|
|
)]
|
|
pub async fn view_auto_responses(ctx: Context<'_>) -> Result<(), Error> {
|
|
let guild_id = ctx
|
|
.guild_id()
|
|
.ok_or_else(|| Error::msg("Guild only command"))?;
|
|
let db = &ctx.data().db;
|
|
|
|
let record: Option<GuildRecord> = db.select(("guilds", guild_id.to_string())).await?;
|
|
|
|
let mut response = String::new();
|
|
|
|
if let Some(record) = record {
|
|
if let Some(responses) = record.auto_responses {
|
|
if responses.is_empty() {
|
|
response = "No auto-responses configured.".to_string();
|
|
} else {
|
|
response.push_str("**Auto-Responses:**\n");
|
|
for (trigger, data) in responses {
|
|
response.push_str(&format!(
|
|
"- `{}` -> `{}` (Reply: {})\n",
|
|
trigger, data.response, data.mention_reply
|
|
));
|
|
}
|
|
}
|
|
} else {
|
|
response = "No auto-responses configured.".to_string();
|
|
}
|
|
} else {
|
|
response = "No configuration found for this guild.".to_string();
|
|
}
|
|
|
|
ctx.say(response).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(
|
|
slash_command,
|
|
prefix_command,
|
|
guild_only,
|
|
default_member_permissions = "MANAGE_MESSAGES",
|
|
required_permissions = "MANAGE_MESSAGES"
|
|
)]
|
|
pub async fn delete_auto_response(
|
|
ctx: Context<'_>,
|
|
#[description = "The trigger message to delete"] msg: String,
|
|
) -> Result<(), Error> {
|
|
let guild_id = ctx
|
|
.guild_id()
|
|
.ok_or_else(|| Error::msg("Guild only command"))?;
|
|
let db = &ctx.data().db;
|
|
|
|
let record: Option<GuildRecord> = db.select(("guilds", guild_id.to_string())).await?;
|
|
|
|
if let Some(record) = record {
|
|
if let Some(mut responses) = record.auto_responses {
|
|
if responses.remove(&msg).is_some() {
|
|
db.query("UPDATE type::thing($thing) SET auto_responses = $responses")
|
|
.bind(("thing", ("guilds", guild_id.to_string())))
|
|
.bind(("responses", responses))
|
|
.await?
|
|
.check()?;
|
|
ctx.say(format!("Auto-response for `{}` deleted.", msg))
|
|
.await?;
|
|
} else {
|
|
ctx.say(format!("No auto-response found for `{}`.", msg))
|
|
.await?;
|
|
}
|
|
} else {
|
|
ctx.say("No auto-responses configured.").await?;
|
|
}
|
|
} else {
|
|
ctx.say("No configuration found for this guild.").await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(
|
|
slash_command,
|
|
prefix_command,
|
|
guild_only,
|
|
default_member_permissions = "MANAGE_MESSAGES",
|
|
required_permissions = "MANAGE_MESSAGES"
|
|
)]
|
|
pub async fn edit_auto_response(
|
|
ctx: Context<'_>,
|
|
#[description = "The trigger message to edit"] msg: String,
|
|
#[description = "The new response message"] new_response: Option<String>,
|
|
#[description = "Reply to the user?"] new_mention_reply: Option<bool>,
|
|
) -> Result<(), Error> {
|
|
let guild_id = ctx
|
|
.guild_id()
|
|
.ok_or_else(|| Error::msg("Guild only command"))?;
|
|
let db = &ctx.data().db;
|
|
|
|
let record: Option<GuildRecord> = db.select(("guilds", guild_id.to_string())).await?;
|
|
|
|
if let Some(record) = record {
|
|
if let Some(mut responses) = record.auto_responses {
|
|
let (response_str, mention_reply_bool) = {
|
|
if let Some(data) = responses.get_mut(&msg) {
|
|
if let Some(response) = new_response {
|
|
data.response = response;
|
|
}
|
|
if let Some(mention_reply) = new_mention_reply {
|
|
data.mention_reply = mention_reply;
|
|
}
|
|
(data.response.clone(), data.mention_reply)
|
|
} else {
|
|
ctx.say(format!("No auto-response found for `{}`.", msg))
|
|
.await?;
|
|
return Ok(());
|
|
}
|
|
};
|
|
|
|
let _: Option<serde::de::IgnoredAny> = db
|
|
.update(("guilds", guild_id.to_string()))
|
|
.merge(serde_json::json!({
|
|
"auto_responses": responses
|
|
}))
|
|
.await?;
|
|
|
|
ctx.say(format!(
|
|
"Auto-response for `{}` updated: `{}` (Reply: {})",
|
|
msg, response_str, mention_reply_bool
|
|
))
|
|
.await?;
|
|
} else {
|
|
ctx.say("No auto-responses configured.").await?;
|
|
}
|
|
} else {
|
|
ctx.say("No configuration found for this guild.").await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(slash_command, prefix_command, guild_only)]
|
|
pub async fn summary(
|
|
ctx: Context<'_>,
|
|
#[description = "Message to summarize (reply to one or provide message link)"] message: Option<
|
|
serenity::Message,
|
|
>,
|
|
) -> Result<(), Error> {
|
|
if let poise::Context::Application(app_ctx) = ctx {
|
|
app_ctx.defer().await?;
|
|
}
|
|
|
|
let msg = if let Some(m) = message {
|
|
m
|
|
} else if let poise::Context::Prefix(prefix_ctx) = ctx {
|
|
// For prefix, check if replying to a message
|
|
if let Some(reply) = prefix_ctx.msg.referenced_message.as_ref() {
|
|
(**reply).clone()
|
|
} else {
|
|
ctx.say("You must reply to a message or provide a message to summarize.")
|
|
.await?;
|
|
return Ok(());
|
|
}
|
|
} else {
|
|
ctx.say("You must reply to a message or provide a message to summarize.")
|
|
.await?;
|
|
return Ok(());
|
|
};
|
|
|
|
let data = ctx.serenity_context().data.read().await;
|
|
let ai_chat_manager = data
|
|
.get::<AiChatKey>()
|
|
.cloned()
|
|
.ok_or_else(|| anyhow::anyhow!("AI Chat manager not found"))?;
|
|
let content = msg.content.trim();
|
|
|
|
if content.is_empty() {
|
|
ctx.say("The message is empty, nothing to summarize.")
|
|
.await?;
|
|
return Ok(());
|
|
}
|
|
|
|
let prompt = format!("Summarize this message in 1-2 sentences: {}", content);
|
|
match ai_chat_manager.query_ollama_direct(&prompt).await {
|
|
Ok(summary) => {
|
|
ctx.say(format!(
|
|
"**Summary of message by {}:**\n{}",
|
|
msg.author.name, summary
|
|
))
|
|
.await?;
|
|
}
|
|
Err(err) => {
|
|
tracing::error!(error = %err, "Failed to summarize message");
|
|
ctx.say("Failed to generate summary. Try again later.")
|
|
.await?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn process_auto_response(
|
|
ctx: &serenity::Context,
|
|
msg: &serenity::Message,
|
|
) -> Result<(), Error> {
|
|
if msg.author.bot {
|
|
return Ok(());
|
|
}
|
|
|
|
let guild_id = match msg.guild_id {
|
|
Some(id) => id,
|
|
None => return Ok(()),
|
|
};
|
|
|
|
let data = ctx.data.read().await;
|
|
let db = match data.get::<DbKey>() {
|
|
Some(db) => db,
|
|
None => {
|
|
tracing::error!("Database connection not found in context data for utility");
|
|
return Ok(());
|
|
}
|
|
};
|
|
|
|
let record: Option<GuildRecord> = db.select(("guilds", guild_id.to_string())).await?;
|
|
|
|
if let Some(record) = record {
|
|
if let Some(responses) = record.auto_responses {
|
|
if let Some(auto_response) = responses.get(&msg.content) {
|
|
if auto_response.mention_reply {
|
|
msg.reply(ctx, &auto_response.response).await?;
|
|
} else {
|
|
msg.channel_id.say(ctx, &auto_response.response).await?;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|