2025-10-12 11:44:35 -03:00
|
|
|
use actix_web::{web, HttpRequest, HttpResponse, Result};
|
|
|
|
|
use actix_ws::Message as WsMessage;
|
|
|
|
|
use chrono::Utc;
|
2025-10-13 00:31:08 -03:00
|
|
|
use log::{debug, error, info, trace, warn};
|
2025-10-12 11:44:35 -03:00
|
|
|
use serde_json;
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::fs;
|
|
|
|
|
use std::sync::Arc;
|
2025-10-12 20:12:49 -03:00
|
|
|
use tokio::sync::mpsc;
|
2025-10-06 10:30:17 -03:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
use crate::channels::ChannelAdapter;
|
|
|
|
|
use crate::shared::models::{BotResponse, UserMessage, UserSession};
|
2025-10-12 20:12:49 -03:00
|
|
|
use crate::shared::state::AppState;
|
2025-10-12 11:44:35 -03:00
|
|
|
|
|
|
|
|
pub struct BotOrchestrator {
|
2025-10-12 20:12:49 -03:00
|
|
|
pub state: Arc<AppState>,
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
2025-10-06 10:30:17 -03:00
|
|
|
|
|
|
|
|
impl BotOrchestrator {
|
2025-10-12 20:12:49 -03:00
|
|
|
pub fn new(state: Arc<AppState>) -> Self {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Creating new BotOrchestrator instance");
|
2025-10-12 20:12:49 -03:00
|
|
|
Self { state }
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
pub async fn handle_user_input(
|
|
|
|
|
&self,
|
|
|
|
|
session_id: Uuid,
|
|
|
|
|
user_input: &str,
|
|
|
|
|
) -> Result<Option<String>, Box<dyn std::error::Error + Send + Sync>> {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!(
|
|
|
|
|
"Handling user input for session {}: '{}'",
|
|
|
|
|
session_id, user_input
|
|
|
|
|
);
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
session_manager.provide_input(session_id, user_input.to_string())?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("User input handled for session {}", session_id);
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(None)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn is_waiting_for_input(&self, session_id: Uuid) -> bool {
|
2025-10-13 00:31:08 -03:00
|
|
|
trace!("Checking if session {} is waiting for input", session_id);
|
2025-10-12 20:12:49 -03:00
|
|
|
let session_manager = self.state.session_manager.lock().await;
|
2025-10-13 00:31:08 -03:00
|
|
|
let result = session_manager.is_waiting_for_input(&session_id);
|
|
|
|
|
trace!("Session {} waiting for input: {}", session_id, result);
|
|
|
|
|
result
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
pub fn add_channel(&self, channel_type: &str, adapter: Arc<dyn ChannelAdapter>) {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Adding channel adapter for type: {}", channel_type);
|
2025-10-12 20:12:49 -03:00
|
|
|
self.state
|
|
|
|
|
.channels
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.insert(channel_type.to_string(), adapter);
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Channel adapter for {} added successfully", channel_type);
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn register_response_channel(
|
|
|
|
|
&self,
|
|
|
|
|
session_id: String,
|
|
|
|
|
sender: mpsc::Sender<BotResponse>,
|
|
|
|
|
) {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Registering response channel for session: {}", session_id);
|
2025-10-12 20:12:49 -03:00
|
|
|
self.state
|
|
|
|
|
.response_channels
|
2025-10-12 11:44:35 -03:00
|
|
|
.lock()
|
|
|
|
|
.await
|
2025-10-13 00:31:08 -03:00
|
|
|
.insert(session_id.clone(), sender);
|
|
|
|
|
trace!("Response channel registered for session: {}", session_id);
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn set_user_answer_mode(
|
|
|
|
|
&self,
|
|
|
|
|
user_id: &str,
|
|
|
|
|
bot_id: &str,
|
2025-10-12 13:27:48 -03:00
|
|
|
mode: i32,
|
2025-10-12 11:44:35 -03:00
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"Setting answer mode for user {} with bot {} to mode {}",
|
|
|
|
|
user_id, bot_id, mode
|
|
|
|
|
);
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
session_manager.update_answer_mode(user_id, bot_id, mode)?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Answer mode updated successfully");
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn send_event(
|
|
|
|
|
&self,
|
|
|
|
|
user_id: &str,
|
|
|
|
|
bot_id: &str,
|
|
|
|
|
session_id: &str,
|
|
|
|
|
channel: &str,
|
|
|
|
|
event_type: &str,
|
|
|
|
|
data: serde_json::Value,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
debug!(
|
|
|
|
|
"Sending event '{}' to session {} on channel {}",
|
|
|
|
|
event_type, session_id, channel
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let event_response = BotResponse {
|
|
|
|
|
bot_id: bot_id.to_string(),
|
|
|
|
|
user_id: user_id.to_string(),
|
|
|
|
|
session_id: session_id.to_string(),
|
|
|
|
|
channel: channel.to_string(),
|
|
|
|
|
content: serde_json::to_string(&serde_json::json!({
|
|
|
|
|
"event": event_type,
|
|
|
|
|
"data": data
|
|
|
|
|
}))?,
|
2025-10-13 09:36:45 -03:00
|
|
|
message_type: 2,
|
2025-10-13 00:31:08 -03:00
|
|
|
stream_token: None,
|
|
|
|
|
is_complete: true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
trace!("Event response created: {:?}", event_response);
|
|
|
|
|
|
|
|
|
|
if let Some(adapter) = self.state.channels.lock().unwrap().get(channel) {
|
|
|
|
|
adapter.send_message(event_response).await?;
|
|
|
|
|
debug!("Event sent successfully via channel adapter");
|
|
|
|
|
} else {
|
|
|
|
|
warn!("No channel adapter found for channel: {}", channel);
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn process_message(
|
|
|
|
|
&self,
|
|
|
|
|
message: UserMessage,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
info!(
|
2025-10-13 00:31:08 -03:00
|
|
|
"Processing message from channel: {}, user: {}, session: {}",
|
|
|
|
|
message.channel, message.user_id, message.session_id
|
|
|
|
|
);
|
|
|
|
|
debug!(
|
|
|
|
|
"Message content: '{}', type: {}",
|
|
|
|
|
message.content, message.message_type
|
2025-10-12 11:44:35 -03:00
|
|
|
);
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
let user_id = Uuid::parse_str(&message.user_id).unwrap_or_else(|_| {
|
|
|
|
|
let new_id = Uuid::new_v4();
|
|
|
|
|
warn!("Invalid user ID provided, generated new UUID: {}", new_id);
|
|
|
|
|
new_id
|
|
|
|
|
});
|
2025-10-12 11:44:35 -03:00
|
|
|
let bot_id = Uuid::parse_str(&message.bot_id)
|
|
|
|
|
.unwrap_or_else(|_| Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap());
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Parsed user_id: {}, bot_id: {}", user_id, bot_id);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
let session = {
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
match session_manager.get_user_session(user_id, bot_id)? {
|
2025-10-13 00:31:08 -03:00
|
|
|
Some(session) => {
|
|
|
|
|
debug!("Found existing session: {}", session.id);
|
|
|
|
|
session
|
|
|
|
|
}
|
2025-10-12 20:12:49 -03:00
|
|
|
None => {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"Creating new session for user {} with bot {}",
|
|
|
|
|
user_id, bot_id
|
|
|
|
|
);
|
2025-10-12 20:12:49 -03:00
|
|
|
let new_session =
|
|
|
|
|
session_manager.create_session(user_id, bot_id, "New Conversation")?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("New session created: {}", new_session.id);
|
2025-10-12 20:12:49 -03:00
|
|
|
Self::run_start_script(&new_session, Arc::clone(&self.state)).await;
|
|
|
|
|
new_session
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
trace!("Current session state: {:?}", session);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
if self.is_waiting_for_input(session.id).await {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!(
|
|
|
|
|
"Session {} is waiting for input, processing as variable input",
|
|
|
|
|
session.id
|
|
|
|
|
);
|
2025-10-12 11:44:35 -03:00
|
|
|
if let Some(variable_name) =
|
|
|
|
|
self.handle_user_input(session.id, &message.content).await?
|
|
|
|
|
{
|
|
|
|
|
info!(
|
|
|
|
|
"Stored user input in variable '{}' for session {}",
|
|
|
|
|
variable_name, session.id
|
|
|
|
|
);
|
|
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
if let Some(adapter) = self.state.channels.lock().unwrap().get(&message.channel) {
|
2025-10-12 11:44:35 -03:00
|
|
|
let ack_response = BotResponse {
|
|
|
|
|
bot_id: message.bot_id.clone(),
|
|
|
|
|
user_id: message.user_id.clone(),
|
|
|
|
|
session_id: message.session_id.clone(),
|
|
|
|
|
channel: message.channel.clone(),
|
|
|
|
|
content: format!("Input stored in '{}'", variable_name),
|
2025-10-12 14:39:23 -03:00
|
|
|
message_type: 1,
|
2025-10-12 11:44:35 -03:00
|
|
|
stream_token: None,
|
|
|
|
|
is_complete: true,
|
|
|
|
|
};
|
|
|
|
|
adapter.send_message(ack_response).await?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Acknowledgment sent for variable storage");
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-12 13:27:48 -03:00
|
|
|
if session.answer_mode == 1 && session.current_tool.is_some() {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Session in answer mode with active tool, providing user response");
|
2025-10-12 20:12:49 -03:00
|
|
|
self.state.tool_manager.provide_user_response(
|
2025-10-12 11:44:35 -03:00
|
|
|
&message.user_id,
|
|
|
|
|
&message.bot_id,
|
|
|
|
|
message.content.clone(),
|
|
|
|
|
)?;
|
2025-10-13 00:31:08 -03:00
|
|
|
trace!("User response provided to tool manager");
|
2025-10-12 11:44:35 -03:00
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
session_manager.save_message(
|
|
|
|
|
session.id,
|
|
|
|
|
user_id,
|
2025-10-12 15:06:16 -03:00
|
|
|
1,
|
2025-10-12 11:44:35 -03:00
|
|
|
&message.content,
|
2025-10-12 14:39:23 -03:00
|
|
|
message.message_type,
|
2025-10-12 11:44:35 -03:00
|
|
|
)?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("User message saved to session history");
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let response_content = self.direct_mode_handler(&message, &session).await?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Generated response content: '{}'", response_content);
|
2025-10-12 11:44:35 -03:00
|
|
|
|
|
|
|
|
{
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 15:06:16 -03:00
|
|
|
session_manager.save_message(session.id, user_id, 2, &response_content, 1)?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Bot response saved to session history");
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let bot_response = BotResponse {
|
|
|
|
|
bot_id: message.bot_id,
|
|
|
|
|
user_id: message.user_id,
|
|
|
|
|
session_id: message.session_id.clone(),
|
|
|
|
|
channel: message.channel.clone(),
|
|
|
|
|
content: response_content,
|
2025-10-12 14:39:23 -03:00
|
|
|
message_type: 1,
|
2025-10-12 11:44:35 -03:00
|
|
|
stream_token: None,
|
|
|
|
|
is_complete: true,
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
trace!("Final bot response: {:?}", bot_response);
|
|
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
if let Some(adapter) = self.state.channels.lock().unwrap().get(&message.channel) {
|
2025-10-12 11:44:35 -03:00
|
|
|
adapter.send_message(bot_response).await?;
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Response sent successfully via channel adapter");
|
|
|
|
|
} else {
|
|
|
|
|
warn!("No channel adapter found for channel: {}", message.channel);
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn direct_mode_handler(
|
|
|
|
|
&self,
|
|
|
|
|
message: &UserMessage,
|
|
|
|
|
session: &UserSession,
|
|
|
|
|
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Using direct mode handler for session {}", session.id);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
let history = {
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
session_manager.get_conversation_history(session.id, session.user_id)?
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Retrieved {} history entries", history.len());
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
let mut prompt = String::new();
|
|
|
|
|
for (role, content) in history {
|
|
|
|
|
prompt.push_str(&format!("{}: {}\n", role, content));
|
|
|
|
|
}
|
|
|
|
|
prompt.push_str(&format!("User: {}\nAssistant:", message.content));
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
trace!("Constructed prompt for LLM: {}", prompt);
|
|
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
self.state
|
|
|
|
|
.llm_provider
|
2025-10-12 11:44:35 -03:00
|
|
|
.generate(&prompt, &serde_json::Value::Null)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn stream_response(
|
|
|
|
|
&self,
|
|
|
|
|
message: UserMessage,
|
|
|
|
|
response_tx: mpsc::Sender<BotResponse>,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"Streaming response for user: {}, session: {}",
|
|
|
|
|
message.user_id, message.session_id
|
|
|
|
|
);
|
|
|
|
|
debug!("Message content: '{}'", message.content);
|
|
|
|
|
|
|
|
|
|
let mut user_id = Uuid::parse_str(&message.user_id).unwrap_or_else(|_| {
|
|
|
|
|
let new_id = Uuid::new_v4();
|
|
|
|
|
warn!("Invalid user ID, generated new: {}", new_id);
|
|
|
|
|
new_id
|
|
|
|
|
});
|
|
|
|
|
let bot_id = Uuid::parse_str(&message.bot_id).unwrap_or_else(|_| {
|
|
|
|
|
warn!("Invalid bot ID, using nil UUID");
|
|
|
|
|
Uuid::nil()
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
debug!("User ID: {}, Bot ID: {}", user_id, bot_id);
|
2025-10-12 11:44:35 -03:00
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut auth = self.state.auth_service.lock().await;
|
2025-10-12 13:38:56 -03:00
|
|
|
let user_exists = auth.get_user_by_id(user_id)?;
|
|
|
|
|
|
|
|
|
|
if user_exists.is_none() {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("User {} not found, creating anonymous user", user_id);
|
2025-10-12 14:39:23 -03:00
|
|
|
user_id = auth.create_user("anonymous1", "anonymous@local", "password")?;
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Created new anonymous user: {}", user_id);
|
2025-10-12 14:39:23 -03:00
|
|
|
} else {
|
|
|
|
|
user_id = user_exists.unwrap().id;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Found existing user: {}", user_id);
|
2025-10-12 13:38:56 -03:00
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
|
|
|
|
|
let session = {
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut sm = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
match sm.get_user_session(user_id, bot_id)? {
|
2025-10-13 00:31:08 -03:00
|
|
|
Some(sess) => {
|
|
|
|
|
debug!("Using existing session: {}", sess.id);
|
|
|
|
|
sess
|
|
|
|
|
}
|
2025-10-12 20:12:49 -03:00
|
|
|
None => {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Creating new session for streaming");
|
2025-10-12 20:12:49 -03:00
|
|
|
let new_session = sm.create_session(user_id, bot_id, "New Conversation")?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("New session created: {}", new_session.id);
|
2025-10-13 09:36:45 -03:00
|
|
|
Self::run_start_script(&new_session, Arc::clone(&self.state)).await;
|
2025-10-12 20:12:49 -03:00
|
|
|
new_session
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
trace!("Session state: {:?}", session);
|
|
|
|
|
|
2025-10-12 13:27:48 -03:00
|
|
|
if session.answer_mode == 1 && session.current_tool.is_some() {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Session in answer mode, forwarding to tool manager");
|
2025-10-12 20:12:49 -03:00
|
|
|
self.state.tool_manager.provide_user_response(
|
2025-10-12 11:44:35 -03:00
|
|
|
&message.user_id,
|
|
|
|
|
&message.bot_id,
|
|
|
|
|
message.content.clone(),
|
|
|
|
|
)?;
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut sm = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
sm.save_message(
|
|
|
|
|
session.id,
|
|
|
|
|
user_id,
|
2025-10-12 15:06:16 -03:00
|
|
|
1,
|
2025-10-12 11:44:35 -03:00
|
|
|
&message.content,
|
2025-10-12 14:39:23 -03:00
|
|
|
message.message_type,
|
2025-10-12 11:44:35 -03:00
|
|
|
)?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("User message saved for streaming session");
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let prompt = {
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut sm = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
let history = sm.get_conversation_history(session.id, user_id)?;
|
|
|
|
|
let mut p = String::new();
|
2025-10-13 00:31:08 -03:00
|
|
|
for (role, content) in &history {
|
2025-10-12 11:44:35 -03:00
|
|
|
p.push_str(&format!("{}: {}\n", role, content));
|
|
|
|
|
}
|
|
|
|
|
p.push_str(&format!("User: {}\nAssistant:", message.content));
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!(
|
|
|
|
|
"Stream prompt constructed with {} history entries",
|
|
|
|
|
history.len()
|
|
|
|
|
);
|
|
|
|
|
trace!("Full prompt: {}", p);
|
2025-10-12 11:44:35 -03:00
|
|
|
p
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let (stream_tx, mut stream_rx) = mpsc::channel::<String>(100);
|
2025-10-12 20:12:49 -03:00
|
|
|
let llm = self.state.llm_provider.clone();
|
2025-10-12 11:44:35 -03:00
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
if message.channel == "web" {
|
|
|
|
|
debug!("Sending thinking start event for web channel");
|
|
|
|
|
self.send_event(
|
|
|
|
|
&message.user_id,
|
|
|
|
|
&message.bot_id,
|
|
|
|
|
&message.session_id,
|
|
|
|
|
&message.channel,
|
|
|
|
|
"thinking_start",
|
|
|
|
|
serde_json::json!({}),
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
} else {
|
|
|
|
|
debug!("Sending thinking message for non-web channel");
|
|
|
|
|
let thinking_response = BotResponse {
|
|
|
|
|
bot_id: message.bot_id.clone(),
|
|
|
|
|
user_id: message.user_id.clone(),
|
|
|
|
|
session_id: message.session_id.clone(),
|
|
|
|
|
channel: message.channel.clone(),
|
|
|
|
|
content: "Thinking...".to_string(),
|
|
|
|
|
message_type: 1,
|
|
|
|
|
stream_token: None,
|
|
|
|
|
is_complete: true,
|
|
|
|
|
};
|
|
|
|
|
response_tx.send(thinking_response).await?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info!("Starting LLM stream generation");
|
2025-10-12 11:44:35 -03:00
|
|
|
tokio::spawn(async move {
|
|
|
|
|
if let Err(e) = llm
|
|
|
|
|
.generate_stream(&prompt, &serde_json::Value::Null, stream_tx)
|
|
|
|
|
.await
|
|
|
|
|
{
|
2025-10-13 00:31:08 -03:00
|
|
|
error!("LLM streaming error: {}", e);
|
|
|
|
|
} else {
|
|
|
|
|
debug!("LLM stream generation completed");
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let mut full_response = String::new();
|
2025-10-13 00:31:08 -03:00
|
|
|
let mut analysis_buffer = String::new();
|
|
|
|
|
let mut in_analysis = false;
|
|
|
|
|
let mut chunk_count = 0;
|
|
|
|
|
|
|
|
|
|
debug!("Starting to process stream chunks");
|
2025-10-12 11:44:35 -03:00
|
|
|
while let Some(chunk) = stream_rx.recv().await {
|
2025-10-13 00:31:08 -03:00
|
|
|
chunk_count += 1;
|
|
|
|
|
trace!("Received chunk {}: '{}'", chunk_count, chunk);
|
|
|
|
|
|
|
|
|
|
analysis_buffer.push_str(&chunk);
|
|
|
|
|
|
|
|
|
|
if analysis_buffer.contains("<|channel|>") {
|
|
|
|
|
debug!("Analysis section started");
|
|
|
|
|
in_analysis = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if in_analysis {
|
|
|
|
|
if analysis_buffer.ends_with("final<|message|>") {
|
|
|
|
|
debug!(
|
|
|
|
|
"Analysis section completed, buffer length: {}",
|
|
|
|
|
analysis_buffer.len()
|
|
|
|
|
);
|
|
|
|
|
in_analysis = false;
|
|
|
|
|
analysis_buffer.clear();
|
|
|
|
|
|
|
|
|
|
if message.channel == "web" {
|
|
|
|
|
let orchestrator = BotOrchestrator::new(Arc::clone(&self.state));
|
|
|
|
|
orchestrator
|
|
|
|
|
.send_event(
|
|
|
|
|
&message.user_id,
|
|
|
|
|
&message.bot_id,
|
|
|
|
|
&message.session_id,
|
|
|
|
|
&message.channel,
|
|
|
|
|
"thinking_end",
|
|
|
|
|
serde_json::json!({
|
|
|
|
|
"user_id": message.user_id.clone()
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.ok();
|
|
|
|
|
}
|
|
|
|
|
analysis_buffer.clear();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trace!("Skipping analysis chunk");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
full_response.push_str(&chunk);
|
|
|
|
|
|
|
|
|
|
let partial = BotResponse {
|
|
|
|
|
bot_id: message.bot_id.clone(),
|
|
|
|
|
user_id: message.user_id.clone(),
|
|
|
|
|
session_id: message.session_id.clone(),
|
|
|
|
|
channel: message.channel.clone(),
|
|
|
|
|
content: chunk,
|
2025-10-12 14:39:23 -03:00
|
|
|
message_type: 1,
|
2025-10-12 11:44:35 -03:00
|
|
|
stream_token: None,
|
|
|
|
|
is_complete: false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if response_tx.send(partial).await.is_err() {
|
2025-10-13 00:31:08 -03:00
|
|
|
warn!("Response channel closed, stopping stream processing");
|
2025-10-12 11:44:35 -03:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!(
|
|
|
|
|
"Stream processing completed, {} chunks processed",
|
|
|
|
|
chunk_count
|
|
|
|
|
);
|
|
|
|
|
info!("Full response length: {} characters", full_response.len());
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
{
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut sm = self.state.session_manager.lock().await;
|
2025-10-12 15:06:16 -03:00
|
|
|
sm.save_message(session.id, user_id, 2, &full_response, 1)?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Stream response saved to session history");
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let final_msg = BotResponse {
|
|
|
|
|
bot_id: message.bot_id,
|
|
|
|
|
user_id: message.user_id,
|
|
|
|
|
session_id: message.session_id,
|
|
|
|
|
channel: message.channel,
|
|
|
|
|
content: String::new(),
|
2025-10-12 14:39:23 -03:00
|
|
|
message_type: 1,
|
2025-10-12 11:44:35 -03:00
|
|
|
stream_token: None,
|
|
|
|
|
is_complete: true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
response_tx.send(final_msg).await?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Final stream message sent");
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn get_user_sessions(
|
|
|
|
|
&self,
|
|
|
|
|
user_id: Uuid,
|
|
|
|
|
) -> Result<Vec<UserSession>, Box<dyn std::error::Error + Send + Sync>> {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Getting sessions for user: {}", user_id);
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-13 00:31:08 -03:00
|
|
|
let sessions = session_manager.get_user_sessions(user_id)?;
|
|
|
|
|
debug!("Found {} sessions for user {}", sessions.len(), user_id);
|
|
|
|
|
Ok(sessions)
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn get_conversation_history(
|
|
|
|
|
&self,
|
|
|
|
|
session_id: Uuid,
|
|
|
|
|
user_id: Uuid,
|
|
|
|
|
) -> Result<Vec<(String, String)>, Box<dyn std::error::Error + Send + Sync>> {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!(
|
|
|
|
|
"Getting conversation history for session {} user {}",
|
|
|
|
|
session_id, user_id
|
|
|
|
|
);
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-13 00:31:08 -03:00
|
|
|
let history = session_manager.get_conversation_history(session_id, user_id)?;
|
|
|
|
|
debug!("Retrieved {} history entries", history.len());
|
|
|
|
|
Ok(history)
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn process_message_with_tools(
|
|
|
|
|
&self,
|
|
|
|
|
message: UserMessage,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
info!(
|
2025-10-13 00:31:08 -03:00
|
|
|
"Processing message with tools from user: {}, session: {}",
|
|
|
|
|
message.user_id, message.session_id
|
2025-10-12 11:44:35 -03:00
|
|
|
);
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Message content: '{}'", message.content);
|
2025-10-12 11:44:35 -03:00
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
let user_id = Uuid::parse_str(&message.user_id).unwrap_or_else(|_| {
|
|
|
|
|
let new_id = Uuid::new_v4();
|
|
|
|
|
warn!("Invalid user ID, generated new: {}", new_id);
|
|
|
|
|
new_id
|
|
|
|
|
});
|
2025-10-12 11:44:35 -03:00
|
|
|
let bot_id = Uuid::parse_str(&message.bot_id)
|
|
|
|
|
.unwrap_or_else(|_| Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap());
|
|
|
|
|
|
|
|
|
|
let session = {
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
match session_manager.get_user_session(user_id, bot_id)? {
|
2025-10-13 00:31:08 -03:00
|
|
|
Some(session) => {
|
|
|
|
|
debug!("Found existing session: {}", session.id);
|
|
|
|
|
session
|
|
|
|
|
}
|
2025-10-12 20:12:49 -03:00
|
|
|
None => {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Creating new session for tools processing");
|
2025-10-12 20:12:49 -03:00
|
|
|
let new_session =
|
|
|
|
|
session_manager.create_session(user_id, bot_id, "New Conversation")?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("New session created: {}", new_session.id);
|
2025-10-12 20:12:49 -03:00
|
|
|
Self::run_start_script(&new_session, Arc::clone(&self.state)).await;
|
|
|
|
|
new_session
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
{
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 11:44:35 -03:00
|
|
|
session_manager.save_message(
|
|
|
|
|
session.id,
|
|
|
|
|
user_id,
|
2025-10-12 15:06:16 -03:00
|
|
|
1,
|
2025-10-12 11:44:35 -03:00
|
|
|
&message.content,
|
2025-10-12 14:39:23 -03:00
|
|
|
message.message_type,
|
2025-10-12 11:44:35 -03:00
|
|
|
)?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("User message saved for tools processing");
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let is_tool_waiting = self
|
2025-10-12 20:12:49 -03:00
|
|
|
.state
|
2025-10-12 11:44:35 -03:00
|
|
|
.tool_manager
|
|
|
|
|
.is_tool_waiting(&message.session_id)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
|
|
|
|
|
if is_tool_waiting {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!(
|
|
|
|
|
"Tool is waiting for input, providing: '{}'",
|
|
|
|
|
message.content
|
|
|
|
|
);
|
2025-10-12 20:12:49 -03:00
|
|
|
self.state
|
|
|
|
|
.tool_manager
|
2025-10-12 11:44:35 -03:00
|
|
|
.provide_input(&message.session_id, &message.content)
|
|
|
|
|
.await?;
|
|
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
if let Ok(tool_output) = self
|
|
|
|
|
.state
|
|
|
|
|
.tool_manager
|
|
|
|
|
.get_tool_output(&message.session_id)
|
|
|
|
|
.await
|
|
|
|
|
{
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Retrieved {} tool output entries", tool_output.len());
|
2025-10-12 11:44:35 -03:00
|
|
|
for output in tool_output {
|
|
|
|
|
let bot_response = BotResponse {
|
|
|
|
|
bot_id: message.bot_id.clone(),
|
|
|
|
|
user_id: message.user_id.clone(),
|
|
|
|
|
session_id: message.session_id.clone(),
|
|
|
|
|
channel: message.channel.clone(),
|
2025-10-13 00:31:08 -03:00
|
|
|
content: output.clone(),
|
2025-10-12 14:39:23 -03:00
|
|
|
message_type: 1,
|
2025-10-12 11:44:35 -03:00
|
|
|
stream_token: None,
|
|
|
|
|
is_complete: true,
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
if let Some(adapter) = self.state.channels.lock().unwrap().get(&message.channel)
|
|
|
|
|
{
|
2025-10-12 11:44:35 -03:00
|
|
|
adapter.send_message(bot_response).await?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Tool output sent: '{}'", output);
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let response = if message.content.to_lowercase().contains("calculator")
|
|
|
|
|
|| message.content.to_lowercase().contains("calculate")
|
|
|
|
|
|| message.content.to_lowercase().contains("math")
|
|
|
|
|
{
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Message requires calculator tool");
|
2025-10-12 11:44:35 -03:00
|
|
|
match self
|
2025-10-12 20:12:49 -03:00
|
|
|
.state
|
2025-10-12 11:44:35 -03:00
|
|
|
.tool_manager
|
|
|
|
|
.execute_tool("calculator", &message.session_id, &message.user_id)
|
|
|
|
|
.await
|
|
|
|
|
{
|
|
|
|
|
Ok(tool_result) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Calculator tool executed successfully");
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 15:06:16 -03:00
|
|
|
session_manager.save_message(session.id, user_id, 2, &tool_result.output, 2)?;
|
2025-10-12 11:44:35 -03:00
|
|
|
tool_result.output
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
error!("Calculator tool error: {}", e);
|
2025-10-12 11:44:35 -03:00
|
|
|
format!("I encountered an error starting the calculator: {}", e)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Using LLM for response generation");
|
2025-10-12 20:12:49 -03:00
|
|
|
let available_tools = self.state.tool_manager.list_tools();
|
2025-10-12 11:44:35 -03:00
|
|
|
let tools_context = if !available_tools.is_empty() {
|
|
|
|
|
format!("\n\nAvailable tools: {}. If the user needs calculations, suggest using the calculator tool.", available_tools.join(", "))
|
|
|
|
|
} else {
|
|
|
|
|
String::new()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let full_prompt = format!("{}{}", message.content, tools_context);
|
2025-10-13 00:31:08 -03:00
|
|
|
trace!("Full prompt with tools context: {}", full_prompt);
|
2025-10-12 11:44:35 -03:00
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
self.state
|
|
|
|
|
.llm_provider
|
2025-10-12 11:44:35 -03:00
|
|
|
.generate(&full_prompt, &serde_json::Value::Null)
|
|
|
|
|
.await?
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Generated response: '{}'", response);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
{
|
2025-10-12 20:12:49 -03:00
|
|
|
let mut session_manager = self.state.session_manager.lock().await;
|
2025-10-12 15:06:16 -03:00
|
|
|
session_manager.save_message(session.id, user_id, 2, &response, 1)?;
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!("Response saved to session history");
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let bot_response = BotResponse {
|
|
|
|
|
bot_id: message.bot_id,
|
|
|
|
|
user_id: message.user_id,
|
|
|
|
|
session_id: message.session_id.clone(),
|
|
|
|
|
channel: message.channel.clone(),
|
|
|
|
|
content: response,
|
2025-10-12 14:39:23 -03:00
|
|
|
message_type: 1,
|
2025-10-12 11:44:35 -03:00
|
|
|
stream_token: None,
|
|
|
|
|
is_complete: true,
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
if let Some(adapter) = self.state.channels.lock().unwrap().get(&message.channel) {
|
2025-10-12 11:44:35 -03:00
|
|
|
adapter.send_message(bot_response).await?;
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Tools response sent successfully");
|
|
|
|
|
} else {
|
|
|
|
|
warn!("No channel adapter found for channel: {}", message.channel);
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2025-10-12 20:12:49 -03:00
|
|
|
|
|
|
|
|
async fn run_start_script(session: &UserSession, state: Arc<AppState>) {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Running start script for session: {}", session.id);
|
2025-10-13 09:36:45 -03:00
|
|
|
|
|
|
|
|
let start_script_path = "start.bas";
|
|
|
|
|
let start_script = match std::fs::read_to_string(start_script_path) {
|
|
|
|
|
Ok(content) => {
|
|
|
|
|
debug!("Loaded start script from {}", start_script_path);
|
|
|
|
|
content
|
|
|
|
|
}
|
|
|
|
|
Err(_) => {
|
|
|
|
|
debug!("No start.bas found, using default welcome script");
|
|
|
|
|
r#"TALK "Welcome to General Bots!""#.to_string()
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-10-12 20:12:49 -03:00
|
|
|
|
2025-10-13 09:36:45 -03:00
|
|
|
debug!("Start script content for session {}: {}", session.id, start_script);
|
2025-10-12 20:12:49 -03:00
|
|
|
|
|
|
|
|
let session_clone = session.clone();
|
|
|
|
|
let state_clone = state.clone();
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
let state_for_run = state_clone.clone();
|
2025-10-13 00:31:08 -03:00
|
|
|
match crate::basic::ScriptService::new(state_clone, session_clone.clone())
|
2025-10-13 09:36:45 -03:00
|
|
|
.compile(&start_script)
|
2025-10-12 20:12:49 -03:00
|
|
|
.and_then(|ast| {
|
|
|
|
|
crate::basic::ScriptService::new(state_for_run, session_clone.clone()).run(&ast)
|
2025-10-13 00:31:08 -03:00
|
|
|
}) {
|
|
|
|
|
Ok(_) => {
|
|
|
|
|
info!(
|
|
|
|
|
"Start script executed successfully for session {}",
|
|
|
|
|
session_clone.id
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
error!(
|
|
|
|
|
"Failed to run start script for session {}: {}",
|
|
|
|
|
session_clone.id, e
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-10-12 20:12:49 -03:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-10-13 00:31:08 -03:00
|
|
|
|
|
|
|
|
pub async fn send_warning(
|
|
|
|
|
&self,
|
|
|
|
|
session_id: &str,
|
|
|
|
|
channel: &str,
|
|
|
|
|
message: &str,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
warn!(
|
|
|
|
|
"Sending warning to session {} on channel {}: {}",
|
|
|
|
|
session_id, channel, message
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if channel == "web" {
|
|
|
|
|
debug!("Sending warning as web event");
|
|
|
|
|
self.send_event(
|
|
|
|
|
"system",
|
|
|
|
|
"system",
|
|
|
|
|
session_id,
|
|
|
|
|
channel,
|
|
|
|
|
"warn",
|
|
|
|
|
serde_json::json!({
|
|
|
|
|
"message": message,
|
|
|
|
|
"timestamp": Utc::now().to_rfc3339()
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
} else {
|
|
|
|
|
debug!("Sending warning as regular message");
|
|
|
|
|
if let Some(adapter) = self.state.channels.lock().unwrap().get(channel) {
|
|
|
|
|
let warn_response = BotResponse {
|
|
|
|
|
bot_id: "system".to_string(),
|
|
|
|
|
user_id: "system".to_string(),
|
|
|
|
|
session_id: session_id.to_string(),
|
|
|
|
|
channel: channel.to_string(),
|
|
|
|
|
content: format!("⚠️ WARNING: {}", message),
|
|
|
|
|
message_type: 1,
|
|
|
|
|
stream_token: None,
|
|
|
|
|
is_complete: true,
|
|
|
|
|
};
|
|
|
|
|
adapter.send_message(warn_response).await
|
|
|
|
|
} else {
|
|
|
|
|
warn!(
|
|
|
|
|
"No channel adapter found for warning on channel: {}",
|
|
|
|
|
channel
|
|
|
|
|
);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-12 20:12:49 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for BotOrchestrator {
|
|
|
|
|
fn default() -> Self {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Creating default BotOrchestrator");
|
2025-10-12 20:12:49 -03:00
|
|
|
Self {
|
|
|
|
|
state: Arc::new(AppState::default()),
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::get("/ws")]
|
|
|
|
|
async fn websocket_handler(
|
|
|
|
|
req: HttpRequest,
|
|
|
|
|
stream: web::Payload,
|
2025-10-12 20:12:49 -03:00
|
|
|
data: web::Data<AppState>,
|
2025-10-12 11:44:35 -03:00
|
|
|
) -> Result<HttpResponse, actix_web::Error> {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("WebSocket connection attempt");
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
let (res, mut session, mut msg_stream) = actix_ws::handle(&req, stream)?;
|
|
|
|
|
let session_id = Uuid::new_v4().to_string();
|
|
|
|
|
let (tx, mut rx) = mpsc::channel::<BotResponse>(100);
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("WebSocket session established: {}", session_id);
|
|
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
|
|
|
|
|
orchestrator
|
2025-10-12 11:44:35 -03:00
|
|
|
.register_response_channel(session_id.clone(), tx.clone())
|
|
|
|
|
.await;
|
|
|
|
|
data.web_adapter
|
|
|
|
|
.add_connection(session_id.clone(), tx.clone())
|
|
|
|
|
.await;
|
|
|
|
|
data.voice_adapter
|
|
|
|
|
.add_connection(session_id.clone(), tx.clone())
|
|
|
|
|
.await;
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
orchestrator
|
|
|
|
|
.send_event(
|
|
|
|
|
"default_user",
|
|
|
|
|
"default_bot",
|
|
|
|
|
&session_id,
|
|
|
|
|
"web",
|
|
|
|
|
"session_start",
|
|
|
|
|
serde_json::json!({
|
|
|
|
|
"session_id": session_id,
|
|
|
|
|
"timestamp": Utc::now().to_rfc3339()
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.ok();
|
2025-10-12 11:44:35 -03:00
|
|
|
let web_adapter = data.web_adapter.clone();
|
2025-10-13 00:31:08 -03:00
|
|
|
let session_id_clone1 = session_id.clone();
|
|
|
|
|
let session_id_clone2 = session_id.clone();
|
2025-10-12 11:44:35 -03:00
|
|
|
|
|
|
|
|
actix_web::rt::spawn(async move {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"Starting WebSocket sender for session {}",
|
|
|
|
|
session_id_clone1
|
|
|
|
|
);
|
|
|
|
|
let mut message_count = 0;
|
2025-10-12 11:44:35 -03:00
|
|
|
while let Some(msg) = rx.recv().await {
|
2025-10-13 00:31:08 -03:00
|
|
|
message_count += 1;
|
2025-10-12 11:44:35 -03:00
|
|
|
if let Ok(json) = serde_json::to_string(&msg) {
|
2025-10-13 00:31:08 -03:00
|
|
|
trace!("Sending WebSocket message {}: {}", message_count, json);
|
|
|
|
|
if let Err(e) = session.text(json).await {
|
|
|
|
|
warn!("Failed to send WebSocket message {}: {}", message_count, e);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
}
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"WebSocket sender terminated for session {}, sent {} messages",
|
|
|
|
|
session_id_clone1, message_count
|
|
|
|
|
);
|
2025-10-12 11:44:35 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
actix_web::rt::spawn(async move {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"Starting WebSocket receiver for session {}",
|
|
|
|
|
session_id_clone2
|
|
|
|
|
);
|
|
|
|
|
let mut message_count = 0;
|
2025-10-12 11:44:35 -03:00
|
|
|
while let Some(Ok(msg)) = msg_stream.recv().await {
|
|
|
|
|
match msg {
|
|
|
|
|
WsMessage::Text(text) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
message_count += 1;
|
|
|
|
|
debug!("Received WebSocket message {}: {}", message_count, text);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
let user_message = UserMessage {
|
|
|
|
|
bot_id: "default_bot".to_string(),
|
|
|
|
|
user_id: "default_user".to_string(),
|
2025-10-13 00:31:08 -03:00
|
|
|
session_id: session_id_clone2.clone(),
|
2025-10-12 11:44:35 -03:00
|
|
|
channel: "web".to_string(),
|
|
|
|
|
content: text.to_string(),
|
2025-10-12 14:39:23 -03:00
|
|
|
message_type: 1,
|
2025-10-12 11:44:35 -03:00
|
|
|
media_url: None,
|
|
|
|
|
timestamp: Utc::now(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if let Err(e) = orchestrator.stream_response(user_message, tx.clone()).await {
|
2025-10-13 00:31:08 -03:00
|
|
|
error!(
|
|
|
|
|
"Error processing WebSocket message {}: {}",
|
|
|
|
|
message_count, e
|
|
|
|
|
);
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
WsMessage::Close(_) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("WebSocket close received for session {}", session_id_clone2);
|
|
|
|
|
orchestrator
|
|
|
|
|
.send_event(
|
|
|
|
|
"default_user",
|
|
|
|
|
"default_bot",
|
|
|
|
|
&session_id_clone2,
|
|
|
|
|
"web",
|
|
|
|
|
"session_end",
|
|
|
|
|
serde_json::json!({}),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.ok();
|
|
|
|
|
|
|
|
|
|
web_adapter.remove_connection(&session_id_clone2).await;
|
2025-10-12 11:44:35 -03:00
|
|
|
break;
|
|
|
|
|
}
|
2025-10-13 00:31:08 -03:00
|
|
|
_ => {
|
|
|
|
|
trace!("Received non-text WebSocket message");
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
}
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"WebSocket receiver terminated for session {}, processed {} messages",
|
|
|
|
|
session_id_clone2, message_count
|
|
|
|
|
);
|
2025-10-12 11:44:35 -03:00
|
|
|
});
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"WebSocket handler setup completed for session {}",
|
|
|
|
|
session_id
|
|
|
|
|
);
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(res)
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::get("/api/whatsapp/webhook")]
|
|
|
|
|
async fn whatsapp_webhook_verify(
|
2025-10-12 20:12:49 -03:00
|
|
|
data: web::Data<AppState>,
|
2025-10-12 11:44:35 -03:00
|
|
|
web::Query(params): web::Query<HashMap<String, String>>,
|
|
|
|
|
) -> Result<HttpResponse> {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("WhatsApp webhook verification request");
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
let empty = String::new();
|
|
|
|
|
let mode = params.get("hub.mode").unwrap_or(&empty);
|
|
|
|
|
let token = params.get("hub.verify_token").unwrap_or(&empty);
|
|
|
|
|
let challenge = params.get("hub.challenge").unwrap_or(&empty);
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!(
|
|
|
|
|
"Verification params - mode: {}, token: {}, challenge: {}",
|
|
|
|
|
mode, token, challenge
|
|
|
|
|
);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
match data.whatsapp_adapter.verify_webhook(mode, token, challenge) {
|
2025-10-13 00:31:08 -03:00
|
|
|
Ok(challenge_response) => {
|
|
|
|
|
info!("WhatsApp webhook verification successful");
|
|
|
|
|
Ok(HttpResponse::Ok().body(challenge_response))
|
|
|
|
|
}
|
|
|
|
|
Err(_) => {
|
|
|
|
|
warn!("WhatsApp webhook verification failed");
|
|
|
|
|
Ok(HttpResponse::Forbidden().body("Verification failed"))
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::post("/api/whatsapp/webhook")]
|
|
|
|
|
async fn whatsapp_webhook(
|
2025-10-12 20:12:49 -03:00
|
|
|
data: web::Data<AppState>,
|
2025-10-12 11:44:35 -03:00
|
|
|
payload: web::Json<crate::whatsapp::WhatsAppMessage>,
|
|
|
|
|
) -> Result<HttpResponse> {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("WhatsApp webhook message received");
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
match data
|
|
|
|
|
.whatsapp_adapter
|
|
|
|
|
.process_incoming_message(payload.into_inner())
|
|
|
|
|
.await
|
|
|
|
|
{
|
|
|
|
|
Ok(user_messages) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Processed {} WhatsApp messages", user_messages.len());
|
2025-10-12 11:44:35 -03:00
|
|
|
for user_message in user_messages {
|
2025-10-12 20:12:49 -03:00
|
|
|
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
|
|
|
|
|
if let Err(e) = orchestrator.process_message(user_message).await {
|
2025-10-13 00:31:08 -03:00
|
|
|
error!("Error processing WhatsApp message: {}", e);
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(HttpResponse::Ok().body(""))
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
error!("Error processing WhatsApp webhook: {}", e);
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(HttpResponse::BadRequest().body("Invalid message"))
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::post("/api/voice/start")]
|
|
|
|
|
async fn voice_start(
|
2025-10-12 20:12:49 -03:00
|
|
|
data: web::Data<AppState>,
|
2025-10-12 11:44:35 -03:00
|
|
|
info: web::Json<serde_json::Value>,
|
|
|
|
|
) -> Result<HttpResponse> {
|
|
|
|
|
let session_id = info
|
|
|
|
|
.get("session_id")
|
|
|
|
|
.and_then(|s| s.as_str())
|
|
|
|
|
.unwrap_or("");
|
|
|
|
|
let user_id = info
|
|
|
|
|
.get("user_id")
|
|
|
|
|
.and_then(|u| u.as_str())
|
|
|
|
|
.unwrap_or("user");
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"Voice session start request - session: {}, user: {}",
|
|
|
|
|
session_id, user_id
|
|
|
|
|
);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
match data
|
|
|
|
|
.voice_adapter
|
|
|
|
|
.start_voice_session(session_id, user_id)
|
|
|
|
|
.await
|
|
|
|
|
{
|
|
|
|
|
Ok(token) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!(
|
|
|
|
|
"Voice session started successfully for session {}",
|
|
|
|
|
session_id
|
|
|
|
|
);
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(HttpResponse::Ok().json(serde_json::json!({"token": token, "status": "started"})))
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
error!(
|
|
|
|
|
"Failed to start voice session for session {}: {}",
|
|
|
|
|
session_id, e
|
|
|
|
|
);
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(HttpResponse::InternalServerError()
|
|
|
|
|
.json(serde_json::json!({"error": e.to_string()})))
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::post("/api/voice/stop")]
|
|
|
|
|
async fn voice_stop(
|
2025-10-12 20:12:49 -03:00
|
|
|
data: web::Data<AppState>,
|
2025-10-12 11:44:35 -03:00
|
|
|
info: web::Json<serde_json::Value>,
|
|
|
|
|
) -> Result<HttpResponse> {
|
|
|
|
|
let session_id = info
|
|
|
|
|
.get("session_id")
|
|
|
|
|
.and_then(|s| s.as_str())
|
|
|
|
|
.unwrap_or("");
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Voice session stop request - session: {}", session_id);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
match data.voice_adapter.stop_voice_session(session_id).await {
|
2025-10-13 00:31:08 -03:00
|
|
|
Ok(()) => {
|
|
|
|
|
info!(
|
|
|
|
|
"Voice session stopped successfully for session {}",
|
|
|
|
|
session_id
|
|
|
|
|
);
|
|
|
|
|
Ok(HttpResponse::Ok().json(serde_json::json!({"status": "stopped"})))
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
Err(e) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
error!(
|
|
|
|
|
"Failed to stop voice session for session {}: {}",
|
|
|
|
|
session_id, e
|
|
|
|
|
);
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(HttpResponse::InternalServerError()
|
|
|
|
|
.json(serde_json::json!({"error": e.to_string()})))
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::post("/api/sessions")]
|
2025-10-13 00:31:08 -03:00
|
|
|
async fn create_session(data: web::Data<AppState>) -> Result<HttpResponse> {
|
|
|
|
|
info!("Creating new session");
|
|
|
|
|
|
|
|
|
|
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
|
|
|
|
|
let bot_id = Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap();
|
|
|
|
|
|
|
|
|
|
let session = {
|
|
|
|
|
let mut session_manager = data.session_manager.lock().await;
|
|
|
|
|
match session_manager.create_session(user_id, bot_id, "New Conversation") {
|
|
|
|
|
Ok(s) => s,
|
|
|
|
|
Err(e) => {
|
|
|
|
|
error!("Failed to create session: {}", e);
|
|
|
|
|
return Ok(HttpResponse::InternalServerError()
|
|
|
|
|
.json(serde_json::json!({"error": e.to_string()})));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(HttpResponse::Ok().json(serde_json::json!({
|
2025-10-13 00:31:08 -03:00
|
|
|
"session_id": session.id,
|
2025-10-12 11:44:35 -03:00
|
|
|
"title": "New Conversation",
|
|
|
|
|
"created_at": Utc::now()
|
|
|
|
|
})))
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::get("/api/sessions")]
|
2025-10-12 20:12:49 -03:00
|
|
|
async fn get_sessions(data: web::Data<AppState>) -> Result<HttpResponse> {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Getting sessions list");
|
2025-10-12 11:44:35 -03:00
|
|
|
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
|
2025-10-12 20:12:49 -03:00
|
|
|
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
|
|
|
|
|
match orchestrator.get_user_sessions(user_id).await {
|
2025-10-13 00:31:08 -03:00
|
|
|
Ok(sessions) => {
|
|
|
|
|
info!("Retrieved {} sessions", sessions.len());
|
|
|
|
|
Ok(HttpResponse::Ok().json(sessions))
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
Err(e) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
error!("Failed to get sessions: {}", e);
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(HttpResponse::InternalServerError()
|
|
|
|
|
.json(serde_json::json!({"error": e.to_string()})))
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::get("/api/sessions/{session_id}")]
|
|
|
|
|
async fn get_session_history(
|
2025-10-12 20:12:49 -03:00
|
|
|
data: web::Data<AppState>,
|
2025-10-12 11:44:35 -03:00
|
|
|
path: web::Path<String>,
|
|
|
|
|
) -> Result<HttpResponse> {
|
|
|
|
|
let session_id = path.into_inner();
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Getting session history for: {}", session_id);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
|
|
|
|
|
|
|
|
|
|
match Uuid::parse_str(&session_id) {
|
2025-10-12 20:12:49 -03:00
|
|
|
Ok(session_uuid) => {
|
|
|
|
|
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
|
|
|
|
|
match orchestrator
|
|
|
|
|
.get_conversation_history(session_uuid, user_id)
|
|
|
|
|
.await
|
|
|
|
|
{
|
2025-10-13 00:31:08 -03:00
|
|
|
Ok(history) => {
|
|
|
|
|
info!(
|
|
|
|
|
"Retrieved {} history entries for session {}",
|
|
|
|
|
history.len(),
|
|
|
|
|
session_id
|
|
|
|
|
);
|
|
|
|
|
Ok(HttpResponse::Ok().json(history))
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
error!("Failed to get session history for {}: {}", session_id, e);
|
|
|
|
|
Ok(HttpResponse::InternalServerError()
|
|
|
|
|
.json(serde_json::json!({"error": e.to_string()})))
|
|
|
|
|
}
|
2025-10-12 20:12:49 -03:00
|
|
|
}
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
Err(_) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
warn!("Invalid session ID format: {}", session_id);
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(HttpResponse::BadRequest().json(serde_json::json!({"error": "Invalid session ID"})))
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-11 20:41:52 -03:00
|
|
|
}
|
2025-10-06 10:30:17 -03:00
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::post("/api/set_mode")]
|
|
|
|
|
async fn set_mode_handler(
|
2025-10-12 20:12:49 -03:00
|
|
|
data: web::Data<AppState>,
|
2025-10-12 11:44:35 -03:00
|
|
|
info: web::Json<HashMap<String, String>>,
|
|
|
|
|
) -> Result<HttpResponse> {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Setting user answer mode");
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
let default_user = "default_user".to_string();
|
|
|
|
|
let default_bot = "default_bot".to_string();
|
2025-10-12 13:27:48 -03:00
|
|
|
let default_mode = "0".to_string();
|
2025-10-12 11:44:35 -03:00
|
|
|
|
|
|
|
|
let user_id = info.get("user_id").unwrap_or(&default_user);
|
|
|
|
|
let bot_id = info.get("bot_id").unwrap_or(&default_bot);
|
2025-10-12 13:27:48 -03:00
|
|
|
let mode_str = info.get("mode").unwrap_or(&default_mode);
|
|
|
|
|
|
|
|
|
|
let mode = mode_str.parse::<i32>().unwrap_or(0);
|
2025-10-12 11:44:35 -03:00
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!(
|
|
|
|
|
"Setting mode - user: {}, bot: {}, mode: {}",
|
|
|
|
|
user_id, bot_id, mode
|
|
|
|
|
);
|
|
|
|
|
|
2025-10-12 20:12:49 -03:00
|
|
|
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
|
|
|
|
|
if let Err(e) = orchestrator
|
2025-10-12 11:44:35 -03:00
|
|
|
.set_user_answer_mode(user_id, bot_id, mode)
|
|
|
|
|
.await
|
|
|
|
|
{
|
2025-10-13 00:31:08 -03:00
|
|
|
error!("Failed to set answer mode: {}", e);
|
2025-10-12 11:44:35 -03:00
|
|
|
return Ok(
|
|
|
|
|
HttpResponse::InternalServerError().json(serde_json::json!({"error": e.to_string()}))
|
|
|
|
|
);
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Answer mode updated successfully");
|
2025-10-12 11:44:35 -03:00
|
|
|
Ok(HttpResponse::Ok().json(serde_json::json!({"status": "mode_updated"})))
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
#[actix_web::post("/api/warn")]
|
|
|
|
|
async fn send_warning_handler(
|
|
|
|
|
data: web::Data<AppState>,
|
|
|
|
|
info: web::Json<HashMap<String, String>>,
|
|
|
|
|
) -> Result<HttpResponse> {
|
|
|
|
|
let default_session = "default".to_string();
|
|
|
|
|
let default_channel = "web".to_string();
|
|
|
|
|
let default_message = "Warning!".to_string();
|
|
|
|
|
|
|
|
|
|
let session_id = info.get("session_id").unwrap_or(&default_session);
|
|
|
|
|
let channel = info.get("channel").unwrap_or(&default_channel);
|
|
|
|
|
let message = info.get("message").unwrap_or(&default_message);
|
|
|
|
|
|
|
|
|
|
info!(
|
|
|
|
|
"Sending warning via API - session: {}, channel: {}",
|
|
|
|
|
session_id, channel
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
|
|
|
|
|
if let Err(e) = orchestrator
|
|
|
|
|
.send_warning(session_id, channel, message)
|
|
|
|
|
.await
|
|
|
|
|
{
|
|
|
|
|
error!("Failed to send warning: {}", e);
|
|
|
|
|
return Ok(
|
|
|
|
|
HttpResponse::InternalServerError().json(serde_json::json!({"error": e.to_string()}))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info!("Warning sent successfully");
|
|
|
|
|
Ok(HttpResponse::Ok().json(serde_json::json!({"status": "warning_sent"})))
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::get("/")]
|
|
|
|
|
async fn index() -> Result<HttpResponse> {
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Serving index page");
|
|
|
|
|
match fs::read_to_string("web/index.html") {
|
|
|
|
|
Ok(html) => {
|
|
|
|
|
debug!("Index page loaded successfully");
|
|
|
|
|
Ok(HttpResponse::Ok().content_type("text/html").body(html))
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
error!("Failed to load index page: {}", e);
|
|
|
|
|
Ok(HttpResponse::InternalServerError().body("Failed to load index page"))
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-06 10:30:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
#[actix_web::get("/static/{filename:.*}")]
|
|
|
|
|
async fn static_files(req: HttpRequest) -> Result<HttpResponse> {
|
|
|
|
|
let filename = req.match_info().query("filename");
|
|
|
|
|
let path = format!("static/{}", filename);
|
|
|
|
|
|
2025-10-13 00:31:08 -03:00
|
|
|
info!("Serving static file: {}", filename);
|
|
|
|
|
|
2025-10-12 11:44:35 -03:00
|
|
|
match fs::read(&path) {
|
|
|
|
|
Ok(content) => {
|
2025-10-13 00:31:08 -03:00
|
|
|
debug!(
|
|
|
|
|
"Static file {} loaded successfully, size: {} bytes",
|
|
|
|
|
filename,
|
|
|
|
|
content.len()
|
|
|
|
|
);
|
2025-10-12 11:44:35 -03:00
|
|
|
let content_type = match filename {
|
|
|
|
|
f if f.ends_with(".js") => "application/javascript",
|
|
|
|
|
f if f.ends_with(".css") => "text/css",
|
|
|
|
|
f if f.ends_with(".png") => "image/png",
|
|
|
|
|
f if f.ends_with(".jpg") | f.ends_with(".jpeg") => "image/jpeg",
|
|
|
|
|
_ => "text/plain",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(HttpResponse::Ok().content_type(content_type).body(content))
|
|
|
|
|
}
|
2025-10-13 00:31:08 -03:00
|
|
|
Err(e) => {
|
|
|
|
|
warn!("Static file not found: {} - {}", filename, e);
|
|
|
|
|
Ok(HttpResponse::NotFound().body("File not found"))
|
|
|
|
|
}
|
2025-10-12 11:44:35 -03:00
|
|
|
}
|
|
|
|
|
}
|