Validado o funcionamento com .env dedicado para noc-cli e noc-corp

This commit is contained in:
2026-07-16 13:58:40 -03:00
parent 82267a01f7
commit 0092cb2e43
3 changed files with 229 additions and 186 deletions

View File

@@ -14,121 +14,6 @@ pub mod send_mail_util;
pub mod zip_directory_util;
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();
println!("Current date: {}", formatted_date);
// Get the day before the current date
let day_before = current_date
.checked_sub_signed(chrono::Duration::days(1))
.expect("Failed to get the day before");
let formatted_day_before = day_before.format("%Y-%m-%d").to_string();
println!("Day before: {}", formatted_day_before);
let day_before_at_midnight = day_before
.with_hour(0)
.unwrap()
.with_minute(0)
.unwrap()
.with_second(0)
.unwrap();
let formatted_day_before_at_midnight =
day_before_at_midnight.format("%Y-%m-%d %H:%M").to_string();
let day_before_at_23_59_59 = day_before
.with_hour(23)
.unwrap()
.with_minute(59)
.unwrap()
.with_second(59)
.unwrap();
let formatted_day_before_at_23_59_59 =
day_before_at_23_59_59.format("%Y-%m-%d %H:%M").to_string();
println!(
"Day before at midnight: {}, Day before at 23:59:59: {}",
formatted_day_before_at_midnight, formatted_day_before_at_23_59_59
);
let formatted_day_before = day_before_at_midnight.format("%Y-%m-%d").to_string();
// Create a folder named with the day_before
if !std::fs::exists(format!("./evaluations/evaluations_noc-cli/{formatted_day_before}")).unwrap() {
std::fs::create_dir(format!("./evaluations/evaluations_noc-cli/{formatted_day_before}"))
.expect("Failed to create directory")
}
// Create the response time folder
if !std::fs::exists(format!(
"./evaluations/evaluations_noc-cli/{formatted_day_before}/response_time.csv"
))
.unwrap()
{
let mut response_time_file = std::fs::File::create_new(format!(
"./evaluations/evaluations_noc-cli/{formatted_day_before}/response_time.csv"
))
.expect("Failed to response_time.csv");
}
/*
// --- NOVO: processar argumento de linha de comando para data específica ---
use std::env;
use chrono::NaiveDate;
let args: Vec<String> = env::args().collect();
//Primeiro argumento: data.
let target_day = if args.len() > 1 {
// Se um argumento foi passado, interpretar como YYYY-MM-DD
let naive_date = NaiveDate::parse_from_str(&args[1], "%Y-%m-%d")
.expect("Formato de data inválido. Use YYYY-MM-DD");
// Converter para DateTime com hora 00:00:00 do fuso local
naive_date.and_hms_opt(0, 0, 0).unwrap()
} else {
// Comportamento padrão: dia anterior ao atual
(chrono::Local::now() - chrono::Duration::days(1)).naive_local()
};
println!("Processando o dia: {}", target_day.format("%Y-%m-%d"));
// Definir início e fim do dia (para consultas na API)
let day_start = target_day; // já 00:00
let day_end = target_day
.with_hour(23).unwrap()
.with_minute(59).unwrap()
.with_second(59).unwrap();
let formatted_day = target_day.format("%Y-%m-%d").to_string();
let formatted_day_start = day_start.format("%Y-%m-%d %H:%M").to_string();
let formatted_day_end = day_end.format("%Y-%m-%d %H:%M").to_string();
println!("Início do dia: {}", formatted_day_start);
println!("Fim do dia: {}", formatted_day_end);
// Criar pasta com o nome do dia processado
if !std::fs::exists(format!("./evaluations/evaluations_noc-cli/{formatted_day}")).unwrap() {
std::fs::create_dir(format!("./evaluations/evaluations_noc-cli/{formatted_day}"))
.expect("Failed to create directory");
}
// Criar arquivo response_time.csv se não existir
if !std::fs::exists(format!("./evaluations/evaluations_noc-cli/{formatted_day}/response_time.csv")).unwrap() {
let _ = std::fs::File::create_new(format!(
"./evaluations/evaluations_noc-cli/{formatted_day}/response_time.csv"
))
.expect("Failed to create response_time.csv");
}
// Segundo argumento: arquivo .env
if args.len() > 2 {
let env_path = &args[2];
dotenv::from_path(env_path).expect("Falha ao carregar .env");
} else {
dotenv::dotenv().ok();
}
*/
// coleta os argumentos da linha de comando.
let args: Vec<String> = env::args().collect();
//Primeiro argumento: arquivo .env
@@ -178,8 +63,16 @@ fn main() -> anyhow::Result<()> {
.parse::<usize>()
.unwrap_or(12);
let BOT_EMAIL = env::var("BOT_EMAIL").expect("BOT_EMAIL has not been set!");
let BOT_EMAIL_PASSWORD =
env::var("BOT_EMAIL_PASSWORD").expect("BOT_EMAIL_PASSWORD has not been set!");
let BOT_EMAIL_PASSWORD = env::var("BOT_EMAIL_PASSWORD").expect("BOT_EMAIL_PASSWORD has not been set!");
let FILA_ID = env::var("FILA_ID").expect("FILA_ID has not been set!");
let PROMPT_X = env::var("PROMPT_X").expect("PROMPT_X has not been set!");
let FILTER_X = env::var("FILTER_X").expect("FILTER_X has not been set!");
let PASTA = env::var("PASTA").expect("PASTA has not been set!");
let NOME_FILA = env::var("NOME_FILA").expect("NOME_FILA has not been set!");
let INICIAL_AGENTE = env::var("INICIAL_AGENTE").expect("INICIAL_AGENTE has not been set!");
let EMAIL_1 = env::var("EMAIL_1").expect("EMAIL_1 has not been set!");
let EMAIL_2 = env::var("EMAIL_2").expect("EMAIL_2 has not been set!");
// let EMAIL_3 = env::var("EMAIL_3").expect("EMAIL_3 has not been set!");
// Print the configuration
println!("OLLAMA_URL: {}", OLLAMA_URL);
@@ -190,6 +83,127 @@ fn main() -> anyhow::Result<()> {
println!("PIPERUN_CLIENT_SECRET: {}", PIPERUN_CLIENT_SECRET);
println!("PIPERUN_BOT_USERNAME: {}", PIPERUN_BOT_USERNAME);
println!("PIPERUN_BOT_PASSWORD: {}", PIPERUN_BOT_PASSWORD);
println!("FILA_ID: {}", FILA_ID);
println!("NOME_FILA: {}", NOME_FILA);
println!("INICIAL_AGENTE: {}", INICIAL_AGENTE);
println!("PASTA: {}", PASTA);
println!("PROMPT_X: {}", PROMPT_X);
println!("FILTER_X: {}", FILTER_X);
// 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();
println!("Current date: {}", formatted_date);
// Get the day before the current date
let day_before = current_date
.checked_sub_signed(chrono::Duration::days(1))
.expect("Failed to get the day before");
let formatted_day_before = day_before.format("%Y-%m-%d").to_string();
println!("Day before: {}", formatted_day_before);
let day_before_at_midnight = day_before
.with_hour(0)
.unwrap()
.with_minute(0)
.unwrap()
.with_second(0)
.unwrap();
let formatted_day_before_at_midnight =
day_before_at_midnight.format("%Y-%m-%d %H:%M").to_string();
let day_before_at_23_59_59 = day_before
.with_hour(23)
.unwrap()
.with_minute(59)
.unwrap()
.with_second(59)
.unwrap();
let formatted_day_before_at_23_59_59 =
day_before_at_23_59_59.format("%Y-%m-%d %H:%M").to_string();
println!(
"Day before at midnight: {}, Day before at 23:59:59: {}",
formatted_day_before_at_midnight, formatted_day_before_at_23_59_59
);
let formatted_day_before = day_before_at_midnight.format("%Y-%m-%d").to_string();
// --- Criação de diretórios usando a variável PASTA ---
let pasta_base = format!("./evaluations/{}", PASTA);
let pasta_dia = format!("{}/{}", pasta_base, formatted_day_before);
if !std::fs::exists(&pasta_base).unwrap_or(false) {
std::fs::create_dir_all(&pasta_base)
.expect("Falha ao criar diretório base");
}
if !std::fs::exists(&pasta_dia).unwrap_or(false) {
std::fs::create_dir_all(&pasta_dia)
.expect("Falha ao criar diretório do dia");
}
let response_time_path = format!("{}/response_time.csv", pasta_dia);
if !std::fs::exists(&response_time_path).unwrap_or(false) {
let _ = std::fs::File::create_new(&response_time_path)
.expect("Falha ao criar response_time.csv");
}
/*
// --- NOVO: processar argumento de linha de comando para data específica ---
use std::env;
use chrono::NaiveDate;
let args: Vec<String> = env::args().collect();
//Primeiro argumento: data.
let target_day = if args.len() > 1 {
// Se um argumento foi passado, interpretar como YYYY-MM-DD
let naive_date = NaiveDate::parse_from_str(&args[1], "%Y-%m-%d")
.expect("Formato de data inválido. Use YYYY-MM-DD");
// Converter para DateTime com hora 00:00:00 do fuso local
naive_date.and_hms_opt(0, 0, 0).unwrap()
} else {
// Comportamento padrão: dia anterior ao atual
(chrono::Local::now() - chrono::Duration::days(1)).naive_local()
};
println!("Processando o dia: {}", target_day.format("%Y-%m-%d"));
// Definir início e fim do dia (para consultas na API)
let day_start = target_day; // já 00:00
let day_end = target_day
.with_hour(23).unwrap()
.with_minute(59).unwrap()
.with_second(59).unwrap();
let formatted_day = target_day.format("%Y-%m-%d").to_string();
let formatted_day_start = day_start.format("%Y-%m-%d %H:%M").to_string();
let formatted_day_end = day_end.format("%Y-%m-%d %H:%M").to_string();
println!("Início do dia: {}", formatted_day_start);
println!("Fim do dia: {}", formatted_day_end);
// Criar pasta com o nome do dia processado
if !std::fs::exists(format!("./evaluations/evaluations_noc-cli/{formatted_day}")).unwrap() {
std::fs::create_dir(format!("./evaluations/evaluations_noc-cli/{formatted_day}"))
.expect("Failed to create directory");
}
// Criar arquivo response_time.csv se não existir
if !std::fs::exists(format!("./evaluations/evaluations_noc-cli/{formatted_day}/response_time.csv")).unwrap() {
let _ = std::fs::File::create_new(format!(
"./evaluations/evaluations_noc-cli/{formatted_day}/response_time.csv"
))
.expect("Failed to create response_time.csv");
}
// Segundo argumento: arquivo .env
if args.len() > 2 {
let env_path = &args[2];
dotenv::from_path(env_path).expect("Falha ao carregar .env");
} else {
dotenv::dotenv().ok();
}
*/
let ip_address = ipaddress::IPAddress::parse(OLLAMA_URL.to_string());
let OLLAMA_SANITIZED_IP = match ip_address {
@@ -257,8 +271,10 @@ fn main() -> anyhow::Result<()> {
};
// Read system prompt
let prompt = std::fs::read_to_string("./prompts/PROMPT_NOC-CLI.txt").unwrap();
let filter_file_contents = std::fs::read_to_string("./filters/FILTER_NOC-CLI.txt").unwrap_or(String::new());
let prompt_path = format!("./prompts/{}",PROMPT_X);
let prompt = std::fs::read_to_string(&prompt_path).unwrap_or_else(|_| panic!("Falha ao ler {}.", &prompt_path));
let filter_path = format!("./filters/{}",FILTER_X);
let filter_file_contents = std::fs::read_to_string(&filter_path).unwrap_or_default();
let filter_keywords = filter_file_contents
.split("\n")
.filter(|keyword| !keyword.is_empty())
@@ -272,6 +288,7 @@ fn main() -> anyhow::Result<()> {
//formatted_day_start,
formatted_day_before_at_23_59_59,
//formatted_day_end,
&FILA_ID,
);
println!("Number of consolidated talks: {}", talks_array.len());
@@ -339,10 +356,8 @@ fn main() -> anyhow::Result<()> {
let template_id = message_object["is_template"]
.as_bool()
.unwrap_or(true);
let found = message.find(
"Atendimento transferido para a fila [NovaNet -> Atendimento -> NOC - Clientes]",
);
let mt_fila = format!("Atendimento transferido para a fila [NovaNet -> Atendimento -> {}]", NOME_FILA);
let found = message.find(&mt_fila );
found.is_some() || template_id
});
@@ -408,6 +423,7 @@ fn main() -> anyhow::Result<()> {
let response_time = filtered_chats
.clone()
.map(|messages| {
let mt_agente = format!("Atendimento entregue da fila de espera para o agente [{}",INICIAL_AGENTE);
let json = messages.unwrap();
let talk_histories = &json["talk_histories"];
let histories = talk_histories.as_array()
@@ -418,8 +434,7 @@ fn main() -> anyhow::Result<()> {
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");
let is_transfer = user == "PipeBot" && message.contains(&mt_agente);
is_template || is_transfer
});
@@ -432,8 +447,7 @@ fn main() -> anyhow::Result<()> {
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")
user == "PipeBot" && message.contains(&mt_agente)
};
let (ref_pos, ref_msg) = if is_transfer_case {
@@ -455,8 +469,11 @@ fn main() -> anyhow::Result<()> {
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 -"))
if m["type"].as_str() == Some("out") &&
m["user"]["name"]
.as_str()
.map(|name| name.starts_with(&INICIAL_AGENTE))
.unwrap_or(false)
{
Some(m)
} else {
@@ -503,17 +520,15 @@ fn main() -> anyhow::Result<()> {
// Open file and write to it
let header = "NOME;ID_TALK;TEMPO DE RESPOSTA;TRANFERENCIA PELO BOT;PRIMEIRA RESPOSTA DO AGENTE";
let pasta_dia = format!("./evaluations/{}/{}", PASTA, formatted_day_before);
//let pasta_dia = format!("./evaluations/{}/{}", PASTA, formatted_day);
let mut response_time_file = std::fs::OpenOptions::new()
.write(true)
.open(format!(
"./evaluations/evaluations_noc-cli/{formatted_day_before}/response_time.csv"
//"./evaluations/evaluations_noc-cli{formatted_day}/response_time.csv"
))
.expect("Failed to open response time file for write");
.write(true)
.open(&response_time_path)
.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");
.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"];
@@ -524,6 +539,8 @@ fn main() -> anyhow::Result<()> {
.expect("Wrong message type received from talk histories")
.iter()
.rev()
.filter(|msg| msg["type"].as_str() == Some("out"))
/*
//filtro para escrever somente as mensagens out no .txt
.filter(|(message_object)| {
let message_type = message_object["type"]
@@ -532,6 +549,7 @@ fn main() -> anyhow::Result<()> {
message_type == "out".to_string()
})
//fim do filtro
*/
.map(|message_object| {
let new_json_filtered = format!(
"{{
@@ -588,51 +606,40 @@ fn main() -> anyhow::Result<()> {
.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/evaluations_noc-cli/{}/{} - {} - {}.csv",
formatted_day_before, user_name, talk_id, tracking_number
//formatted_day, user_name, talk_id, tracking_number
),
csv_response,
)
.expect("Unable to write file");
std::fs::write(
format!(
"./evaluations/evaluations_noc-cli/{}/{} - {} - {} - prompt.txt",
formatted_day_before, user_name, talk_id, tracking_number
//formatted_day, user_name, talk_id, tracking_number
),
format!("{prompt} \n{talk}"),
)
.expect("Unable to write file");
std::fs::write(
format!("{}/{} - {} - {}.csv", pasta_dia, user_name, talk_id, tracking_number),
csv_response,
)
.expect("Unable to write file");
std::fs::write(
format!("{}/{} - {} - {} - prompt.txt", pasta_dia, user_name, talk_id, tracking_number),
format!("{prompt} \n{talk}"),
)
.expect("Unable to write file");
}
Err(error) => {
println!("Error {error}");
}
};
});
let nome_fila_email = format!("{}", NOME_FILA);
// Compress folder into zip
let source_dir_str = format!("./evaluations/evaluations_noc-cli/{formatted_day_before}");
//let source_dir_str = format!("./evaluations/evaluations_noc-cli/{formatted_day}");
let output_zip_file_str = format!("./evaluations/evaluations_noc-cli/{formatted_day_before}.zip");
//let output_zip_file_str = format!("./evaluations/evaluations_noc-cli/{formatted_day}.zip");
let source_dir = std::path::Path::new(source_dir_str.as_str());
let output_zip_file = std::path::Path::new(output_zip_file_str.as_str());
zip_directory_util::zip_directory_util::zip_source_dir_to_dst_file(source_dir, output_zip_file);
let source_dir = std::path::Path::new(&pasta_dia);
let output_zip_file_str = format!("{}.zip", pasta_dia);
let output_zip_file = std::path::Path::new(&output_zip_file_str);
zip_directory_util::zip_directory_util::zip_source_dir_to_dst_file(source_dir, output_zip_file);
// Send folder to email
let recipients = "nicolas.borges@nova.net.br, wilson@nova.net.br";
println!("Trying to send email... Recipients {recipients}");
let recipients = format!("{}, {}", EMAIL_1, EMAIL_2);
//let recipients = "nicolas@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 NOC - Clientes do dia {formatted_day}"),
&format!("Avaliacao atendimentos da fila {} do dia {}", nome_fila_email, formatted_day_before),
//&format!("Avaliacao atendimentos da fila {} do dia {}", nome_fila_email, formatted_day),
&BOT_EMAIL,
&BOT_EMAIL_PASSWORD,
recipients,
&recipients,
&output_zip_file_str,
);
@@ -644,14 +651,11 @@ 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_start: String,
formatted_day_before_at_23_59_59: String,
//formatted_day_end: String,
formatted_day_start: String,
formatted_day_end: String,
fila_id: &String,
) -> Vec<serde_json::Value> {
let start_of_talk_code: String = "talk_start".to_string();
let support_queue_id: String = "19".to_string();
// API V2
let report_type = "consolidated".to_string();
let page = "1".to_string();
@@ -666,12 +670,10 @@ fn get_piperun_chats_on_date(
("page", page.clone()),
("perPage", per_page.clone()),
("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_end.clone()),
("start_date", formatted_day_start.clone()),
("end_date", formatted_day_end.clone()),
("date_range_type", start_of_talk_code.clone()),
("queue_id[]", support_queue_id.clone()),
("queue_id[]", fila_id.to_string()),
]);
println!("Sending request for consolidated talks... {talks_request:?}");
@@ -724,12 +726,10 @@ fn get_piperun_chats_on_date(
("page", page_to_request.to_string()),
("perPage", per_page.clone()),
("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_end.clone()),
("start_date", formatted_day_start.clone()),
("end_date", formatted_day_end.clone()),
("date_range_type", start_of_talk_code.clone()),
("queue_id[]", support_queue_id.clone()),
("queue_id[]", fila_id.to_string()),
]);
println!("Sending request for consolidated talks... {talks_request:?}");