caarleexx commited on
Commit
35e36f1
·
verified ·
1 Parent(s): 0cf34e5

Upload 7 files

Browse files
Files changed (7) hide show
  1. GUIA_USO.txt +159 -0
  2. README.md +74 -66
  3. app_gradio.py +476 -0
  4. deploy_integrado.sh +79 -0
  5. exemplos.json +33 -0
  6. requirements.txt +4 -15
  7. test_api.py +65 -0
GUIA_USO.txt ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ╔══════════════════════════════════════════════════════════════════════════════╗
2
+ ║ PARA.AI RAG - GUIA DE USO VISUAL ║
3
+ ╚══════════════════════════════════════════════════════════════════════════════╝
4
+
5
+ ┌──────────────────────────────────────────────────────────────────────────────┐
6
+ │ TELA INICIAL │
7
+ └──────────────────────────────────────────────────────────────────────────────┘
8
+
9
+ ╔════════════════════════════════════════════════════════════════╗
10
+ ║ 🐝⚛️ (voando) ⚖️ Para.AI RAG Cluster 🌻 🌼 🌺 ║
11
+ ║ Busca Inteligente de Jurisprudências ║
12
+ ╚════════════════════════════════════════════════════════════════╝
13
+
14
+ ┌─────────────────────┐ ┌────────────────────────────────────┐
15
+ │ 🎯 Tipo de Busca │ │ ✍️ Sua Consulta │
16
+ │ │ │ │
17
+ │ ○ Busca Semântica ✓ │ │ despejo por falta de pagamento │
18
+ │ ○ Palavras-Chave │ │ │
19
+ │ ○ Busca por ID │ │ │
20
+ │ │ ├────────────────────────────────────┤
21
+ │ 📊 Resultados: [5] │ │ [🔍 Pesquisar] [🗑️ Limpar] │
22
+ └─────────────────────┘ └────────────────────────────────────┘
23
+
24
+ ┌──────────────────────────────────────────────────────────────────────────────┐
25
+ │ RESULTADOS │
26
+ └──────────────────────────────────────────────────────────────────────────────┘
27
+
28
+ ╔════════════════════════════════════════════════════════════════╗
29
+ ║ 🐝 Resultados da Busca ║
30
+ ║ ║
31
+ ║ 📊 5 resultado(s) ⚡ 145ms 🏷️ RAG-0301 ║
32
+ ╚════════════════════════════════════════════════════════════════╝
33
+
34
+ ┌────────────────────────────────────────────────────────────────┐
35
+ │ ① 1234567-89.2023.8.16.0001 Distância: 0.2341 │
36
+ │ │
37
+ │ APELAÇÃO CÍVEL. AÇÃO DE DESPEJO POR FALTA DE PAGAMENTO. │
38
+ │ LOCAÇÃO RESIDENCIAL. DÉBITOS COMPROVADOS. NOTIFICAÇÃO │
39
+ │ PREMONITÓRIA VÁLIDA. SENTENÇA MANTIDA... │
40
+ └────────────────────────────────────────────────────────────────┘
41
+
42
+ ┌────────────────────────────────────────────────────────────────┐
43
+ │ ② 9876543-21.2022.8.16.0013 Distância: 0.2567 │
44
+ │ │
45
+ │ AGRAVO DE INSTRUMENTO. LOCAÇÃO NÃO RESIDENCIAL. DESPEJO │
46
+ │ POR FALTA DE PAGAMENTO. LIMINAR DEFERIDA. PRESENÇA DOS │
47
+ │ REQUISITOS LEGAIS. MANUTENÇÃO DA DECISÃO... │
48
+ └────────────────────────────────────────────────────────────────┘
49
+
50
+ [... mais 3 resultados ...]
51
+
52
+
53
+ ┌──────────────────────────────────────────────────────────────────────────────┐
54
+ │ STATUS DURANTE SETUP │
55
+ └──────────────────────────────────────────────────────────────────────────────┘
56
+
57
+ ┌────────────────────────────────────────────────────────────────┐
58
+ │ 🔧 RAG Ainda em Construção │
59
+ │ │
60
+ │ Status: Construindo ChromaDB com embeddings │
61
+ │ │
62
+ │ ████████████████████████████████░░░░░░░░░░░░░░░░░░░░ 70% │
63
+ │ │
64
+ │ Aguarde alguns minutos e tente novamente... │
65
+ └────────────────────────────────────────────────────────────────┘
66
+
67
+
68
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
69
+
70
+ 💡 EXEMPLOS DE USO
71
+
72
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
73
+
74
+ 1️⃣ BUSCA SEMÂNTICA (mais inteligente)
75
+
76
+ Digite: "despejo por falta de pagamento do aluguel"
77
+
78
+ A IA entende:
79
+ - Contexto de locação
80
+ - Inadimplemento do locatário
81
+ - Processo de despejo
82
+
83
+ Retorna: Acórdãos sobre despejo + locação + falta de pagamento
84
+
85
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
86
+
87
+ 2️⃣ BUSCA POR PALAVRAS-CHAVE (mais rápida)
88
+
89
+ Digite: "despejo, locação, inadimplemento"
90
+
91
+ Busca literal por:
92
+ - "despejo" OU
93
+ - "locação" OU
94
+ - "inadimplemento"
95
+
96
+ Retorna: Documentos que contêm esses termos
97
+
98
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
99
+
100
+ 3️⃣ BUSCA POR ID (mais precisa)
101
+
102
+ Digite: "1234567-89.2023.8.16.0001"
103
+
104
+ Retorna: Exatamente esse processo
105
+
106
+ (Múltiplos IDs separados por vírgula também funcionam)
107
+
108
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
109
+
110
+
111
+ 🎨 CORES E ANIMAÇÕES
112
+
113
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
114
+
115
+ 🐝 Abelha: Voa da esquerda para direita com movimento suave
116
+ Brilho dourado pulsante (efeito atômico ⚛️)
117
+
118
+ 🌻 Flores: Balançam suavemente no vento
119
+ Aparecem no "campo" na parte inferior
120
+
121
+ 🎨 Tema: Gradiente roxo/violeta (profissional)
122
+ Cards brancos com sombra
123
+ Badges coloridos por tipo de info
124
+
125
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
126
+
127
+
128
+ ⚡ PERFORMANCE
129
+
130
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
131
+
132
+ Busca Semântica: ~150-300ms (depende do top_k)
133
+ Palavras-Chave: ~50-100ms (mais rápida)
134
+ Busca por ID: ~20-50ms (instantânea)
135
+
136
+ Timeout: 30 segundos
137
+ Retry: Automático em caso de falha
138
+
139
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
140
+
141
+
142
+ 🔧 CONFIGURAÇÃO AVANÇADA
143
+
144
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
145
+
146
+ Edite app_gradio.py:
147
+
148
+ # URL da API (se diferente de localhost)
149
+ API_BASE_URL = "https://seu-usuario-para-ai-rag.hf.space"
150
+
151
+ # Porta do Gradio
152
+ demo.launch(server_port=7861)
153
+
154
+ # Compartilhar publicamente (gera link temporário)
155
+ demo.launch(share=True)
156
+
157
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
158
+
159
+ ⚖️ Para.AI - InJustiça não para o Paraná! 🐝
README.md CHANGED
@@ -1,89 +1,97 @@
1
- ---
2
- title: Para.AI RAG Cluster 0301
3
- emoji: ⚖️
4
- colorFrom: blue
5
- colorTo: purple
6
- sdk: docker
7
- pinned: false
8
- license: agpl-3.0
9
- ---
10
 
