Compare commits
No commits in common. "a23b4f1983f646282a0727428e18a13d790ec4ed" and "db119148cf601d84c4c9b21967cd89fdfe9e396e" have entirely different histories.
a23b4f1983
...
db119148cf
4 changed files with 2 additions and 326 deletions
17
AGENTS.md
17
AGENTS.md
|
|
@ -334,23 +334,6 @@ After UI interactions, validate backend state via `psql` or `tail` logs.
|
||||||
- **Error handling**: ALL error paths must have tests
|
- **Error handling**: ALL error paths must have tests
|
||||||
- **Security**: All security guards must have tests
|
- **Security**: All security guards must have tests
|
||||||
|
|
||||||
### WhatsApp Integration Testing
|
|
||||||
|
|
||||||
#### Prerequisites
|
|
||||||
1. **Enable WhatsApp Feature**: Build botserver with whatsapp feature enabled:
|
|
||||||
```bash
|
|
||||||
cargo build -p botserver --bin botserver --features whatsapp
|
|
||||||
```
|
|
||||||
2. **Bot Configuration**: Ensure the bot has WhatsApp credentials configured in `config.csv`:
|
|
||||||
- `whatsapp-api-key` - API key from Meta Business Suite
|
|
||||||
- `whatsapp-verify-token` - Custom token for webhook verification
|
|
||||||
- `whatsapp-phone-number-id` - Phone Number ID from Meta
|
|
||||||
- `whatsapp-business-account-id` - Business Account ID from Meta
|
|
||||||
|
|
||||||
#### Using Localtunnel (lt) as Reverse Proxy
|
|
||||||
|
|
||||||
# Check database for message storage
|
|
||||||
psql -h localhost -U postgres -d botserver -c "SELECT * FROM messages WHERE bot_id = '<bot_id>' ORDER BY created_at DESC LIMIT 5;"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🐛 Debugging Rules
|
## 🐛 Debugging Rules
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit c072fb936e9847aa03b90e35c752a1da9f8cf71b
|
Subproject commit 859db6b8a0b654d632de7b8fd16a66c50c1861d2
|
||||||
|
|
@ -14,7 +14,7 @@ cargo build -p botserver
|
||||||
cargo build -p botui
|
cargo build -p botui
|
||||||
|
|
||||||
echo "Starting botserver..."
|
echo "Starting botserver..."
|
||||||
RUST_LOG=debug ./target/debug/botserver --noconsole > botserver.log 2>&1 &
|
RUST_LOG=trace ./target/debug/botserver --noconsole > botserver.log 2>&1 &
|
||||||
echo " PID: $!"
|
echo " PID: $!"
|
||||||
|
|
||||||
echo "Starting botui..."
|
echo "Starting botui..."
|
||||||
|
|
|
||||||
307
zap.md
307
zap.md
|
|
@ -1,307 +0,0 @@
|
||||||
# WhatsApp - Bot Salesianos
|
|
||||||
|
|
||||||
## Status: Operacional
|
|
||||||
|
|
||||||
| Campo | Valor |
|
|
||||||
|-------|-------|
|
|
||||||
| Bot ID | `32c579e5-609b-4a07-8599-4e0fccc4d764` |
|
|
||||||
| Phone | +15558293147 |
|
|
||||||
| Phone ID | 323250907549153 |
|
|
||||||
| Business ID | 1261667644771701 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Comandos
|
|
||||||
|
|
||||||
- `/clear` - Limpa histórico da conversa
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Streaming
|
|
||||||
|
|
||||||
1. Mensagens sem lista: enviar a cada 3 parágrafos
|
|
||||||
2. Mensagens com lista: **ISOLAR como mensagem única** (sem texto antes ou depois)
|
|
||||||
3. Limite máximo: 4000 caracteres por mensagem
|
|
||||||
|
|
||||||
### Exemplo de Agrupamento Correto
|
|
||||||
|
|
||||||
**Resposta completa do bot:**
|
|
||||||
```
|
|
||||||
Olá! 😊
|
|
||||||
|
|
||||||
Infelizmente, não tenho a informação específica sobre o horário de funcionamento da Escola Salesiana no momento.
|
|
||||||
|
|
||||||
Para obter essa informação, você pode:
|
|
||||||
1. *Entrar em contato com a secretaria* - Posso te ajudar a enviar uma mensagem perguntando sobre os horários
|
|
||||||
2. *Agendar uma visita* - Assim você conhece a escola pessoalmente e obtém todas as informações necessárias
|
|
||||||
|
|
||||||
Gostaria que eu te ajudasse com alguma dessas opções? Se quiser entrar em contato com a secretaria, preciso apenas de:
|
|
||||||
- Seu nome
|
|
||||||
- Telefone
|
|
||||||
- Email
|
|
||||||
- Sua pergunta sobre os horários
|
|
||||||
|
|
||||||
Ou, se preferir, posso agendar uma visita para você conhecer a escola! 🏫
|
|
||||||
|
|
||||||
O que prefere?
|
|
||||||
```
|
|
||||||
|
|
||||||
**Deve ser enviado como 5 mensagens separadas:**
|
|
||||||
|
|
||||||
**Mensagem 1:**
|
|
||||||
```
|
|
||||||
Olá! 😊
|
|
||||||
|
|
||||||
Infelizmente, não tenho a informação específica sobre o horário de funcionamento da Escola Salesiana no momento.
|
|
||||||
|
|
||||||
Para obter essa informação, você pode:
|
|
||||||
```
|
|
||||||
|
|
||||||
**Mensagem 2 (LISTA ISOLADA):**
|
|
||||||
```
|
|
||||||
1. *Entrar em contato com a secretaria* - Posso te ajudar a enviar uma mensagem perguntando sobre os horários
|
|
||||||
2. *Agendar uma visita* - Assim você conhece a escola pessoalmente e obtém todas as informações necessárias
|
|
||||||
```
|
|
||||||
|
|
||||||
**Mensagem 3:**
|
|
||||||
```
|
|
||||||
Gostaria que eu te ajudasse com alguma dessas opções? Se quiser entrar em contato com a secretaria, preciso apenas de:
|
|
||||||
```
|
|
||||||
|
|
||||||
**Mensagem 4 (LISTA ISOLADA):**
|
|
||||||
```
|
|
||||||
- Seu nome
|
|
||||||
- Telefone
|
|
||||||
- Email
|
|
||||||
- Sua pergunta sobre os horários
|
|
||||||
```
|
|
||||||
|
|
||||||
**Mensagem 5:**
|
|
||||||
```
|
|
||||||
Ou, se preferir, posso agendar uma visita para você conhecer a escola! 🏫
|
|
||||||
|
|
||||||
O que prefere?
|
|
||||||
```
|
|
||||||
|
|
||||||
**Regras:**
|
|
||||||
- ✅ Cada lista = **1 mensagem ISOLADA** (nunca misturar com texto)
|
|
||||||
- ✅ Texto antes da lista = mensagem separada
|
|
||||||
- ✅ Texto depois da lista = mensagem separada
|
|
||||||
- ✅ Listas nunca são quebradas no meio
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testar Webhook (Simular Callback)
|
|
||||||
|
|
||||||
Script de teste em `/tmp/test_whatsapp.sh`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/bin/bash
|
|
||||||
# Testa o webhook do WhatsApp simulando uma mensagem
|
|
||||||
|
|
||||||
BOT_ID="32c579e5-609b-4a07-8599-4e0fccc4d764"
|
|
||||||
FROM="5521972102162" # Número de teste
|
|
||||||
|
|
||||||
curl -X POST "http://localhost:8080/webhook/whatsapp/${BOT_ID}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{
|
|
||||||
"object": "whatsapp_business_account",
|
|
||||||
"entry": [{
|
|
||||||
"id": "1261667644771701",
|
|
||||||
"changes": [{
|
|
||||||
"field": "messages",
|
|
||||||
"value": {
|
|
||||||
"messaging_product": "whatsapp",
|
|
||||||
"metadata": {
|
|
||||||
"display_phone_number": "15558293147",
|
|
||||||
"phone_number_id": "323250907549153"
|
|
||||||
},
|
|
||||||
"contacts": [{
|
|
||||||
"wa_id": "'${FROM}'",
|
|
||||||
"profile": { "name": "Teste Usuario" }
|
|
||||||
}],
|
|
||||||
"messages": [{
|
|
||||||
"id": "test_msg_'$(date +%s)'",
|
|
||||||
"from": "'${FROM}'",
|
|
||||||
"timestamp": "'$(date +%s)'",
|
|
||||||
"type": "text",
|
|
||||||
"text": { "body": "Olá, como posso ajudar?" }
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
Executar teste:
|
|
||||||
```bash
|
|
||||||
bash /tmp/test_whatsapp.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testar Comando /clear
|
|
||||||
|
|
||||||
```bash
|
|
||||||
BOT_ID="32c579e5-609b-4a07-8599-4e0fccc4d764"
|
|
||||||
FROM="5521972102162"
|
|
||||||
|
|
||||||
curl -X POST "http://localhost:8080/webhook/whatsapp/${BOT_ID}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{
|
|
||||||
"object": "whatsapp_business_account",
|
|
||||||
"entry": [{
|
|
||||||
"id": "1261667644771701",
|
|
||||||
"changes": [{
|
|
||||||
"field": "messages",
|
|
||||||
"value": {
|
|
||||||
"messaging_product": "whatsapp",
|
|
||||||
"metadata": {
|
|
||||||
"display_phone_number": "15558293147",
|
|
||||||
"phone_number_id": "323250907549153"
|
|
||||||
},
|
|
||||||
"contacts": [{
|
|
||||||
"wa_id": "'${FROM}'",
|
|
||||||
"profile": { "name": "Teste Usuario" }
|
|
||||||
}],
|
|
||||||
"messages": [{
|
|
||||||
"id": "test_clear_'$(date +%s)'",
|
|
||||||
"from": "'${FROM}'",
|
|
||||||
"timestamp": "'$(date +%s)'",
|
|
||||||
"type": "text",
|
|
||||||
"text": { "body": "/clear" }
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Debug
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Verificar servidor
|
|
||||||
curl http://localhost:8080/health
|
|
||||||
|
|
||||||
# Monitorar logs
|
|
||||||
tail -f botserver.log | grep -iE "(whatsapp|Embedding)"
|
|
||||||
|
|
||||||
# Verificar sessões ativas (requer acesso ao banco)
|
|
||||||
# SELECT * FROM user_sessions WHERE bot_id = '32c579e5-609b-4a07-8599-4e0fccc4d764';
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Arquivos Relacionados
|
|
||||||
|
|
||||||
- Config: `/opt/gbo/data/salesianos.gbai/salesianos.gbot/config.csv`
|
|
||||||
- Handler: `botserver/src/whatsapp/mod.rs`
|
|
||||||
- Adapter: `botserver/src/core/bot/channels/whatsapp.rs`
|
|
||||||
- Cache: `botserver/src/llm/cache.rs`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Pendências
|
|
||||||
|
|
||||||
1. ~~Filtrar caracteres Markdown inválidos no WhatsApp (###, **, etc)~~ ✅ **Concluído em 2025-03-08**
|
|
||||||
2. Configurar webhook na Meta Business Suite para produção
|
|
||||||
3. Configurar SSL/TLS no servidor de produção
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Histórico de Correções
|
|
||||||
|
|
||||||
### 2025-03-08: Sanitização de Markdown para WhatsApp
|
|
||||||
|
|
||||||
**Problema**: O WhatsApp não suporta Markdown completo (headers, links formatados, etc), causando exibição incorreta de mensagens.
|
|
||||||
|
|
||||||
**Solução**: Adicionada função `sanitize_for_whatsapp()` em `botserver/src/core/bot/channels/whatsapp.rs` que:
|
|
||||||
- Remove headers Markdown (###, ##, #)
|
|
||||||
- Converte links `[texto](url)` para `texto: url`
|
|
||||||
- Remove sintaxe de imagem ``
|
|
||||||
- Converte checkboxes `[ ]` e `[x]` para bullets
|
|
||||||
- Remove horizontal rules (`---`, `***`)
|
|
||||||
- Remove tags HTML
|
|
||||||
- Limpa linhas em branco excessivas
|
|
||||||
|
|
||||||
**Resultado**: Mensagens agora são exibidas corretamente no WhatsApp.
|
|
||||||
|
|
||||||
### 2025-03-08: Cache Semântico
|
|
||||||
|
|
||||||
**Problema**: O cache semântico estava enviando todo o histórico de conversa (10000+ chars) para o embedding, causando falsos positivos.
|
|
||||||
|
|
||||||
**Solução**: Modificado `botserver/src/llm/cache.rs` para extrair apenas a última pergunta do usuário do array de mensagens.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
// Antes (problemático):
|
|
||||||
let combined_context = format!("{}\n{}", prompt, actual_messages);
|
|
||||||
|
|
||||||
// Depois (corrigido):
|
|
||||||
let latest_user_question = msgs.iter().rev()
|
|
||||||
.find_map(|msg| {
|
|
||||||
if msg.get("role") == Some("user") {
|
|
||||||
msg.get("content").and_then(|c| c.as_str())
|
|
||||||
} else { None }
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
**Resultado**: Embedding agora usa apenas ~52 chars (pergunta do usuário) em vez de 10000+ chars.
|
|
||||||
|
|
||||||
### 2025-03-08: Correção de Streaming para Listas
|
|
||||||
|
|
||||||
**Problema**: Listas numeradas estavam sendo quebradas em múltiplas mensagens durante o streaming, mesmo quando cabiam em uma única mensagem de 4000 caracteres.
|
|
||||||
|
|
||||||
**Causa**: A detecção de lista era feita APÓS decidir fazer flush baseado em 3 parágrafos. Quando o streaming enviava chunks parciais, o código não detectava que uma lista estava começando.
|
|
||||||
|
|
||||||
**Solução**: Melhorada a lógica de detecção em `botserver/src/whatsapp/mod.rs`:
|
|
||||||
|
|
||||||
1. **Detecção mais precisa de listas numeradas**: Agora requer padrão `N.` ou `N)` seguido de espaço (ex: "1. Item", "10) Item")
|
|
||||||
2. **Detecção de início de lista**: Nova função `looks_like_list_start()` detecta quando o buffer parece estar começando uma lista (header terminando em `:` ou número no início)
|
|
||||||
3. **Logs detalhados**: Adicionado logging para debug de streaming
|
|
||||||
|
|
||||||
**Resultado**: Listas agora são acumuladas corretamente e enviadas em uma única mensagem quando possível.
|
|
||||||
|
|
||||||
### 2025-03-08: Detecção de Fim de Lista no Streaming
|
|
||||||
|
|
||||||
**Problema**: Listas estavam sendo enviadas como mensagens únicas apenas quando o streaming terminava (`is_final`), mesmo que a lista já tivesse terminado. Isso causava atrasos na entrega de mensagens quando havia conteúdo após a lista.
|
|
||||||
|
|
||||||
**Causa**: Uma vez que uma lista era detectada (`has_list = true`), o código esperava até `is_final` ou `buffer.len() >= MAX_WHATSAPP_LENGTH` para fazer flush. Não havia detecção de quando a lista terminava.
|
|
||||||
|
|
||||||
**Solução**:
|
|
||||||
- Adicionada função `looks_like_list_end()` em `botserver/src/whatsapp/mod.rs` que detecta quando uma lista terminou (verifica se as últimas 2 linhas não-brancas não são itens de lista)
|
|
||||||
- Modificada a lógica de streaming para fazer flush quando `list_ended = true`
|
|
||||||
- Adicionados testes unitários para validar o novo comportamento
|
|
||||||
|
|
||||||
**Resultado**: Listas agora são enviadas assim que terminam, sem esperar o streaming completar. Conteúdo após a lista é entregue prontamente, melhorando a experiência do usuário.
|
|
||||||
|
|
||||||
### 2025-03-08: Isolamento de Listas como Mensagens Únicas
|
|
||||||
|
|
||||||
**Problema**: Listas estavam sendo enviadas misturadas com texto antes e depois, em vez de serem isoladas como mensagens únicas. Por exemplo, "Texto introdutório\n1. Item\n2. Item\nTexto final" era enviado como uma única mensagem, quando deveria ser 3 mensagens separadas.
|
|
||||||
|
|
||||||
**Causa**: A lógica de streaming acumulava todo o buffer quando detectava uma lista, sem separar o texto antes/depois da lista. O buffer era enviado como um bloco único.
|
|
||||||
|
|
||||||
**Solução**: Implementado isolamento de listas em `botserver/src/whatsapp/mod.rs`:
|
|
||||||
- Adicionada função `split_text_before_list()` para separar texto antes da lista
|
|
||||||
- Adicionada função `split_list_from_text()` para separar lista do texto depois
|
|
||||||
- Modificada lógica de streaming para:
|
|
||||||
1. Detectar quando lista termina (`list_ended = true`)
|
|
||||||
2. Separar texto ANTES da lista e enviar como mensagem
|
|
||||||
3. Separar lista e enviar como mensagem ISOLADA
|
|
||||||
4. Manter texto DEPOIS no buffer para próxima mensagem
|
|
||||||
|
|
||||||
**Resultado**: Listas agora são enviadas como mensagens ISOLADAS, sem misturar com texto antes ou depois. Cada lista = 1 mensagem separada, melhorando a legibilidade e experiência do usuário no WhatsApp.
|
|
||||||
|
|
||||||
### 2025-03-08: Remoção de Blocos de Código JavaScript
|
|
||||||
|
|
||||||
**Problema**: Código de programação (JavaScript, C#, etc.) estava vazando nas mensagens do WhatsApp. Exemplos como `var telefoneDigits = new string(args.Phone.Where(char.IsDigit).ToArray());` eram enviados para os usuários, quando deveriam ser removidos.
|
|
||||||
|
|
||||||
**Causa**: A função `sanitize_for_whatsapp()` em `botserver/src/core/bot/channels/whatsapp.rs` removia Markdown e HTML, mas não removia blocos de código cercados por crases (backticks).
|
|
||||||
|
|
||||||
**Solução**: Adicionados padrões regex à função `sanitize_for_whatsapp()`:
|
|
||||||
- Remove blocos de código com crases triplas: ```code```
|
|
||||||
- Remove código inline com crase simples: `code`
|
|
||||||
- Limpa código de programação antes de enviar para WhatsApp
|
|
||||||
|
|
||||||
**Resultado**: Mensagens do WhatsApp agora estão livres de código de programação, exibindo apenas texto legível para o usuário. Código JavaScript, C#, e outras linguagens são automaticamente removidos durante a sanitização.
|
|
||||||
Loading…
Add table
Reference in a new issue