anderson-ufrj commited on
Commit
0c5f570
·
1 Parent(s): 1edd4d6

refactor: organize project structure and remove sensitive files

Browse files

- Remove all sensitive documentation from repository
- Move internal docs to protected directories
- Update .gitignore to exclude docs/internal/
- Organize test files into proper directories
- Clean up debug scripts and backup files
- Fix DataSourceType.BIDDINGS enum in chat.py
- Maintain clean repository structure

.gitignore CHANGED
@@ -235,6 +235,7 @@ prometheus_data/
235
 
236
  # Internal documentation - IGNORE FROM REPOSITORY
237
  docs-internal/
 
238
 
239
  # Claude Code artifacts
240
  .claude/
 
235
 
236
  # Internal documentation - IGNORE FROM REPOSITORY
237
  docs-internal/
238
+ docs/internal/
239
 
240
  # Claude Code artifacts
241
  .claude/
CODEBASE_ANALYSIS_REPORT.md DELETED
@@ -1,330 +0,0 @@
1
- # Relatório de Análise Completa - Cidadão.AI Backend
2
-
3
- **Autor**: Anderson Henrique da Silva
4
- **Data de Criação**: 2025-09-20 08:45:00 -03 (São Paulo, Brasil)
5
- **Versão do Sistema**: 2.2.0
6
-
7
- ## Sumário Executivo
8
-
9
- O Cidadão.AI Backend é uma plataforma de IA multi-agente de nível empresarial para análise de transparência governamental brasileira. O sistema demonstra arquitetura sofisticada com 17 agentes especializados (8 operacionais), integração com Portal da Transparência, detecção avançada de anomalias usando ML/análise espectral, e infraestrutura enterprise-grade com observabilidade completa.
10
-
11
- ### Principais Destaques
12
-
13
- - **Arquitetura Multi-Agente**: 17 agentes com identidades culturais brasileiras
14
- - **Performance**: Latência P95 <180ms, throughput 12k req/s, cache hit rate 92%
15
- - **Segurança**: JWT auth, rate limiting, circuit breakers, audit logging
16
- - **Observabilidade**: Prometheus + Grafana, métricas customizadas, alertas SLO/SLA
17
- - **Otimizações**: orjson (3x mais rápido), Brotli (70-90% compressão), cache multi-nível
18
-
19
- ## 1. Estrutura do Projeto
20
-
21
- ### 1.1 Organização de Diretórios
22
-
23
- ```
24
- cidadao.ai-backend/
25
- ├── app.py # Entry point HuggingFace (porta 7860)
26
- ├── src/ # Código fonte principal
27
- │ ├── agents/ # 17 agentes IA especializados
28
- │ ├── api/ # Endpoints REST/WebSocket/GraphQL
29
- │ ├── core/ # Utilitários centrais
30
- │ ├── infrastructure/ # Recursos enterprise
31
- │ ├── ml/ # Pipeline ML/IA
32
- │ ├── services/ # Lógica de negócio
33
- │ └── tools/ # Integrações externas
34
- ├── tests/ # Suite de testes (45% cobertura)
35
- ├── docs/ # Documentação completa
36
- ├── monitoring/ # Stack Prometheus + Grafana
37
- ├── scripts/ # Automação e deployment
38
- └── requirements/ # Gestão de dependências
39
- ```
40
-
41
- ### 1.2 Arquivos de Configuração Principais
42
-
43
- - **pyproject.toml**: Configuração moderna Python com seções organizadas
44
- - **Makefile**: 30+ comandos para workflow de desenvolvimento
45
- - **pytest.ini**: Configuração de testes com markers e coverage
46
- - **docker-compose.monitoring.yml**: Stack completa de observabilidade
47
-
48
- ## 2. Sistema Multi-Agente
49
-
50
- ### 2.1 Agentes Operacionais (8/17)
51
-
52
- 1. **Abaporu** - Orquestrador mestre
53
- - Coordena investigações multi-agente
54
- - Execução paralela de tarefas independentes
55
- - Loop de reflexão para melhoria de qualidade
56
-
57
- 2. **Zumbi dos Palmares** - Investigador de anomalias
58
- - Análise estatística (Z-score, threshold 2.5σ)
59
- - Análise espectral (FFT) para padrões periódicos
60
- - ML: Isolation Forest, One-Class SVM, LOF
61
- - Detecção de similaridade (Jaccard 85%)
62
-
63
- 3. **Anita Garibaldi** - Especialista em análise
64
- - Correlação de padrões
65
- - Análise de tendências
66
- - Identificação de relacionamentos
67
-
68
- 4. **Tiradentes** - Geração de relatórios
69
- - Linguagem natural em português
70
- - Formatação estruturada
71
- - Sumarização executiva
72
-
73
- 5. **Nanã** - Gerenciamento de memória
74
- - Memória episódica (eventos)
75
- - Memória semântica (conhecimento)
76
- - Memória conversacional (contexto)
77
-
78
- 6. **Ayrton Senna** - Roteamento semântico
79
- - Detecção de intenção (7 tipos)
80
- - Roteamento otimizado
81
- - Balanceamento de carga
82
-
83
- 7. **Machado de Assis** - Análise textual
84
- - NER (Named Entity Recognition)
85
- - Análise de documentos
86
- - Extração de informações
87
-
88
- 8. **Dandara** - Análise de justiça social
89
- - Equidade em contratos
90
- - Distribuição de recursos
91
- - Impacto social
92
-
93
- ### 2.2 Arquitetura de Comunicação
94
-
95
- ```python
96
- # Padrão de comunicação entre agentes
97
- message = AgentMessage(
98
- sender="MasterAgent",
99
- recipient="InvestigatorAgent",
100
- action="detect_anomalies",
101
- payload={"query": "contratos acima de 1M"},
102
- context=context.to_dict()
103
- )
104
-
105
- # Execução paralela
106
- tasks = [
107
- ParallelTask(agent_type=AgentType.INVESTIGATOR, message=msg1),
108
- ParallelTask(agent_type=AgentType.ANALYST, message=msg2)
109
- ]
110
- results = await parallel_processor.execute_parallel(tasks, context)
111
- ```
112
-
113
- ## 3. Detecção de Anomalias e Pipeline ML
114
-
115
- ### 3.1 Métodos de Detecção
116
-
117
- 1. **Análise Estatística**:
118
- - Anomalias de preço (Z-score > 2.5)
119
- - Concentração de fornecedores (>70%)
120
- - Padrões temporais (picos de atividade)
121
-
122
- 2. **Análise Espectral (FFT)**:
123
- - Detecção de padrões semanais/mensais/trimestrais
124
- - Mudanças de regime em gastos
125
- - Regularidade excessiva (indicador de fraude)
126
-
127
- 3. **Machine Learning**:
128
- - Isolation Forest (isolamento)
129
- - One-Class SVM (novidade)
130
- - Local Outlier Factor (densidade)
131
- - Modelo Cidadão.AI customizado com atenção
132
-
133
- 4. **Detecção de Similaridade**:
134
- - Contratos duplicados (Jaccard > 85%)
135
- - Padrões de pagamento anômalos (>50% discrepância)
136
-
137
- ### 3.2 Resultados de Performance
138
-
139
- - **Precisão de detecção**: >90%
140
- - **Taxa de falsos positivos**: <5%
141
- - **Tempo de análise**: <2s por investigação
142
- - **Volume processado**: 10k+ contratos/hora
143
-
144
- ## 4. API e Endpoints
145
-
146
- ### 4.1 Endpoints Principais
147
-
148
- ```
149
- REST API:
150
- - POST /api/v1/investigations/create
151
- - GET /api/v1/investigations/{id}/status
152
- - POST /api/v1/analysis/patterns
153
- - POST /api/v1/chat/message
154
- - GET /api/v1/chat/stream (SSE)
155
-
156
- WebSocket:
157
- - WS /api/v1/ws/chat/{session_id}
158
- - WS /api/v1/ws/investigations/{id}
159
-
160
- GraphQL:
161
- - /graphql (queries flexíveis)
162
-
163
- Batch API:
164
- - POST /api/v1/batch/process
165
-
166
- Métricas:
167
- - GET /health/metrics (Prometheus)
168
- - GET /health/metrics/json
169
- ```
170
-
171
- ### 4.2 Recursos Avançados
172
-
173
- - **Streaming SSE**: Respostas em tempo real
174
- - **WebSocket**: Comunicação bidirecional
175
- - **GraphQL**: Queries flexíveis com limites
176
- - **Batch API**: Múltiplas operações paralelas
177
- - **CQRS**: Separação comando/consulta
178
-
179
- ## 5. Segurança e Autenticação
180
-
181
- ### 5.1 Implementação de Segurança
182
-
183
- - **JWT Dual Token**: Access (30min) + Refresh (7 dias)
184
- - **Hashing**: bcrypt para senhas
185
- - **Roles**: admin, analyst com permissões
186
- - **Rate Limiting**: Por usuário/endpoint
187
- - **Circuit Breakers**: Prevenção de cascata
188
- - **Audit Logging**: Rastreamento completo
189
-
190
- ### 5.2 Middleware Stack
191
-
192
- 1. SecurityMiddleware (headers, XSS)
193
- 2. LoggingMiddleware (audit trail)
194
- 3. RateLimitMiddleware (throttling)
195
- 4. AuthenticationMiddleware (JWT)
196
- 5. CORS (origens configuráveis)
197
-
198
- ## 6. Otimizações de Performance
199
-
200
- ### 6.1 Cache Multi-Nível
201
-
202
- - **L1 Memory**: LRU in-memory (ms latência)
203
- - **L2 Redis**: Distribuído (10ms latência)
204
- - **L3 Database**: Persistente (100ms latência)
205
-
206
- TTLs configurados:
207
- - API responses: 5 minutos
208
- - Dados transparência: 1 hora
209
- - Resultados análise: 24 horas
210
- - Embeddings ML: 1 semana
211
-
212
- ### 6.2 Otimizações Implementadas
213
-
214
- 1. **orjson**: 3x mais rápido que json padrão
215
- 2. **Brotli/Gzip**: 70-90% redução bandwidth
216
- 3. **Connection Pooling**: 20+30 conexões DB
217
- 4. **Agent Pooling**: Instâncias pré-aquecidas
218
- 5. **Parallel Processing**: MapReduce patterns
219
- 6. **HTTP/2**: Multiplexing para LLM providers
220
-
221
- ### 6.3 Resultados Alcançados
222
-
223
- - **Latência API**: P95 < 180ms ✅
224
- - **Throughput**: 12,000 req/s ✅
225
- - **Cache Hit Rate**: 92% ✅
226
- - **Tempo resposta agente**: <2s ✅
227
- - **Uso memória**: 1.8GB ✅
228
-
229
- ## 7. Integração Portal da Transparência
230
-
231
- ### 7.1 Cliente API
232
-
233
- ```python
234
- async with TransparencyAPIClient() as client:
235
- filters = TransparencyAPIFilter(
236
- codigo_orgao="26000",
237
- ano=2024,
238
- valor_inicial=100000
239
- )
240
- response = await client.get_contracts(filters)
241
- ```
242
-
243
- ### 7.2 Recursos
244
-
245
- - **Fallback automático**: Dados demo sem API key
246
- - **Rate limiting**: 90 req/min com espera
247
- - **Retry logic**: Backoff exponencial
248
- - **Multi-endpoint**: Contratos, despesas, servidores
249
- - **Paginação**: Automática
250
-
251
- ## 8. Monitoramento e Observabilidade
252
-
253
- ### 8.1 Stack Prometheus + Grafana
254
-
255
- - **Métricas customizadas**: 15+ métricas específicas
256
- - **Dashboards**: Overview, Agents, Performance
257
- - **Alertas**: 6 categorias (saúde, infra, agentes, negócio, SLO, segurança)
258
- - **Retenção**: 30 dias / 5GB
259
-
260
- ### 8.2 Métricas Principais
261
-
262
- - `cidadao_ai_agent_tasks_total`
263
- - `cidadao_ai_investigations_total`
264
- - `cidadao_ai_anomalies_detected_total`
265
- - `cidadao_ai_request_duration_seconds`
266
- - `cidadao_ai_cache_hit_ratio`
267
-
268
- ## 9. Testing e CI/CD
269
-
270
- ### 9.1 Estado Atual
271
-
272
- - **Cobertura**: 45% (meta: 80%)
273
- - **Categorias**: Unit, Integration, Multi-agent, E2E
274
- - **CI Pipeline**: GitHub Actions completo
275
- - **Deployment**: Automático para HuggingFace
276
-
277
- ### 9.2 Gaps Identificados
278
-
279
- - 13/17 agentes sem testes
280
- - Falta suite de performance
281
- - WebSocket tests incompletos
282
- - Security tests ausentes
283
-
284
- ## 10. Débito Técnico e Próximos Passos
285
-
286
- ### 10.1 Prioridades Imediatas (1-2 semanas)
287
-
288
- 1. Completar testes dos agentes restantes
289
- 2. Implementar métricas Prometheus no código
290
- 3. Documentar deployment produção
291
- 4. Adicionar autenticação WebSocket
292
- 5. Criar plano disaster recovery
293
-
294
- ### 10.2 Metas Curto Prazo (1 mês)
295
-
296
- 1. Atingir 80% cobertura testes
297
- 2. Implementar distributed tracing
298
- 3. Completar auditoria segurança
299
- 4. Adicionar testes performance automatizados
300
- 5. Documentar SLAs/SLOs
301
-
302
- ### 10.3 Visão Longo Prazo (3 meses)
303
-
304
- 1. Considerar arquitetura microserviços
305
- 2. Manifests Kubernetes
306
- 3. Estratégia multi-região
307
- 4. Infraestrutura ML avançada
308
- 5. API gateway completo
309
-
310
- ## 11. Conclusão
311
-
312
- O Cidadão.AI Backend demonstra maturidade arquitetural com recursos enterprise-grade, sistema multi-agente sofisticado, e infraestrutura pronta para produção. As otimizações recentes posicionam o sistema para alto desempenho e escalabilidade. Os principais desafios estão na cobertura de testes e documentação de produção, mas a fundação é sólida para deployment e crescimento.
313
-
314
- ### Pontos Fortes
315
-
316
- - ✅ Arquitetura multi-agente inovadora
317
- - ✅ Performance excepcional alcançada
318
- - ✅ Segurança enterprise implementada
319
- - ✅ Observabilidade completa
320
- - ✅ Integração governo funcional
321
-
322
- ### Áreas de Melhoria
323
-
324
- - ⚠️ Cobertura testes abaixo da meta
325
- - ⚠️ Documentação produção incompleta
326
- - ⚠️ Falta testes performance automatizados
327
- - ⚠️ Disaster recovery não documentado
328
- - ⚠️ 9 agentes aguardando implementação
329
-
330
- O projeto está bem posicionado para se tornar a principal plataforma de transparência governamental do Brasil, com tecnologia de ponta e foco em resultados práticos para a sociedade.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
EMERGENCY_SOLUTION.md DELETED
@@ -1,84 +0,0 @@
1
- # 🚨 Solução de Emergência - Chat Endpoints
2
-
3
- ## Status dos Endpoints
4
-
5
- ### ✅ FUNCIONANDO 100%
6
- 1. **`/api/v1/chat/simple`** - Endpoint principal com Maritaca AI
7
- - Taxa de sucesso: 100%
8
- - Modelo: Sabiá-3
9
- - Tempo de resposta: 1.4s - 14.6s
10
-
11
- 2. **`/api/v1/chat/emergency`** - NOVO endpoint ultra-confiável
12
- - Sem dependências complexas
13
- - Fallback inteligente garantido
14
- - Sempre retorna resposta válida
15
-
16
- ### ⚠️ EM CORREÇÃO
17
- 3. **`/api/v1/chat/stable`** - Corrigido mas ainda testando
18
- 4. **`/api/v1/chat/optimized`** - Com Sabiazinho (econômico)
19
- 5. **`/api/v1/chat/message`** - Original com problemas
20
-
21
- ## Recomendação para Frontend
22
-
23
- **USE IMEDIATAMENTE**: `/api/v1/chat/emergency`
24
-
25
- ```typescript
26
- // Exemplo de integração
27
- const response = await fetch('https://neural-thinker-cidadao-ai-backend.hf.space/api/v1/chat/emergency', {
28
- method: 'POST',
29
- headers: { 'Content-Type': 'application/json' },
30
- body: JSON.stringify({
31
- message: "Olá, como você pode me ajudar?",
32
- session_id: "session_123"
33
- })
34
- })
35
-
36
- const data = await response.json()
37
- // Sempre retorna resposta válida!
38
- ```
39
-
40
- ## Características do Emergency Endpoint
41
-
42
- 1. **Zero dependências complexas** - Não usa IntentDetector ou serviços externos
43
- 2. **Maritaca com fallback** - Tenta Maritaca primeiro, mas tem respostas prontas
44
- 3. **Respostas contextualizadas** - Diferentes respostas para cada tipo de pergunta
45
- 4. **100% disponibilidade** - Nunca falha, sempre responde
46
-
47
- ## Ordem de Prioridade para Frontend
48
-
49
- 1. **Primeira escolha**: `/api/v1/chat/emergency` (100% confiável)
50
- 2. **Segunda escolha**: `/api/v1/chat/simple` (funcionando bem)
51
- 3. **Futura**: `/api/v1/chat/optimized` (quando estabilizar)
52
-
53
- ## Exemplo de Resposta
54
-
55
- ```json
56
- {
57
- "session_id": "emergency_1234567890",
58
- "agent_id": "assistant",
59
- "agent_name": "Assistente Cidadão.AI",
60
- "message": "Olá! Sou o assistente do Cidadão.AI...",
61
- "confidence": 0.95,
62
- "suggested_actions": ["start_investigation", "view_recent_contracts", "help"],
63
- "metadata": {
64
- "backend": "maritaca_ai",
65
- "timestamp": "2025-09-20T20:30:00Z"
66
- }
67
- }
68
- ```
69
-
70
- ## Monitoramento
71
-
72
- Endpoint de saúde: `GET /api/v1/chat/emergency/health`
73
-
74
- ```json
75
- {
76
- "status": "operational",
77
- "endpoint": "/api/v1/chat/emergency",
78
- "maritaca_configured": true,
79
- "fallback_ready": true,
80
- "timestamp": "2025-09-20T20:30:00Z"
81
- }
82
- ```
83
-
84
- **ESTE ENDPOINT GARANTE 100% DE DISPONIBILIDADE!**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FIX_HUGGINGFACE_DEPLOYMENT.md DELETED
@@ -1,117 +0,0 @@
1
- # 🚨 Correção Urgente - Backend HuggingFace
2
-
3
- ## Problema Identificado
4
-
5
- O backend no HuggingFace está rodando a versão **ERRADA** do código:
6
-
7
- 1. **Versão atual** (app.py): Apenas tem o EnhancedZumbiAgent
8
- 2. **Versão correta** (src/api/app.py): Sistema completo com Drummond e todos os agentes
9
-
10
- Por isso o frontend sempre retorna "modo manutenção" - o Drummond não existe!
11
-
12
- ## Solução Imediata
13
-
14
- ### Opção 1: Substituir app.py (Mais Simples)
15
-
16
- ```bash
17
- # No branch hf-fastapi
18
- git checkout hf-fastapi
19
-
20
- # Backup do app.py atual
21
- mv app.py app_simple.py
22
-
23
- # Criar novo app.py que importa o sistema completo
24
- cat > app.py << 'EOF'
25
- #!/usr/bin/env python3
26
- import os
27
- import sys
28
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
29
-
30
- from src.api.app import app
31
- import uvicorn
32
-
33
- if __name__ == "__main__":
34
- port = int(os.getenv("PORT", 7860))
35
- uvicorn.run(app, host="0.0.0.0", port=port, forwarded_allow_ips="*", proxy_headers=True)
36
- EOF
37
-
38
- # Commit e push
39
- git add app.py app_simple.py
40
- git commit -m "fix: use full multi-agent system with Drummond in HuggingFace deployment"
41
- git push origin hf-fastapi
42
- ```
43
-
44
- ### Opção 2: Adicionar Drummond ao app.py Atual
45
-
46
- Se preferir manter o app.py simplificado, adicione o Drummond:
47
-
48
- ```python
49
- # No app.py, após a linha 522 (onde cria enhanced_zumbi):
50
- from src.agents.drummond_simple import SimpleDrummondAgent
51
- drummond_agent = SimpleDrummondAgent()
52
-
53
- # Adicionar endpoint do Drummond
54
- @app.post("/api/v1/chat/message")
55
- async def chat_message(request: ChatRequest):
56
- """Chat endpoint with Drummond agent."""
57
- try:
58
- response = await drummond_agent.process_message(request.message)
59
- return {
60
- "status": "success",
61
- "agent": "drummond",
62
- "message": response,
63
- "is_demo_mode": False
64
- }
65
- except Exception as e:
66
- logger.error(f"Drummond error: {str(e)}")
67
- return {
68
- "status": "maintenance",
69
- "agent": "system",
70
- "message": "Sistema em manutenção temporária",
71
- "is_demo_mode": True
72
- }
73
- ```
74
-
75
- ## Correção do Erro 403 da API
76
-
77
- O erro 403 indica que a API key do Portal da Transparência está inválida:
78
-
79
- 1. Verifique no HuggingFace Spaces Settings:
80
- - Vá para: https://huggingface.co/spaces/neural-thinker/cidadao.ai-backend/settings
81
- - Procure por `TRANSPARENCY_API_KEY`
82
- - Se não existir ou estiver inválida, adicione uma nova
83
-
84
- 2. Para obter nova API key:
85
- - Acesse: https://www.portaldatransparencia.gov.br/api-de-dados
86
- - Cadastre-se e gere uma nova chave
87
- - Adicione no HuggingFace Spaces
88
-
89
- ## Deploy Correto
90
-
91
- ```bash
92
- # Após fazer as correções
93
- git push origin hf-fastapi
94
-
95
- # O HuggingFace deve fazer redeploy automático
96
- # Se não, vá em Settings > Factory reboot
97
- ```
98
-
99
- ## Verificação
100
-
101
- Após o deploy, teste:
102
-
103
- ```bash
104
- # Verificar se Drummond está disponível
105
- curl https://neural-thinker-cidadao-ai-backend.hf.space/api/v1/chat/message \
106
- -H "Content-Type: application/json" \
107
- -d '{"message": "Olá, como você pode me ajudar?"}'
108
-
109
- # Deve retornar resposta do Drummond, não "modo manutenção"
110
- ```
111
-
112
- ## Resumo
113
-
114
- 1. **Problema**: Versão errada deployada (sem Drummond)
115
- 2. **Solução**: Usar app.py que importa src.api.app completo
116
- 3. **Extra**: Corrigir API key do Portal da Transparência
117
- 4. **Resultado**: Frontend funcionará normalmente com chat ativo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FRONTEND_CHAT_INTEGRATION.md DELETED
@@ -1,363 +0,0 @@
1
- # 🤖 Guia de Integração: Chat Drummond/Maritaca AI no Frontend Next.js
2
-
3
- ## 🏗️ Arquitetura da Integração
4
-
5
- ```
6
- Frontend Next.js → Backend API → Agente Drummond → Maritaca AI
7
- (Interface) (FastAPI) (Poeta Mineiro) (LLM Brasileiro)
8
- ```
9
-
10
- ## 📡 Endpoints Disponíveis
11
-
12
- ### 1. Endpoint Principal (Recomendado)
13
- ```
14
- POST https://neural-thinker-cidadao-ai-backend.hf.space/api/v1/chat/message
15
- ```
16
-
17
- **Request:**
18
- ```json
19
- {
20
- "message": "Olá, como posso investigar contratos públicos?",
21
- "session_id": "uuid-opcional", // Mantém contexto da conversa
22
- "context": {} // Contexto adicional (opcional)
23
- }
24
- ```
25
-
26
- **Response:**
27
- ```json
28
- {
29
- "session_id": "550e8400-e29b-41d4-a716-446655440000",
30
- "agent_id": "drummond",
31
- "agent_name": "Carlos Drummond de Andrade",
32
- "message": "Uai! Que bom falar com você...",
33
- "confidence": 0.95,
34
- "suggested_actions": ["investigar_contratos", "ver_gastos"],
35
- "requires_input": null,
36
- "metadata": {
37
- "intent_type": "greeting",
38
- "agent_version": "1.0"
39
- }
40
- }
41
- ```
42
-
43
- ### 2. Endpoint Alternativo (Fallback)
44
- ```
45
- POST https://neural-thinker-cidadao-ai-backend.hf.space/api/v1/chat/simple
46
- ```
47
-
48
- **Request:**
49
- ```json
50
- {
51
- "message": "Sua mensagem aqui",
52
- "session_id": "uuid-opcional"
53
- }
54
- ```
55
-
56
- **Response:**
57
- ```json
58
- {
59
- "message": "Resposta do Drummond via Maritaca AI",
60
- "session_id": "550e8400-e29b-41d4-a716-446655440000",
61
- "timestamp": "2025-09-20T20:00:00Z",
62
- "model_used": "sabia-3" // ou "fallback" se Maritaca estiver offline
63
- }
64
- ```
65
-
66
- ## 🛠️ Implementação Passo a Passo
67
-
68
- ### Passo 1: Criar o Serviço de API
69
-
70
- ```typescript
71
- // services/cidadaoChat.service.ts
72
-
73
- const API_URL = process.env.NEXT_PUBLIC_CIDADAO_API_URL ||
74
- 'https://neural-thinker-cidadao-ai-backend.hf.space';
75
-
76
- export class CidadaoChatService {
77
- private sessionId: string | null = null;
78
-
79
- async sendMessage(message: string) {
80
- try {
81
- const response = await fetch(`${API_URL}/api/v1/chat/message`, {
82
- method: 'POST',
83
- headers: {
84
- 'Content-Type': 'application/json',
85
- },
86
- body: JSON.stringify({
87
- message,
88
- session_id: this.sessionId,
89
- context: {}
90
- }),
91
- });
92
-
93
- const data = await response.json();
94
-
95
- // Guarda o session_id para manter contexto
96
- if (!this.sessionId && data.session_id) {
97
- this.sessionId = data.session_id;
98
- }
99
-
100
- return data;
101
- } catch (error) {
102
- console.error('Erro na comunicação:', error);
103
- throw error;
104
- }
105
- }
106
- }
107
- ```
108
-
109
- ### Passo 2: Hook React para Gerenciar o Chat
110
-
111
- ```typescript
112
- // hooks/useCidadaoChat.ts
113
-
114
- import { useState, useCallback } from 'react';
115
- import { CidadaoChatService } from '../services/cidadaoChat.service';
116
-
117
- const chatService = new CidadaoChatService();
118
-
119
- export function useCidadaoChat() {
120
- const [messages, setMessages] = useState([]);
121
- const [isLoading, setIsLoading] = useState(false);
122
-
123
- const sendMessage = useCallback(async (text: string) => {
124
- // Adiciona mensagem do usuário
125
- setMessages(prev => [...prev, {
126
- id: Date.now(),
127
- role: 'user',
128
- content: text,
129
- timestamp: new Date()
130
- }]);
131
-
132
- setIsLoading(true);
133
-
134
- try {
135
- const response = await chatService.sendMessage(text);
136
-
137
- // Adiciona resposta do Drummond
138
- setMessages(prev => [...prev, {
139
- id: Date.now() + 1,
140
- role: 'assistant',
141
- content: response.message,
142
- agentName: response.agent_name,
143
- confidence: response.confidence,
144
- timestamp: new Date()
145
- }]);
146
-
147
- return response;
148
- } finally {
149
- setIsLoading(false);
150
- }
151
- }, []);
152
-
153
- return {
154
- messages,
155
- sendMessage,
156
- isLoading
157
- };
158
- }
159
- ```
160
-
161
- ### Passo 3: Componente de Chat
162
-
163
- ```tsx
164
- // components/CidadaoChat.tsx
165
-
166
- export function CidadaoChat() {
167
- const { messages, sendMessage, isLoading } = useCidadaoChat();
168
- const [input, setInput] = useState('');
169
-
170
- const handleSubmit = async (e: FormEvent) => {
171
- e.preventDefault();
172
- if (input.trim() && !isLoading) {
173
- await sendMessage(input);
174
- setInput('');
175
- }
176
- };
177
-
178
- return (
179
- <div className="chat-container">
180
- <div className="messages">
181
- {messages.map((msg) => (
182
- <div key={msg.id} className={`message ${msg.role}`}>
183
- {msg.agentName && (
184
- <span className="agent-name">{msg.agentName}</span>
185
- )}
186
- <p>{msg.content}</p>
187
- </div>
188
- ))}
189
- {isLoading && <div className="loading">Drummond está pensando...</div>}
190
- </div>
191
-
192
- <form onSubmit={handleSubmit}>
193
- <input
194
- type="text"
195
- value={input}
196
- onChange={(e) => setInput(e.target.value)}
197
- placeholder="Pergunte sobre transparência pública..."
198
- disabled={isLoading}
199
- />
200
- <button type="submit" disabled={isLoading}>
201
- Enviar
202
- </button>
203
- </form>
204
- </div>
205
- );
206
- }
207
- ```
208
-
209
- ## 🎯 Casos de Uso e Intents
210
-
211
- O Drummond responde melhor a estes tipos de mensagem:
212
-
213
- ### 1. **Saudações** (IntentType.GREETING)
214
- - "Olá", "Oi", "Bom dia", "Boa tarde"
215
- - **Resposta**: Saudação mineira calorosa com explicação do Cidadão.AI
216
-
217
- ### 2. **Investigações** (IntentType.INVESTIGATE)
218
- - "Quero investigar contratos de saúde"
219
- - "Mostre gastos com educação em SP"
220
- - **Resposta**: Direcionamento para investigação ou relatório
221
-
222
- ### 3. **Ajuda** (IntentType.HELP_REQUEST)
223
- - "Como funciona?", "Me ajuda", "O que você faz?"
224
- - **Resposta**: Explicação das capacidades do sistema
225
-
226
- ### 4. **Sobre o Sistema** (IntentType.ABOUT_SYSTEM)
227
- - "O que é o Cidadão.AI?"
228
- - "Como funciona o portal da transparência?"
229
- - **Resposta**: Informações educativas sobre transparência
230
-
231
- ## 🔧 Configurações Importantes
232
-
233
- ### Variáveis de Ambiente (.env.local)
234
- ```bash
235
- NEXT_PUBLIC_CIDADAO_API_URL=https://neural-thinker-cidadao-ai-backend.hf.space
236
- ```
237
-
238
- ### Headers CORS
239
- O backend já está configurado para aceitar requisições de:
240
- - http://localhost:3000
241
- - https://*.vercel.app
242
- - Seu domínio customizado
243
-
244
- ### Timeout Recomendado
245
- ```javascript
246
- // Configure timeout de 30 segundos para a Maritaca AI
247
- const controller = new AbortController();
248
- const timeoutId = setTimeout(() => controller.abort(), 30000);
249
-
250
- fetch(url, {
251
- signal: controller.signal,
252
- // ... outras configs
253
- });
254
- ```
255
-
256
- ## 🚨 Tratamento de Erros
257
-
258
- ```typescript
259
- async function sendMessageWithErrorHandling(message: string) {
260
- try {
261
- const response = await chatService.sendMessage(message);
262
- return response;
263
- } catch (error) {
264
- if (error.name === 'AbortError') {
265
- // Timeout - Maritaca demorou muito
266
- return {
267
- message: 'A resposta está demorando. Por favor, tente novamente.',
268
- agent_name: 'Sistema',
269
- confidence: 0
270
- };
271
- }
272
-
273
- // Outros erros
274
- return {
275
- message: 'Desculpe, estou com dificuldades técnicas no momento.',
276
- agent_name: 'Sistema',
277
- confidence: 0
278
- };
279
- }
280
- }
281
- ```
282
-
283
- ## 📊 Monitoramento e Status
284
-
285
- ### Verificar Status do Serviço
286
- ```typescript
287
- async function checkServiceHealth() {
288
- try {
289
- const response = await fetch(`${API_URL}/health`);
290
- const data = await response.json();
291
-
292
- console.log('Status:', data.status); // 'healthy' ou 'degraded'
293
- console.log('Serviços:', data.services);
294
-
295
- return data.status === 'healthy';
296
- } catch (error) {
297
- return false;
298
- }
299
- }
300
- ```
301
-
302
- ### Indicador de Status no UI
303
- ```tsx
304
- function ServiceStatus() {
305
- const [status, setStatus] = useState('checking');
306
-
307
- useEffect(() => {
308
- checkServiceHealth().then(isHealthy => {
309
- setStatus(isHealthy ? 'online' : 'limited');
310
- });
311
- }, []);
312
-
313
- return (
314
- <div className={`status-badge ${status}`}>
315
- {status === 'online' ? '🟢 Maritaca AI Online' : '🟡 Modo Limitado'}
316
- </div>
317
- );
318
- }
319
- ```
320
-
321
- ## 🎨 Personalização da Interface
322
-
323
- ### Identificando o Agente
324
- Quando a resposta vem do Drummond com Maritaca AI:
325
- ```javascript
326
- if (response.agent_name === 'Carlos Drummond de Andrade') {
327
- // Mostra avatar do Drummond
328
- // Adiciona estilo "poético mineiro"
329
- // Confidence > 0.8 = Maritaca está respondendo
330
- }
331
- ```
332
-
333
- ### Sugestões de Ações
334
- Se `suggested_actions` estiver presente:
335
- ```tsx
336
- {response.suggested_actions?.map(action => (
337
- <button
338
- key={action}
339
- onClick={() => handleQuickAction(action)}
340
- className="quick-action"
341
- >
342
- {getActionLabel(action)}
343
- </button>
344
- ))}
345
- ```
346
-
347
- ## 🚀 Próximos Passos
348
-
349
- 1. **Implementar o serviço** seguindo os exemplos
350
- 2. **Testar a conexão** com o endpoint de health
351
- 3. **Adicionar o componente** de chat na interface
352
- 4. **Personalizar** visual e comportamento
353
- 5. **Monitorar** logs e métricas de uso
354
-
355
- ## 📞 Suporte
356
-
357
- - **Documentação da API**: https://neural-thinker-cidadao-ai-backend.hf.space/docs
358
- - **Status do Serviço**: https://neural-thinker-cidadao-ai-backend.hf.space/health
359
- - **GitHub**: https://github.com/anderson-ufrj/cidadao.ai-backend
360
-
361
- ---
362
-
363
- *Drummond está ansioso para conversar com os cidadãos brasileiros sobre transparência pública! 🇧🇷*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FRONTEND_INTEGRATION.md DELETED
@@ -1,254 +0,0 @@
1
- # Integração Frontend - Cidadão.AI Chat com Maritaca AI
2
-
3
- ## Status Atual ✅
4
-
5
- - **Backend**: Funcionando em https://neural-thinker-cidadao-ai-backend.hf.space
6
- - **Maritaca AI**: Configurada e pronta para uso
7
- - **Endpoints**: Disponíveis para integração
8
-
9
- ## Endpoints Principais
10
-
11
- ### 1. Chat Principal (com Drummond/Maritaca)
12
- ```
13
- POST https://neural-thinker-cidadao-ai-backend.hf.space/api/v1/chat/message
14
- ```
15
-
16
- **Request:**
17
- ```json
18
- {
19
- "message": "Olá, como posso investigar contratos públicos?",
20
- "session_id": "opcional-uuid",
21
- "context": {}
22
- }
23
- ```
24
-
25
- **Response:**
26
- ```json
27
- {
28
- "session_id": "uuid",
29
- "agent_id": "drummond",
30
- "agent_name": "Carlos Drummond de Andrade",
31
- "message": "Resposta do agente...",
32
- "confidence": 0.8,
33
- "suggested_actions": ["investigar_contratos", "ver_gastos"],
34
- "metadata": {}
35
- }
36
- ```
37
-
38
- ### 2. Chat Simplificado (Novo - Mais Confiável)
39
- ```
40
- POST https://neural-thinker-cidadao-ai-backend.hf.space/api/v1/chat/simple
41
- ```
42
-
43
- **Request:**
44
- ```json
45
- {
46
- "message": "Sua mensagem aqui",
47
- "session_id": "opcional"
48
- }
49
- ```
50
-
51
- **Response:**
52
- ```json
53
- {
54
- "message": "Resposta da Maritaca AI ou fallback",
55
- "session_id": "uuid",
56
- "timestamp": "2025-09-20T19:45:00Z",
57
- "model_used": "sabia-3" // ou "fallback"
58
- }
59
- ```
60
-
61
- ### 3. Status do Chat
62
- ```
63
- GET https://neural-thinker-cidadao-ai-backend.hf.space/api/v1/chat/simple/status
64
- ```
65
-
66
- **Response:**
67
- ```json
68
- {
69
- "maritaca_available": true,
70
- "api_key_configured": true,
71
- "timestamp": "2025-09-20T19:45:00Z"
72
- }
73
- ```
74
-
75
- ## Exemplo de Integração no Next.js
76
-
77
- ```typescript
78
- // services/chatService.ts
79
- const BACKEND_URL = 'https://neural-thinker-cidadao-ai-backend.hf.space';
80
-
81
- export interface ChatMessage {
82
- message: string;
83
- session_id?: string;
84
- }
85
-
86
- export interface ChatResponse {
87
- message: string;
88
- session_id: string;
89
- timestamp: string;
90
- model_used: string;
91
- }
92
-
93
- export async function sendChatMessage(message: string, sessionId?: string): Promise<ChatResponse> {
94
- try {
95
- const response = await fetch(`${BACKEND_URL}/api/v1/chat/simple`, {
96
- method: 'POST',
97
- headers: {
98
- 'Content-Type': 'application/json',
99
- },
100
- body: JSON.stringify({
101
- message,
102
- session_id: sessionId
103
- })
104
- });
105
-
106
- if (!response.ok) {
107
- throw new Error(`HTTP error! status: ${response.status}`);
108
- }
109
-
110
- return await response.json();
111
- } catch (error) {
112
- console.error('Chat error:', error);
113
- throw error;
114
- }
115
- }
116
-
117
- // Verificar status do serviço
118
- export async function checkChatStatus() {
119
- try {
120
- const response = await fetch(`${BACKEND_URL}/api/v1/chat/simple/status`);
121
- return await response.json();
122
- } catch (error) {
123
- console.error('Status check error:', error);
124
- return { maritaca_available: false, api_key_configured: false };
125
- }
126
- }
127
- ```
128
-
129
- ## Componente React Exemplo
130
-
131
- ```tsx
132
- // components/Chat.tsx
133
- import { useState, useEffect } from 'react';
134
- import { sendChatMessage, checkChatStatus } from '../services/chatService';
135
-
136
- export function Chat() {
137
- const [messages, setMessages] = useState<Array<{role: string, content: string}>>([]);
138
- const [input, setInput] = useState('');
139
- const [loading, setLoading] = useState(false);
140
- const [sessionId, setSessionId] = useState<string>();
141
- const [serviceStatus, setServiceStatus] = useState<any>();
142
-
143
- useEffect(() => {
144
- // Verificar status do serviço ao carregar
145
- checkChatStatus().then(setServiceStatus);
146
- }, []);
147
-
148
- const handleSend = async () => {
149
- if (!input.trim()) return;
150
-
151
- // Adicionar mensagem do usuário
152
- setMessages(prev => [...prev, { role: 'user', content: input }]);
153
- setLoading(true);
154
-
155
- try {
156
- const response = await sendChatMessage(input, sessionId);
157
-
158
- // Salvar session ID para próximas mensagens
159
- if (!sessionId) {
160
- setSessionId(response.session_id);
161
- }
162
-
163
- // Adicionar resposta do bot
164
- setMessages(prev => [...prev, { role: 'assistant', content: response.message }]);
165
- } catch (error) {
166
- setMessages(prev => [...prev, {
167
- role: 'assistant',
168
- content: 'Desculpe, ocorreu um erro. Por favor, tente novamente.'
169
- }]);
170
- } finally {
171
- setLoading(false);
172
- setInput('');
173
- }
174
- };
175
-
176
- return (
177
- <div>
178
- {serviceStatus && (
179
- <div className="status">
180
- Maritaca AI: {serviceStatus.maritaca_available ? '✅' : '❌'}
181
- </div>
182
- )}
183
-
184
- <div className="messages">
185
- {messages.map((msg, idx) => (
186
- <div key={idx} className={`message ${msg.role}`}>
187
- {msg.content}
188
- </div>
189
- ))}
190
- </div>
191
-
192
- <div className="input-area">
193
- <input
194
- value={input}
195
- onChange={(e) => setInput(e.target.value)}
196
- onKeyPress={(e) => e.key === 'Enter' && handleSend()}
197
- placeholder="Digite sua mensagem..."
198
- disabled={loading}
199
- />
200
- <button onClick={handleSend} disabled={loading}>
201
- {loading ? 'Enviando...' : 'Enviar'}
202
- </button>
203
- </div>
204
- </div>
205
- );
206
- }
207
- ```
208
-
209
- ## Sugestões de Mensagens para Testar
210
-
211
- 1. **Saudações:**
212
- - "Olá, como você pode me ajudar?"
213
- - "Bom dia! O que é o Cidadão.AI?"
214
-
215
- 2. **Investigações:**
216
- - "Quero investigar contratos de saúde"
217
- - "Como posso analisar gastos com educação?"
218
- - "Mostre contratos do Ministério da Saúde"
219
-
220
- 3. **Ajuda:**
221
- - "Me ajude a entender o portal da transparência"
222
- - "Quais tipos de dados posso consultar?"
223
- - "Como funciona a detecção de anomalias?"
224
-
225
- ## Tratamento de Erros
226
-
227
- O backend pode retornar diferentes tipos de respostas:
228
-
229
- 1. **Sucesso com Maritaca AI**: `model_used: "sabia-3"`
230
- 2. **Fallback (sem Maritaca)**: `model_used: "fallback"`
231
- 3. **Erro 500**: Sistema temporariamente indisponível
232
- 4. **Erro 422**: Dados de entrada inválidos
233
-
234
- ## Notas Importantes
235
-
236
- 1. **Session ID**: Mantenha o mesmo `session_id` para manter contexto da conversa
237
- 2. **Rate Limiting**: O backend tem limite de requisições por minuto
238
- 3. **Timeout**: Configure timeout de pelo menos 30 segundos para a Maritaca AI
239
- 4. **CORS**: Já configurado para aceitar requisições do Vercel
240
-
241
- ## Próximos Passos
242
-
243
- 1. Aguardar alguns minutos para o deploy no HuggingFace Spaces
244
- 2. Testar o endpoint `/api/v1/chat/simple`
245
- 3. Integrar no frontend Next.js
246
- 4. Adicionar tratamento de erros e loading states
247
- 5. Implementar persistência de sessão no localStorage
248
-
249
- ## Suporte
250
-
251
- Em caso de problemas:
252
- 1. Verifique o status em: `/api/v1/chat/simple/status`
253
- 2. Consulte os logs do HuggingFace Spaces
254
- 3. Use o endpoint fallback se a Maritaca estiver indisponível
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FRONTEND_STABLE_INTEGRATION.md DELETED
@@ -1,235 +0,0 @@
1
- # 🚀 Integração Frontend Estável - Cidadão.AI
2
-
3
- ## Solução para 100% de Disponibilidade
4
-
5
- ### Problema Identificado
6
- - Drummond funcionando em apenas 30% das requisições
7
- - Falhas em perguntas complexas (~15% sucesso)
8
- - Instabilidade no backend afetando experiência do usuário
9
-
10
- ### Solução Implementada
11
-
12
- Criamos um novo endpoint **ultra-estável** com múltiplas camadas de fallback:
13
-
14
- ```
15
- POST /api/v1/chat/stable
16
- ```
17
-
18
- ### Características
19
-
20
- 1. **3 Camadas de Fallback**:
21
- - **Camada 1**: Maritaca AI (LLM brasileiro)
22
- - **Camada 2**: Requisição HTTP direta para Maritaca
23
- - **Camada 3**: Respostas inteligentes baseadas em regras
24
-
25
- 2. **Garantia de Resposta**:
26
- - Sempre retorna uma resposta válida
27
- - Tempo de resposta consistente
28
- - Detecção de intent funciona sempre
29
-
30
- 3. **Respostas Contextualizadas**:
31
- - Diferentes respostas para cada tipo de intent
32
- - Múltiplas variações para evitar repetição
33
- - Foco em transparência pública
34
-
35
- ## Implementação no Frontend
36
-
37
- ### 1. Atualizar o Serviço de Chat
38
-
39
- ```typescript
40
- // services/chatService.ts
41
- export class ChatService {
42
- private readonly API_URL = process.env.NEXT_PUBLIC_API_URL || 'https://neural-thinker-cidadao-ai-backend.hf.space'
43
-
44
- async sendMessage(message: string, sessionId?: string): Promise<ChatResponse> {
45
- try {
46
- // Usar o novo endpoint estável
47
- const response = await fetch(`${this.API_URL}/api/v1/chat/stable`, {
48
- method: 'POST',
49
- headers: {
50
- 'Content-Type': 'application/json',
51
- },
52
- body: JSON.stringify({
53
- message,
54
- session_id: sessionId || `session_${Date.now()}`
55
- })
56
- })
57
-
58
- if (!response.ok) {
59
- throw new Error(`HTTP error! status: ${response.status}`)
60
- }
61
-
62
- return await response.json()
63
- } catch (error) {
64
- // Fallback local se API falhar
65
- return {
66
- session_id: sessionId || `session_${Date.now()}`,
67
- agent_id: 'system',
68
- agent_name: 'Sistema',
69
- message: 'Desculpe, estou com dificuldades técnicas. Por favor, tente novamente.',
70
- confidence: 0.0,
71
- suggested_actions: ['retry'],
72
- metadata: {
73
- error: true,
74
- local_fallback: true
75
- }
76
- }
77
- }
78
- }
79
- }
80
- ```
81
-
82
- ### 2. Componente de Chat Atualizado
83
-
84
- ```tsx
85
- // components/Chat.tsx
86
- import { useState } from 'react'
87
- import { ChatService } from '@/services/chatService'
88
-
89
- export function Chat() {
90
- const [messages, setMessages] = useState<Message[]>([])
91
- const [isLoading, setIsLoading] = useState(false)
92
- const chatService = new ChatService()
93
-
94
- const handleSendMessage = async (message: string) => {
95
- // Adicionar mensagem do usuário
96
- const userMessage = {
97
- id: Date.now().toString(),
98
- text: message,
99
- sender: 'user',
100
- timestamp: new Date()
101
- }
102
- setMessages(prev => [...prev, userMessage])
103
-
104
- setIsLoading(true)
105
-
106
- try {
107
- const response = await chatService.sendMessage(message)
108
-
109
- // Adicionar resposta do assistente
110
- const assistantMessage = {
111
- id: (Date.now() + 1).toString(),
112
- text: response.message,
113
- sender: response.agent_name,
114
- timestamp: new Date(),
115
- metadata: {
116
- confidence: response.confidence,
117
- agent_id: response.agent_id,
118
- backend_used: response.metadata?.agent_used || 'unknown'
119
- }
120
- }
121
-
122
- setMessages(prev => [...prev, assistantMessage])
123
-
124
- // Log para monitoramento
125
- console.log('Chat metrics:', {
126
- agent: response.agent_name,
127
- confidence: response.confidence,
128
- backend: response.metadata?.agent_used,
129
- stable_version: response.metadata?.stable_version
130
- })
131
-
132
- } catch (error) {
133
- console.error('Chat error:', error)
134
- // Erro já tratado no serviço
135
- } finally {
136
- setIsLoading(false)
137
- }
138
- }
139
-
140
- return (
141
- <div className="chat-container">
142
- {/* Renderizar mensagens */}
143
- {/* Renderizar input */}
144
- {/* Renderizar suggested actions */}
145
- </div>
146
- )
147
- }
148
- ```
149
-
150
- ### 3. Monitoramento de Performance
151
-
152
- ```typescript
153
- // utils/chatMetrics.ts
154
- export class ChatMetrics {
155
- private successCount = 0
156
- private totalCount = 0
157
- private backendStats = new Map<string, number>()
158
-
159
- recordResponse(response: ChatResponse) {
160
- this.totalCount++
161
-
162
- if (response.confidence > 0) {
163
- this.successCount++
164
- }
165
-
166
- const backend = response.metadata?.agent_used || 'unknown'
167
- this.backendStats.set(
168
- backend,
169
- (this.backendStats.get(backend) || 0) + 1
170
- )
171
- }
172
-
173
- getStats() {
174
- return {
175
- successRate: (this.successCount / this.totalCount) * 100,
176
- totalRequests: this.totalCount,
177
- backendUsage: Object.fromEntries(this.backendStats),
178
- timestamp: new Date()
179
- }
180
- }
181
- }
182
- ```
183
-
184
- ## Benefícios da Nova Solução
185
-
186
- 1. **100% Disponibilidade**: Sempre retorna resposta válida
187
- 2. **Tempo Consistente**: ~200-300ms para todas as requisições
188
- 3. **Fallback Inteligente**: Respostas contextualizadas mesmo sem LLM
189
- 4. **Transparente**: Frontend sabe qual backend foi usado
190
- 5. **Métricas**: Fácil monitorar qual camada está sendo usada
191
-
192
- ## Próximos Passos
193
-
194
- 1. **Deploy Imediato**:
195
- ```bash
196
- git add .
197
- git commit -m "feat: add ultra-stable chat endpoint with smart fallbacks"
198
- git push origin main
199
- git push huggingface main:main
200
- ```
201
-
202
- 2. **Frontend**:
203
- - Atualizar para usar `/api/v1/chat/stable`
204
- - Implementar métricas de monitoramento
205
- - Testar todas as scenarios
206
-
207
- 3. **Monitoramento**:
208
- - Acompanhar taxa de uso de cada backend
209
- - Ajustar fallbacks baseado em métricas
210
- - Otimizar respostas mais comuns
211
-
212
- ## Teste Rápido
213
-
214
- ```bash
215
- # Testar localmente
216
- curl -X POST http://localhost:8000/api/v1/chat/stable \
217
- -H "Content-Type: application/json" \
218
- -d '{"message": "Olá, como você pode me ajudar?"}'
219
-
220
- # Testar em produção (após deploy)
221
- curl -X POST https://neural-thinker-cidadao-ai-backend.hf.space/api/v1/chat/stable \
222
- -H "Content-Type: application/json" \
223
- -d '{"message": "Investigue contratos suspeitos"}'
224
- ```
225
-
226
- ## Garantia
227
-
228
- Este endpoint garante:
229
- - ✅ Sempre retorna resposta válida
230
- - ✅ Nunca retorna erro 500
231
- - ✅ Tempo de resposta < 500ms
232
- - ✅ Respostas relevantes para transparência pública
233
- - ✅ Detecção de intent funcionando 100%
234
-
235
- Com esta solução, o frontend terá **100% de estabilidade** independente do status dos serviços de AI!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
MARITACA_OPTIMIZATION_GUIDE.md DELETED
@@ -1,372 +0,0 @@
1
- # 🚀 Guia de Otimização Maritaca AI - Cidadão.AI
2
-
3
- ## Resumo das Melhorias
4
-
5
- ### 1. Novo Endpoint Otimizado
6
- - **URL**: `/api/v1/chat/optimized`
7
- - **Modelo**: Sabiazinho-3 (mais econômico)
8
- - **Persona**: Carlos Drummond de Andrade
9
- - **Economia**: ~40-50% menor custo por requisição
10
-
11
- ### 2. Comparação de Modelos
12
-
13
- | Modelo | Custo | Qualidade | Tempo Resposta | Uso Recomendado |
14
- |--------|-------|-----------|----------------|-----------------|
15
- | Sabiazinho-3 | 💰 | ⭐⭐⭐⭐ | 1-5s | Conversas gerais, saudações |
16
- | Sabiá-3 | 💰💰💰 | ⭐⭐⭐⭐⭐ | 3-15s | Análises complexas |
17
-
18
- ### 3. Endpoints Disponíveis
19
-
20
- ```bash
21
- # 1. Simple (Sabiá-3) - FUNCIONANDO 100%
22
- POST /api/v1/chat/simple
23
-
24
- # 2. Stable (Multi-fallback) - NOVO
25
- POST /api/v1/chat/stable
26
-
27
- # 3. Optimized (Sabiazinho-3 + Drummond) - NOVO
28
- POST /api/v1/chat/optimized
29
- ```
30
-
31
- ## Integração Frontend - Versão Otimizada
32
-
33
- ### Serviço de Chat Atualizado
34
-
35
- ```typescript
36
- // services/chatService.ts
37
- export interface ChatEndpoint {
38
- url: string;
39
- name: string;
40
- priority: number;
41
- model: string;
42
- }
43
-
44
- export class ChatService {
45
- private readonly API_URL = process.env.NEXT_PUBLIC_API_URL
46
-
47
- private endpoints: ChatEndpoint[] = [
48
- {
49
- url: '/api/v1/chat/optimized',
50
- name: 'Optimized (Sabiazinho)',
51
- priority: 1,
52
- model: 'sabiazinho-3'
53
- },
54
- {
55
- url: '/api/v1/chat/simple',
56
- name: 'Simple (Sabiá-3)',
57
- priority: 2,
58
- model: 'sabia-3'
59
- },
60
- {
61
- url: '/api/v1/chat/stable',
62
- name: 'Stable (Fallback)',
63
- priority: 3,
64
- model: 'mixed'
65
- }
66
- ]
67
-
68
- async sendMessage(
69
- message: string,
70
- options?: {
71
- preferredModel?: 'economic' | 'quality';
72
- useDrummond?: boolean;
73
- }
74
- ): Promise<ChatResponse> {
75
- const sessionId = `session_${Date.now()}`
76
-
77
- // Select endpoint based on preference
78
- let selectedEndpoints = [...this.endpoints]
79
-
80
- if (options?.preferredModel === 'economic') {
81
- // Prioritize Sabiazinho
82
- selectedEndpoints.sort((a, b) =>
83
- a.model === 'sabiazinho-3' ? -1 : 1
84
- )
85
- } else if (options?.preferredModel === 'quality') {
86
- // Prioritize Sabiá-3
87
- selectedEndpoints.sort((a, b) =>
88
- a.model === 'sabia-3' ? -1 : 1
89
- )
90
- }
91
-
92
- // Try endpoints in order
93
- for (const endpoint of selectedEndpoints) {
94
- try {
95
- const body: any = { message, session_id: sessionId }
96
-
97
- // Add Drummond flag for optimized endpoint
98
- if (endpoint.url.includes('optimized')) {
99
- body.use_drummond = options?.useDrummond ?? true
100
- }
101
-
102
- const response = await fetch(`${this.API_URL}${endpoint.url}`, {
103
- method: 'POST',
104
- headers: { 'Content-Type': 'application/json' },
105
- body: JSON.stringify(body)
106
- })
107
-
108
- if (response.ok) {
109
- const data = await response.json()
110
- console.log(`✅ Success with ${endpoint.name}`)
111
- return data
112
- }
113
- } catch (error) {
114
- console.warn(`Failed ${endpoint.name}:`, error)
115
- }
116
- }
117
-
118
- // Ultimate fallback
119
- return {
120
- message: 'Desculpe, estou temporariamente indisponível.',
121
- session_id: sessionId,
122
- agent_name: 'Sistema',
123
- agent_id: 'system',
124
- confidence: 0,
125
- metadata: { fallback: true }
126
- }
127
- }
128
-
129
- // Analyze message to decide best model
130
- analyzeComplexity(message: string): 'simple' | 'complex' {
131
- const complexKeywords = [
132
- 'analise', 'investigue', 'compare', 'tendência',
133
- 'padrão', 'anomalia', 'detalhe', 'relatório'
134
- ]
135
-
136
- const hasComplexKeyword = complexKeywords.some(
137
- keyword => message.toLowerCase().includes(keyword)
138
- )
139
-
140
- return hasComplexKeyword || message.length > 100
141
- ? 'complex'
142
- : 'simple'
143
- }
144
- }
145
- ```
146
-
147
- ### Componente Inteligente
148
-
149
- ```tsx
150
- // components/SmartChat.tsx
151
- export function SmartChat() {
152
- const [messages, setMessages] = useState<Message[]>([])
153
- const [modelPreference, setModelPreference] = useState<'auto' | 'economic' | 'quality'>('auto')
154
- const chatService = new ChatService()
155
-
156
- const handleSendMessage = async (text: string) => {
157
- // Add user message
158
- const userMessage = createUserMessage(text)
159
- setMessages(prev => [...prev, userMessage])
160
-
161
- // Analyze complexity for auto mode
162
- let preference: 'economic' | 'quality' | undefined
163
-
164
- if (modelPreference === 'auto') {
165
- const complexity = chatService.analyzeComplexity(text)
166
- preference = complexity === 'simple' ? 'economic' : 'quality'
167
- } else if (modelPreference !== 'auto') {
168
- preference = modelPreference
169
- }
170
-
171
- // Send with appropriate model
172
- const response = await chatService.sendMessage(text, {
173
- preferredModel: preference,
174
- useDrummond: true // Enable cultural persona
175
- })
176
-
177
- // Add response
178
- const assistantMessage = {
179
- ...createAssistantMessage(response),
180
- metadata: {
181
- ...response.metadata,
182
- model_preference: preference,
183
- actual_model: response.model_used
184
- }
185
- }
186
-
187
- setMessages(prev => [...prev, assistantMessage])
188
-
189
- // Log for monitoring
190
- logChatMetrics({
191
- model_used: response.model_used,
192
- response_time: response.metadata?.response_time_ms,
193
- tokens: response.metadata?.tokens_used,
194
- success: true
195
- })
196
- }
197
-
198
- return (
199
- <div className="smart-chat">
200
- {/* Model preference selector */}
201
- <div className="model-selector">
202
- <label>Modo:</label>
203
- <select
204
- value={modelPreference}
205
- onChange={(e) => setModelPreference(e.target.value as any)}
206
- >
207
- <option value="auto">Automático</option>
208
- <option value="economic">Econômico (Sabiazinho)</option>
209
- <option value="quality">Qualidade (Sabiá-3)</option>
210
- </select>
211
- </div>
212
-
213
- {/* Chat messages */}
214
- <MessageList messages={messages} />
215
-
216
- {/* Input */}
217
- <ChatInput onSend={handleSendMessage} />
218
-
219
- {/* Status indicator */}
220
- <ChatStatus
221
- lastModel={messages[messages.length - 1]?.metadata?.actual_model}
222
- preference={modelPreference}
223
- />
224
- </div>
225
- )
226
- }
227
- ```
228
-
229
- ## Otimizações de Custo
230
-
231
- ### 1. Cache Inteligente
232
- ```typescript
233
- class CachedChatService extends ChatService {
234
- private cache = new Map<string, CachedResponse>()
235
-
236
- async sendMessage(message: string, options?: any) {
237
- // Check cache for common questions
238
- const cacheKey = this.normalizeMessage(message)
239
- const cached = this.cache.get(cacheKey)
240
-
241
- if (cached && !this.isExpired(cached)) {
242
- return {
243
- ...cached.response,
244
- metadata: {
245
- ...cached.response.metadata,
246
- from_cache: true
247
- }
248
- }
249
- }
250
-
251
- // Get fresh response
252
- const response = await super.sendMessage(message, options)
253
-
254
- // Cache if successful
255
- if (response.confidence > 0.8) {
256
- this.cache.set(cacheKey, {
257
- response,
258
- timestamp: Date.now()
259
- })
260
- }
261
-
262
- return response
263
- }
264
- }
265
- ```
266
-
267
- ### 2. Batching de Requisições
268
- ```typescript
269
- class BatchedChatService extends ChatService {
270
- private queue: QueuedMessage[] = []
271
- private timer: NodeJS.Timeout | null = null
272
-
273
- async sendMessage(message: string, options?: any) {
274
- return new Promise((resolve) => {
275
- this.queue.push({ message, options, resolve })
276
-
277
- if (!this.timer) {
278
- this.timer = setTimeout(() => this.processBatch(), 100)
279
- }
280
- })
281
- }
282
-
283
- private async processBatch() {
284
- const batch = this.queue.splice(0, 5) // Max 5 per batch
285
-
286
- // Send all at once (if API supports)
287
- const responses = await this.sendBatch(batch)
288
-
289
- // Resolve individual promises
290
- batch.forEach((item, index) => {
291
- item.resolve(responses[index])
292
- })
293
-
294
- this.timer = null
295
- }
296
- }
297
- ```
298
-
299
- ## Métricas e Monitoramento
300
-
301
- ```typescript
302
- // utils/chatMetrics.ts
303
- export class ChatMetricsCollector {
304
- private metrics = {
305
- totalRequests: 0,
306
- modelUsage: new Map<string, number>(),
307
- avgResponseTime: 0,
308
- totalTokens: 0,
309
- errorRate: 0,
310
- cacheHitRate: 0
311
- }
312
-
313
- recordMetric(data: ChatMetric) {
314
- this.metrics.totalRequests++
315
-
316
- // Track model usage
317
- const model = data.model_used || 'unknown'
318
- this.metrics.modelUsage.set(
319
- model,
320
- (this.metrics.modelUsage.get(model) || 0) + 1
321
- )
322
-
323
- // Update averages
324
- this.updateAverages(data)
325
-
326
- // Send to analytics (optional)
327
- if (window.gtag) {
328
- window.gtag('event', 'chat_interaction', {
329
- model_used: model,
330
- response_time: data.response_time,
331
- success: !data.error
332
- })
333
- }
334
- }
335
-
336
- getCostEstimate(): number {
337
- const sabiazinhoCost = 0.001 // per request
338
- const sabia3Cost = 0.003 // per request
339
-
340
- const sabiazinhoCount = this.metrics.modelUsage.get('sabiazinho-3') || 0
341
- const sabia3Count = this.metrics.modelUsage.get('sabia-3') || 0
342
-
343
- return (sabiazinhoCount * sabiazinhoCost) + (sabia3Count * sabia3Cost)
344
- }
345
-
346
- getReport() {
347
- return {
348
- ...this.metrics,
349
- estimatedCost: this.getCostEstimate(),
350
- modelDistribution: Object.fromEntries(this.metrics.modelUsage)
351
- }
352
- }
353
- }
354
- ```
355
-
356
- ## Recomendações de Uso
357
-
358
- ### Para o Frontend:
359
- 1. **Perguntas Simples/Saudações**: Use Sabiazinho (economic mode)
360
- 2. **Análises Complexas**: Use Sabiá-3 (quality mode)
361
- 3. **Auto Mode**: Deixa o sistema decidir baseado na complexidade
362
-
363
- ### Economia Estimada:
364
- - Conversas simples: 40-50% economia usando Sabiazinho
365
- - Mix típico (70% simples, 30% complexo): ~35% economia total
366
- - Com cache: Adicional 10-20% economia
367
-
368
- ### Próximos Passos:
369
- 1. Implementar cache para perguntas frequentes
370
- 2. Adicionar análise de sentimento para ajustar tom
371
- 3. Criar dashboards de custo em tempo real
372
- 4. A/B testing entre modelos
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_simple.py DELETED
@@ -1,706 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Cidadão.AI Backend - Expanded Version with Multiple Data Sources
4
- Supports: Contracts, Servants, Expenses, Biddings, and more
5
- """
6
-
7
- import asyncio
8
- import logging
9
- import os
10
- import sys
11
- import time
12
- import traceback
13
- import hashlib
14
- from contextlib import asynccontextmanager
15
- from typing import Any, Dict, List, Optional, Union
16
- from datetime import datetime, timedelta
17
- from enum import Enum
18
-
19
- import uvicorn
20
- from fastapi import FastAPI, HTTPException, status, Query
21
- from fastapi.middleware.cors import CORSMiddleware
22
- from fastapi.responses import JSONResponse
23
- from pydantic import BaseModel, Field
24
- from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
25
-
26
- # Configure logging
27
- logging.basicConfig(
28
- level=logging.INFO,
29
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
30
- )
31
- logger = logging.getLogger(__name__)
32
-
33
- # ==================== DATA MODELS ====================
34
-
35
- class DataSourceType(str, Enum):
36
- """Types of data sources available."""
37
- CONTRACTS = "contratos"
38
- SERVANTS = "servidores"
39
- EXPENSES = "despesas"
40
- BIDDINGS = "licitacoes"
41
- AGREEMENTS = "convenios"
42
- SANCTIONS = "empresas-sancionadas"
43
-
44
- class HealthResponse(BaseModel):
45
- """Health check response model."""
46
- status: str = "healthy"
47
- version: str = "2.0.0"
48
- agents: Dict[str, str] = Field(default_factory=lambda: {"zumbi": "active"})
49
- data_sources: List[str] = Field(default_factory=lambda: [e.value for e in DataSourceType])
50
- uptime: str = "operational"
51
-
52
- class UniversalSearchRequest(BaseModel):
53
- """Universal search request for any data type."""
54
- query: str = Field(..., description="Search query")
55
- data_source: DataSourceType = Field(..., description="Type of data to search")
56
- filters: Dict[str, Any] = Field(default_factory=dict, description="Additional filters")
57
- max_results: int = Field(default=100, ge=1, le=500, description="Maximum results")
58
-
59
- class ServantData(BaseModel):
60
- """Servant/Employee data model."""
61
- nome: str
62
- cpf_masked: str
63
- matricula: str
64
- orgao: str
65
- cargo: str
66
- funcao: Optional[str] = None
67
- remuneracao: Dict[str, float]
68
- mes_ano_referencia: str
69
-
70
- class ContractData(BaseModel):
71
- """Contract data model."""
72
- id: str
73
- numero: str
74
- objeto: str
75
- valor: float
76
- fornecedor: Dict[str, str]
77
- orgao: str
78
- data_assinatura: str
79
- vigencia: Dict[str, str]
80
- modalidade: Optional[str] = None
81
-
82
- class ExpenseData(BaseModel):
83
- """Expense data model."""
84
- id: str
85
- descricao: str
86
- valor: float
87
- favorecido: Dict[str, str]
88
- orgao: str
89
- data: str
90
- programa: Optional[str] = None
91
- acao: Optional[str] = None
92
-
93
- class UniversalSearchResponse(BaseModel):
94
- """Universal search response."""
95
- status: str
96
- data_source: str
97
- query: str
98
- results: List[Union[ServantData, ContractData, ExpenseData, Dict[str, Any]]]
99
- total_found: int
100
- anomalies_detected: int
101
- confidence_score: float
102
- processing_time_ms: int
103
- metadata: Dict[str, Any] = Field(default_factory=dict)
104
-
105
- # ==================== CACHE ====================
106
-
107
- class SimpleCache:
108
- """In-memory cache for API responses with TTL."""
109
-
110
- def __init__(self):
111
- self._cache: Dict[str, Dict] = {}
112
- self._ttl_cache: Dict[str, datetime] = {}
113
- self.default_ttl = 3600 # 1 hour
114
-
115
- def _generate_key(self, **kwargs) -> str:
116
- """Generate cache key from parameters."""
117
- key_string = "&".join([f"{k}={v}" for k, v in sorted(kwargs.items())])
118
- return hashlib.md5(key_string.encode()).hexdigest()
119
-
120
- def get(self, **kwargs) -> Optional[Dict]:
121
- """Get cached value if not expired."""
122
- key = self._generate_key(**kwargs)
123
-
124
- if key not in self._cache:
125
- return None
126
-
127
- if key in self._ttl_cache:
128
- if datetime.now() > self._ttl_cache[key]:
129
- del self._cache[key]
130
- del self._ttl_cache[key]
131
- return None
132
-
133
- return self._cache[key]
134
-
135
- def set(self, value: Dict, ttl_seconds: int = None, **kwargs) -> None:
136
- """Set cached value with TTL."""
137
- key = self._generate_key(**kwargs)
138
- self._cache[key] = value
139
-
140
- ttl = ttl_seconds or self.default_ttl
141
- self._ttl_cache[key] = datetime.now() + timedelta(seconds=ttl)
142
-
143
- # Global cache instance
144
- api_cache = SimpleCache()
145
-
146
- # ==================== ENHANCED ZUMBI AGENT ====================
147
-
148
- class EnhancedZumbiAgent:
149
- """Enhanced Zumbi agent that can investigate multiple data sources."""
150
-
151
- def __init__(self):
152
- self.name = "Zumbi dos Palmares"
153
- self.role = "Universal Investigator"
154
- self.specialty = "Multi-source anomaly detection"
155
- logger.info(f"🏹 {self.name} - Enhanced {self.role} initialized")
156
-
157
- async def investigate_universal(self, request: UniversalSearchRequest) -> UniversalSearchResponse:
158
- """Investigate any data source."""
159
- import os
160
- import numpy as np
161
- from collections import defaultdict
162
- start_time = time.time()
163
-
164
- try:
165
- # Get API key
166
- api_key = os.getenv("TRANSPARENCY_API_KEY")
167
- if not api_key:
168
- logger.warning("⚠️ No API key, using demo data")
169
- return await self._get_demo_data(request, start_time)
170
-
171
- # Route to appropriate handler
172
- if request.data_source == DataSourceType.SERVANTS:
173
- return await self._search_servants(request, api_key, start_time)
174
- elif request.data_source == DataSourceType.CONTRACTS:
175
- return await self._search_contracts(request, api_key, start_time)
176
- elif request.data_source == DataSourceType.EXPENSES:
177
- return await self._search_expenses(request, api_key, start_time)
178
- elif request.data_source == DataSourceType.BIDDINGS:
179
- return await self._search_biddings(request, api_key, start_time)
180
- else:
181
- return await self._search_generic(request, api_key, start_time)
182
-
183
- except Exception as e:
184
- logger.error(f"Investigation error: {str(e)}")
185
- return UniversalSearchResponse(
186
- status="error",
187
- data_source=request.data_source.value,
188
- query=request.query,
189
- results=[],
190
- total_found=0,
191
- anomalies_detected=0,
192
- confidence_score=0.0,
193
- processing_time_ms=int((time.time() - start_time) * 1000),
194
- metadata={"error": str(e)}
195
- )
196
-
197
- async def _search_servants(self, request: UniversalSearchRequest, api_key: str, start_time: float) -> UniversalSearchResponse:
198
- """Search for government servants."""
199
- import httpx
200
-
201
- # Check cache first
202
- cache_key = f"servants_{request.query}_{request.max_results}"
203
- cached = api_cache.get(source=cache_key)
204
- if cached:
205
- logger.info("📦 Using cached servants data")
206
- return cached
207
-
208
- results = []
209
- anomalies = 0
210
-
211
- async with httpx.AsyncClient(timeout=30.0) as client:
212
- url = "https://api.portaldatransparencia.gov.br/api-de-dados/servidores"
213
- headers = {
214
- "chave-api-dados": api_key,
215
- "Accept": "application/json"
216
- }
217
- params = {
218
- "nome": request.query.upper(),
219
- "pagina": 1,
220
- "tamanhoPagina": min(request.max_results, 50)
221
- }
222
-
223
- # Add filters from request
224
- if "orgao" in request.filters:
225
- params["orgao"] = request.filters["orgao"]
226
- if "funcao" in request.filters:
227
- params["funcao"] = request.filters["funcao"]
228
-
229
- response = await client.get(url, headers=headers, params=params)
230
-
231
- if response.status_code == 200:
232
- data = response.json()
233
-
234
- # Process servants
235
- for item in data:
236
- servant_info = item.get("servidor", {})
237
- org_info = item.get("unidadeOrganizacional", {})
238
-
239
- # Extract salary info
240
- salary = item.get("remuneracaoBasicaBruta", 0)
241
- total = item.get("remuneracaoAposDeducoes", 0)
242
-
243
- # Detect anomalies (e.g., very high salaries)
244
- if salary > 40000: # Above R$ 40k is unusual
245
- anomalies += 1
246
-
247
- servant = ServantData(
248
- nome=servant_info.get("nome", "N/A"),
249
- cpf_masked=servant_info.get("cpf", "***.***.***-**"),
250
- matricula=servant_info.get("matricula", "N/A"),
251
- orgao=org_info.get("nomeUnidade", "N/A"),
252
- cargo=item.get("cargo", {}).get("descricao", "N/A"),
253
- funcao=item.get("funcao", {}).get("descricao"),
254
- remuneracao={
255
- "basica": salary,
256
- "total_liquido": total,
257
- "gratificacoes": item.get("gratificacoes", 0),
258
- "auxilios": item.get("auxilios", 0)
259
- },
260
- mes_ano_referencia=f"{item.get('mesReferencia', 'N/A')}/{item.get('anoReferencia', 'N/A')}"
261
- )
262
- results.append(servant.dict())
263
-
264
- response_data = UniversalSearchResponse(
265
- status="success",
266
- data_source=request.data_source.value,
267
- query=request.query,
268
- results=results,
269
- total_found=len(results),
270
- anomalies_detected=anomalies,
271
- confidence_score=0.95,
272
- processing_time_ms=int((time.time() - start_time) * 1000),
273
- metadata={"source": "real_api", "anomaly_threshold": 40000}
274
- )
275
-
276
- # Cache the response
277
- api_cache.set(response_data.dict(), source=cache_key)
278
-
279
- return response_data
280
- else:
281
- raise HTTPException(status_code=response.status_code, detail="API request failed")
282
-
283
- async def _search_contracts(self, request: UniversalSearchRequest, api_key: str, start_time: float) -> UniversalSearchResponse:
284
- """Search for contracts with anomaly detection."""
285
- import httpx
286
- import numpy as np
287
-
288
- results = []
289
- anomalies = 0
290
-
291
- async with httpx.AsyncClient(timeout=30.0) as client:
292
- # Search multiple organizations
293
- org_codes = request.filters.get("orgaos", ["26000", "25000", "44000"])
294
-
295
- all_contracts = []
296
- for org_code in org_codes[:3]: # Limit to 3 orgs
297
- url = "https://api.portaldatransparencia.gov.br/api-de-dados/contratos"
298
- headers = {
299
- "chave-api-dados": api_key,
300
- "Accept": "application/json"
301
- }
302
- params = {
303
- "codigoOrgao": org_code,
304
- "ano": request.filters.get("ano", 2024),
305
- "tamanhoPagina": 50
306
- }
307
-
308
- # Add search term if provided
309
- if request.query and request.query.lower() != "todos":
310
- params["descricao"] = request.query
311
-
312
- response = await client.get(url, headers=headers, params=params)
313
-
314
- if response.status_code == 200:
315
- contracts = response.json()
316
- all_contracts.extend(contracts)
317
-
318
- # Analyze contracts for anomalies
319
- if all_contracts:
320
- values = [c.get("valorInicial", 0) for c in all_contracts if c.get("valorInicial", 0) > 0]
321
-
322
- if len(values) > 3:
323
- mean_val = np.mean(values)
324
- std_val = np.std(values)
325
-
326
- for contract in all_contracts[:request.max_results]:
327
- valor = contract.get("valorInicial", 0)
328
- z_score = abs((valor - mean_val) / std_val) if std_val > 0 else 0
329
-
330
- # Flag as anomaly if z-score > 1.5
331
- is_anomaly = z_score > 1.5
332
- if is_anomaly:
333
- anomalies += 1
334
-
335
- contract_data = {
336
- "id": contract.get("id", "N/A"),
337
- "numero": contract.get("numero", "N/A"),
338
- "objeto": contract.get("objeto", "N/A")[:200],
339
- "valor": valor,
340
- "fornecedor": {
341
- "nome": contract.get("nomeFornecedor", "N/A"),
342
- "cnpj": contract.get("cnpjFornecedor", "N/A")
343
- },
344
- "orgao": contract.get("nomeOrgao", org_code),
345
- "data_assinatura": contract.get("dataAssinatura", "N/A"),
346
- "vigencia": {
347
- "inicio": contract.get("dataInicioVigencia", "N/A"),
348
- "fim": contract.get("dataFimVigencia", "N/A")
349
- },
350
- "modalidade": contract.get("modalidadeCompra", "N/A"),
351
- "_anomaly": is_anomaly,
352
- "_z_score": z_score
353
- }
354
- results.append(contract_data)
355
-
356
- return UniversalSearchResponse(
357
- status="success",
358
- data_source=request.data_source.value,
359
- query=request.query,
360
- results=results,
361
- total_found=len(results),
362
- anomalies_detected=anomalies,
363
- confidence_score=0.87,
364
- processing_time_ms=int((time.time() - start_time) * 1000),
365
- metadata={
366
- "organizations_searched": org_codes[:3],
367
- "anomaly_method": "z_score",
368
- "threshold": 1.5
369
- }
370
- )
371
-
372
- async def _search_expenses(self, request: UniversalSearchRequest, api_key: str, start_time: float) -> UniversalSearchResponse:
373
- """Search for government expenses."""
374
- import httpx
375
-
376
- results = []
377
- anomalies = 0
378
-
379
- async with httpx.AsyncClient(timeout=30.0) as client:
380
- url = "https://api.portaldatransparencia.gov.br/api-de-dados/despesas"
381
- headers = {
382
- "chave-api-dados": api_key,
383
- "Accept": "application/json"
384
- }
385
- params = {
386
- "ano": request.filters.get("ano", 2024),
387
- "mes": request.filters.get("mes", 12),
388
- "pagina": 1,
389
- "tamanhoPagina": min(request.max_results, 50)
390
- }
391
-
392
- if "orgao" in request.filters:
393
- params["orgao"] = request.filters["orgao"]
394
-
395
- response = await client.get(url, headers=headers, params=params)
396
-
397
- if response.status_code == 200:
398
- data = response.json()
399
-
400
- for expense in data:
401
- valor = expense.get("valor", 0)
402
-
403
- # Simple anomaly detection for high values
404
- if valor > 1000000: # Above 1M
405
- anomalies += 1
406
-
407
- expense_data = ExpenseData(
408
- id=expense.get("id", "N/A"),
409
- descricao=expense.get("descricao", "N/A"),
410
- valor=valor,
411
- favorecido={
412
- "nome": expense.get("nomeFavorecido", "N/A"),
413
- "codigo": expense.get("codigoFavorecido", "N/A")
414
- },
415
- orgao=expense.get("nomeOrgao", "N/A"),
416
- data=expense.get("data", "N/A"),
417
- programa=expense.get("nomePrograma"),
418
- acao=expense.get("nomeAcao")
419
- )
420
- results.append(expense_data.dict())
421
-
422
- return UniversalSearchResponse(
423
- status="success",
424
- data_source=request.data_source.value,
425
- query=request.query,
426
- results=results,
427
- total_found=len(results),
428
- anomalies_detected=anomalies,
429
- confidence_score=0.85,
430
- processing_time_ms=int((time.time() - start_time) * 1000),
431
- metadata={"high_value_threshold": 1000000}
432
- )
433
- else:
434
- raise HTTPException(status_code=response.status_code, detail="API request failed")
435
-
436
- async def _search_biddings(self, request: UniversalSearchRequest, api_key: str, start_time: float) -> UniversalSearchResponse:
437
- """Search for biddings/licitações."""
438
- # Implementation similar to contracts
439
- # For brevity, returning a simplified response
440
- return UniversalSearchResponse(
441
- status="success",
442
- data_source=request.data_source.value,
443
- query=request.query,
444
- results=[],
445
- total_found=0,
446
- anomalies_detected=0,
447
- confidence_score=0.8,
448
- processing_time_ms=int((time.time() - start_time) * 1000),
449
- metadata={"note": "Biddings endpoint to be implemented"}
450
- )
451
-
452
- async def _search_generic(self, request: UniversalSearchRequest, api_key: str, start_time: float) -> UniversalSearchResponse:
453
- """Generic search for other data types."""
454
- return UniversalSearchResponse(
455
- status="success",
456
- data_source=request.data_source.value,
457
- query=request.query,
458
- results=[],
459
- total_found=0,
460
- anomalies_detected=0,
461
- confidence_score=0.7,
462
- processing_time_ms=int((time.time() - start_time) * 1000),
463
- metadata={"note": f"Generic handler for {request.data_source.value}"}
464
- )
465
-
466
- async def _get_demo_data(self, request: UniversalSearchRequest, start_time: float) -> UniversalSearchResponse:
467
- """Return demo data when no API key is available."""
468
- demo_results = []
469
-
470
- if request.data_source == DataSourceType.SERVANTS:
471
- demo_results = [{
472
- "nome": "MARIA DA SILVA",
473
- "cpf_masked": "***.***.***-**",
474
- "matricula": "1234567",
475
- "orgao": "MINISTERIO DA SAUDE",
476
- "cargo": "ANALISTA",
477
- "funcao": "ANALISTA TECNICO",
478
- "remuneracao": {
479
- "basica": 8500.00,
480
- "total_liquido": 9876.54,
481
- "gratificacoes": 2000.00,
482
- "auxilios": 458.00
483
- },
484
- "mes_ano_referencia": "12/2024"
485
- }]
486
- elif request.data_source == DataSourceType.CONTRACTS:
487
- demo_results = [{
488
- "id": "demo-001",
489
- "numero": "2024/001",
490
- "objeto": "Contrato demonstrativo para testes",
491
- "valor": 150000.00,
492
- "fornecedor": {
493
- "nome": "EMPRESA DEMO LTDA",
494
- "cnpj": "00.000.000/0001-00"
495
- },
496
- "orgao": "ORGAO DEMONSTRATIVO",
497
- "data_assinatura": "01/01/2024",
498
- "vigencia": {
499
- "inicio": "01/01/2024",
500
- "fim": "31/12/2024"
501
- },
502
- "modalidade": "Pregão Eletrônico",
503
- "_anomaly": False,
504
- "_z_score": 0.5
505
- }]
506
-
507
- return UniversalSearchResponse(
508
- status="demo",
509
- data_source=request.data_source.value,
510
- query=request.query,
511
- results=demo_results,
512
- total_found=len(demo_results),
513
- anomalies_detected=0,
514
- confidence_score=0.5,
515
- processing_time_ms=int((time.time() - start_time) * 1000),
516
- metadata={"mode": "demo", "message": "Configure TRANSPARENCY_API_KEY for real data"}
517
- )
518
-
519
- # ==================== FASTAPI APP ====================
520
-
521
- # Create agent instance
522
- enhanced_zumbi = EnhancedZumbiAgent()
523
-
524
- # Lifespan context manager
525
- @asynccontextmanager
526
- async def lifespan(app: FastAPI):
527
- logger.info("🏛️ Cidadão.AI Enhanced Backend starting up...")
528
- logger.info("🏹 Enhanced Zumbi agent ready for multi-source investigations")
529
- yield
530
- logger.info("👋 Cidadão.AI Enhanced Backend shutting down...")
531
-
532
- # Create FastAPI app
533
- app = FastAPI(
534
- title="Cidadão.AI Enhanced Backend",
535
- description="Multi-source government transparency analysis with AI",
536
- version="2.0.0",
537
- docs_url="/docs",
538
- redoc_url="/redoc",
539
- lifespan=lifespan
540
- )
541
-
542
- # Add CORS middleware
543
- app.add_middleware(
544
- CORSMiddleware,
545
- allow_origins=["*"],
546
- allow_credentials=True,
547
- allow_methods=["*"],
548
- allow_headers=["*"],
549
- )
550
-
551
- # Add compression middleware for better performance
552
- from src.api.middleware.compression import add_compression_middleware
553
- add_compression_middleware(
554
- app,
555
- minimum_size=1024, # Compress responses larger than 1KB
556
- gzip_level=6, # Good balance of speed vs compression
557
- brotli_quality=4, # Fast brotli compression
558
- exclude_paths={"/health", "/metrics", "/health/metrics"}
559
- )
560
-
561
- # ==================== ENDPOINTS ====================
562
-
563
- @app.get("/", response_model=HealthResponse)
564
- async def root():
565
- """Root endpoint with system status."""
566
- return HealthResponse()
567
-
568
- @app.get("/health", response_model=HealthResponse)
569
- async def health_check():
570
- """Health check endpoint."""
571
- return HealthResponse()
572
-
573
- @app.post("/api/investigate", response_model=UniversalSearchResponse)
574
- async def investigate_universal(request: UniversalSearchRequest):
575
- """
576
- Universal investigation endpoint for any data source.
577
-
578
- Example queries:
579
- - Servants: {"query": "João Silva", "data_source": "servidores"}
580
- - Contracts: {"query": "informática", "data_source": "contratos"}
581
- - Expenses: {"query": "todos", "data_source": "despesas", "filters": {"mes": 12}}
582
- """
583
- try:
584
- result = await enhanced_zumbi.investigate_universal(request)
585
- return result
586
- except Exception as e:
587
- logger.error(f"Investigation error: {str(e)}")
588
- raise HTTPException(
589
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
590
- detail=f"Investigation failed: {str(e)}"
591
- )
592
-
593
- @app.get("/api/data-sources")
594
- async def list_data_sources():
595
- """List all available data sources."""
596
- return {
597
- "sources": [
598
- {
599
- "id": ds.value,
600
- "name": ds.name,
601
- "description": {
602
- DataSourceType.CONTRACTS: "Government contracts and procurements",
603
- DataSourceType.SERVANTS: "Public servants and their salaries",
604
- DataSourceType.EXPENSES: "Government expenses and payments",
605
- DataSourceType.BIDDINGS: "Public biddings and auctions",
606
- DataSourceType.AGREEMENTS: "Government agreements and partnerships",
607
- DataSourceType.SANCTIONS: "Sanctioned companies"
608
- }.get(ds, "Data source")
609
- }
610
- for ds in DataSourceType
611
- ]
612
- }
613
-
614
- @app.get("/api/search/servants")
615
- async def search_servants_quick(
616
- nome: str = Query(..., description="Nome do servidor"),
617
- orgao: Optional[str] = Query(None, description="Código do órgão"),
618
- limit: int = Query(10, ge=1, le=50, description="Limite de resultados")
619
- ):
620
- """Quick endpoint to search servants by name."""
621
- request = UniversalSearchRequest(
622
- query=nome,
623
- data_source=DataSourceType.SERVANTS,
624
- filters={"orgao": orgao} if orgao else {},
625
- max_results=limit
626
- )
627
- return await investigate_universal(request)
628
-
629
- @app.get("/api/search/contracts")
630
- async def search_contracts_quick(
631
- query: str = Query("todos", description="Termo de busca"),
632
- orgao: Optional[str] = Query(None, description="Código do órgão"),
633
- ano: int = Query(2024, description="Ano"),
634
- limit: int = Query(50, ge=1, le=100, description="Limite de resultados")
635
- ):
636
- """Quick endpoint to search contracts."""
637
- request = UniversalSearchRequest(
638
- query=query,
639
- data_source=DataSourceType.CONTRACTS,
640
- filters={"orgaos": [orgao] if orgao else ["26000", "25000"], "ano": ano},
641
- max_results=limit
642
- )
643
- return await investigate_universal(request)
644
-
645
- @app.get("/api/cache/stats")
646
- async def cache_stats():
647
- """Get cache statistics."""
648
- return {
649
- "cache_size": len(api_cache._cache),
650
- "active_entries": len([k for k, v in api_cache._ttl_cache.items() if v > datetime.now()]),
651
- "ttl_seconds": api_cache.default_ttl
652
- }
653
-
654
- # Debug endpoint for Drummond issue
655
- @app.get("/debug/drummond-status")
656
- async def debug_drummond_status():
657
- """Debug endpoint to check Drummond agent status."""
658
- import traceback
659
-
660
- result = {
661
- "python_version": sys.version,
662
- "checks": {}
663
- }
664
-
665
- # Check if we can import CommunicationAgent
666
- try:
667
- from src.agents.drummond import CommunicationAgent
668
- abstract_methods = getattr(CommunicationAgent, '__abstractmethods__', set())
669
- result["checks"]["import"] = {
670
- "status": "success",
671
- "abstract_methods": list(abstract_methods) if abstract_methods else "none",
672
- "has_shutdown": hasattr(CommunicationAgent, 'shutdown'),
673
- "has_initialize": hasattr(CommunicationAgent, 'initialize'),
674
- "has_process": hasattr(CommunicationAgent, 'process')
675
- }
676
-
677
- # Try to instantiate
678
- try:
679
- agent = CommunicationAgent()
680
- result["checks"]["instantiation"] = {"status": "success", "agent_name": agent.name}
681
- except Exception as e:
682
- result["checks"]["instantiation"] = {
683
- "status": "failed",
684
- "error": str(e),
685
- "error_type": type(e).__name__
686
- }
687
- except Exception as e:
688
- result["checks"]["import"] = {
689
- "status": "failed",
690
- "error": str(e),
691
- "traceback": traceback.format_exc()[:500] # Limit traceback size
692
- }
693
-
694
- return result
695
-
696
- if __name__ == "__main__":
697
- port = int(os.getenv("PORT", 7860))
698
- logger.info(f"🚀 Starting Enhanced Cidadão.AI Backend on port {port}")
699
- # Disable host header validation for HuggingFace Spaces
700
- uvicorn.run(
701
- app,
702
- host="0.0.0.0",
703
- port=port,
704
- forwarded_allow_ips="*", # Allow all proxy IPs
705
- proxy_headers=True # Trust proxy headers
706
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
debug_drummond_import.py DELETED
@@ -1,97 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Debug script to trace Drummond import issues.
4
- """
5
-
6
- import sys
7
- import traceback
8
-
9
- def test_import_chain():
10
- """Test the import chain to find where the error occurs."""
11
-
12
- print("=== DRUMMOND IMPORT DEBUG ===")
13
- print(f"Python version: {sys.version}")
14
- print(f"Python path: {sys.path}")
15
- print()
16
-
17
- # Test 1: Import BaseAgent
18
- print("1. Testing BaseAgent import...")
19
- try:
20
- from src.agents.deodoro import BaseAgent
21
- print(" ✓ BaseAgent imported successfully")
22
-
23
- # Check if shutdown is abstract
24
- import inspect
25
- methods = inspect.getmembers(BaseAgent, predicate=inspect.ismethod)
26
- for name, method in methods:
27
- if name == 'shutdown':
28
- print(f" - shutdown method found: {method}")
29
- if hasattr(method, '__isabstractmethod__'):
30
- print(f" - Is abstract: {method.__isabstractmethod__}")
31
- except Exception as e:
32
- print(f" ✗ Failed to import BaseAgent: {e}")
33
- traceback.print_exc()
34
- return
35
-
36
- # Test 2: Import CommunicationAgent directly
37
- print("\n2. Testing CommunicationAgent import...")
38
- try:
39
- from src.agents.drummond import CommunicationAgent
40
- print(" ✓ CommunicationAgent imported successfully")
41
-
42
- # Check if shutdown is implemented
43
- if hasattr(CommunicationAgent, 'shutdown'):
44
- print(" ✓ shutdown method exists in CommunicationAgent")
45
-
46
- # Check method resolution order
47
- print(f" - MRO: {[c.__name__ for c in CommunicationAgent.__mro__]}")
48
-
49
- # Check abstract methods
50
- abstract_methods = getattr(CommunicationAgent, '__abstractmethods__', set())
51
- print(f" - Abstract methods: {abstract_methods}")
52
-
53
- except Exception as e:
54
- print(f" ✗ Failed to import CommunicationAgent: {e}")
55
- traceback.print_exc()
56
- return
57
-
58
- # Test 3: Try to instantiate
59
- print("\n3. Testing CommunicationAgent instantiation...")
60
- try:
61
- agent = CommunicationAgent()
62
- print(" ✓ CommunicationAgent instantiated successfully")
63
- except Exception as e:
64
- print(f" ✗ Failed to instantiate CommunicationAgent: {e}")
65
- traceback.print_exc()
66
-
67
- # Additional diagnostics
68
- print("\n Additional diagnostics:")
69
- try:
70
- from src.agents.drummond import CommunicationAgent
71
- print(f" - Class type: {type(CommunicationAgent)}")
72
- print(f" - Base classes: {CommunicationAgent.__bases__}")
73
-
74
- # List all methods
75
- print(" - All methods:")
76
- for attr in dir(CommunicationAgent):
77
- if not attr.startswith('_'):
78
- obj = getattr(CommunicationAgent, attr)
79
- if callable(obj):
80
- print(f" * {attr}: {type(obj)}")
81
-
82
- except Exception as e2:
83
- print(f" - Failed diagnostics: {e2}")
84
-
85
- # Test 4: Test the factory
86
- print("\n4. Testing chat_drummond_factory...")
87
- try:
88
- from src.api.routes.chat_drummond_factory import get_drummond_agent
89
- print(" ✓ Factory imported successfully")
90
- except Exception as e:
91
- print(f" ✗ Failed to import factory: {e}")
92
- traceback.print_exc()
93
-
94
- print("\n=== END DEBUG ===")
95
-
96
- if __name__ == "__main__":
97
- test_import_chain()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
debug_hf_error.py DELETED
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Debug script to understand the HuggingFace error"""
3
-
4
- print("=== Debugging HuggingFace Import Error ===\n")
5
-
6
- # Check if we can find where the error is really coming from
7
- import re
8
-
9
- log_line = '{"event": "Failed to initialize Drummond agent: Can\'t instantiate abstract class CommunicationAgent with abstract method shutdown", "logger": "src.api.routes.chat", "level": "error", "timestamp": "2025-09-20T16:17:42.475125Z", "filename": "chat.py", "func_name": "<module>", "lineno": 33}'
10
-
11
- print("Log says:")
12
- print(f"- File: chat.py")
13
- print(f"- Line: 33")
14
- print(f"- Function: <module> (module-level code)")
15
- print(f"- Error: Can't instantiate abstract class CommunicationAgent with abstract method shutdown")
16
-
17
- print("\nThis suggests that somewhere at the module level (not inside a function),")
18
- print("there's an attempt to instantiate CommunicationAgent directly.")
19
- print("\nBut line 33 is just a comment. Possible explanations:")
20
- print("1. Line numbers are off due to imports or preprocessing")
21
- print("2. There's a hidden try/except block wrapping an import")
22
- print("3. The error is actually from a different file that's imported")
23
- print("4. MasterAgent (line 35) might be trying to instantiate CommunicationAgent")
24
-
25
- print("\nLet's check if MasterAgent exists...")
26
-
27
- try:
28
- from src.agents.abaporu import MasterAgent
29
- print("✓ MasterAgent found in abaporu.py")
30
- except ImportError as e:
31
- print(f"✗ MasterAgent not found: {e}")
32
- print(" This would cause an error at line 35!")
33
-
34
- print("\nThe real issue might be that MasterAgent is not imported in chat.py!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/api/routes/chat.py CHANGED
@@ -27,6 +27,7 @@ class DataSourceType:
27
  CONTRACTS = "contratos"
28
  SERVANTS = "servidores"
29
  EXPENSES = "despesas"
 
30
 
31
  class UniversalSearchRequest(BaseModel):
32
  """Universal search request model."""
 
27
  CONTRACTS = "contratos"
28
  SERVANTS = "servidores"
29
  EXPENSES = "despesas"
30
+ BIDDINGS = "licitacoes"
31
 
32
  class UniversalSearchRequest(BaseModel):
33
  """Universal search request model."""
test_chat_detailed.py DELETED
@@ -1,103 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Detailed test for chat endpoints with exact response format
4
- """
5
-
6
- import requests
7
- import json
8
- from datetime import datetime
9
-
10
- BASE_URL = "https://neural-thinker-cidadao-ai-backend.hf.space"
11
-
12
- def test_chat_message_detailed():
13
- """Test main chat endpoint and print full response"""
14
- print("\n🔍 Testing /api/v1/chat/message with full response...")
15
-
16
- payload = {
17
- "message": "Olá, como você pode me ajudar?",
18
- "session_id": f"test-{datetime.now().timestamp()}"
19
- }
20
-
21
- try:
22
- response = requests.post(
23
- f"{BASE_URL}/api/v1/chat/message",
24
- json=payload,
25
- headers={"Content-Type": "application/json"}
26
- )
27
-
28
- print(f"Status Code: {response.status_code}")
29
- print(f"Headers: {dict(response.headers)}")
30
- print("\nFull Response:")
31
- print(json.dumps(response.json(), indent=2, ensure_ascii=False))
32
-
33
- except Exception as e:
34
- print(f"Error: {e}")
35
- print(f"Response Text: {response.text if 'response' in locals() else 'No response'}")
36
-
37
- def test_chat_simple_detailed():
38
- """Test simple chat endpoint"""
39
- print("\n🔍 Testing /api/v1/chat/simple...")
40
-
41
- payload = {
42
- "message": "Olá, como você pode me ajudar?",
43
- "session_id": f"test-{datetime.now().timestamp()}"
44
- }
45
-
46
- try:
47
- response = requests.post(
48
- f"{BASE_URL}/api/v1/chat/simple",
49
- json=payload,
50
- headers={"Content-Type": "application/json"}
51
- )
52
-
53
- print(f"Status Code: {response.status_code}")
54
-
55
- if response.status_code == 200:
56
- print("\nFull Response:")
57
- print(json.dumps(response.json(), indent=2, ensure_ascii=False))
58
- else:
59
- print(f"Response: {response.text}")
60
-
61
- except Exception as e:
62
- print(f"Error: {e}")
63
-
64
- def test_available_endpoints():
65
- """Check which endpoints are available"""
66
- print("\n📋 Checking available endpoints...")
67
-
68
- endpoints = [
69
- "/api/v1/chat/message",
70
- "/api/v1/chat/simple",
71
- "/api/v1/chat/agents",
72
- "/api/v1/chat/suggestions",
73
- "/api/v1/chat/stream",
74
- "/docs",
75
- "/openapi.json"
76
- ]
77
-
78
- for endpoint in endpoints:
79
- try:
80
- if endpoint in ["/api/v1/chat/message", "/api/v1/chat/simple", "/api/v1/chat/stream"]:
81
- # POST endpoints
82
- response = requests.post(
83
- f"{BASE_URL}{endpoint}",
84
- json={"message": "test", "session_id": "test"},
85
- timeout=5
86
- )
87
- else:
88
- # GET endpoints
89
- response = requests.get(f"{BASE_URL}{endpoint}", timeout=5)
90
-
91
- print(f"{endpoint}: {response.status_code} {'✅' if response.status_code != 404 else '❌'}")
92
- except Exception as e:
93
- print(f"{endpoint}: Error - {str(e)[:50]}")
94
-
95
- if __name__ == "__main__":
96
- print("=" * 60)
97
- print("🔬 Detailed Chat Endpoint Test")
98
- print(f"🌐 URL: {BASE_URL}")
99
- print("=" * 60)
100
-
101
- test_available_endpoints()
102
- test_chat_message_detailed()
103
- test_chat_simple_detailed()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_chat_simple.py DELETED
@@ -1,99 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Teste do endpoint simples de chat com Maritaca AI
4
- """
5
-
6
- import requests
7
- import json
8
- from datetime import datetime
9
- import time
10
-
11
- # URL do backend no HuggingFace Spaces
12
- BASE_URL = "https://neural-thinker-cidadao-ai-backend.hf.space"
13
-
14
- def test_chat_simple():
15
- """Testa o novo endpoint simples de chat"""
16
- endpoint = f"{BASE_URL}/api/v1/chat/simple"
17
-
18
- print("🧪 Testando endpoint /api/v1/chat/simple")
19
- print("="*50)
20
-
21
- # Primeiro, verifica o status
22
- status_endpoint = f"{BASE_URL}/api/v1/chat/simple/status"
23
- try:
24
- response = requests.get(status_endpoint)
25
- if response.status_code == 200:
26
- status = response.json()
27
- print(f"📊 Status do Chat:")
28
- print(f" Maritaca disponível: {status.get('maritaca_available', False)}")
29
- print(f" API Key configurada: {status.get('api_key_configured', False)}")
30
- print()
31
- except Exception as e:
32
- print(f"❌ Erro ao verificar status: {e}")
33
-
34
- # Mensagens de teste
35
- test_messages = [
36
- "Olá, como você está?",
37
- "O que é o Cidadão.AI?",
38
- "Como posso investigar contratos públicos?",
39
- "Me ajuda a entender o portal da transparência",
40
- "Quero analisar gastos com saúde em 2024"
41
- ]
42
-
43
- headers = {
44
- "Content-Type": "application/json",
45
- "Accept": "application/json"
46
- }
47
-
48
- session_id = f"test-session-{int(time.time())}"
49
-
50
- for i, message in enumerate(test_messages, 1):
51
- print(f"\n💬 Teste {i}: {message}")
52
-
53
- payload = {
54
- "message": message,
55
- "session_id": session_id
56
- }
57
-
58
- try:
59
- start_time = time.time()
60
- response = requests.post(
61
- endpoint,
62
- json=payload,
63
- headers=headers,
64
- timeout=30
65
- )
66
- elapsed = time.time() - start_time
67
-
68
- print(f" ⏱️ Tempo de resposta: {elapsed:.2f}s")
69
- print(f" 📡 Status HTTP: {response.status_code}")
70
-
71
- if response.status_code == 200:
72
- data = response.json()
73
- print(f" ✅ Resposta recebida!")
74
- print(f" 🤖 Modelo usado: {data.get('model_used', 'N/A')}")
75
- print(f" 💬 Resposta: {data.get('message', '')[:150]}...")
76
-
77
- # Verifica se está usando Maritaca
78
- if data.get('model_used') != 'fallback':
79
- print(f" 🎉 Usando Maritaca AI! Modelo: {data.get('model_used')}")
80
- else:
81
- print(f" ❌ Erro: {response.text[:200]}")
82
-
83
- except requests.exceptions.Timeout:
84
- print(f" ⏱️ Timeout - demorou mais de 30 segundos")
85
- except Exception as e:
86
- print(f" ❌ Erro: {e}")
87
-
88
- # Pequena pausa entre requisições
89
- if i < len(test_messages):
90
- time.sleep(1)
91
-
92
- print("\n" + "="*50)
93
- print("✅ Teste concluído!")
94
- print(f"\n💡 Dica: Para usar no frontend, faça requisições POST para:")
95
- print(f" {endpoint}")
96
- print(f" Com body: {{\"message\": \"sua mensagem\", \"session_id\": \"opcional\"}}")
97
-
98
- if __name__ == "__main__":
99
- test_chat_simple()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_drummond_import.py DELETED
@@ -1,42 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Test Drummond import to debug the issue."""
3
-
4
- import inspect
5
-
6
- # Test direct import
7
- try:
8
- from src.agents.drummond import CommunicationAgent
9
- print("✅ Import successful!")
10
-
11
- # Check abstract methods
12
- abstract_methods = getattr(CommunicationAgent, '__abstractmethods__', set())
13
- print(f"Abstract methods: {abstract_methods}")
14
-
15
- # Check if shutdown is implemented
16
- if hasattr(CommunicationAgent, 'shutdown'):
17
- print("✅ shutdown method exists")
18
- shutdown_method = getattr(CommunicationAgent, 'shutdown')
19
- print(f" Is coroutine: {inspect.iscoroutinefunction(shutdown_method)}")
20
- else:
21
- print("❌ shutdown method NOT FOUND")
22
-
23
- # Check all methods
24
- all_methods = [m for m in dir(CommunicationAgent) if not m.startswith('_')]
25
- print(f"\nAll public methods: {all_methods}")
26
-
27
- except Exception as e:
28
- print(f"❌ Import failed: {type(e).__name__}: {e}")
29
-
30
- # Try simpler import
31
- try:
32
- import sys
33
- import os
34
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
35
- from src.agents.deodoro import BaseAgent
36
- print("\n✅ BaseAgent imported successfully")
37
-
38
- # Check BaseAgent abstract methods
39
- abstract_base = getattr(BaseAgent, '__abstractmethods__', set())
40
- print(f"BaseAgent abstract methods: {abstract_base}")
41
- except Exception as e2:
42
- print(f"❌ BaseAgent import also failed: {e2}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_drummond_init.py DELETED
@@ -1,30 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Test Drummond initialization locally"""
3
- import os
4
- import sys
5
-
6
- # Add the src directory to the path
7
- sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
8
-
9
- # Set necessary environment variables for testing
10
- os.environ["GROQ_API_KEY"] = "dummy_key_for_test"
11
- os.environ["JWT_SECRET_KEY"] = "test_secret"
12
- os.environ["SECRET_KEY"] = "test_secret"
13
-
14
- try:
15
- print("Testing Drummond agent initialization...")
16
- from src.agents.drummond import CommunicationAgent
17
-
18
- # Try to create agent
19
- print("Creating CommunicationAgent...")
20
- agent = CommunicationAgent()
21
- print("✓ Agent created successfully!")
22
-
23
- # Check if it has the necessary methods
24
- print(f"Has process method: {hasattr(agent, 'process')}")
25
- print(f"Has shutdown method: {hasattr(agent, 'shutdown')}")
26
-
27
- except Exception as e:
28
- print(f"✗ Error creating agent: {e}")
29
- import traceback
30
- traceback.print_exc()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_drummond_live.py DELETED
@@ -1,46 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Test Drummond agent on live HuggingFace deployment"""
3
- import requests
4
- import json
5
-
6
- # Test the chat endpoint with a greeting
7
- url = "https://neural-thinker-cidadao-ai-backend.hf.space/api/v1/chat/message"
8
- headers = {"Content-Type": "application/json"}
9
-
10
- # Test 1: Simple greeting (should route to Drummond)
11
- print("Test 1: Testing greeting message...")
12
- data = {"message": "Olá, pode me ajudar?"}
13
- try:
14
- response = requests.post(url, json=data, headers=headers)
15
- print(f"Status: {response.status_code}")
16
- print(f"Response: {json.dumps(response.json(), indent=2, ensure_ascii=False)}")
17
- except Exception as e:
18
- print(f"Error: {e}")
19
- if hasattr(response, 'text'):
20
- print(f"Raw response: {response.text}")
21
-
22
- print("\n" + "="*50 + "\n")
23
-
24
- # Test 2: Literary analysis request
25
- print("Test 2: Testing literary analysis...")
26
- data = {"message": "Analise o poema 'No meio do caminho tinha uma pedra' de Drummond"}
27
- try:
28
- response = requests.post(url, json=data, headers=headers)
29
- print(f"Status: {response.status_code}")
30
- print(f"Response: {json.dumps(response.json(), indent=2, ensure_ascii=False)}")
31
- except Exception as e:
32
- print(f"Error: {e}")
33
- if hasattr(response, 'text'):
34
- print(f"Raw response: {response.text}")
35
-
36
- print("\n" + "="*50 + "\n")
37
-
38
- # Test 3: Check health endpoint
39
- print("Test 3: Checking health endpoint...")
40
- health_url = "https://neural-thinker-cidadao-ai-backend.hf.space/health"
41
- try:
42
- response = requests.get(health_url)
43
- print(f"Status: {response.status_code}")
44
- print(f"Response: {json.dumps(response.json(), indent=2)}")
45
- except Exception as e:
46
- print(f"Error: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_drummond_minimal.py DELETED
@@ -1,60 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Minimal test to verify CommunicationAgent can be imported and instantiated.
4
- This simulates what happens on HuggingFace Spaces.
5
- """
6
-
7
- import sys
8
- import os
9
-
10
- # Add src to path like HuggingFace does
11
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
12
-
13
- def test_minimal_import():
14
- print("=== MINIMAL DRUMMOND TEST ===")
15
-
16
- # Step 1: Try importing just the class
17
- try:
18
- print("1. Importing CommunicationAgent class...")
19
- from src.agents.drummond import CommunicationAgent
20
- print(" ✓ Import successful")
21
- except Exception as e:
22
- print(f" ✗ Import failed: {e}")
23
- import traceback
24
- traceback.print_exc()
25
- return False
26
-
27
- # Step 2: Check if it's a proper class
28
- print("\n2. Checking class structure...")
29
- print(f" - Type: {type(CommunicationAgent)}")
30
- print(f" - Base classes: {CommunicationAgent.__bases__}")
31
- print(f" - Module: {CommunicationAgent.__module__}")
32
-
33
- # Check abstract methods
34
- abstract_methods = getattr(CommunicationAgent, '__abstractmethods__', None)
35
- if abstract_methods:
36
- print(f" - Abstract methods remaining: {abstract_methods}")
37
- else:
38
- print(" - No abstract methods remaining")
39
-
40
- # Step 3: Try instantiation without any dependencies
41
- print("\n3. Testing instantiation...")
42
- try:
43
- # Mock the logger to avoid dependency issues
44
- import logging
45
- logging.basicConfig(level=logging.INFO)
46
-
47
- # Try to create instance
48
- agent = CommunicationAgent()
49
- print(" ✓ Instantiation successful")
50
- return True
51
- except Exception as e:
52
- print(f" ✗ Instantiation failed: {e}")
53
- import traceback
54
- traceback.print_exc()
55
- return False
56
-
57
- if __name__ == "__main__":
58
- success = test_minimal_import()
59
- print(f"\n=== TEST {'PASSED' if success else 'FAILED'} ===")
60
- sys.exit(0 if success else 1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_hf_chat.py DELETED
@@ -1,152 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Test script for HuggingFace Spaces chat endpoints
4
- Tests both main and simple chat endpoints with Maritaca AI
5
- """
6
-
7
- import requests
8
- import json
9
- from datetime import datetime
10
-
11
- # HuggingFace Spaces URL
12
- BASE_URL = "https://neural-thinker-cidadao-ai-backend.hf.space"
13
-
14
- def test_health():
15
- """Test if API is running"""
16
- print("\n1️⃣ Testing API Health...")
17
- try:
18
- response = requests.get(f"{BASE_URL}/")
19
- print(f"✅ API Status: {response.status_code}")
20
- print(f"Response: {response.json()}")
21
- return True
22
- except Exception as e:
23
- print(f"❌ Health check failed: {e}")
24
- return False
25
-
26
- def test_docs():
27
- """Test if API docs are accessible"""
28
- print("\n2️⃣ Testing API Documentation...")
29
- try:
30
- response = requests.get(f"{BASE_URL}/docs")
31
- print(f"✅ Docs Status: {response.status_code}")
32
- return True
33
- except Exception as e:
34
- print(f"❌ Docs check failed: {e}")
35
- return False
36
-
37
- def test_simple_chat():
38
- """Test simple chat endpoint with Maritaca AI"""
39
- print("\n3️⃣ Testing Simple Chat Endpoint (Maritaca AI direct)...")
40
-
41
- test_messages = [
42
- "Olá, como você pode me ajudar?",
43
- "Quais são os gastos públicos mais recentes?",
44
- "Me explique sobre transparência governamental"
45
- ]
46
-
47
- for message in test_messages:
48
- print(f"\n📤 Sending: {message}")
49
- try:
50
- response = requests.post(
51
- f"{BASE_URL}/api/v1/chat/simple",
52
- json={
53
- "message": message,
54
- "session_id": f"test-session-{datetime.now().timestamp()}"
55
- },
56
- headers={"Content-Type": "application/json"}
57
- )
58
-
59
- if response.status_code == 200:
60
- data = response.json()
61
- print(f"✅ Response Status: {response.status_code}")
62
- print(f"📥 Assistant: {data['response'][:200]}...")
63
- print(f"🤖 Agent Used: {data.get('agent_used', 'Unknown')}")
64
- else:
65
- print(f"⚠️ Status: {response.status_code}")
66
- print(f"Response: {response.text}")
67
-
68
- except Exception as e:
69
- print(f"❌ Error: {e}")
70
-
71
- def test_main_chat():
72
- """Test main chat endpoint with full agent system"""
73
- print("\n4️⃣ Testing Main Chat Endpoint (Full Agent System)...")
74
-
75
- test_messages = [
76
- {"message": "Oi, tudo bem?", "expected_agent": "Drummond"},
77
- {"message": "Investigue contratos suspeitos em São Paulo", "expected_agent": "Abaporu/Zumbi"},
78
- {"message": "Análise de gastos com educação", "expected_agent": "Abaporu"}
79
- ]
80
-
81
- for test in test_messages:
82
- print(f"\n📤 Sending: {test['message']}")
83
- print(f"🎯 Expected Agent: {test['expected_agent']}")
84
-
85
- try:
86
- response = requests.post(
87
- f"{BASE_URL}/api/v1/chat/message",
88
- json={
89
- "message": test["message"],
90
- "session_id": f"test-session-{datetime.now().timestamp()}"
91
- },
92
- headers={"Content-Type": "application/json"}
93
- )
94
-
95
- if response.status_code == 200:
96
- data = response.json()
97
- print(f"✅ Response Status: {response.status_code}")
98
- print(f"📥 Response: {data['response'][:200]}...")
99
- print(f"🤖 Agent: {data.get('agent_name', 'Unknown')}")
100
- print(f"💬 Type: {data.get('response_type', 'Unknown')}")
101
- else:
102
- print(f"⚠️ Status: {response.status_code}")
103
- print(f"Response: {response.text}")
104
-
105
- except Exception as e:
106
- print(f"❌ Error: {e}")
107
-
108
- def test_chat_suggestions():
109
- """Test chat suggestions endpoint"""
110
- print("\n5️⃣ Testing Chat Suggestions...")
111
- try:
112
- response = requests.get(
113
- f"{BASE_URL}/api/v1/chat/suggestions",
114
- params={"limit": 5}
115
- )
116
-
117
- if response.status_code == 200:
118
- suggestions = response.json()
119
- print(f"✅ Found {len(suggestions)} suggestions:")
120
- for idx, suggestion in enumerate(suggestions[:3], 1):
121
- print(f" {idx}. {suggestion['text']}")
122
- else:
123
- print(f"⚠️ Status: {response.status_code}")
124
-
125
- except Exception as e:
126
- print(f"❌ Error: {e}")
127
-
128
- def main():
129
- """Run all tests"""
130
- print("🚀 Testing Cidadão.AI Backend on HuggingFace Spaces")
131
- print("=" * 60)
132
- print(f"🌐 Base URL: {BASE_URL}")
133
- print(f"🕐 Test Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
134
- print("=" * 60)
135
-
136
- # Run tests
137
- if test_health():
138
- test_docs()
139
- test_simple_chat()
140
- test_main_chat()
141
- test_chat_suggestions()
142
-
143
- print("\n" + "=" * 60)
144
- print("✅ Tests completed!")
145
- print("\n💡 Integration Tips for Frontend:")
146
- print("1. Use /api/v1/chat/simple for reliable Maritaca AI responses")
147
- print("2. Use /api/v1/chat/message for full agent capabilities")
148
- print("3. Handle both 200 (success) and 500 (fallback) responses")
149
- print("4. Check the 'agent_used' field to know which agent responded")
150
-
151
- if __name__ == "__main__":
152
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_hf_spaces.py DELETED
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- 🔍 Teste de HuggingFace Spaces
4
- Verifica se os Spaces estão rodando e quais endpoints respondem
5
- """
6
-
7
- import asyncio
8
- import httpx
9
-
10
- async def test_hf_spaces():
11
- """🔍 Testa diferentes endpoints dos HF Spaces"""
12
- print("🔍 VERIFICANDO HUGGINGFACE SPACES")
13
- print("=" * 50)
14
-
15
- # URLs para testar
16
- backend_urls = [
17
- "https://neural-thinker-cidadao-ai-backend.hf.space",
18
- "https://neural-thinker-cidadao-ai-backend.hf.space/",
19
- "https://neural-thinker-cidadao-ai-backend.hf.space/health",
20
- "https://neural-thinker-cidadao-ai-backend.hf.space/docs",
21
- "https://huggingface.co/spaces/neural-thinker/cidadao.ai-backend"
22
- ]
23
-
24
- models_urls = [
25
- "https://neural-thinker-cidadao-ai-models.hf.space",
26
- "https://neural-thinker-cidadao-ai-models.hf.space/",
27
- "https://neural-thinker-cidadao-ai-models.hf.space/health",
28
- "https://huggingface.co/spaces/neural-thinker/cidadao.ai-models"
29
- ]
30
-
31
- async with httpx.AsyncClient(timeout=10.0) as client:
32
-
33
- print("🏛️ TESTANDO BACKEND SPACES:")
34
- for url in backend_urls:
35
- try:
36
- response = await client.get(url)
37
- status = "✅" if response.status_code == 200 else f"❌ {response.status_code}"
38
- print(f" {status} {url}")
39
-
40
- if response.status_code == 200 and 'application/json' in response.headers.get('content-type', ''):
41
- try:
42
- data = response.json()
43
- if 'status' in data:
44
- print(f" 📊 Status: {data.get('status')}")
45
- if 'agents' in data:
46
- print(f" 🤖 Agentes: {list(data.get('agents', {}).keys())}")
47
- except:
48
- print(f" 📝 HTML response (não JSON)")
49
-
50
- except Exception as e:
51
- print(f" ❌ {url} - Erro: {str(e)[:50]}...")
52
-
53
- print("\n🤖 TESTANDO MODELS SPACES:")
54
- for url in models_urls:
55
- try:
56
- response = await client.get(url)
57
- status = "✅" if response.status_code == 200 else f"❌ {response.status_code}"
58
- print(f" {status} {url}")
59
-
60
- if response.status_code == 200 and 'application/json' in response.headers.get('content-type', ''):
61
- try:
62
- data = response.json()
63
- if 'api' in data:
64
- print(f" 📊 API: {data.get('api')}")
65
- if 'version' in data:
66
- print(f" 🔢 Version: {data.get('version')}")
67
- except:
68
- print(f" 📝 HTML response (não JSON)")
69
-
70
- except Exception as e:
71
- print(f" ❌ {url} - Erro: {str(e)[:50]}...")
72
-
73
- if __name__ == "__main__":
74
- asyncio.run(test_hf_spaces())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_maritaca_integration.py DELETED
@@ -1,118 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Script para testar a integração Maritaca AI no Cidadão.AI
4
- """
5
-
6
- import requests
7
- import json
8
- from datetime import datetime
9
-
10
- # URL do backend no HuggingFace Spaces
11
- BASE_URL = "https://neural-thinker-cidadao-ai-backend.hf.space"
12
-
13
- def test_health():
14
- """Testa se a API está online"""
15
- try:
16
- response = requests.get(f"{BASE_URL}/health")
17
- print(f"✅ Health Check: {response.status_code}")
18
- if response.status_code == 200:
19
- print(f" Response: {response.json()}")
20
- return response.status_code == 200
21
- except Exception as e:
22
- print(f"❌ Health Check Error: {e}")
23
- return False
24
-
25
- def test_chat_endpoint():
26
- """Testa o endpoint de chat com a Maritaca AI"""
27
- endpoint = f"{BASE_URL}/api/v1/chat/message"
28
-
29
- # Mensagens de teste
30
- test_messages = [
31
- {
32
- "message": "Olá, tudo bem?",
33
- "expected_agent": "drummond"
34
- },
35
- {
36
- "message": "Quero investigar contratos de saúde em São Paulo",
37
- "expected_agent": "abaporu"
38
- },
39
- {
40
- "message": "Me explique como funciona o portal da transparência",
41
- "expected_agent": "drummond"
42
- }
43
- ]
44
-
45
- headers = {
46
- "Content-Type": "application/json",
47
- "Accept": "application/json"
48
- }
49
-
50
- for test in test_messages:
51
- print(f"\n📤 Testando: '{test['message']}'")
52
- print(f" Agente esperado: {test['expected_agent']}")
53
-
54
- payload = {
55
- "message": test["message"],
56
- "session_id": f"test-{datetime.now().timestamp()}"
57
- }
58
-
59
- try:
60
- response = requests.post(
61
- endpoint,
62
- json=payload,
63
- headers=headers,
64
- timeout=30
65
- )
66
-
67
- print(f" Status: {response.status_code}")
68
-
69
- if response.status_code == 200:
70
- data = response.json()
71
- print(f" ✅ Resposta recebida!")
72
- print(f" Agente: {data.get('agent_name', 'N/A')}")
73
- print(f" Mensagem: {data.get('message', 'N/A')[:100]}...")
74
- print(f" Confiança: {data.get('confidence', 'N/A')}")
75
-
76
- # Verifica se está usando Maritaca
77
- if "drummond" in data.get('agent_id', '').lower():
78
- print(f" 🤖 Drummond ativado (deve estar usando Maritaca AI)")
79
-
80
- elif response.status_code == 422:
81
- print(f" ❌ Erro de validação: {response.json()}")
82
- else:
83
- print(f" ❌ Erro: {response.text[:200]}")
84
-
85
- except requests.exceptions.Timeout:
86
- print(f" ⏱️ Timeout - a requisição demorou mais de 30 segundos")
87
- except Exception as e:
88
- print(f" ❌ Erro na requisição: {e}")
89
-
90
- def test_api_docs():
91
- """Verifica se a documentação da API está acessível"""
92
- try:
93
- response = requests.get(f"{BASE_URL}/docs")
94
- print(f"\n📚 API Docs: {response.status_code}")
95
- if response.status_code == 200:
96
- print(f" ✅ Documentação disponível em: {BASE_URL}/docs")
97
- return response.status_code == 200
98
- except Exception as e:
99
- print(f"❌ API Docs Error: {e}")
100
- return False
101
-
102
- if __name__ == "__main__":
103
- print("🧪 Testando integração Maritaca AI no Cidadão.AI")
104
- print(f"🌐 Backend URL: {BASE_URL}")
105
- print("="*50)
106
-
107
- # Testa health check
108
- if test_health():
109
- # Testa documentação
110
- test_api_docs()
111
-
112
- # Testa endpoint de chat
113
- test_chat_endpoint()
114
- else:
115
- print("\n❌ API não está respondendo. Verifique se o HuggingFace Spaces está online.")
116
-
117
- print("\n"+"="*50)
118
- print("✅ Testes concluídos!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_models_communication.py DELETED
@@ -1,235 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- 🧪 Teste de Comunicação Backend ↔ Models
4
- Verifica se os repositórios estão conversando via API
5
- """
6
-
7
- import asyncio
8
- import sys
9
- import os
10
- import httpx
11
- import json
12
- from datetime import datetime
13
-
14
- # Add src to path
15
- sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
16
-
17
- from src.tools.models_client import ModelsClient
18
- from src.core.config import Settings
19
-
20
- # Test configuration
21
- MODELS_API_URL = "https://neural-thinker-cidadao-ai-models.hf.space"
22
- BACKEND_API_URL = "https://neural-thinker-cidadao-ai-backend.hf.space"
23
-
24
- async def test_models_api_direct():
25
- """🔍 TESTE 1: Acesso direto à API de Modelos"""
26
- print("=" * 60)
27
- print("🔍 TESTE 1: MODELS API - ACESSO DIRETO")
28
- print("=" * 60)
29
-
30
- try:
31
- async with httpx.AsyncClient(timeout=30.0) as client:
32
- # Test root endpoint
33
- print(f"📡 Testando: {MODELS_API_URL}")
34
- response = await client.get(f"{MODELS_API_URL}/")
35
-
36
- if response.status_code == 200:
37
- data = response.json()
38
- print("✅ Models API está ONLINE!")
39
- print(f" 📊 API: {data.get('api', 'N/A')}")
40
- print(f" 🔢 Versão: {data.get('version', 'N/A')}")
41
- print(f" 📋 Status: {data.get('status', 'N/A')}")
42
- print(f" 🔗 Endpoints: {list(data.get('endpoints', {}).keys())}")
43
- return True
44
- else:
45
- print(f"❌ Models API retornou status: {response.status_code}")
46
- return False
47
-
48
- except Exception as e:
49
- print(f"❌ Erro ao conectar Models API: {str(e)}")
50
- return False
51
-
52
- async def test_models_health():
53
- """🏥 TESTE 2: Health check da API de Modelos"""
54
- print("\n" + "=" * 60)
55
- print("🏥 TESTE 2: MODELS API - HEALTH CHECK")
56
- print("=" * 60)
57
-
58
- try:
59
- async with httpx.AsyncClient(timeout=30.0) as client:
60
- response = await client.get(f"{MODELS_API_URL}/health")
61
-
62
- if response.status_code == 200:
63
- data = response.json()
64
- print("✅ Health check OK!")
65
- print(f" 📊 Status: {data.get('status', 'N/A')}")
66
- print(f" 🤖 Modelos carregados: {data.get('models_loaded', 'N/A')}")
67
- return True
68
- else:
69
- print(f"❌ Health check falhou: {response.status_code}")
70
- return False
71
-
72
- except Exception as e:
73
- print(f"❌ Erro no health check: {str(e)}")
74
- return False
75
-
76
- async def test_backend_to_models():
77
- """🔄 TESTE 3: Backend chamando Models via Client"""
78
- print("\n" + "=" * 60)
79
- print("🔄 TESTE 3: BACKEND → MODELS VIA CLIENT")
80
- print("=" * 60)
81
-
82
- try:
83
- # Initialize client with explicit URL
84
- async with ModelsClient(base_url=MODELS_API_URL) as client:
85
-
86
- # Test anomaly detection
87
- print("🧠 Testando detecção de anomalias...")
88
-
89
- # Sample data for testing
90
- test_data = {
91
- "transaction_amount": 150000.00,
92
- "vendor_name": "Tech Solutions LTDA",
93
- "contract_type": "informática",
94
- "transaction_date": "2024-08-18"
95
- }
96
-
97
- result = await client.detect_anomaly(test_data)
98
-
99
- if result:
100
- print("✅ Comunicação Backend → Models OK!")
101
- print(f" 🎯 Resultado: {result}")
102
- return True
103
- else:
104
- print("❌ Nenhum resultado retornado")
105
- return False
106
-
107
- except Exception as e:
108
- print(f"❌ Erro na comunicação: {str(e)}")
109
- return False
110
-
111
- async def test_models_specific_endpoints():
112
- """🎯 TESTE 4: Endpoints específicos de modelos"""
113
- print("\n" + "=" * 60)
114
- print("🎯 TESTE 4: ENDPOINTS ESPECÍFICOS DE MODELOS")
115
- print("=" * 60)
116
-
117
- endpoints_to_test = [
118
- "/models/anomaly/detect",
119
- "/models/pattern/analyze",
120
- "/models/spectral/analyze"
121
- ]
122
-
123
- results = {}
124
-
125
- async with httpx.AsyncClient(timeout=30.0) as client:
126
- for endpoint in endpoints_to_test:
127
- try:
128
- url = f"{MODELS_API_URL}{endpoint}"
129
- print(f"📡 Testando: {endpoint}")
130
-
131
- # Sample request data
132
- test_payload = {
133
- "data": [1, 2, 3, 4, 5],
134
- "params": {"threshold": 0.8}
135
- }
136
-
137
- response = await client.post(url, json=test_payload)
138
-
139
- if response.status_code == 200:
140
- print(f" ✅ {endpoint} - OK")
141
- results[endpoint] = "OK"
142
- elif response.status_code == 422:
143
- print(f" ⚠️ {endpoint} - Schema validation (normal)")
144
- results[endpoint] = "Schema OK"
145
- else:
146
- print(f" ❌ {endpoint} - Status: {response.status_code}")
147
- results[endpoint] = f"Error: {response.status_code}"
148
-
149
- except Exception as e:
150
- print(f" ❌ {endpoint} - Erro: {str(e)}")
151
- results[endpoint] = f"Exception: {str(e)}"
152
-
153
- return results
154
-
155
- async def test_backend_api_integration():
156
- """🏛️ TESTE 5: Backend API usando Models internamente"""
157
- print("\n" + "=" * 60)
158
- print("🏛️ TESTE 5: BACKEND API - INTEGRAÇÃO COM MODELS")
159
- print("=" * 60)
160
-
161
- try:
162
- async with httpx.AsyncClient(timeout=30.0) as client:
163
- # Test investigation endpoint (should use models internally)
164
- print("🔍 Testando investigação (usa models internamente)...")
165
-
166
- payload = {
167
- "query": "Analisar contratos de informática com valores suspeitos",
168
- "data_source": "contracts",
169
- "max_results": 10
170
- }
171
-
172
- response = await client.post(
173
- f"{BACKEND_API_URL}/api/agents/zumbi/investigate",
174
- json=payload
175
- )
176
-
177
- if response.status_code == 200:
178
- data = response.json()
179
- print("✅ Backend API funcionando!")
180
- print(f" 🔍 Status: {data.get('status', 'N/A')}")
181
- print(f" 📊 Anomalias: {data.get('anomalies_found', 'N/A')}")
182
- print(f" ⏱️ Tempo: {data.get('processing_time_ms', 'N/A')}ms")
183
- return True
184
- else:
185
- print(f"❌ Backend API erro: {response.status_code}")
186
- return False
187
-
188
- except Exception as e:
189
- print(f"❌ Erro no Backend API: {str(e)}")
190
- return False
191
-
192
- async def run_communication_tests():
193
- """🚀 Executar todos os testes de comunicação"""
194
- print("🧪 TESTE DE COMUNICAÇÃO CIDADÃO.AI BACKEND ↔ MODELS")
195
- print("🕐 Iniciado em:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
196
- print()
197
-
198
- results = {
199
- "models_api_direct": await test_models_api_direct(),
200
- "models_health": await test_models_health(),
201
- "backend_to_models": await test_backend_to_models(),
202
- "models_endpoints": await test_models_specific_endpoints(),
203
- "backend_integration": await test_backend_api_integration()
204
- }
205
-
206
- # Summary
207
- print("\n" + "=" * 60)
208
- print("📊 RESUMO DOS TESTES")
209
- print("=" * 60)
210
-
211
- total_tests = len(results)
212
- passed_tests = sum(1 for v in results.values() if v is True or (isinstance(v, dict) and any("OK" in str(val) for val in v.values())))
213
-
214
- for test_name, result in results.items():
215
- status = "✅ PASSOU" if result is True else "📊 DETALHES" if isinstance(result, dict) else "❌ FALHOU"
216
- print(f" {test_name}: {status}")
217
-
218
- if isinstance(result, dict):
219
- for endpoint, endpoint_result in result.items():
220
- emoji = "✅" if "OK" in str(endpoint_result) else "❌"
221
- print(f" {emoji} {endpoint}: {endpoint_result}")
222
-
223
- print(f"\n🎯 RESULTADO GERAL: {passed_tests}/{total_tests} testes funcionais")
224
-
225
- if passed_tests == total_tests:
226
- print("🎉 COMUNICAÇÃO BACKEND ↔ MODELS TOTALMENTE FUNCIONAL!")
227
- elif passed_tests > 0:
228
- print("⚠️ COMUNICAÇÃO PARCIALMENTE FUNCIONAL - Verificar issues")
229
- else:
230
- print("❌ COMUNICAÇÃO NÃO FUNCIONAL - Verificar deployment")
231
-
232
- return results
233
-
234
- if __name__ == "__main__":
235
- asyncio.run(run_communication_tests())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_models_endpoints.py DELETED
@@ -1,142 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- 🧪 Teste dos Endpoints da Models API
4
- Verifica quando os endpoints ML estão disponíveis
5
- """
6
-
7
- import asyncio
8
- import httpx
9
- import json
10
- from datetime import datetime
11
-
12
- # Models API URL
13
- MODELS_URL = "https://neural-thinker-cidadao-ai-models.hf.space"
14
-
15
- async def test_endpoints():
16
- """🔍 Testa todos os endpoints da Models API"""
17
- print("🧪 TESTE DOS ENDPOINTS DA MODELS API")
18
- print("=" * 50)
19
- print(f"🔗 Base URL: {MODELS_URL}")
20
- print(f"🕐 Teste iniciado: {datetime.now().strftime('%H:%M:%S')}")
21
- print()
22
-
23
- async with httpx.AsyncClient(timeout=30.0) as client:
24
-
25
- # 1. Health Check
26
- print("1️⃣ HEALTH CHECK")
27
- try:
28
- response = await client.get(f"{MODELS_URL}/health")
29
- data = response.json()
30
- print(f" Status: {data.get('status')}")
31
- print(f" Models loaded: {data.get('models_loaded')}")
32
- print(f" Message: {data.get('message')}")
33
-
34
- if data.get('models_loaded') == True:
35
- print(" ✅ Models API está COMPLETA!")
36
- else:
37
- print(" ⚠️ Models API em modo fallback")
38
- except Exception as e:
39
- print(f" ❌ Erro: {str(e)}")
40
-
41
- # 2. Documentação
42
- print("\n2️⃣ DOCUMENTAÇÃO")
43
- print(f" 📚 Swagger UI: {MODELS_URL}/docs")
44
- print(f" 📋 OpenAPI JSON: {MODELS_URL}/openapi.json")
45
-
46
- # 3. Endpoints ML
47
- print("\n3️⃣ ENDPOINTS DE ML")
48
-
49
- # Anomaly Detection
50
- print("\n 🔍 DETECÇÃO DE ANOMALIAS")
51
- print(f" POST {MODELS_URL}/v1/detect-anomalies")
52
- try:
53
- test_data = {
54
- "contracts": [
55
- {
56
- "id": "TEST-001",
57
- "vendor": "Empresa Teste LTDA",
58
- "amount": 50000.00,
59
- "date": "2025-08-18",
60
- "category": "Serviços de TI"
61
- }
62
- ],
63
- "threshold": 0.7
64
- }
65
-
66
- response = await client.post(
67
- f"{MODELS_URL}/v1/detect-anomalies",
68
- json=test_data
69
- )
70
-
71
- if response.status_code == 200:
72
- result = response.json()
73
- print(f" ✅ Endpoint funcional!")
74
- print(f" 📊 Anomalias encontradas: {result.get('anomalies_found', 0)}")
75
- elif response.status_code == 404:
76
- print(f" ❌ Endpoint não encontrado (Models em fallback)")
77
- else:
78
- print(f" ⚠️ Status: {response.status_code}")
79
-
80
- except Exception as e:
81
- print(f" ❌ Erro: {str(e)[:50]}...")
82
-
83
- # Pattern Analysis
84
- print("\n 📊 ANÁLISE DE PADRÕES")
85
- print(f" POST {MODELS_URL}/v1/analyze-patterns")
86
- try:
87
- test_data = {
88
- "data": {
89
- "time_series": [100, 120, 90, 150, 200, 180],
90
- "categories": ["A", "B", "A", "C", "B", "A"]
91
- },
92
- "analysis_type": "temporal"
93
- }
94
-
95
- response = await client.post(
96
- f"{MODELS_URL}/v1/analyze-patterns",
97
- json=test_data
98
- )
99
-
100
- if response.status_code == 200:
101
- result = response.json()
102
- print(f" ✅ Endpoint funcional!")
103
- print(f" 📈 Padrões encontrados: {result.get('pattern_count', 0)}")
104
- elif response.status_code == 404:
105
- print(f" ❌ Endpoint não encontrado (Models em fallback)")
106
- else:
107
- print(f" ⚠️ Status: {response.status_code}")
108
-
109
- except Exception as e:
110
- print(f" ❌ Erro: {str(e)[:50]}...")
111
-
112
- # Spectral Analysis
113
- print("\n 🌊 ANÁLISE ESPECTRAL")
114
- print(f" POST {MODELS_URL}/v1/analyze-spectral")
115
- try:
116
- test_data = {
117
- "time_series": [1, 2, 3, 2, 1, 2, 3, 2, 1],
118
- "sampling_rate": 1.0
119
- }
120
-
121
- response = await client.post(
122
- f"{MODELS_URL}/v1/analyze-spectral",
123
- json=test_data
124
- )
125
-
126
- if response.status_code == 200:
127
- result = response.json()
128
- print(f" ✅ Endpoint funcional!")
129
- print(f" 🎵 Frequência dominante: {result.get('dominant_frequency', 'N/A')}")
130
- elif response.status_code == 404:
131
- print(f" ❌ Endpoint não encontrado (Models em fallback)")
132
- else:
133
- print(f" ⚠️ Status: {response.status_code}")
134
-
135
- except Exception as e:
136
- print(f" ❌ Erro: {str(e)[:50]}...")
137
-
138
- print("\n" + "=" * 50)
139
- print("🏁 Teste concluído!")
140
-
141
- if __name__ == "__main__":
142
- asyncio.run(test_endpoints())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_models_only.py DELETED
@@ -1,125 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- 🧪 Teste Simples - Apenas Models API
4
- Testa apenas a API de modelos sem dependências do backend
5
- """
6
-
7
- import asyncio
8
- import httpx
9
- import json
10
- from datetime import datetime
11
-
12
- # Models API URL (confirmed working)
13
- MODELS_URL = "https://neural-thinker-cidadao-ai-models.hf.space"
14
-
15
- async def test_models_api():
16
- """🤖 Teste completo da Models API"""
17
- print("🤖 TESTE DA CIDADÃO.AI MODELS API")
18
- print("=" * 50)
19
- print(f"🔗 URL: {MODELS_URL}")
20
- print(f"🕐 Iniciado em: {datetime.now().strftime('%H:%M:%S')}")
21
- print()
22
-
23
- async with httpx.AsyncClient(timeout=30.0) as client:
24
-
25
- # 1. Root endpoint
26
- print("1️⃣ TESTANDO ROOT ENDPOINT")
27
- try:
28
- response = await client.get(f"{MODELS_URL}/")
29
- if response.status_code == 200:
30
- data = response.json()
31
- print(" ✅ Root endpoint OK")
32
- print(f" 📊 API: {data.get('api', 'N/A')}")
33
- print(f" 🔢 Version: {data.get('version', 'N/A')}")
34
- print(f" 📋 Status: {data.get('status', 'N/A')}")
35
- else:
36
- print(f" ❌ Root: {response.status_code}")
37
- except Exception as e:
38
- print(f" ❌ Root error: {str(e)}")
39
-
40
- # 2. Health check
41
- print("\n2️⃣ TESTANDO HEALTH CHECK")
42
- try:
43
- response = await client.get(f"{MODELS_URL}/health")
44
- if response.status_code == 200:
45
- data = response.json()
46
- print(" ✅ Health check OK")
47
- print(f" 📊 Status: {data.get('status', 'N/A')}")
48
- print(f" 🤖 Models loaded: {data.get('models_loaded', 'N/A')}")
49
- print(f" 💬 Message: {data.get('message', 'N/A')}")
50
- else:
51
- print(f" ❌ Health: {response.status_code}")
52
- except Exception as e:
53
- print(f" ❌ Health error: {str(e)}")
54
-
55
- # 3. Test docs endpoint
56
- print("\n3️⃣ TESTANDO DOCUMENTAÇÃO")
57
- try:
58
- response = await client.get(f"{MODELS_URL}/docs")
59
- if response.status_code == 200:
60
- print(" ✅ Docs available")
61
- print(f" 📝 Content-Type: {response.headers.get('content-type', 'N/A')}")
62
- else:
63
- print(f" ❌ Docs: {response.status_code}")
64
- except Exception as e:
65
- print(f" ❌ Docs error: {str(e)}")
66
-
67
- # 4. Test spaces-info
68
- print("\n4️⃣ TESTANDO SPACES INFO")
69
- try:
70
- response = await client.get(f"{MODELS_URL}/spaces-info")
71
- if response.status_code == 200:
72
- data = response.json()
73
- print(" ✅ Spaces info OK")
74
- print(f" 🏠 Space ID: {data.get('space_id', 'N/A')}")
75
- print(f" 👤 Author: {data.get('space_author', 'N/A')}")
76
- print(f" 📦 Platform: {data.get('platform', 'N/A')}")
77
- print(f" 🤖 Models available: {data.get('models_available', 'N/A')}")
78
- else:
79
- print(f" ❌ Spaces info: {response.status_code}")
80
- except Exception as e:
81
- print(f" ❌ Spaces info error: {str(e)}")
82
-
83
- # 5. Test model endpoints (if available)
84
- print("\n5️⃣ TESTANDO ENDPOINTS DE MODELO")
85
-
86
- model_endpoints = [
87
- "/v1/detect-anomalies",
88
- "/v1/analyze-patterns",
89
- "/v1/analyze-spectral"
90
- ]
91
-
92
- for endpoint in model_endpoints:
93
- try:
94
- # Test with minimal payload
95
- test_payload = {
96
- "contracts": [{"value": 1000, "vendor": "test"}],
97
- "threshold": 0.7
98
- } if "anomalies" in endpoint else {
99
- "data": [1, 2, 3, 4, 5],
100
- "params": {"test": True}
101
- }
102
-
103
- response = await client.post(f"{MODELS_URL}{endpoint}", json=test_payload)
104
-
105
- if response.status_code == 200:
106
- print(f" ✅ {endpoint} - Functional")
107
- elif response.status_code == 422:
108
- print(f" 📋 {endpoint} - Schema validation (endpoint exists)")
109
- elif response.status_code == 404:
110
- print(f" ❌ {endpoint} - Not found")
111
- else:
112
- print(f" ⚠️ {endpoint} - Status: {response.status_code}")
113
-
114
- except Exception as e:
115
- print(f" ❌ {endpoint} - Error: {str(e)[:50]}...")
116
-
117
- print("\n" + "=" * 50)
118
- print("🎯 RESUMO")
119
- print("✅ Models API está ONLINE e acessível")
120
- print("🔗 URL funcional:", MODELS_URL)
121
- print("📚 Documentação:", f"{MODELS_URL}/docs")
122
- print("🏥 Health check:", f"{MODELS_URL}/health")
123
-
124
- if __name__ == "__main__":
125
- asyncio.run(test_models_api())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_quick_connectivity.py DELETED
@@ -1,62 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- ⚡ Teste Rápido de Conectividade
4
- Verifica rapidamente se os serviços estão online
5
- """
6
-
7
- import asyncio
8
- import httpx
9
-
10
- # URLs dos serviços
11
- BACKEND_URL = "https://neural-thinker-cidadao-ai-backend.hf.space"
12
- MODELS_URL = "https://neural-thinker-cidadao-ai-models.hf.space"
13
-
14
- async def quick_test():
15
- """🚀 Teste rápido de conectividade"""
16
- print("⚡ TESTE RÁPIDO DE CONECTIVIDADE")
17
- print("=" * 50)
18
-
19
- async with httpx.AsyncClient(timeout=15.0) as client:
20
-
21
- # Test Backend
22
- print(f"🔍 Testando Backend: {BACKEND_URL}")
23
- try:
24
- response = await client.get(f"{BACKEND_URL}")
25
- if response.status_code == 200:
26
- data = response.json()
27
- print(f" ✅ Backend ONLINE - {data.get('status', 'N/A')}")
28
- print(f" 🤖 Agentes: {list(data.get('agents', {}).keys())}")
29
- else:
30
- print(f" ❌ Backend retornou: {response.status_code}")
31
- except Exception as e:
32
- print(f" ❌ Backend OFFLINE: {str(e)}")
33
-
34
- # Test Models
35
- print(f"🤖 Testando Models: {MODELS_URL}")
36
- try:
37
- response = await client.get(f"{MODELS_URL}/")
38
- if response.status_code == 200:
39
- data = response.json()
40
- print(f" ✅ Models ONLINE - {data.get('api', 'N/A')}")
41
- else:
42
- print(f" ❌ Models retornou: {response.status_code}")
43
- except Exception as e:
44
- print(f" ❌ Models OFFLINE: {str(e)}")
45
-
46
- # Test Backend → Models integration (via backend status)
47
- print(f"🔄 Testando Integração via Backend Status:")
48
- try:
49
- response = await client.get(f"{BACKEND_URL}/api/status")
50
- if response.status_code == 200:
51
- data = response.json()
52
- cache_info = data.get('performance', {}).get('cache', {})
53
- print(f" ✅ Backend Status OK")
54
- print(f" 📊 Cache: {cache_info.get('total_entries', 0)} entries")
55
- print(f" 🎯 API Version: {data.get('version', 'N/A')}")
56
- else:
57
- print(f" ❌ Backend Status: {response.status_code}")
58
- except Exception as e:
59
- print(f" ❌ Backend Status Error: {str(e)}")
60
-
61
- if __name__ == "__main__":
62
- asyncio.run(quick_test())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test_stable_endpoint.py DELETED
@@ -1,99 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Test the new stable chat endpoint locally
4
- """
5
-
6
- import asyncio
7
- import httpx
8
- from datetime import datetime
9
-
10
- async def test_stable_endpoint():
11
- """Test the stable chat endpoint"""
12
-
13
- # Test messages covering all scenarios
14
- test_cases = [
15
- # Greetings
16
- {"message": "Olá, tudo bem?", "expected_intent": "greeting"},
17
- {"message": "Boa tarde!", "expected_intent": "greeting"},
18
-
19
- # Investigations
20
- {"message": "Quero investigar contratos do Ministério da Saúde", "expected_intent": "investigation"},
21
- {"message": "Buscar licitações suspeitas em São Paulo", "expected_intent": "investigation"},
22
-
23
- # Analysis
24
- {"message": "Analise os gastos com educação em 2024", "expected_intent": "analysis"},
25
- {"message": "Faça uma análise dos fornecedores do governo", "expected_intent": "analysis"},
26
-
27
- # Help
28
- {"message": "Como você pode me ajudar?", "expected_intent": "help"},
29
- {"message": "O que você faz?", "expected_intent": "help"},
30
-
31
- # Complex questions
32
- {"message": "Existe algum padrão suspeito nos contratos de TI dos últimos 6 meses?", "expected_intent": "investigation/analysis"},
33
- {"message": "Quais foram os maiores gastos do governo federal este ano?", "expected_intent": "analysis"},
34
- ]
35
-
36
- print("🧪 Testing Stable Chat Endpoint")
37
- print("=" * 60)
38
-
39
- # Test locally first
40
- base_url = "http://localhost:8000"
41
-
42
- async with httpx.AsyncClient(timeout=10.0) as client:
43
- # Check if server is running
44
- try:
45
- health = await client.get(f"{base_url}/health")
46
- print(f"✅ Local server is running: {health.status_code}")
47
- except:
48
- print("❌ Local server not running. Please start with: make run-dev")
49
- return
50
-
51
- print("\n📊 Testing various message types:")
52
- print("-" * 60)
53
-
54
- success_count = 0
55
- total_tests = len(test_cases)
56
-
57
- for i, test in enumerate(test_cases, 1):
58
- print(f"\n Test {i}/{total_tests}")
59
- print(f"📤 Message: {test['message']}")
60
- print(f"🎯 Expected: {test['expected_intent']}")
61
-
62
- try:
63
- start_time = datetime.now()
64
- response = await client.post(
65
- f"{base_url}/api/v1/chat/stable",
66
- json={
67
- "message": test["message"],
68
- "session_id": f"test-{i}"
69
- }
70
- )
71
- duration = (datetime.now() - start_time).total_seconds() * 1000
72
-
73
- if response.status_code == 200:
74
- data = response.json()
75
- print(f"✅ Success in {duration:.0f}ms")
76
- print(f"🤖 Agent: {data['agent_name']}")
77
- print(f"💬 Response: {data['message'][:100]}...")
78
- print(f"📊 Confidence: {data['confidence']:.2f}")
79
- print(f"🔧 Backend: {data['metadata'].get('agent_used', 'unknown')}")
80
- success_count += 1
81
- else:
82
- print(f"❌ Failed: {response.status_code}")
83
- print(f"Error: {response.text}")
84
-
85
- except Exception as e:
86
- print(f"❌ Exception: {str(e)}")
87
-
88
- print("\n" + "=" * 60)
89
- print(f"📈 Results: {success_count}/{total_tests} successful ({success_count/total_tests*100:.0f}%)")
90
-
91
- if success_count == total_tests:
92
- print("🎉 Perfect! 100% success rate!")
93
- elif success_count >= total_tests * 0.9:
94
- print("✅ Excellent! Above 90% success rate")
95
- else:
96
- print("⚠️ Needs improvement - below 90% success rate")
97
-
98
- if __name__ == "__main__":
99
- asyncio.run(test_stable_endpoint())