11
- # ⚖️ Para.AI RAG Cluster
12
 
13
- Micro-cluster RAG para jurisprudências do TJPR usando Hugging Face Spaces (free tier).
14
 
15
- ## 🚀 Como Funciona
 
 
 
 
 
 
16
 
17
- **Arquitetura anti-timeout:**
18
- 1. FastAPI inicia **imediatamente** (<3s)
19
- 2. Setup roda em **background** (~15min)
20
- 3. HF Spaces **não fecha** por timeout
21
- 4. Você acompanha progresso via `/setup/status`
22
 
23
- ## 📡 Endpoints
24
 
25
- ### Durante Setup (primeiros 15min)
 
 
 
 
 
 
 
 
 
26
 
27
  ```bash
28
- # Ver progresso
29
- curl https://SEU-USUARIO-para-ai-rag-0301.hf.space/setup/status
30
-
31
- # Resposta:
32
- {
33
- "status": "building",
34
- "message": "Construindo ChromaDB com embeddings",
35
- "progress": 70,
36
- "timestamp": "2026-02-10T20:15:00"
37
- }
38
  ```
39
 
40
- ### Após Setup Completo
 
 
41
 
42
- - `POST /search/embedding` - Busca semântica
43
- - `POST /search/keywords` - Busca por termos
44
- - `POST /search/by_id` - Busca por ID
45
- - `GET /cluster/info` - Info do cluster
46
 
47
- ## 🔧 Deploy
 
 
48
 
49
- 1. **Editar `config.yaml`:**
50
- ```yaml
51
- cluster_id: "RAG-0301"
52
- chunk_start: 301
53
- chunk_end: 600
54
- github_repo: "https://github.com/SEU-USUARIO/para-ai-data.git"
55
- ```
56
 
57
- 2. **Criar Space:**
58
- ```bash
59
- huggingface-cli repo create para-ai-rag-0301 --type space --space_sdk docker
60
- ```
61
 
62
- 3. **Upload:**
63
- ```bash
64
- git init
65
- git remote add origin https://huggingface.co/spaces/SEU-USUARIO/para-ai-rag-0301
66
- git add .
67
- git commit -m "Deploy"
68
- git push origin main
69
- ```
70
 
71
- 4. **Monitorar:**
72
- Space fica online em ~3s, RAG pronto em ~15min
 
 
73
 
74
- ## 📊 Monitoramento
75
 
76
- ```bash
77
- # Status atual
78
- curl https://SEU-USUARIO-para-ai-rag-0301.hf.space/
79
 
80
- # Logs do setup
81
- # (via interface HF Spaces)
 
 
 
 
 
 
82
  ```
