forked from jelson.rodrigues/piperun-bot
chore: extract filtering into filter_map instead of for_each
This commit is contained in:
30
PROMPT.txt
Normal file
30
PROMPT.txt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
SEGUINDO OS CRITÉRIOS QUE VÃO ESTAR ABAIXO, AVALIE ATENDIMENTOS DE SUPORTE PRESTADOS VIA CHAT.
|
||||||
|
|
||||||
|
01 (APRESENTAÇÃO) - O AGENTE DEVE SE APRESENTAR NO INÍCIO DO ATENDIMENTO.
|
||||||
|
|
||||||
|
02 (CONFIRMAÇÃO DE E-MAIL) - O AGENTE DEVE SOLICITAR OU CONFIRMAR O E-MAIL DO CLIENTE DURANTE A CONVERSA.
|
||||||
|
|
||||||
|
03 (PROTOCOLO) - O AGENTE DEVE INFORMOU O PROTOCOLO DE ATENDIMENTO DURANTE A CONVERSA.
|
||||||
|
|
||||||
|
04 (USO DO PORTUGUÊS) - O AGENTE DEVE UTILIZAR CORRETAMENTE O PORTUGUÊS. LEMBRANDO QUE SOMOS UMA EMPRESA REGIONAL, UTILIZAMOS UMA LINGUAGEM MAIS INFORMAL. NÃO ESTÁ ERRADO SE O AGENTE UTILIZAR 'TU', 'TEU', 'TUA'.
|
||||||
|
|
||||||
|
05 (PACIÊNCIA E EDUCAÇÃO) - O AGENTE DEVE SER PACIENTE E EDUCADO, UTILIZANDO O USO DE AGRADECIMENTOS, SAUDAÇÕES, PEDIDOS DE DESCULPAS E LINGUAGEM RESPEITOSA, COMO POR EXEMPLO 'COMO POSSO TE AJUDAR?', 'PERFEITO', 'VOU VERIFICAR, AGUARDE UM MOMENTO POR GENTILEZA', 'DESCULPE, MAS NÃO TE COMPREENDI', 'PODERIA EXPLICAR DE NOVO?', 'OBRIGADO PELAS INFORMAÇÕES'.
|
||||||
|
|
||||||
|
06 (DISPONIBILIDADE) - O AGENTE DEVE SE COLOCAR À DISPOSIÇÃO DO CLIENTE, DEIXANDO CLARO QUE A EMPRESA ESTÁ SEMPRE DISPONÍVEL PARA AJUDAR
|
||||||
|
----------
|
||||||
|
|
||||||
|
As mensagens do chat estão estruturadas no formato JSON com os campos:
|
||||||
|
- **message**: conteúdo da mensagem
|
||||||
|
- **sent_at**: horário de envio
|
||||||
|
- **type**: tipo da mensagem ('IN', 'OUT' ou 'SYSTEM'). As mensagens do agente são sempre do tipo 'OUT'.
|
||||||
|
- **user_name**: nome do usuário que enviou a mensagem. Não considere respostas do PipeBot como do agente
|
||||||
|
|
||||||
|
O fluxo de mensagens inica-se com o cliente interagindo com o BOT, e então a mensagem é transferida para o atendente.
|
||||||
|
|
||||||
|
Em cada categoria, atribua 0 quando o agente não tiver atendido o critétio e 1 caso tenha atendido.
|
||||||
|
|
||||||
|
A sua resposta deve ser uma apenas uma tabela CSV e nada mais, utilizando como separador o caracter ';' com as colunas: CATEGORIA;PONTOS;MOTIVO;EVIDENCIA onde cada linha contém a avaliação de um dos critérios acima.
|
||||||
|
|
||||||
|
Na saída CSV, na coluna categoria, utilize o nome correspondente ao invés do número
|
||||||
|
|
||||||
|
A seguir estão as mensagens do atendimento, em JSON, avalie e retorne apenas um CSV.
|
||||||
70
src/main.rs
70
src/main.rs
@@ -170,6 +170,9 @@ fn main() -> anyhow::Result<()> {
|
|||||||
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read system prompt
|
||||||
|
let prompt = std::fs::read_to_string("PROMPT.txt").unwrap();
|
||||||
|
|
||||||
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());
|
println!("Number of consolidated talks: {}", talks_array.len());
|
||||||
@@ -206,16 +209,14 @@ fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
return talk_id_get_result;
|
return talk_id_get_result;
|
||||||
})
|
})
|
||||||
.skip(0)
|
.filter_map_ok(|result| {
|
||||||
.take(15)
|
let json = result.json::<serde_json::Value>().expect("Failed to deserialize response to JSON").to_owned();
|
||||||
.for_each(|result| {
|
|
||||||
let json = result.unwrap().json::<serde_json::Value>().expect("Failed to deserialize response to JSON");
|
|
||||||
let talk_histories = &json["talk_histories"];
|
let talk_histories = &json["talk_histories"];
|
||||||
let data = &talk_histories["data"];
|
let data = &talk_histories["data"];
|
||||||
|
|
||||||
// Filter chats that have very few messages
|
// Filter chats that have very few messages
|
||||||
let talk_lenght = talk_histories.as_array().expect("Wrong message type received from talk histories").len();
|
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;}
|
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
|
// 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 found = talk_histories.as_array().expect("Wrong message type received from talk histories").into_iter().enumerate().find(|(pos, message_object)|{
|
||||||
@@ -225,10 +226,10 @@ fn main() -> anyhow::Result<()> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
match found {
|
match found {
|
||||||
None => {return;},
|
None => {return None;},
|
||||||
Some(pos) => {
|
Some(pos) => {
|
||||||
let pos_found = pos.0;
|
let pos_found = pos.0;
|
||||||
if pos_found < MINIMUM_NUMBER_OF_MESSAGES_WITH_AGENT_TO_EVALUATE {return;}
|
if pos_found < MINIMUM_NUMBER_OF_MESSAGES_WITH_AGENT_TO_EVALUATE {return None;}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -238,7 +239,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
.filter(|name| name.as_str().unwrap() != "PipeBot".to_string())
|
.filter(|name| name.as_str().unwrap() != "PipeBot".to_string())
|
||||||
.unique()
|
.unique()
|
||||||
.count();
|
.count();
|
||||||
if number_of_agents_except_pipebot > 1 {return;}
|
if number_of_agents_except_pipebot > 1 {return None;}
|
||||||
|
|
||||||
// Filter stop notification active
|
// Filter stop notification active
|
||||||
let found_stop_notification = talk_histories.as_array().expect("Wrong message type received from talk histories").into_iter().enumerate().find(|(pos, message_object)|{
|
let found_stop_notification = talk_histories.as_array().expect("Wrong message type received from talk histories").into_iter().enumerate().find(|(pos, message_object)|{
|
||||||
@@ -247,11 +248,20 @@ fn main() -> anyhow::Result<()> {
|
|||||||
found.is_some()
|
found.is_some()
|
||||||
});
|
});
|
||||||
|
|
||||||
if found_stop_notification.is_some() {return;}
|
if found_stop_notification.is_some() {return None;}
|
||||||
|
|
||||||
// Filter Bot finished chats
|
// Filter Bot finished chats
|
||||||
if json["agent"]["user"]["name"].as_str().unwrap_or("unknown_user") == "PipeBot" {return;}
|
if json["agent"]["user"]["name"].as_str().unwrap_or("unknown_user") == "PipeBot" {return None;}
|
||||||
|
|
||||||
|
return Some(json);
|
||||||
|
})
|
||||||
|
.skip(0)
|
||||||
|
.take(15)
|
||||||
|
.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|
|
let talk = talk_histories.as_array().expect("Wrong message type received from talk histories").iter().rev().map(|message_object|
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -271,47 +281,13 @@ fn main() -> anyhow::Result<()> {
|
|||||||
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");
|
||||||
|
|
||||||
let system =
|
println!("{prompt}\n {talk}");
|
||||||
"
|
|
||||||
SEGUINDO OS CRITÉRIOS QUE VÃO ESTAR ABAIXO, AVALIE ATENDIMENTOS DE SUPORTE PRESTADOS VIA CHAT.
|
|
||||||
|
|
||||||
01 (APRESENTAÇÃO) - O AGENTE DEVE SE APRESENTAR NO INÍCIO DO ATENDIMENTO.
|
|
||||||
|
|
||||||
02 (CONFIRMAÇÃO DE E-MAIL) - O AGENTE DEVE SOLICITAR OU CONFIRMAR O E-MAIL DO CLIENTE DURANTE A CONVERSA.
|
|
||||||
|
|
||||||
03 (PROTOCOLO) - O AGENTE DEVE INFORMOU O PROTOCOLO DE ATENDIMENTO DURANTE A CONVERSA.
|
|
||||||
|
|
||||||
04 (USO DO PORTUGUÊS) - O AGENTE DEVE UTILIZAR CORRETAMENTE O PORTUGUÊS. LEMBRANDO QUE SOMOS UMA EMPRESA REGIONAL, UTILIZAMOS UMA LINGUAGEM MAIS INFORMAL. NÃO ESTÁ ERRADO SE O AGENTE UTILIZAR 'TU', 'TEU', 'TUA'.
|
|
||||||
|
|
||||||
05 (PACIÊNCIA E EDUCAÇÃO) - O AGENTE DEVE SER PACIENTE E EDUCADO, UTILIZANDO O USO DE AGRADECIMENTOS, SAUDAÇÕES, PEDIDOS DE DESCULPAS E LINGUAGEM RESPEITOSA, COMO POR EXEMPLO 'COMO POSSO TE AJUDAR?', 'PERFEITO', 'VOU VERIFICAR, AGUARDE UM MOMENTO POR GENTILEZA', 'DESCULPE, MAS NÃO TE COMPREENDI', 'PODERIA EXPLICAR DE NOVO?', 'OBRIGADO PELAS INFORMAÇÕES'.
|
|
||||||
|
|
||||||
06 (DISPONIBILIDADE) - O AGENTE DEVE SE COLOCAR À DISPOSIÇÃO DO CLIENTE, DEIXANDO CLARO QUE A EMPRESA ESTÁ SEMPRE DISPONÍVEL PARA AJUDAR
|
|
||||||
----------
|
|
||||||
|
|
||||||
As mensagens do chat estão estruturadas no formato JSON com os campos:
|
|
||||||
- **message**: conteúdo da mensagem
|
|
||||||
- **sent_at**: horário de envio
|
|
||||||
- **type**: tipo da mensagem ('IN', 'OUT' ou 'SYSTEM'). As mensagens do agente são sempre do tipo 'OUT'.
|
|
||||||
- **user_name**: nome do usuário que enviou a mensagem. Não considere respostas do PipeBot como do agente
|
|
||||||
|
|
||||||
O fluxo de mensagens inica-se com o cliente interagindo com o BOT, e então a mensagem é transferida para o atendente.
|
|
||||||
|
|
||||||
Em cada categoria, atribua 0 quando o agente não tiver atendido o critétio e 1 caso tenha atendido.
|
|
||||||
|
|
||||||
A sua resposta deve ser uma apenas uma tabela CSV e nada mais, utilizando como separador o caracter ';' com as colunas: CATEGORIA;PONTOS;MOTIVO;EVIDENCIA onde cada linha contém a avaliação de um dos critérios acima.
|
|
||||||
|
|
||||||
Na saída CSV, na coluna categoria, utilize o nome correspondente ao invés do número
|
|
||||||
|
|
||||||
A seguir estão as mensagens do atendimento, em JSON, avalie e retorne apenas um CSV.
|
|
||||||
|
|
||||||
";
|
|
||||||
// println!("{system}\n {talk}");
|
|
||||||
|
|
||||||
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,
|
"model": OLLAMA_AI_MODEL,
|
||||||
"prompt": format!("{system} \n{talk}"),
|
"prompt": format!("{prompt} \n{talk}"),
|
||||||
// "options": serde_json::json!({"temperature": 0.1}),
|
// "options": serde_json::json!({"temperature": 0.1}),
|
||||||
"stream": false,
|
"stream": false,
|
||||||
}).to_string()
|
}).to_string()
|
||||||
@@ -336,7 +312,7 @@ A seguir estão as mensagens do atendimento, em JSON, avalie e retorne apenas um
|
|||||||
let talk_id = &json["id"].as_u64().unwrap_or(0);
|
let talk_id = &json["id"].as_u64().unwrap_or(0);
|
||||||
let tracking_number = &json["tracking_number"].as_str().unwrap_or("");
|
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/{}/{} - {} - {}.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!("{system} \n{talk}")).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}");}
|
Err(error) => {println!("Error {error}");}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user