From 7d2ae90eb39111737ad6b8cc18160176f33ef8a1 Mon Sep 17 00:00:00 2001 From: Jelson Rodrigues Date: Wed, 5 Nov 2025 08:33:39 -0300 Subject: [PATCH] style: format code --- src/main.rs | 461 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 305 insertions(+), 156 deletions(-) diff --git a/src/main.rs b/src/main.rs index ba2e7f3..da1753e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -166,20 +166,37 @@ fn main() -> anyhow::Result<()> { // Create a folder named with the day_before if !std::fs::exists(format!("./evaluations/{formatted_day_before}")).unwrap() { - std::fs::create_dir(format!("./evaluations/{formatted_day_before}")).expect("Failed to create directory") + std::fs::create_dir(format!("./evaluations/{formatted_day_before}")) + .expect("Failed to create directory") } // Create the response time folder - if !std::fs::exists(format!("./evaluations/{formatted_day_before}/response_time.csv")).unwrap() { - let mut response_time_file = std::fs::File::create_new(format!("./evaluations/{formatted_day_before}/response_time.csv")).expect("Failed to response_time.csv"); + if !std::fs::exists(format!( + "./evaluations/{formatted_day_before}/response_time.csv" + )) + .unwrap() + { + let mut response_time_file = std::fs::File::create_new(format!( + "./evaluations/{formatted_day_before}/response_time.csv" + )) + .expect("Failed to 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()); - let filter_keywords = filter_file_contents.split("\n").filter(|keyword| !keyword.is_empty()).collect::>(); + let filter_keywords = filter_file_contents + .split("\n") + .filter(|keyword| !keyword.is_empty()) + .collect::>(); - let talks_array = get_piperun_chats_on_date(&PIPERUN_API_URL, &client, &access_token, formatted_day_before_at_midnight, formatted_day_before_at_23_59_59); + let talks_array = get_piperun_chats_on_date( + &PIPERUN_API_URL, + &client, + &access_token, + formatted_day_before_at_midnight, + formatted_day_before_at_23_59_59, + ); println!("Number of consolidated talks: {}", talks_array.len()); @@ -215,41 +232,82 @@ fn main() -> anyhow::Result<()> { let talk_id_get_result = talk_id_get_request.send(); return talk_id_get_result; - }).filter_map_ok(|result| { - let json = result.json::().expect("Failed to deserialize response to JSON").to_owned(); + }) + .filter_map_ok(|result| { + let json = result + .json::() + .expect("Failed to deserialize response to JSON") + .to_owned(); let talk_histories = &json["talk_histories"]; let data = &talk_histories["data"]; // Filter chats that have very few messages - let talk_lenght = talk_histories.as_array().expect("Wrong message type received from talk histories").len(); - if talk_lenght < MINIMUM_NUMBER_OF_MESSAGES_TO_EVALUATE {return None;} + let talk_lenght = talk_histories + .as_array() + .expect("Wrong message type received from talk histories") + .len(); + if talk_lenght < MINIMUM_NUMBER_OF_MESSAGES_TO_EVALUATE { + return None; + } // Filter chats that have less that specified ammount of talks with support agent form the last queue transfer - let found = talk_histories.as_array().expect("Wrong message type received from talk histories").into_iter().enumerate().find(|(pos, message_object)|{ - let message = message_object["message"].as_str().expect("Failed to decode message as string"); - let found = message.find("Atendimento transferido para a fila [NovaNet -> Atendimento -> Suporte]"); - found.is_some() - }); + let found = talk_histories + .as_array() + .expect("Wrong message type received from talk histories") + .into_iter() + .enumerate() + .find(|(pos, message_object)| { + let message = message_object["message"] + .as_str() + .expect("Failed to decode message as string"); + let found = message.find( + "Atendimento transferido para a fila [NovaNet -> Atendimento -> Suporte]", + ); + found.is_some() + }); match found { - None => {return None;}, + None => { + return None; + } Some(pos) => { let pos_found = pos.0; - if pos_found < MINIMUM_NUMBER_OF_MESSAGES_WITH_AGENT_TO_EVALUATE {return None;} + if pos_found < MINIMUM_NUMBER_OF_MESSAGES_WITH_AGENT_TO_EVALUATE { + return None; + } } }; // Filter Bot finished chats - if json["agent"]["user"]["name"].as_str().unwrap_or("unknown_user") == "PipeBot" {return None;} + if json["agent"]["user"]["name"] + .as_str() + .unwrap_or("unknown_user") + == "PipeBot" + { + return None; + } // Apply keyword based filtering - let filter_keywords_found = talk_histories.as_array().expect("Wrong message type received from talk histories").into_iter().any(|message_object|{ - let message = message_object["message"].as_str().expect("Failed to decode message as string"); - let found = filter_keywords.iter().any(|keyword|{message.to_uppercase().find(&keyword.to_uppercase()).is_some()}); - found - }); + let filter_keywords_found = talk_histories + .as_array() + .expect("Wrong message type received from talk histories") + .into_iter() + .any(|message_object| { + let message = message_object["message"] + .as_str() + .expect("Failed to decode message as string"); + let found = filter_keywords.iter().any(|keyword| { + message + .to_uppercase() + .find(&keyword.to_uppercase()) + .is_some() + }); + found + }); - if filter_keywords_found {return None;} + if filter_keywords_found { + return None; + } return Some(json); }); @@ -264,79 +322,122 @@ fn main() -> anyhow::Result<()> { // dbg!(&talk_histories); // talk_histories.as_array().unwrap().into_iter().enumerate().for_each(|(pos, message_obj)|{println!("{}: {}", pos, message_obj["message"])}); - + // 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 transferido para a fila [NovaNet -> Atendimento -> Suporte]"); - let found = message.find("Atendimento entregue da fila de espera para o agente"); - found.is_some() - }); + .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 transferido para a fila [NovaNet -> Atendimento -> Suporte]"); + let found = + message.find("Atendimento entregue da fila de espera para o agente"); + found.is_some() + }); // 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"); - - 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() - }) - .take(1).collect_vec(); - + let (pos, transfer_message) = + bot_transfer_message.expect("Failed to get the transfer bot message position"); + + 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() + }) + .take(1) + .collect_vec(); + 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_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 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 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()); + 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) - }).reduce(|acc, e|{format!("{}\n{}",acc,e)}) + format!( + "{};{};{};{};{}", + name, id, response_time, bot_transfer_date, user_response_date + ) + }) + .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().write(true).open(format!("./evaluations/{formatted_day_before}/response_time.csv")).expect("Failed to open response time file for write"); - response_time_file.write_all(format!("{header}\n{response_time}").as_bytes()).expect("Failed to write header to file"); + let mut response_time_file = std::fs::OpenOptions::new() + .write(true) + .open(format!( + "./evaluations/{formatted_day_before}/response_time.csv" + )) + .expect("Failed to open response time file for write"); + response_time_file + .write_all(format!("{header}\n{response_time}").as_bytes()) + .expect("Failed to write header to file"); - filtered_chats - .clone() - .skip(0) - .for_each(|result| { - let json = result.unwrap(); - let talk_histories = &json["talk_histories"]; - let data = &talk_histories["data"]; - - let talk = talk_histories.as_array().expect("Wrong message type received from talk histories").iter().rev().map(|message_object| - { + filtered_chats.clone().skip(0).for_each(|result| { + let json = result.unwrap(); + let talk_histories = &json["talk_histories"]; + let data = &talk_histories["data"]; - let new_json_filtered = format!( -"{{ + let talk = talk_histories + .as_array() + .expect("Wrong message type received from talk histories") + .iter() + .rev() + .map(|message_object| { + let new_json_filtered = format!( + "{{ message: {}, sent_at: {}, type: {}, @@ -349,44 +450,71 @@ fn main() -> anyhow::Result<()> { ); // println!("{}", new_json_filtered); new_json_filtered - }).reduce(|acc, e| {format!("{acc}\n{e}")}).expect("Error extracting talk"); + }) + .reduce(|acc, e| format!("{acc}\n{e}")) + .expect("Error extracting talk"); - println!("{prompt}\n {talk}"); + println!("{prompt}\n {talk}"); - let ollama_api_request = client.post(format!("http://{OLLAMA_SANITIZED_IP}:{OLLAMA_PORT}/api/generate")) - .body( - serde_json::json!({ - "model": OLLAMA_AI_MODEL, - "prompt": format!("{prompt} \n{talk}"), - // "options": serde_json::json!({"temperature": 0.1}), - "stream": false, - }).to_string() - ); + let ollama_api_request = client + .post(format!( + "http://{OLLAMA_SANITIZED_IP}:{OLLAMA_PORT}/api/generate" + )) + .body( + serde_json::json!({ + "model": OLLAMA_AI_MODEL, + "prompt": format!("{prompt} \n{talk}"), + // "options": serde_json::json!({"temperature": 0.1}), + "stream": false, + }) + .to_string(), + ); - let result = ollama_api_request.timeout(Duration::from_secs(3600)).send(); + let result = ollama_api_request.timeout(Duration::from_secs(3600)).send(); - match result { - Ok(response) => {println!("Response: {:?}", response); - let response_json = response.json::().expect("Failed to deserialize response to JSON"); - println!("{}", response_json); - let ai_response = response_json["response"] - .as_str() - .expect("Failed to get AI response as string"); - println!("AI Response: {}", ai_response); + match result { + Ok(response) => { + println!("Response: {:?}", response); + let response_json = response + .json::() + .expect("Failed to deserialize response to JSON"); + println!("{}", response_json); + let ai_response = response_json["response"] + .as_str() + .expect("Failed to get AI response as string"); + println!("AI Response: {}", ai_response); - let csv_response = ai_response.replace("```csv\n", "").replace("```", ""); + let csv_response = ai_response.replace("```csv\n", "").replace("```", ""); - // Save the CSV response to a file + // Save the CSV response to a file - let user_name = &json["agent"]["user"]["name"].as_str().unwrap_or("unknown_user"); - let talk_id = &json["id"].as_u64().unwrap_or(0); - 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), csv_response).expect("Unable to write file"); - std::fs::write(format!("./evaluations/{}/{} - {} - {} - prompt.txt", formatted_day_before, user_name, talk_id, tracking_number), format!("{prompt} \n{talk}")).expect("Unable to write file"); - }, - Err(error) => {println!("Error {error}");} - }; - }); + let user_name = &json["agent"]["user"]["name"] + .as_str() + .unwrap_or("unknown_user"); + let talk_id = &json["id"].as_u64().unwrap_or(0); + 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 + ), + csv_response, + ) + .expect("Unable to write file"); + std::fs::write( + format!( + "./evaluations/{}/{} - {} - {} - prompt.txt", + formatted_day_before, user_name, talk_id, tracking_number + ), + format!("{prompt} \n{talk}"), + ) + .expect("Unable to write file"); + } + Err(error) => { + println!("Error {error}"); + } + }; + }); // Compress folder into zip let source_dir_str = format!("./evaluations/{formatted_day_before}"); @@ -409,7 +537,13 @@ fn main() -> anyhow::Result<()> { return Ok(()); } -fn get_piperun_chats_on_date(PIPERUN_API_URL: &String, client: &reqwest::blocking::Client, access_token: &String, formatted_day_before_at_midnight: String, formatted_day_before_at_23_59_59: String) -> Vec { +fn get_piperun_chats_on_date( + PIPERUN_API_URL: &String, + client: &reqwest::blocking::Client, + access_token: &String, + formatted_day_before_at_midnight: String, + formatted_day_before_at_23_59_59: String, +) -> Vec { let start_of_talk_code: String = "talk_start".to_string(); let support_queue_id: String = "13".to_string(); @@ -454,59 +588,74 @@ fn get_piperun_chats_on_date(PIPERUN_API_URL: &String, client: &reqwest::blockin } }; - let mut aggregated_talks = json_response["data"].as_array().expect("Failed to parse messages as array").to_owned(); + let mut aggregated_talks = json_response["data"] + .as_array() + .expect("Failed to parse messages as array") + .to_owned(); - let current_page = json_response["current_page"].as_i64().expect("Failed to obtain current page number"); - let last_page = json_response["last_page"].as_i64().expect("Failed to obtain current page number"); - - if current_page == last_page { return aggregated_talks; } - - let mut all_other_messages = (current_page..last_page).into_iter() - .map(|page| { - let page_to_request = page + 1; - let talks_request = client - .get(format!("https://{}/api/v2/reports/talks", PIPERUN_API_URL)) - .bearer_auth(access_token) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .query(&[ - ("page", page_to_request.to_string()), - ("perPage", per_page.clone()), - ("report_type", report_type.clone()), - ("start_date", formatted_day_before_at_midnight.clone()), - ("end_date", formatted_day_before_at_23_59_59.clone()), - ("date_range_type", start_of_talk_code.clone()), - ("queue_id[]", support_queue_id.clone()), - ]); - - println!("Sending request for consolidated talks... {talks_request:?}"); - let talks_response = talks_request.send(); - - let json_response = match talks_response { - Ok(resp) => { - if resp.status().is_success() { - let json: serde_json::Value = resp.json().unwrap(); - json - } else { - eprintln!("Failed to get consolidated talks: {}", resp.status()); - let json: serde_json::Value = resp.json().unwrap(); - eprintln!("Response body: {:?}", json); - panic!("Failed to retrieve consolidated talks from Piperun API"); - } - } - Err(e) => { - eprintln!("Error: {e}"); - panic!("Failed to send the request for talks to PipeRUN API"); - } - }; - - let aggregated_talks = json_response["data"].as_array().expect("Failed to parse messages as array").to_owned(); + let current_page = json_response["current_page"] + .as_i64() + .expect("Failed to obtain current page number"); + let last_page = json_response["last_page"] + .as_i64() + .expect("Failed to obtain current page number"); + if current_page == last_page { return aggregated_talks; - }) - .reduce(|mut this, mut acc| {acc.append(&mut this); acc}) - .expect("Failed to concatenate all vectors of messages"); + } + let mut all_other_messages = (current_page..last_page) + .into_iter() + .map(|page| { + let page_to_request = page + 1; + let talks_request = client + .get(format!("https://{}/api/v2/reports/talks", PIPERUN_API_URL)) + .bearer_auth(access_token) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .query(&[ + ("page", page_to_request.to_string()), + ("perPage", per_page.clone()), + ("report_type", report_type.clone()), + ("start_date", formatted_day_before_at_midnight.clone()), + ("end_date", formatted_day_before_at_23_59_59.clone()), + ("date_range_type", start_of_talk_code.clone()), + ("queue_id[]", support_queue_id.clone()), + ]); + + println!("Sending request for consolidated talks... {talks_request:?}"); + let talks_response = talks_request.send(); + + let json_response = match talks_response { + Ok(resp) => { + if resp.status().is_success() { + let json: serde_json::Value = resp.json().unwrap(); + json + } else { + eprintln!("Failed to get consolidated talks: {}", resp.status()); + let json: serde_json::Value = resp.json().unwrap(); + eprintln!("Response body: {:?}", json); + panic!("Failed to retrieve consolidated talks from Piperun API"); + } + } + Err(e) => { + eprintln!("Error: {e}"); + panic!("Failed to send the request for talks to PipeRUN API"); + } + }; + + let aggregated_talks = json_response["data"] + .as_array() + .expect("Failed to parse messages as array") + .to_owned(); + + return aggregated_talks; + }) + .reduce(|mut this, mut acc| { + acc.append(&mut this); + acc + }) + .expect("Failed to concatenate all vectors of messages"); aggregated_talks.append(&mut all_other_messages); aggregated_talks @@ -597,7 +746,7 @@ fn send_email( let filebody = std::fs::read(zip_file_name).unwrap(); let content_type = ContentType::parse("application/zip").unwrap(); let attachment = Attachment::new(zip_file_name.to_string()).body(filebody, content_type); - let mailboxes : Mailboxes = to.parse().unwrap(); + let mailboxes: Mailboxes = to.parse().unwrap(); let to_header: message::header::To = mailboxes.into(); let email = Message::builder()