diff --git a/src/main.rs b/src/main.rs index f54467e..424a049 100644 --- a/src/main.rs +++ b/src/main.rs @@ -126,7 +126,6 @@ fn main() -> anyhow::Result<()> { }; - // Get the current day in the format YYYY-MM-DD let current_date = chrono::Local::now(); let formatted_date = current_date.format("%Y-%m-%d").to_string(); @@ -232,9 +231,9 @@ fn main() -> anyhow::Result<()> { )) .expect("Failed to create response_time.csv"); } - */ + // Read system prompt let prompt = std::fs::read_to_string("PROMPT.txt").unwrap(); let filter_file_contents = std::fs::read_to_string("FILTER.txt").unwrap_or(String::new()); @@ -318,7 +317,6 @@ fn main() -> anyhow::Result<()> { let template_id = message_object["is_template"] .as_bool() .unwrap_or(true); - // println!("Conteudo do template_id da mensagem {}: {:?}", pos, template_id); let found = message.find( "Atendimento transferido para a fila [NovaNet -> Atendimento -> NOC - Clientes]", ); @@ -373,12 +371,6 @@ fn main() -> anyhow::Result<()> { .find(&keyword.to_uppercase()) .is_some() }); - /* - let found2 = message_object["is_template"] - .as_bool() - .unwrap_or(true); - let found = found1 || found2; - */ found1 }); @@ -390,115 +382,103 @@ fn main() -> anyhow::Result<()> { return Some(json); }); - // Calculate the response time in seconds - let response_time = filtered_chats - .clone() - .map(|messages| { - let json = messages.unwrap(); - let talk_histories = &json["talk_histories"]; - - // find the bot transfer message - let bot_transfer_message = talk_histories - .as_array() - .expect("Wrong message type received from talk histories") - .into_iter() - .enumerate() - .filter(|(pos, message_object)| { - let user_name = message_object["user"]["name"] - .as_str() - .expect("Failed to decode message as string"); - user_name == "PipeBot".to_string() - }) - .find(|(pos, message_object)| { - let message = message_object["message"] - .as_str() - .expect("Failed to decode message as string"); - let found = message.find("Atendimento entregue da fila de espera para o agente [NOC"); - let is_template = message_object["is_template"] - .as_bool() - .unwrap_or(true); - found.is_some() || is_template - }); - - // Find first agent message sent after the last bot message - // let (pos, transfer_message) = - // bot_transfer_message.expect("Failed to get the transfer bot message position"); + //INICIO do response time consideranto template ou transferência. + let response_time = filtered_chats + .clone() + .map(|messages| { + let json = messages.unwrap(); + let talk_histories = &json["talk_histories"]; + let histories = talk_histories.as_array() + .expect("Wrong message type received from talk histories"); - let (pos, transfer_message) = match bot_transfer_message { - Some((pos, msg)) => (pos, msg), - None => return "".to_string(), // Retorna string vazia em vez de panic - }; + // 1. Encontrar o primeiro gatilho na ordem cronológica (percorrendo do índice mais alto para o mais baixo) + let trigger = histories.iter().enumerate().rev().find(|(_, msg)| { + let is_template = msg["is_template"].as_bool().unwrap_or(false); + let user = msg["user"]["name"].as_str().unwrap_or(""); + let message = msg["message"].as_str().unwrap_or(""); + let is_transfer = user == "PipeBot" + && message.contains("Atendimento entregue da fila de espera para o agente [NOC"); + is_template || is_transfer + }); + + let (trigger_pos, trigger_msg) = match trigger { + Some(pair) => pair, + None => return "".to_string(), + }; + + // 2. Determinar se é transferência (para escolher a referência correta) + let is_transfer_case = { + let user = trigger_msg["user"]["name"].as_str().unwrap_or(""); + let message = trigger_msg["message"].as_str().unwrap_or(""); + user == "PipeBot" + && message.contains("Atendimento entregue da fila de espera para o agente [NOC") + }; + + let (ref_pos, ref_msg) = if is_transfer_case { + // Caso transferência: referência é o próprio gatilho + (trigger_pos, trigger_msg) + } else { + // Caso template: referência é a próxima mensagem cronológica (índice trigger_pos - 1) + if trigger_pos > 0 { + match histories.get(trigger_pos - 1) { + Some(next_msg) => (trigger_pos - 1, next_msg), + None => return "".to_string(), + } + } else { + return "".to_string(); // template na última posição (sem resposta do cliente) + } + }; + + // 3. Procurar a primeira resposta do agente após a referência (índices menores que ref_pos) + let agent_msg = (0..ref_pos).rev() + .filter_map(|i| { + let m = &histories[i]; + if m["type"].as_str() == Some("out") + && m["user"]["name"].as_str().map_or(false, |name| name.starts_with("NOC -")) + { + Some(m) + } else { + None + } + }) + .take(1) + .collect::>(); + + if agent_msg.is_empty() { + return "".to_string(); + } + let agent_first_message = agent_msg[0]; + + // 4. Calcular tempo entre referência e primeira resposta do agente + let format = "%Y-%m-%d %H:%M:%S"; + let t_ref = chrono::NaiveDateTime::parse_from_str( + ref_msg["sent_at"].as_str().unwrap(), + format, + ).expect("Erro ao parsear data da referência"); + let t_agent = chrono::NaiveDateTime::parse_from_str( + agent_first_message["sent_at"].as_str().unwrap(), + format, + ).expect("Erro ao parsear data do agente"); + + let response_time = (t_agent - t_ref).num_seconds() as f32; + + let name = agent_first_message["user"]["name"].as_str().unwrap().to_owned(); + let id = json["tracking_number"].as_str().unwrap_or("").to_owned(); + let ref_date = ref_msg["sent_at"].as_str().unwrap().to_owned(); + let agent_date = agent_first_message["sent_at"].as_str().unwrap().to_owned(); + + println!("response_time: {}s", response_time); + + format!( + "{};{};{};{};{}", + name, id, response_time, ref_date, agent_date + ) + }) + .filter(|s| !s.is_empty()) + .reduce(|acc, e| format!("{}\n{}", acc, e)) + .unwrap_or("".to_string()); + //FIM do response time considerando template ou transferência. - let msg = talk_histories - .as_array() - .expect("Wrong message type received from talk histories") - .into_iter() - .take(pos) - .rev() - .filter(|message| { - message["type"] == "out".to_string() - // && message["user"]["name"] != "PipeBot".to_string() - && message["user"]["name"].as_str().map_or(false, |name| name.starts_with("NOC -")) - }) - .take(1) - .collect_vec(); - // Se não encontrar mensagem do agente, retorna string vazia - if msg.is_empty() { - return "".to_string(); - } - - let agent_first_message = msg[0]; - - // Calculate time difference between bot message and agent message - let date_user_message_sent = agent_first_message["sent_at"].as_str().unwrap(); - - let format = "%Y-%m-%d %H:%M:%S"; - - let date_user_message_sent_parsed = - match chrono::NaiveDateTime::parse_from_str(date_user_message_sent, format) { - Ok(dt) => dt, - Err(e) => { - println!("Error parsing DateTime: {}", e); - panic!("Failed parsing date") - } - }; - - let date_transfer_message_sent_parsed = match chrono::NaiveDateTime::parse_from_str( - transfer_message["sent_at"].as_str().unwrap(), - format, - ) { - Ok(dt) => dt, - Err(e) => { - println!("Error parsing DateTime: {}", e); - panic!("Failed parsing date") - } - }; - - let response_time = (date_user_message_sent_parsed - date_transfer_message_sent_parsed) - .as_seconds_f32(); - let name = agent_first_message["user"]["name"] - .as_str() - .unwrap() - .to_owned(); - let id = json["tracking_number"].as_str().unwrap_or("").to_owned(); - let bot_transfer_date = date_transfer_message_sent_parsed.to_owned(); - let user_response_date = date_user_message_sent.to_owned(); - println!( - "response_time: {}s", - (date_user_message_sent_parsed - date_transfer_message_sent_parsed) - .as_seconds_f32() - ); - - format!( - "{};{};{};{};{}", - name, id, response_time, bot_transfer_date, user_response_date - ) - }) - .filter(|s| !s.is_empty()) // Filtra strings vazias - .reduce(|acc, e| format!("{}\n{}", acc, e)) - .unwrap_or("".to_string()); - - // return Ok(()); // Open file and write to it let header = "NOME;ID_TALK;TEMPO DE RESPOSTA;TRANFERENCIA PELO BOT;PRIMEIRA RESPOSTA DO AGENTE"; let mut response_time_file = std::fs::OpenOptions::new() @@ -535,7 +515,6 @@ fn main() -> anyhow::Result<()> { message_object["type"], message_object["user"]["name"] ); - // println!("{}", new_json_filtered); new_json_filtered }) .reduce(|acc, e| format!("{acc}\n{e}")) @@ -551,7 +530,6 @@ fn main() -> anyhow::Result<()> { serde_json::json!({ "model": OLLAMA_AI_MODEL, "prompt": format!("{prompt} \n{talk}"), - // "options": serde_json::json!({"temperature": 0.1}), "stream": false, }) .to_string(), @@ -582,8 +560,8 @@ fn main() -> anyhow::Result<()> { let tracking_number = &json["tracking_number"].as_str().unwrap_or(""); std::fs::write( format!( - "./evaluations/{}/{} - {} - {}.csv", - formatted_day_before, user_name, talk_id, tracking_number + "./evaluations/{}/{} - {} - {}.csv", + formatted_day_before, user_name, talk_id, tracking_number //formatted_day, user_name, talk_id, tracking_number ), csv_response, @@ -616,12 +594,12 @@ fn main() -> anyhow::Result<()> { // Send folder to email - let recipients = "Nicolas Borges da Silva , wilson@nova.net.br"; + let recipients = "nicolas.borges@nova.net.br, wilson@nova.net.br"; println!("Trying to send email... Recipients {recipients}"); send_mail_util::send_mail_util::send_email( &format!("Avaliacao atendimentos da fila NOC - Clientes do dia {formatted_day_before}"), - //&format!("Avaliacao atendimentos da fila Financeiro NVL2 do dia {formatted_day}"), + //&format!("Avaliacao atendimentos da fila NOC - Clientes do dia {formatted_day}"), &BOT_EMAIL, &BOT_EMAIL_PASSWORD, recipients, @@ -660,7 +638,7 @@ fn get_piperun_chats_on_date( ("report_type", report_type.clone()), ("start_date", formatted_day_before_at_midnight.clone()), //("start_date", formatted_day_start.clone()), - ("end_date", formatted_day_before_at_23_59_59.clone()), + ("end_date", formatted_day_before_at_23_59_59.clone()), //("end_date", formatted_day_end.clone()), ("date_range_type", start_of_talk_code.clone()), ("queue_id[]", support_queue_id.clone()),