Compare commits

..

4 Commits

5 changed files with 220 additions and 15 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@ src/.env
.env
log/
.zip
.vscode/
evaluations
# Added by cargo
#

31
Cargo.lock generated
View File

@@ -581,6 +581,27 @@ dependencies = [
"typenum",
]
[[package]]
name = "csv"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde_core",
]
[[package]]
name = "csv-core"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
dependencies = [
"memchr",
]
[[package]]
name = "debug_unsafe"
version = "0.1.3"
@@ -1381,9 +1402,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lettre"
version = "0.11.18"
version = "0.11.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cb54db6ff7a89efac87dba5baeac57bb9ccd726b49a9b6f21fb92b3966aaf56"
checksum = "9e13e10e8818f8b2a60f52cb127041d388b89f3a96a62be9ceaffa22262fef7f"
dependencies = [
"base64",
"chumsky",
@@ -1836,6 +1857,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"csv",
"dotenv",
"http",
"ipaddress",
@@ -1844,6 +1866,7 @@ dependencies = [
"polars",
"regex",
"reqwest",
"serde",
"serde_json",
"walkdir",
"zip",
@@ -4061,9 +4084,9 @@ dependencies = [
[[package]]
name = "zip"
version = "5.1.1"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f852905151ac8d4d06fdca66520a661c09730a74c6d4e2b0f27b436b382e532"
checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b"
dependencies = [
"aes",
"arbitrary",

View File

@@ -19,9 +19,11 @@ reqwest = { version = "0.12.23", features = ["json", "cookies", "blocking"] }
chrono = { version = "0.4.42" }
itertools = {version = "0.14.0"}
ipaddress = {version = "0.1.3"}
zip = { version = "5.1.1"}
zip = { version = "6.0.0"}
walkdir = { version = "2.5.0"}
lettre = {version = "0.11.18", features = ["builder"]}
lettre = {version = "0.11.19", features = ["builder"]}
anyhow = { version = "1.0.100"}
polars = { version = "0.51.0" }
polars = { version = "0.51.0"}
serde = { version = "1.0.228" }
csv = {version = "1.4.0"}
regex = { version = "1.12.2" }

View File

@@ -1,8 +1,111 @@
Abaixo está a avaliação de um atendimento que foi realizado. Eu preciso que a formatação fique consistente e padronizada.
Padronize o arquivo CSV da seguinte forma, deixando apenas as colunas listadas.
Título: CATEGORIA;PONTOS
A sua resposta deve ser apenas o CSV com a formatação corrigida, nada mais deve ser incluído na sua resposta.
Se não for possível padronizar o arquivo de entrada de acordo com as instruções fornecidas a resposta deve ser vazia.
As categorias são: APRESENTAÇÃO, CONFIRMAÇÃO DE E-MAIL, CONFIRMAÇÃO DE TELEFONE, PROTOCOLO, USO DO PORTUGUÊS, PACIÊNCIA E EDUCAÇÃO, DISPONIBILIDADE, CONHECIMENTO TÉCNICO, DIDATISMO, ESCLARECIMENTO, TEMPO DE ESPERA
A coluna pontos deve ter apenas os valores 0 ou 1, se no arquivo de entrada estiver incorreto a resposta deve ser vazia.
A sua resposta deve ser apenas o CSV com a formatação corrigida, nada mais deve ser incluído na sua resposta, nem mesmo notas sobre a resposta.
Se não for possível padronizar o arquivo de entrada de acordo com as instruções fornecidas a resposta deve ser o CSV com o campo de pontuação vazio.
As categorias são: APRESENTAÇÃO, CONFIRMAÇÃO DE E-MAIL, CONFIRMAÇÃO DE TELEFONE, PROTOCOLO, USO DO PORTUGUÊS, PACIÊNCIA E EDUCAÇÃO, DISPONIBILIDADE, CONHECIMENTO TÉCNICO, DIDATISMO
A coluna pontos deve ter apenas os valores 0, 1 ou vazio, se no arquivo de entrada não houver a avaliação da categoria, a columa de pontos deve ser vazia.
Aqui estão alguns exemplos de formatação de como deve ser a sua resposta:
Exemplo 01:
Dado o seguinte arquivo de entrada:
APRESENTAÇÃO;1;O agente se apresentou ao cliente.;Boa noite, me chamo Ander.;Certo, um bom final de semana! 😊
CONFIRMAÇÃO DE E-MAIL;1;O agente pediu confirmação do e-mail.;Para manter o cadastro atualizado, poderia me confirmar se o e-mail continua sendo janainads.sls@gmail.com e se o telefone do titular do cadastro permanece (53) 98446-2208?;Obrigado pela confirmação.
CONFIRMAÇÃO DE TELEFONE;1;O agente pediu confirmação do telefone.;Para manter o cadastro atualizado, poderia me confirmar se o e-mail continua sendo janainads.sls@gmail.com e se o telefone do titular do cadastro permanece (53) 98446-2208?;Obrigado pela confirmação.
PROTOCOLO;1;O agente informou o protocolo.;Aqui está o protocolo do teu atendimento: 2510.3624;Boa noite, me chamo Ander.
USO DO PORTUGUÊS;1;O agente utilizou português correto.;Aqui está o protocolo do teu atendimento: 2510.3624;Para manter o cadastro atualizado, poderia me confirmar se o e-mail continua sendo janainads.sls@gmail.com e se o telefone do titular do cadastro permanece (53) 98446-2208?
PACIÊNCIA E EDUCAÇÃO;1;O agente foi paciente e educado.;Obrigado pela confirmação.;Certo, um bom final de semana! 😊
DISPONIBILIDADE;1;O agente demonstrou disponibilidade.;Caso tenha alguma dúvida, nos contate. A equipe da NovaNet está sempre aqui para te ajudar.😊;Certo, um bom final de semana! 😊
CONHECIMENTO TÉCNICO;1;O agente identificou que não havia problemas nos equipamentos.;Verifiquei aqui os equipamentos e não identifiquei nenhum problema com eles.;A potência recebida pelo equipamento está normal e as configurações do roteador estão todas corretas.
DIDATISMO;1;O agente foi didático ao orientar o cliente.;Certo, tu poderia se conectar na rede do primeiro roteador e verificar se ocorre algum problema?;Entendi, pode ser algum problema neste segundo roteador, tu pode estar reiniciando ele na tomada para caso seja algum travamento.
100%
A resposta sua deve ser:
```csv
CATEGORIA;PONTOS
APRESENTAÇÃO;1
CONFIRMAÇÃO DE E-MAIL;1
CONFIRMAÇÃO DE TELEFONE;1
PROTOCOLO;1
USO DO PORTUGUÊS;1
PACIÊNCIA E EDUCAÇÃO;1
DISPONIBILIDADE;1
CONHECIMENTO TÉCNICO;1
DIDATISMO;1
```
Exemplo 02:
Dado o seguinte arquivo de entrada:
01,1,Apresentação,"Boa tarde, me chamo Ander. (12:10:05)"
02,1,Confirmou email,"Para manter o cadastro atualizado, poderia me confirmar se o email continua sendo mmaicomvoss@gmail.com? (13:01:40)"
03,1,Confirmou telefone,"para manter o cadastro atualizado, poderia me confirmar se o telefone continua (53) 984143027? (13:01:40)"
04,1,Informa protocolo,"Aqui está o protocolo do teu atendimento: 2510.2749 (12:10:06)"
05,1,Uso correto do português,"Todas as mensagens foram escritas em português formal e correto, inclusive com 'tu' permitido. (12:10:0513:03:08)"
06,1,Uso de linguagem paciente e educada,"Aguarde meu retorno, por gentileza; me informe, por gentileza; obrigado pela confirmação. (12:10:1313:03:07)"
07,1,Disponibilidade expressa,"Caso tenha alguma dúvida, nos contate. A equipe da NovaNet está sempre aqui para te ajudar. (13:03:08)"
08,1,Conhecimento técnico,"Identificou mau contato no cabo, instruiu reconexões, avaliou ordem de serviço, cotou peças. (12:25:4412:57:10)"
09,1,Didático,"Desconecte o cabo LAN/WAN passo a passo e me informe quando terminar. (12:25:5612:26:06)"
10,1,Eclaração diagnóstica,"Fez diagnóstico de mau contato no cabo e ofereceu ordem de serviço sem custo. (12:55:1713:01:15)"
11,2,Tempo de espera excedido, 2 ocorrências,"Intervalos superiores a 5min: 12:55:1713:01:15 (5min58s) e 12:27:5112:54:11 (26min20s)"
A resposta sua deve ser:
```csv
CATEGORIA;PONTOS
APRESENTAÇÃO;1
CONFIRMAÇÃO DE E-MAIL;1
CONFIRMAÇÃO DE TELEFONE;1
PROTOCOLO;1
USO DO PORTUGUÊS;1
PACIÊNCIA E EDUCAÇÃO;1
DISPONIBILIDADE;1
CONHECIMENTO TÉCNICO;1
DIDATISMO;1
```
Exemplo 03:
Dado o seguinte arquivo de entrada:
Identificação e abertura do atendimento,1,
Confirmação de dados do cliente,1,
Verificação do histórico e do plano do cliente,1,
Análise e diagnóstico da falha na conectividade,1,
Verificação e teste de equipamentos,1,
Sugestão de solução de conectividade,1,
Escala de serviço,1,
Encerramento de atendimento,1,
Follow-up,1,
Comunicação com o cliente,1,
Tempo de Resposta,1
A sua resposta deve ser vazia neste caso, pois a entrada não fornece a pontuação adequada para os critérios.
Ou seja o retorno deve ser o seguinte
```csv
CATEGORIA;PONTOS
APRESENTAÇÃO;
CONFIRMAÇÃO DE E-MAIL;
CONFIRMAÇÃO DE TELEFONE;
PROTOCOLO;
USO DO PORTUGUÊS;
PACIÊNCIA E EDUCAÇÃO;
DISPONIBILIDADE;
CONHECIMENTO TÉCNICO;
DIDATISMO;
```
Aqui um exemplo de formatação de como não deve ser sua resposta
Erro 01: Não utilizar o formato estritamente como fornecido nas instruções e copiar da entrada que está sendo avaliada
```csv
CATEGORIA;PONTOS
APRESENTAÇÃO;1
Confirmação de e-mail;1
CONFIRMAÇÃO DE TELEFONE;1
PROTOCOLO;1
USO DO PORTUGUÊS;1
PACIÊNCIA E EDUCAÇÃO;1
DISPONIBILIDADE;1
CONHECIMENTO TÉCNICO;1
DIDATISMO;1
```
Abaixo está a avaliação que deve ser processada
--------------------------------

View File

@@ -2,12 +2,35 @@ use std::fmt::Debug;
use chrono::Datelike;
use itertools::Itertools;
use polars::prelude::buffer::validate_utf8;
use polars::prelude::*;
use reqwest;
use walkdir;
use std::time::Duration;
use std::env;
use csv;
#[derive(Debug, serde::Deserialize)]
struct CsvHeader {
CATEGORIA: String,
PONTOS: Option<u8>,
}
#[derive(Debug, serde::Deserialize)]
struct CsvEvaluation {
APRESENTAÇÃO: u8,
CONFIRMAÇÃO_DE_EMAIL: u8,
CONFIRMAÇÃO_DE_TELEFONE: u8,
PROTOCOLO: u8,
USO_DO_PORTUGUÊS: u8,
PACIÊNCIA_E_EDUCAÇÃO: u8,
DISPONIBILIDADE: u8,
CONHECIMENTO_TÉCNICO: u8,
DIDATISMO: u8,
ID_TALK: String
}
fn main() {
match dotenv::dotenv().ok() {
Some(_) => println!("Environment variables loaded from .env file"),
@@ -105,14 +128,15 @@ fn main() {
})
.take(1)
.map(|file_name_csv| {
println!("{:?}", file_name_csv.path());
let file_contents = std::fs::read_to_string(file_name_csv.path()).expect("Failed to read CSV file");
println!("{}", format!("{prompt_data_sanitization} \n{file_contents}"));
let ollama_api_request = client.post(format!("http://{OLLAMA_SANITIZED_IP}:{OLLAMA_PORT}/api/generate"))
.body(
serde_json::json!({
"model": OLLAMA_AI_MODEL_DATA_SANITIZATION,
"prompt": format!("{prompt_data_sanitization} \n{file_contents}"),
"temperature": 0.0, // Get predictable and reproducible output
"stream": false,
}).to_string()
);
@@ -125,13 +149,65 @@ fn main() {
let ai_response = response_json["response"]
.as_str()
.expect("Failed to get AI response as string");
println!("AI Response: {}", ai_response);
let ai_response = ai_response.to_string();
let ai_response = if let Some(resp) = ai_response.strip_prefix(" ").unwrap_or(&ai_response).strip_prefix("```csv\n") { resp.to_string() } else { ai_response };
let ai_response = if let Some(resp) = ai_response.strip_suffix(" ").unwrap_or(&ai_response).strip_suffix("```") { resp.to_string() } else { ai_response };
return Ok((ai_response, file_name_csv));
},
Err(error) => {println!("Error {error}");}
Err(error) => {println!("Error {error}"); return Err(error);}
};
})
.for_each(|value| println!("{:?}", value));
.filter_map_ok(|(ai_repsonse, file_path_csv)| {
let mut reader = csv::ReaderBuilder::new()
.has_headers(true)
.delimiter(b';')
.from_reader(ai_repsonse.as_bytes());
let mut deserialized_iter = reader.deserialize::<CsvHeader>();
let correctly_parsed = deserialized_iter.all(|value| {
value.is_ok() && value.unwrap().PONTOS.is_some()
});
if !correctly_parsed { return None; }
// Parse id talk from file_path
// filename example is: CC - Erraoander Quintana - 515578 - 20251020515578.csv
// id talk is the last information, so in the example is: 20251020515578
let regex_filename = regex::Regex::new(r"(CC - )((\w+\s*)+) - (\d+) - (\d+).csv").unwrap();
let filename = file_path_csv
.file_name()
.into_string()
.expect("Failed to convert file name as Rust &str");
let found_regex_groups_in_filename = regex_filename.captures(
filename.as_str()
).expect("Failed to do regex capture");
let talk_id = found_regex_groups_in_filename.get(5).expect("Failed to get the id from regex maches").clone();
println!("{:?}", talk_id);
// a.for_each(|val| { println!("{:?}", val)});
// println!("{:?}", a);
// Do validation on CSV parsed
// let records_parsed = reader.records();
// if records_parsed.try_len().expect("Failed to obtain lenght") != 9 { return None; }
// reader.records().for_each(|record| println!("{:?}", record));
return Some(());
})
.for_each(|_value| {});
// println!("{:?}", files_inside_folder_on_date);
return Some(());