diff --git a/src/basic/keywords/hear_talk.rs b/src/basic/keywords/hear_talk.rs index a785dec0..7c2c89bd 100644 --- a/src/basic/keywords/hear_talk.rs +++ b/src/basic/keywords/hear_talk.rs @@ -2,6 +2,7 @@ use crate::shared::models::{BotResponse, UserSession}; use crate::shared::state::AppState; use log::{debug, error, info}; use rhai::{Dynamic, Engine, EvalAltResult}; +use std::env; use std::sync::Arc; use uuid::Uuid; @@ -66,60 +67,70 @@ pub fn talk_keyword(state: Arc, user: UserSession, engine: &mut Engine engine .register_custom_syntax(&["TALK", "$expr$"], true, move |context, inputs| { + // Evaluate the expression that produces the message text. let message = context.eval_expression_tree(&inputs[0])?.to_string(); - info!("TALK command executed: {}", message); + debug!("TALK: Sending message: {}", message); - let state_for_spawn = Arc::clone(&state_clone); - let user_clone_spawn = user_clone.clone(); - let message_clone = message.clone(); + // Build the bot response that will be sent back to the client. + let bot_id = env::var("BOT_GUID").unwrap_or_else(|_| "default_bot".to_string()); + let response = BotResponse { + bot_id, + user_id: user_clone.user_id.to_string(), + session_id: user_clone.id.to_string(), + channel: "web".to_string(), + content: message, + message_type: 1, + stream_token: None, + is_complete: true, + }; - tokio::spawn(async move { - debug!("TALK: Sending message via WebSocket: {}", message_clone); + let user_id = user_clone.id.to_string(); - let bot_id = - std::env::var("BOT_GUID").unwrap_or_else(|_| "default_bot".to_string()); - - let response = BotResponse { - bot_id: bot_id, - user_id: user_clone_spawn.user_id.to_string(), - session_id: user_clone_spawn.id.to_string(), - channel: "web".to_string(), - content: message_clone, - message_type: 1, - stream_token: None, - is_complete: true, - }; - - let response_channels = state_for_spawn.response_channels.lock().await; - if let Some(tx) = response_channels.get(&user_clone_spawn.id.to_string()) { - if let Err(e) = tx.send(response).await { - error!("Failed to send TALK message via WebSocket: {}", e); + // Try to acquire the lock on the response_channels map. The map is protected + // by an async `tokio::sync::Mutex`, so we use `try_lock` to avoid awaiting + // inside this non‑async closure. + match state_clone.response_channels.try_lock() { + Ok(mut response_channels) => { + if let Some(tx) = response_channels.get(&user_id) { + // Use `try_send` to avoid blocking the runtime. + if let Err(e) = tx.try_send(response.clone()) { + error!("Failed to send TALK message via WebSocket: {}", e); + } else { + debug!("TALK message sent successfully via WebSocket"); + } } else { - debug!("TALK message sent successfully via WebSocket"); - } - } else { - debug!( - "No WebSocket connection found for session {}, sending via web adapter", - user_clone_spawn.id - ); - - if let Err(e) = state_for_spawn - .web_adapter - .send_message_to_session(&user_clone_spawn.id.to_string(), response) - .await - { - error!("Failed to send TALK message via web adapter: {}", e); - } else { - debug!("TALK message sent successfully via web adapter"); + debug!( + "No WebSocket connection found for session {}, sending via web adapter", + user_id + ); + // The web adapter method is async (`send_message_to_session`), so we + // spawn a detached task to perform the send without blocking. + let web_adapter = Arc::clone(&state_clone.web_adapter); + let resp_clone = response.clone(); + let sess_id = user_id.clone(); + tokio::spawn(async move { + if let Err(e) = web_adapter + .send_message_to_session(&sess_id, resp_clone) + .await + { + error!("Failed to send TALK message via web adapter: {}", e); + } else { + debug!("TALK message sent successfully via web adapter"); + } + }); } } - }); + Err(_) => { + error!("Failed to acquire lock on response_channels for TALK command"); + } + } Ok(Dynamic::UNIT) }) .unwrap(); } + pub fn set_user_keyword(state: Arc, user: UserSession, engine: &mut Engine) { let state_clone = Arc::clone(&state); let user_clone = user.clone(); diff --git a/templates/annoucements.gbai/annoucements.gbdialog/start.bas b/templates/annoucements.gbai/annoucements.gbdialog/start.bas index 6e49dc23..3eee8385 100644 --- a/templates/annoucements.gbai/annoucements.gbdialog/start.bas +++ b/templates/annoucements.gbai/annoucements.gbdialog/start.bas @@ -1,5 +1,4 @@ TALK "Olá, pode me perguntar sobre qualquer coisa..." - let text = GET "default.gbdrive/default.pdf" let resume = LLM "Say Hello and present a a resume from " + text TALK resume