83
 
84
- ## 📚 Documentação
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
- - `QUICKSTART.txt` - Deploy em 5 minutos
87
- - `INSTRUCTIONS.md` - Guia completo
88
 
89
- ⚖️ **InJustiça não para o Paraná!** 🐝
 
1
+ # Para.AI RAG - Interface Gradio
 
 
 
 
 
 
 
 
2
 
3
+ Interface web linda para busca de jurisprudências do TJPR! 🐝⚛️
4
 
5
+ ## Features
6
 
7
+ - 🐝 Abelha atômica animada voando sobre campo de flores
8
+ - 🎯 3 tipos de busca: Semântica, Palavras-Chave, ID
9
+ - 📊 Controle de número de resultados (1-20)
10
+ - 📋 Exibição elegante com cards coloridos
11
+ - 🔧 Monitoramento de setup em tempo real
12
+ - ⚡ Mostra tempo de resposta
13
+ - 💡 Exemplos contextuais
14
 
15
+ ## 🚀 Como Rodar
 
 
 
 
16
 
17
+ ### Pré-requisitos
18
 
19
+ 1. API FastAPI rodando (do projeto anterior)
20
+ 2. Python 3.11+
21
+
22
+ ### Instalação
23
+
24
+ ```bash
25
+ pip install -r requirements.txt
26
+ ```
27
+
28
+ ### Executar
29
 
30
  ```bash
31
+ python app_gradio.py
 
 
 
 
 
 
 
 
 
32
  ```
33
 
34
+ Acesse: http://localhost:7861
35
+
36
+ ## 🔧 Configuração
37
 
38
+ Edite `API_BASE_URL` no início do `app_gradio.py` se sua API estiver em outro endereço:
 
 
 
39
 
40
+ ```python
41
+ API_BASE_URL = "http://localhost:7860" # Ou URL do HF Space
42
+ ```
43
 
44
+ ## 📖 Como Usar
 
 
 
 
 
 
45
 
46
+ ### Busca Semântica (Recomendado)
47
+ Digite uma frase natural:
48
+ - "despejo por falta de pagamento do aluguel"
49
+ - "acidente de trânsito com danos morais"
50
 
51
+ ### Busca por Palavras-Chave
52
+ Digite termos separados por vírgula:
53
+ - despejo, locação, inadimplemento
54
+ - danos morais, acidente
 
 
 
 
55
 
56
+ ### Busca por ID
57
+ Digite IDs de processos separados por vírgula:
58
+ - 1234567-89.2023.8.16.0001
59
+ - 9876543-21.2022.8.16.0013, 1111111-11.2021.8.16.0001
60
 
61
+ ## 🎨 Personalização
62
 
63
+ ### Mudar Cores
 
 
64
 
65
+ Edite o tema no código:
66
+
67
+ ```python
68
+ theme=gr.themes.Soft(
69
+ primary_hue="purple", # Mude aqui!
70
+ secondary_hue="violet",
71
+ neutral_hue="slate",
72
+ )
73
  ```
74
 
75
+ ### Mudar Animações
76
+
77
+ Edite o CSS customizado na variável `custom_css`.
78
+
79
+ ## 🐛 Troubleshooting
80
+
81
+ **Erro "Connection refused":**
82
+ - Verifique se a API FastAPI está rodando
83
+ - Confirme o `API_BASE_URL`
84
+
85
+ **Resultados vazios:**
86
+ - Aguarde o setup completar (veja progresso na interface)
87
+ - Tente termos mais específicos
88
+
89
+ **Interface não carrega:**
90
+ - Verifique se a porta 7861 está livre
91
+ - Rode com `python app_gradio.py --debug`
92
+
93
+ ## ⚖️ Para.AI
94
 
95
+ InJustiça não para o Paraná! 🐝
 
96
 
