Compare commits
4 Commits
7fb6021e64
...
ca406b4601
| Author | SHA1 | Date | |
|---|---|---|---|
| ca406b4601 | |||
| 197642727c | |||
| 99a4c81a58 | |||
| 178219c4df |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@ src/.env
|
|||||||
.env
|
.env
|
||||||
log/
|
log/
|
||||||
.zip
|
.zip
|
||||||
|
.vscode/
|
||||||
evaluations
|
evaluations
|
||||||
# Added by cargo
|
# Added by cargo
|
||||||
#
|
#
|
||||||
|
|||||||
31
Cargo.lock
generated
31
Cargo.lock
generated
@@ -581,6 +581,27 @@ dependencies = [
|
|||||||
"typenum",
|
"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]]
|
[[package]]
|
||||||
name = "debug_unsafe"
|
name = "debug_unsafe"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@@ -1381,9 +1402,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lettre"
|
name = "lettre"
|
||||||
version = "0.11.18"
|
version = "0.11.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5cb54db6ff7a89efac87dba5baeac57bb9ccd726b49a9b6f21fb92b3966aaf56"
|
checksum = "9e13e10e8818f8b2a60f52cb127041d388b89f3a96a62be9ceaffa22262fef7f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"chumsky",
|
"chumsky",
|
||||||
@@ -1836,6 +1857,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"csv",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"http",
|
"http",
|
||||||
"ipaddress",
|
"ipaddress",
|
||||||
@@ -1844,6 +1866,7 @@ dependencies = [
|
|||||||
"polars",
|
"polars",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"zip",
|
"zip",
|
||||||
@@ -4061,9 +4084,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zip"
|
name = "zip"
|
||||||
version = "5.1.1"
|
version = "6.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f852905151ac8d4d06fdca66520a661c09730a74c6d4e2b0f27b436b382e532"
|
checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"arbitrary",
|
"arbitrary",
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ reqwest = { version = "0.12.23", features = ["json", "cookies", "blocking"] }
|
|||||||
chrono = { version = "0.4.42" }
|
chrono = { version = "0.4.42" }
|
||||||
itertools = {version = "0.14.0"}
|
itertools = {version = "0.14.0"}
|
||||||
ipaddress = {version = "0.1.3"}
|
ipaddress = {version = "0.1.3"}
|
||||||
zip = { version = "5.1.1"}
|
zip = { version = "6.0.0"}
|
||||||
walkdir = { version = "2.5.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"}
|
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" }
|
regex = { version = "1.12.2" }
|
||||||
@@ -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.
|
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.
|
Padronize o arquivo CSV da seguinte forma, deixando apenas as colunas listadas.
|
||||||
Título: CATEGORIA;PONTOS
|
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.
|
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 vazia.
|
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, ESCLARECIMENTO, TEMPO DE ESPERA
|
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 ou 1, se no arquivo de entrada estiver incorreto a resposta deve ser vazia.
|
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 e‑mail,"Para manter o cadastro atualizado, poderia me confirmar se o e‑mail 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) 98414‑3027? (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:05‑13: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:13‑13: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:44‑12:57:10)"
|
||||||
|
09,1,Didático,"Desconecte o cabo LAN/WAN passo a passo e me informe quando terminar. (12:25:56‑12: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:17‑13:01:15)"
|
||||||
|
11,2,Tempo de espera excedido, 2 ocorrências,"Intervalos superiores a 5 min: 12:55:17‑13:01:15 (5 min 58 s) e 12:27:51‑12:54:11 (26 min 20 s)"
|
||||||
|
|
||||||
|
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
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|||||||
@@ -2,12 +2,35 @@ use std::fmt::Debug;
|
|||||||
|
|
||||||
use chrono::Datelike;
|
use chrono::Datelike;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use polars::prelude::buffer::validate_utf8;
|
||||||
use polars::prelude::*;
|
use polars::prelude::*;
|
||||||
use reqwest;
|
use reqwest;
|
||||||
use walkdir;
|
use walkdir;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::env;
|
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() {
|
fn main() {
|
||||||
match dotenv::dotenv().ok() {
|
match dotenv::dotenv().ok() {
|
||||||
Some(_) => println!("Environment variables loaded from .env file"),
|
Some(_) => println!("Environment variables loaded from .env file"),
|
||||||
@@ -105,14 +128,15 @@ fn main() {
|
|||||||
})
|
})
|
||||||
.take(1)
|
.take(1)
|
||||||
.map(|file_name_csv| {
|
.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");
|
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"))
|
let ollama_api_request = client.post(format!("http://{OLLAMA_SANITIZED_IP}:{OLLAMA_PORT}/api/generate"))
|
||||||
.body(
|
.body(
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"model": OLLAMA_AI_MODEL_DATA_SANITIZATION,
|
"model": OLLAMA_AI_MODEL_DATA_SANITIZATION,
|
||||||
"prompt": format!("{prompt_data_sanitization} \n{file_contents}"),
|
"prompt": format!("{prompt_data_sanitization} \n{file_contents}"),
|
||||||
|
"temperature": 0.0, // Get predictable and reproducible output
|
||||||
"stream": false,
|
"stream": false,
|
||||||
}).to_string()
|
}).to_string()
|
||||||
);
|
);
|
||||||
@@ -125,13 +149,65 @@ fn main() {
|
|||||||
let ai_response = response_json["response"]
|
let ai_response = response_json["response"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.expect("Failed to get AI response as string");
|
.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);
|
// println!("{:?}", files_inside_folder_on_date);
|
||||||
|
|
||||||
return Some(());
|
return Some(());
|
||||||
|
|||||||
Reference in New Issue
Block a user