PT: Monitor autônomo de contratos públicos do município do Rio de Janeiro — detecção de anomalias com IA, investigação multi-fonte e dashboard em tempo real.
EN: Autonomous public contracts monitor for Rio de Janeiro — AI-powered anomaly detection, multi-source investigation and real-time dashboard.
🔗 Demo ao vivo · 📖 Documentação · 🐛 Reportar bug · 💡 Sugerir feature
Do alerta detectado à narrativa investigativa da IA · experimente ao vivo
- Sobre
- Por que importa
- Competências demonstradas
- Números atuais
- Caso real documentado
- Funcionalidades
- Detectores de anomalia
- Pipeline de IA
- Agente Investigador
- Stack
- Instalação
- Uso
- Variáveis de Ambiente
- Arquitetura
- Deploy Fly.io
- Testes
- O que aprendi
- Roadmap
- Autor
PT:
O Sentinela RJ coleta automaticamente contratos públicos do Portal Nacional de Contratações Públicas (PNCP), aplica 9 detectores estatísticos e cadastrais para identificar anomalias, e usa IA local (Gemma 4) + Gemini para gerar narrativas investigativas com comparação A/B de vereditos. Um agente ReAct cruza múltiplas fontes externas para investigação profunda. Tudo disponível em dashboard público com dados abertos.
EN:
Sentinela RJ automatically collects public contracts from Brazil's PNCP portal, applies 9 statistical and registry detectors to identify anomalies, and uses local AI (Gemma 4) + Gemini to generate investigative narratives with A/B verdict comparison. A ReAct agent crosses multiple external sources for deep investigation. All available on a public dashboard with open data.
PT:
Contratos públicos são dados abertos, mas raramente são fáceis de analisar. O Sentinela RJ transforma milhares de registros do PNCP em alertas acionáveis, destacando valores atípicos, concentração de fornecedores, possíveis fracionamentos e sinais cadastrais que merecem auditoria humana.
O objetivo não é substituir controle institucional ou análise jurídica. É criar uma camada técnica de triagem: coletar, normalizar, cruzar, priorizar e explicar indícios para que pessoas consigam investigar mais rápido.
EN:
Public contracts are open data, but they are rarely easy to analyze. Sentinela RJ turns thousands of PNCP records into actionable alerts, surfacing outliers, supplier concentration, possible contract splitting and registry signals that deserve human review.
The goal is not to replace institutional oversight or legal analysis. It is a technical triage layer: collect, normalize, cross-check, prioritize and explain signals so people can investigate faster.
| Área | Evidência no projeto |
|---|---|
| Backend Python | CLI, Flask dashboard, pipeline agendado e serviços de análise |
| Dados e SQL | SQLite persistente, migrações, consultas para contratos, alertas e fornecedores |
| Análise de anomalias | Detectores estatísticos, cadastrais e regras de negócio aplicadas a dados reais |
| IA aplicada | Narrativas investigativas, comparação A/B de vereditos e fallback entre provedores |
| Civic tech | Uso de dados públicos para transparência e priorização de investigação |
| Deploy | Fly.io com volume SQLite persistente e configuração por variáveis de ambiente |
| Testes | 272 testes pytest cobrindo detectores, banco, pipeline, dashboard, dossiê, triagem e conflito de interesse |
| Indicador | Valor |
|---|---|
| 📄 Contratos analisados | 4.925+ |
| 💰 Valor total monitorado | R$ 11,28 bilhões+ |
| 🚨 Anomalias detectadas | 1.497+ |
| 🔴 Risco alto | 174+ |
| 🏢 Fornecedores distintos | 1.549+ |
| 📅 Período coberto | Jul/2022 → hoje |
MJRE Construtora — contrato de R$ 315,9 milhões suspenso judicialmente 11 dias após assinatura
| Fato | Detalhe |
|---|---|
| 🤖 Detecção automática | Outlier estatístico — 13 desvios padrão acima da média da categoria |
| ⚖️ Decisão judicial | 3ª Vara da Fazenda Pública do TJRJ — juíza Mirela Erbisti, 03/04/2026 |
| 💸 Prejuízo evitado | Concorrente R$ 25 milhões mais barato foi desclassificado sem análise |
| 📂 Fonte | Dados públicos PNCP + decisão judicial TJRJ |
- ✅ Coleta automática via API PNCP com pipeline agendado (cron)
- ✅ 9 detectores de anomalia estatísticos e cadastrais
- ✅ Narrativa investigativa — Gemma 4 12B gera o corpo da análise
- ✅ Vereditos A/B — Gemini e Gemma4 emitem vereditos independentes para comparação
- ✅ Agente Investigador ReAct — coleta BrasilAPI, PNCP histórico, DataJud CNJ, TCM-RJ
- ✅ Investigação profunda em background com polling em tempo real
- ✅ Dashboard interativo — triagem, linha do tempo, rede de fornecedores
- ✅ Dossiê exportável — Markdown, PDF e JSON por alerta
- ✅ Deploy público — Fly.io com SQLite persistente em volume
- ✅ Dados abertos — export CSV de contratos e alertas
- ✅ API pública REST — OpenAPI 3.0 + Swagger UI (
/api/docs); alertas, contratos e precisão sob/api/v1/ - ✅ Multi-município — monitoramento configurável por IBGE
- 🚧 TJRJ processos — aguardando API pública com campo
partes(issue #2)
| Detector | O que detecta |
|---|---|
outlier_valor |
Contratos com valor estatisticamente atípico (IQR + Z-score por categoria) |
concentracao_fornecedor |
Fornecedor concentrando contratos em janela de 90 dias |
fracionamento_ap |
Possível fracionamento por Área de Planejamento |
inexigibilidade |
Contratações sem licitação com valor elevado |
emergencia |
Contratações de emergência acima do limiar legal |
aceleracao_contratual |
Crescimento atípico de contratos por fornecedor |
capital_social_baixo |
Capital incompatível com valor contratado |
empresa_jovem_contrato_grande |
Empresa nova com contrato de alto valor |
socios_compartilhados |
Fornecedores com sócios em comum |
desconto_zero_licitacao |
Certame homologado ~no valor estimado (mediana real: 22,6% de desconto) |
licitacao_itens_desertos |
Maioria dos itens do certame deserta/fracassada |
📖 Metodologia completa — método estatístico, limiares reais e fundamento legal de cada detector em
docs/DETECTORES.md.
Cada detector é validado contra triagem humana real — não é estimativa.
precisão = confirmados ÷ (confirmados + descartados), com no mínimo 10 alertas
rotulados por detector. Snapshot de jul/2026 (números ao vivo em /precisao):
| Detector | Precisão | Confirmados / Descartados |
|---|---|---|
inexigibilidade |
75,0% | 15 / 5 |
concentracao_fornecedor |
72,7% | 8 / 3 |
emergencia |
66,7% | 8 / 4 |
dispensa |
50,0% | 5 / 5 |
outlier_valor |
45,5% | 5 / 6 |
Publicamos as taxas inclusive quando são baixas: uma precisão de ~50% indica que o detector reduz pela metade o volume de revisão de um fiscal. O número honesto — sem 0% nem 100% — é a prova de que a triagem foi feita de verdade. Each detector is validated against real human triage, published even when low.
Alerta detectado
↓
Gemma 4 12B (Ollama local) — gera corpo da narrativa investigativa
↓
┌──────────────────┬──────────────────┐
│ Gemma4 veredito │ Gemini veredito │ ← comparação A/B
│ (local, grátis) │ (API, preciso) │
└──────────────────┴──────────────────┘
↓
Auditor humano aplica o veredito preferido com 1 clique
ReAct loop com 5 ferramentas — roda em background, resultado via polling:
| Ferramenta | Fonte | Dados coletados |
|---|---|---|
brasilapi_enriquecido |
BrasilAPI | Cadastro, sócios, capital social, CNAE |
pncp_historico |
PNCP API | Histórico completo de contratos do fornecedor |
pncp_orgao |
PNCP API | Contratos recentes do órgão contratante |
datajud_tjrj |
DataJud CNJ | Processos judiciais (campo partes não exposto na API pública) |
tcm |
TCM-RJ | Decisões de auditoria via Playwright |
Gemma 4 sintetiza as evidências e emite conclusão estruturada:
- Status:
confirmar/arquivar/escalar/inconclusivo - Grau de confiança:
alto/medio/baixo - Recomendação: ação concreta baseada nos dados
| Camada | Tecnologia |
|---|---|
| Backend | Python 3.11+ · Flask · Waitress |
| Frontend | HTML/CSS/JS vanilla |
| Banco | SQLite (data/sentinela_rj.db) + Volume Fly.io |
| IA narrativa | Gemma 4 12B via Ollama (local) |
| IA veredito | Gemini 2.5 Flash + Gemma 4 (A/B) |
| Coleta | PNCP API REST (dados abertos) |
| Enriquecimento | BrasilAPI · DataJud CNJ |
| Scraping | Playwright (TCM-RJ) |
| Deploy | Fly.io · região gru · SQLite volume 1GB |
| Testes | pytest — 272 testes |
- Python 3.11+
- Ollama para IA local —
ollama pull llama3.1e/ouollama pull gemma4:12b - Chave Gemini (gratuita em aistudio.google.com)
# Clone o repositório
git clone https://github.com/simoesleandro/sentinela-rj
cd sentinela-rj
# Instale as dependências
pip install -r requirements-web.txt
pip install -r requirements-ia.txt # opcional: Gemini/Groq
# Configure as variáveis de ambiente
cp .env.example .env
# Edite .env com sua GEMINI_API_KEY
# Rode o dashboard
python web_app.py
# → http://localhost:5055/dashboardpython __main__.py coletar # coleta contratos do PNCP
python __main__.py enriquecer # enriquece com BrasilAPI
python __main__.py analisar # detecta anomalias
python __main__.py investigar # gera narrativas IA (Gemma4 + Gemini)python __main__.py investigar_profundo <alerta_id>python -m automacoes.pipeline --once # uma execução
python -m automacoes.pipeline --daemon # APScheduler contínuopython __main__.py dossie --alerta 42 --formato md
python __main__.py dossie --alerta 42 --formato pdfDocumentação interativa em /api/docs (Swagger UI). Só GET, sem autenticação, CORS liberado, com rate limit por IP (60 req/min por padrão; resposta 429 + cabeçalhos X-RateLimit-*):
# Alertas de alto risco no Rio de Janeiro (IBGE 3304557)
curl "https://sentinela-rj.fly.dev/api/v1/alertas?severidade=alta&municipio_ibge=3304557"
# Contratos de um fornecedor específico (CNPJ só dígitos)
curl "https://sentinela-rj.fly.dev/api/v1/contratos?fornecedor_ni=98765432000111"
# Precisão medida de cada detector
curl "https://sentinela-rj.fly.dev/api/v1/precisao"
# Especificação OpenAPI 3.0
curl "https://sentinela-rj.fly.dev/api/v1/openapi.json"| Variável | Descrição | Padrão |
|---|---|---|
GEMINI_API_KEY |
Gemini API (narrativas e vereditos) | — |
SENTINELA_IA_PROVIDER |
gemini no deploy, ollama local |
ollama |
GROQ_API_KEY |
Groq (fallback opcional) | — |
DB_PATH |
Caminho do SQLite | data/sentinela_rj.db |
DATAJUD_API_KEY |
DataJud CNJ (chave pública disponível na wiki) | — |
SENTINELA_IA_REVISAO_GEMINI |
Habilita veredito Gemini | true |
SENTINELA_IA_REVISAO_GEMMA4 |
Habilita veredito Gemma4 | true |
GEMMA4_MODEL |
Modelo Gemma4 no Ollama | gemma4:12b |
MUNICIPIO_IBGE |
Código IBGE do município | 3304557 (Rio) |
PIPELINE_CRON |
Expressão cron do pipeline | 0 8 * * 1 |
SENTINELA_API_RATELIMIT |
Limite por IP da API pública (/api/v1) |
60 per minute |
Lista completa em:
.env.example
sentinela-rj/
├── web_app.py # Núcleo Flask — app, segurança, recursos compartilhados
├── routes/ # Blueprints por domínio (alertas, fornecedores,
│ # painel, watchlists, conflitos, casos, exportação)
├── __main__.py # CLI (coletar, analisar, investigar...)
├── analise/
│ └── motor_ia.py # Gemma4 + Gemini — narrativas e vereditos A/B
├── analisador/ # 9 detectores de anomalia
├── investigacao/ # Agente ReAct
│ ├── agente.py # ReAct loop principal
│ └── ferramentas/ # BrasilAPI, PNCP, DataJud, TCM
├── automacoes/
│ └── pipeline.py # Pipeline agendado
├── db/ # SQLite — conexão e migrações
├── relatorios/
│ └── dossie.py # Dossiê exportável (MD/PDF/JSON)
├── static/ # UI web (HTML/CSS/JS)
├── tests/ # 101+ testes pytest
├── Dockerfile # Container para Fly.io
├── fly.toml # Config deploy
└── .env.example # Variáveis documentadas
Fluxo principal:
PNCP API → extrator → SQLite
↓
9 detectores → alertas
↓
Gemma4 (narrativa) + Gemini/Gemma4 (veredito A/B)
↓
Dashboard Flask → Auditor humano
↓
Agente ReAct (investigação profunda) → Dossiê
fly auth login
fly launch --no-deploy --name sentinela-rj --region gru
fly volumes create sentinela_data --region gru --size 1
fly secrets set GEMINI_API_KEY=... SENTINELA_IA_PROVIDER=gemini
fly deploy
# Upload do banco local
fly sftp shell
# >> put data/sentinela_rj.db /data/sentinela_rj.db
⚠️ Ollama/Gemma4 não disponíveis no Fly.io — IA via Gemini em produção.
# Instalar as dependências de desenvolvimento (inclui pytest + libs de todos os domínios)
pip install -r requirements-dev.txt
# Rodar todos os testes
pytest
# Com cobertura
pytest --cov=analise --cov-report=term-missing
# Teste específico
pytest tests/test_motor_ia.py -v272 testes cobrindo motor IA, detectores, pipeline, dashboard, dossiê e conflito de interesse.
- Modelar um pipeline de dados públicos ponta a ponta: coleta, persistência, enriquecimento, análise e apresentação.
- Separar sinais estatísticos de conclusões: o sistema aponta indícios, mas mantém a decisão final como auditoria humana.
- Trabalhar com limitações reais de APIs públicas, dados incompletos e diferenças entre ambiente local e produção.
- Usar LLMs como apoio explicativo, não como única fonte de decisão.
- Criar testes para regras de negócio sensíveis, como detectores de anomalia, score composto, dossiês e triagem.
- Fazer deploy de uma aplicação orientada a dados com SQLite persistente em produção.
📋 Plano estratégico completo — pilares, fases e métricas para tornar o Sentinela referência em fiscalização pública:
docs/ROADMAP.md.
- Dashboard Flask com triagem, dossiê, grafo e narrativa IA
- 9 detectores de anomalia (IQR, concentração, fracionamento, etc.)
- Pipeline agendado com notificações Discord
- Gemma 4 12B como gerador principal de narrativas
- Comparação A/B de vereditos Gemini vs Gemma4
- Agente Investigador ReAct com 5 ferramentas
- Investigação profunda em background com polling
- Deploy público Fly.io com SQLite persistente
- Multi-município via env
- API pública REST documentada (OpenAPI 3.0 + Swagger UI em
/api/docs) - TJRJ processos via Playwright com credencial (issue #2)
- Transparência RJ empenhos reais
- Busca natural em linguagem humana
- Alertas Telegram para cidadãos
- Mapa geográfico de contratos por bairro
Feito com ☕ e IA em / Made with ☕ and AI in 🇧🇷 Rio de Janeiro
Todos os dados são públicos e obtidos de fontes oficiais do governo brasileiro.
All data is public and sourced from official Brazilian government portals.