97
+ Desenvolvido com ❤️ usando Gradio
app_gradio.py ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Para.AI RAG Cluster - Interface Gradio
4
+ Frontend bonito com abelha atômica! 🐝⚛️
5
+ """
6
+
7
+ import gradio as gr
8
+ import requests
9
+ import json
10
+ import time
11
+ from typing import Dict, List, Any
12
+
13
+ # ============================================================================
14
+ # CONFIGURAÇÃO
15
+ # ============================================================================
16
+
17
+ API_BASE_URL = "http://localhost:7860" # Mude se necessário
18
+
19
+ # ============================================================================
20
+ # FUNÇÕES DE BUSCA
21
+ # ============================================================================
22
+
23
+ def check_status() -> Dict[str, Any]:
24
+ """Verifica status do RAG"""
25
+ try:
26
+ response = requests.get(f"{API_BASE_URL}/")
27
+ return response.json()
28
+ except Exception as e:
29
+ return {"error": str(e)}
30
+
31
+ def check_setup_status() -> Dict[str, Any]:
32
+ """Verifica progresso do setup"""
33
+ try:
34
+ response = requests.get(f"{API_BASE_URL}/setup/status")
35
+ return response.json()
36
+ except Exception as e:
37
+ return {"error": str(e)}
38
+
39
+ def buscar_jurisprudencia(tipo_busca: str, query: str, top_k: int = 5) -> str:
40
+ """
41
+ Busca jurisprudências via API
42
+
43
+ Args:
44
+ tipo_busca: "Busca Semântica", "Busca por Palavras-Chave", ou "Busca por ID"
45
+ query: Texto de busca
46
+ top_k: Número de resultados
47
+
48
+ Returns:
49
+ HTML formatado com resultados
50
+ """
51
+
52
+ # Verificar se query não está vazia
53
+ if not query or query.strip() == "":
54
+ return """
55
+ <div style="padding: 20px; background: #fff3cd; border-left: 4px solid #ffc107; border-radius: 8px;">
56
+ <h3 style="color: #856404; margin: 0;">⚠️ Campo Vazio</h3>
57
+ <p style="color: #856404; margin: 10px 0 0 0;">Por favor, insira um termo de busca!</p>
58
+ </div>
59
+ """
60
+
61
+ # Verificar se RAG está pronto
62
+ status = check_status()
63
+ if not status.get("rag_ready", False):
64
+ setup_info = check_setup_status()
65
+ progress = setup_info.get("progress", 0)
66
+ message = setup_info.get("message", "Setup em andamento...")
67
+
68
+ return f"""
69
+ <div style="padding: 20px; background: #d1ecf1; border-left: 4px solid #0c5460; border-radius: 8px;">
70
+ <h3 style="color: #0c5460; margin: 0;">🔧 RAG Ainda em Construção</h3>
71
+ <p style="color: #0c5460; margin: 10px 0;">Status: {message}</p>
72
+ <div style="background: #bee5eb; border-radius: 8px; height: 30px; margin-top: 10px; overflow: hidden;">
73
+ <div style="background: linear-gradient(90deg, #17a2b8, #138496); height: 100%; width: {progress}%;
74
+ display: flex; align-items: center; justify-content: center; color: white; font-weight: bold;
75
+ transition: width 0.3s ease;">
76
+ {progress}%
77
+ </div>
78
+ </div>
79
+ <p style="color: #0c5460; margin: 10px 0 0 0; font-size: 0.9em;">
80
+ Aguarde alguns minutos e tente novamente...
81
+ </p>
82
+ </div>
83
+ """
84
+
85
+ try:
86
+ start_time = time.time()
87
+
88
+ # Determinar endpoint e payload
89
+ if tipo_busca == "Busca Semântica (Embeddings)":
90
+ endpoint = f"{API_BASE_URL}/search/embedding"
91
+ payload = {
92
+ "query": query,
93
+ "top_k": top_k,
94
+ "return_embeddings": False
95
+ }
96
+
97
+ elif tipo_busca == "Busca por Palavras-Chave":
98
+ # Dividir query em keywords
99
+ keywords = [k.strip() for k in query.split(",") if k.strip()]
100
+ if not keywords:
101
+ keywords = query.split()
102
+
103
+ endpoint = f"{API_BASE_URL}/search/keywords"
104
+ payload = {
105
+ "keywords": keywords,
106
+ "operator": "OR",
107
+ "top_k": top_k
108
+ }
109
+
110
+ else: # Busca por ID
111
+ # IDs separados por vírgula
112
+ ids = [id.strip() for id in query.split(",") if id.strip()]
113
+
114
+ endpoint = f"{API_BASE_URL}/search/by_id"
115
+ payload = {
116
+ "ids": ids,
117
+ "return_embeddings": False
118
+ }
119
+
120
+ # Fazer request
121
+ response = requests.post(
122
+ endpoint,
123
+ json=payload,
124
+ headers={"Content-Type": "application/json"},
125
+ timeout=30
126
+ )
127
+
128
+ elapsed_time = (time.time() - start_time) * 1000 # ms
129
+
130
+ if response.status_code != 200:
131
+ return f"""
132
+ <div style="padding: 20px; background: #f8d7da; border-left: 4px solid #dc3545; border-radius: 8px;">
133
+ <h3 style="color: #721c24; margin: 0;">❌ Erro na Busca</h3>
134
+ <p style="color: #721c24; margin: 10px 0 0 0;">{response.text}</p>
135
+ </div>
136
+ """
137
+
138
+ data = response.json()
139
+ results = data.get("results", [])
140
+ total = data.get("total_results", 0)
141
+ cluster_id = data.get("cluster_id", "N/A")
142
+
143
+ # Gerar HTML dos resultados
144
+ html = f"""
145
+ <div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;">
146
+ <!-- Header -->
147
+ <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
148
+ color: white; padding: 20px; border-radius: 12px 12px 0 0; margin-bottom: 20px;">
149
+ <h2 style="margin: 0; display: flex; align-items: center; gap: 10px;">
150
+ 🐝 Resultados da Busca
151
+ </h2>
152
+ <div style="margin-top: 10px; font-size: 0.9em; opacity: 0.9;">
153
+ <span style="background: rgba(255,255,255,0.2); padding: 5px 10px; border-radius: 5px; margin-right: 10px;">
154
+ 📊 {total} resultado(s)
155
+ </span>
156
+ <span style="background: rgba(255,255,255,0.2); padding: 5px 10px; border-radius: 5px; margin-right: 10px;">
157
+ ⚡ {elapsed_time:.0f}ms
158
+ </span>
159
+ <span style="background: rgba(255,255,255,0.2); padding: 5px 10px; border-radius: 5px;">
160
+ 🏷️ {cluster_id}
161
+ </span>
162
+ </div>
163
+ </div>
164
+ """
165
+
166
+ if not results:
167
+ html += """
168
+ <div style="padding: 40px; text-align: center; background: #f8f9fa; border-radius: 8px;">
169
+ <div style="font-size: 48px; margin-bottom: 10px;">🔍</div>
170
+ <h3 style="color: #6c757d; margin: 0;">Nenhum resultado encontrado</h3>
171
+ <p style="color: #6c757d; margin: 10px 0 0 0;">Tente outros termos de busca</p>
172
+ </div>
173
+ """
174
+ else:
175
+ # Resultados
176
+ for idx, result in enumerate(results, 1):
177
+ doc_id = result.get("id", "N/A")
178
+ ementa = result.get("ementa", "")
179
+ distance = result.get("distance")
180
+ score = result.get("score")
181
+
182
+ # Truncar ementa se muito longa
183
+ if len(ementa) > 500:
184
+ ementa_display = ementa[:500] + "..."
185
+ else:
186
+ ementa_display = ementa
187
+
188
+ # Score/distance badge
189
+ if distance is not None:
190
+ badge = f'<span style="background: #28a745; color: white; padding: 3px 8px; border-radius: 5px; font-size: 0.85em;">Distância: {distance:.4f}</span>'
191
+ elif score is not None:
192
+ badge = f'<span style="background: #007bff; color: white; padding: 3px 8px; border-radius: 5px; font-size: 0.85em;">Score: {score:.4f}</span>'
193
+ else:
194
+ badge = ''
195
+
196
+ html += f"""
197
+ <div style="background: white; border: 2px solid #e9ecef; border-radius: 12px;
198
+ padding: 20px; margin-bottom: 15px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
199
+
200
+ <!-- Cabeçalho do resultado -->
201
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
202
+ <div style="display: flex; align-items: center; gap: 10px;">
203
+ <span style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
204
+ color: white; width: 32px; height: 32px; border-radius: 50%;
205
+ display: flex; align-items: center; justify-content: center;
206
+ font-weight: bold; font-size: 14px;">
207
+ {idx}
208
+ </span>
209
+ <code style="background: #f8f9fa; padding: 5px 10px; border-radius: 5px;
210
+ font-size: 0.9em; color: #495057;">
211
+ {doc_id}
212
+ </code>
213
+ </div>
214
+ {badge}
215
+ </div>
216
+
217
+ <!-- Ementa -->
218
+ <div style="color: #343a40; line-height: 1.6; text-align: justify;">
219
+ {ementa_display}
220
+ </div>
221
+ </div>
222
+ """
223
+
224
+ html += "</div>"
225
+ return html
226
+
227
+ except requests.exceptions.Timeout:
228
+ return """
229
+ <div style="padding: 20px; background: #f8d7da; border-left: 4px solid #dc3545; border-radius: 8px;">
230
+ <h3 style="color: #721c24; margin: 0;">⏱️ Timeout</h3>
231
+ <p style="color: #721c24; margin: 10px 0 0 0;">A busca demorou muito. Tente novamente.</p>
232
+ </div>
233
+ """
234
+
235
+ except Exception as e:
236
+ return f"""
237
+ <div style="padding: 20px; background: #f8d7da; border-left: 4px solid #dc3545; border-radius: 8px;">
238
+ <h3 style="color: #721c24; margin: 0;">❌ Erro Inesperado</h3>
239
+ <p style="color: #721c24; margin: 10px 0 0 0;">{str(e)}</p>
240
+ </div>
241
+ """
242
+
243
+ # ============================================================================
244
+ # INTERFACE GRADIO
245
+ # ============================================================================
246
+
247
+ # CSS customizado com abelha atômica animada
248
+ custom_css = """
249
+ @keyframes fly {
250
+ 0%, 100% { transform: translate(0, 0) rotate(0deg); }
251
+ 25% { transform: translate(10px, -10px) rotate(5deg); }
252
+ 50% { transform: translate(20px, 0) rotate(0deg); }
253
+ 75% { transform: translate(10px, 10px) rotate(-5deg); }
254
+ }
255
+
256
+ @keyframes glow {
257
+ 0%, 100% { filter: drop-shadow(0 0 5px rgba(255, 215, 0, 0.7)); }
258
+ 50% { filter: drop-shadow(0 0 15px rgba(255, 215, 0, 1)); }
259
+ }
260
+
261
+ .bee-container {
262
+ position: relative;
263
+ width: 100%;
264
+ height: 120px;
265
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
266
+ border-radius: 12px;
267
+ overflow: hidden;
268
+ margin-bottom: 20px;
269
+ }
270
+
271
+ .bee {
272
+ position: absolute;
273
+ top: 40%;
274
+ left: 10%;
275
+ font-size: 48px;
276
+ animation: fly 4s ease-in-out infinite, glow 2s ease-in-out infinite;
277
+ }
278
+
279
+ .field {
280
+ position: absolute;
281
+ bottom: 0;
282
+ width: 100%;
283
+ height: 30%;
284
+ background: linear-gradient(to top, rgba(76, 175, 80, 0.3), transparent);
285
+ }
286
+
287
+ .flower {
288
+ position: absolute;
289
+ bottom: 10px;
290
+ font-size: 24px;
291
+ animation: sway 2s ease-in-out infinite;
292
+ }
293
+
294
+ @keyframes sway {
295
+ 0%, 100% { transform: rotate(-3deg); }
296
+ 50% { transform: rotate(3deg); }
297
+ }
298
+
299
+ .title-container {
300
+ position: absolute;
301
+ top: 50%;
302
+ left: 50%;
303
+ transform: translate(-50%, -50%);
304
+ text-align: center;
305
+ color: white;
306
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
307
+ }
308
+
309
+ footer {visibility: hidden;}
310
+ """
311
+
312
+ # Interface
313
+ with gr.Blocks(
314
+ title="Para.AI RAG - Busca de Jurisprudência",
315
+ css=custom_css,
316
+ theme=gr.themes.Soft(
317
+ primary_hue="purple",
318
+ secondary_hue="violet",
319
+ neutral_hue="slate",
320
+ )
321
+ ) as demo:
322
+
323
+ # Header com abelha
324
+ gr.HTML("""
325
+ <div class="bee-container">
326
+ <div class="bee">🐝⚛️</div>
327
+ <div class="field">
328
+ <span class="flower" style="left: 20%;">🌻</span>
329
+ <span class="flower" style="left: 50%;">🌼</span>
330
+ <span class="flower" style="left: 80%;">🌺</span>
331
+ </div>
332
+ <div class="title-container">
333
+ <h1 style="margin: 0; font-size: 32px;">⚖️ Para.AI RAG Cluster</h1>
334
+ <p style="margin: 5px 0 0 0; font-size: 16px; opacity: 0.9;">
335
+ Busca Inteligente de Jurisprudências do TJPR
336
+ </p>
337
+ </div>
338
+ </div>
339
+ """)
340
+
341
+ gr.Markdown("""
342
+ ### 🔍 Como Usar
343
+
344
+ 1. **Selecione o tipo de busca** que deseja realizar
345
+ 2. **Digite sua consulta** no campo de texto
346
+ 3. **Clique em Pesquisar** e aguarde os resultados
347
+
348
+ ---
349
+ """)
350
+
351
+ with gr.Row():
352
+ with gr.Column(scale=1):
353
+ tipo_busca = gr.Radio(
354
+ choices=[
355
+ "Busca Semântica (Embeddings)",
356
+ "Busca por Palavras-Chave",
357
+ "Busca por ID"
358
+ ],
359
+ value="Busca Semântica (Embeddings)",
360
+ label="🎯 Tipo de Busca",
361
+ info="Escolha o método de busca mais adequado"
362
+ )
363
+
364
+ top_k = gr.Slider(
365
+ minimum=1,
366
+ maximum=20,
367
+ value=5,
368
+ step=1,
369
+ label="📊 Número de Resultados",
370
+ info="Quantos resultados exibir (1-20)"
371
+ )
372
+
373
+ with gr.Column(scale=2):
374
+ query_input = gr.Textbox(
375
+ label="✍️ Sua Consulta",
376
+ placeholder="Ex: despejo por falta de pagamento, usucapião, danos morais...",
377
+ lines=3,
378
+ info="Digite os termos de busca, IDs separados por vírgula, ou uma pergunta"
379
+ )
380
+
381
+ with gr.Row():
382
+ search_btn = gr.Button(
383
+ "🔍 Pesquisar",
384
+ variant="primary",
385
+ size="lg"
386
+ )
387
+ clear_btn = gr.Button(
388
+ "🗑️ Limpar",
389
+ variant="secondary"
390
+ )
391
+
392
+ # Resultados
393
+ gr.Markdown("### 📋 Resultados")
394
+ results_output = gr.HTML(
395
+ value="""
396
+ <div style="padding: 40px; text-align: center; background: #f8f9fa; border-radius: 12px;">
397
+ <div style="font-size: 64px; margin-bottom: 15px;">🐝</div>
398
+ <h3 style="color: #6c757d; margin: 0;">Pronto para buscar!</h3>
399
+ <p style="color: #6c757d; margin: 10px 0 0 0;">
400
+ Digite sua consulta acima e clique em Pesquisar
401
+ </p>
402
+ </div>
403
+ """
404
+ )
405
+
406
+ # Exemplos
407
+ gr.Markdown("""
408
+ ---
409
+ ### 💡 Exemplos de Consultas
410
+
411
+ **Busca Semântica:**
412
+ - "despejo por falta de pagamento do aluguel"
413
+ - "acidente de trânsito com danos morais"
414
+ - "usucapião de imóvel rural"
415
+
416
+ **Busca por Palavras-Chave:**
417
+ - despejo, locação, inadimplemento
418
+ - danos morais, acidente, trânsito
419
+
420
+ **Busca por ID:**
421
+ - 1234567-89.2023.8.16.0001
422
+ - 9876543-21.2022.8.16.0013, 1111111-11.2021.8.16.0001
423
+ """)
424
+
425
+ # Rodapé
426
+ gr.Markdown("""
427
+ ---
428
+ <div style="text-align: center; color: #6c757d; padding: 20px;">
429
+ <p style="margin: 0;">
430
+ ⚖️ <strong>Para.AI</strong> - InJustiça não para o Paraná! 🐝
431
+ </p>
432
+ <p style="margin: 5px 0 0 0; font-size: 0.9em;">
433
+ Desenvolvido com ❤️ usando Gradio + ChromaDB + Sentence Transformers
434
+ </p>
435
+ </div>
436
+ """)
437
+
438
+ # Eventos
439
+ search_btn.click(
440
+ fn=buscar_jurisprudencia,
441
+ inputs=[tipo_busca, query_input, top_k],
442
+ outputs=results_output
443
+ )
444
+
445
+ clear_btn.click(
446
+ fn=lambda: ("", """
447
+ <div style="padding: 40px; text-align: center; background: #f8f9fa; border-radius: 12px;">
448
+ <div style="font-size: 64px; margin-bottom: 15px;">🐝</div>
449
+ <h3 style="color: #6c757d; margin: 0;">Pronto para buscar!</h3>
450
+ <p style="color: #6c757d; margin: 10px 0 0 0;">
451
+ Digite sua consulta acima e clique em Pesquisar
452
+ </p>
453
+ </div>
454
+ """),
455
+ inputs=None,
456
+ outputs=[query_input, results_output]
457
+ )
458
+
459
+ # Enter key para buscar
460
+ query_input.submit(
461
+ fn=buscar_jurisprudencia,
462
+ inputs=[tipo_busca, query_input, top_k],
463
+ outputs=results_output
464
+ )
465
+
466
+ # ============================================================================
467
+ # LAUNCH
468
+ # ============================================================================
469
+
470
+ if __name__ == "__main__":
471
+ demo.launch(
472
+ server_name="0.0.0.0",
473
+ server_port=7861,
474
+ share=False,
475
+ show_error=True
476
+ )
deploy_integrado.sh ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # deploy_integrado.sh - Deploy completo (API + Frontend)
3
+
4
+ set -e
5
+
6
+ echo "╔══════════════════════════════════════════════════════════════╗"
7
+ echo "║ PARA.AI RAG - DEPLOY INTEGRADO ║"
8
+ echo "╚══════════════════════════════════════════════════════════════╝"
9
+ echo ""
10
+
11
+ # Verificar dependências
12
+ echo "1️⃣ Verificando dependências..."
13
+ command -v python3 >/dev/null 2>&1 || { echo "❌ Python3 não encontrado!"; exit 1; }
14
+ command -v pip >/dev/null 2>&1 || { echo "❌ pip não encontrado!"; exit 1; }
15
+ echo " ✅ Python OK"
16
+ echo ""
17
+
18
+ # Instalar dependências
19
+ echo "2️⃣ Instalando dependências..."
20
+ pip install -q -r requirements.txt
21
+ echo " ✅ Dependências instaladas"
22
+ echo ""
23
+
24
+ # Iniciar API em background
25
+ echo "3️⃣ Iniciando API FastAPI..."
26
+ cd ../para_ai_rag_cluster 2>/dev/null || {
27
+ echo " ⚠️ Pasta para_ai_rag_cluster não encontrada"
28
+ echo " Pulando inicialização da API..."
29
+ }
30
+
31
+ if [ -f "app.py" ]; then
32
+ python3 -u app.py > /tmp/para_ai_api.log 2>&1 &
33
+ API_PID=$!
34
+ echo " ✅ API iniciada (PID: $API_PID)"
35
+ echo " 📋 Logs em: /tmp/para_ai_api.log"
36
+
37
+ # Aguardar API iniciar
38
+ echo " ⏳ Aguardando API responder..."
39
+ sleep 5
40
+
41
+ # Testar conexão
42
+ if curl -s http://localhost:7860/ > /dev/null 2>&1; then
43
+ echo " ✅ API respondendo!"
44
+ else
45
+ echo " ⚠️ API pode não estar pronta ainda"
46
+ echo " (Normal se setup ainda rodando)"
47
+ fi
48
+
49
+ cd - > /dev/null
50
+ else
51
+ echo " ⚠️ app.py não encontrado, pulando..."
52
+ fi
53
+
54
+ echo ""
55
+
56
+ # Iniciar Gradio
57
+ echo "4️⃣ Iniciando Interface Gradio..."
58
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
59
+ echo ""
60
+ echo "🐝 Interface estará disponível em:"
61
+ echo " → http://localhost:7861"
62
+ echo ""
63
+ echo "📊 API estará em:"
64
+ echo " → http://localhost:7860"
65
+ echo ""
66
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
67
+ echo ""
68
+
69
+ # Executar Gradio (bloqueia aqui)
70
+ python3 app_gradio.py
71
+
72
+ # Cleanup (só chega aqui se Ctrl+C)
73
+ echo ""
74
+ echo "🛑 Encerrando..."
75
+ if [ ! -z "$API_PID" ]; then
76
+ kill $API_PID 2>/dev/null || true
77
+ echo " ✅ API encerrada"
78
+ fi
79
+ echo "✅ Shutdown completo!"
exemplos.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "exemplos_busca_semantica": [
3
+ "despejo por falta de pagamento do aluguel",
4
+ "acidente de trânsito com danos morais e materiais",
5
+ "usucapião de imóvel rural abandonado",
6
+ "rescisão de contrato por inadimplemento",
7
+ "pensão alimentícia para filho menor",
8
+ "indenização por danos morais e materiais em acidente de trabalho",
9
+ "guarda compartilhada de filhos menores",
10
+ "divórcio consensual com partilha de bens",
11
+ "ação de cobrança de valores não pagos",
12
+ "direito de vizinhança e construção irregular"
13
+ ],
14
+
15
+ "exemplos_palavras_chave": [
16
+ "despejo, locação, inadimplemento",
17
+ "danos morais, acidente, trânsito",
18
+ "usucapião, posse, propriedade",
19
+ "alimentos, pensão, menor",
20
+ "trabalhista, rescisão, indenização",
21
+ "guarda, filhos, divórcio",
22
+ "cobrança, dívida, valores",
23
+ "vizinhança, construção, direito",
24
+ "contrato, rescisão, cláusula",
25
+ "herança, inventário, sucessão"
26
+ ],
27
+
28
+ "dicas": {
29
+ "busca_semantica": "Use frases completas e naturais. A IA entende o contexto!",
30
+ "palavras_chave": "Separe termos por vírgula. Busca mais rápida mas menos inteligente.",
31
+ "busca_id": "Cole o número do processo completo ou vários separados por vírgula."
32
+ }
33
+ }
requirements.txt CHANGED
@@ -1,16 +1,5 @@
1
- # FastAPI
2
- fastapi==0.109.0
3
- uvicorn[standard]==0.27.0
4
- pydantic==2.5.0
5
 
6
- # RAG / Embeddings
7
- chromadb==0.4.22
8
- sentence-transformers==2.3.1
9
- torch==2.1.2
10
-
11
- # Utilities
12
- PyYAML==6.0.1
13
- GitPython==3.1.41
14
- pandas==2.1.4
15
- numpy==1.26.3
16
- tqdm==4.66.1
 
1
+ # Interface Gradio
2
+ gradio==4.19.2
 
 
3
 
4
+ # HTTP requests
5
+ requests==2.31.0
 
 
 
 
 
 
 
 
 
test_api.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Script de teste rápido para verificar conexão com API
4
+ """
5
+ import requests
6
+ import json
7
+
8
+ API_URL = "http://localhost:7860"
9
+
10
+ print("🔍 Testando conexão com API...")
11
+ print("="*60)
12
+
13
+ # Teste 1: Status
14
+ print("\n1. Verificando status...")
15
+ try:
16
+ r = requests.get(f"{API_URL}/")
17
+ print(f" ✅ Status: {r.status_code}")
18
+ data = r.json()
19
+ print(f" RAG Ready: {data.get('rag_ready', False)}")
20
+ print(f" Setup: {data.get('setup', {}).get('status', 'N/A')}")
21
+ except Exception as e:
22
+ print(f" ❌ Erro: {e}")
23
+
24
+ # Teste 2: Setup status
25
+ print("\n2. Verificando setup...")
26
+ try:
27
+ r = requests.get(f"{API_URL}/setup/status")
28
+ print(f" ✅ Status: {r.status_code}")
29
+ data = r.json()
30
+ print(f" Progresso: {data.get('progress', 0)}%")
31
+ print(f" Mensagem: {data.get('message', 'N/A')}")
32
+ except Exception as e:
33
+ print(f" ❌ Erro: {e}")
34
+
35
+ # Teste 3: Busca (se pronto)
36
+ print("\n3. Testando busca semântica...")
37
+ try:
38
+ payload = {
39
+ "query": "teste",
40
+ "top_k": 3,
41
+ "return_embeddings": False
42
+ }
43
+ r = requests.post(
44
+ f"{API_URL}/search/embedding",
45
+ json=payload,
46
+ timeout=10
47
+ )
48
+
49
+ if r.status_code == 200:
50
+ data = r.json()
51
+ print(f" ✅ Busca OK!")
52
+ print(f" Total: {data.get('total_results', 0)} resultados")
53
+ print(f" Tempo: {data.get('query_time_ms', 0)}ms")
54
+ elif r.status_code == 503:
55
+ print(f" ⏳ RAG ainda não pronto (503)")
56
+ else:
57
+ print(f" ❌ Erro: {r.status_code}")
58
+
59
+ except Exception as e:
60
+ print(f" ❌ Erro: {e}")
61
+
62
+ print("\n" + "="*60)
63
+ print("✅ Testes completos!")
64
+ print("\nSe todos os testes passaram, rode:")
65
+ print(" python app_gradio.py")