caarleexx commited on
Commit
6bd6d32
·
verified ·
1 Parent(s): 53841dc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +824 -125
app.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import os
2
  import sys
3
  import json
@@ -177,97 +178,611 @@ def index():
177
  <!DOCTYPE html>
178
  <html>
179
  <head>
180
- <title>⚖️ STF - Busca Jurisprudencial</title>
181
  <meta charset="utf-8">
182
  <meta name="viewport" content="width=device-width, initial-scale=1">
183
  <style>
184
- body { font-family: 'Segoe UI', Roboto, system-ui, sans-serif; max-width: 1400px; margin: 0 auto; padding: 20px; background: #f0f2f5; }
185
- .container { background: white; border-radius: 20px; padding: 30px; box-shadow: 0 10px 40px rgba(0,0,0,0.1); }
186
- h1 { color: #1a1a2e; border-bottom: 3px solid #4CAF50; padding-bottom: 15px; display: flex; align-items: center; gap: 10px; }
187
- h1:before { content: "⚖️"; font-size: 1.2em; }
188
- .info-box { background: #e8f0fe; border-left: 6px solid #2196F3; padding: 15px 25px; margin: 20px 0; border-radius: 8px; }
189
- .base-selector { background: #f8f9fa; border-radius: 12px; padding: 20px; margin: 20px 0; border: 1px solid #e0e0e0; }
190
- .base-selector h3 { margin-top: 0; color: #2c3e50; font-size: 16px; margin-bottom: 15px; }
191
- .checkbox-group { display: flex; gap: 30px; flex-wrap: wrap; }
192
- .checkbox-item { display: flex; align-items: center; gap: 10px; cursor: pointer; }
193
- .checkbox-item input[type="checkbox"] { width: 18px; height: 18px; cursor: pointer; accent-color: #4CAF50; }
194
- .checkbox-item label { font-size: 16px; cursor: pointer; font-weight: 500; }
195
- .badge { background: #4CAF50; color: white; padding: 4px 12px; border-radius: 20px; font-size: 13px; font-weight: 500; margin-left: 8px; }
196
- .badge.acordaos { background: #1a73e8; }
197
- .badge.decisoes { background: #7b1fa2; }
198
- .search-box { display: flex; gap: 12px; margin: 20px 0; }
199
- .search-box input { flex: 1; padding: 16px; font-size: 16px; border: 2px solid #e0e0e0; border-radius: 12px; transition: all 0.3s; background: #fafafa; }
200
- .search-box input:focus { outline: none; border-color: #4CAF50; box-shadow: 0 0 0 3px rgba(76,175,80,0.1); background: white; }
201
- .search-box button { padding: 16px 36px; background: #4CAF50; color: white; border: none; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; gap: 8px; box-shadow: 0 4px 12px rgba(76,175,80,0.3); }
202
- .search-box button:hover { background: #45a049; transform: translateY(-1px); box-shadow: 0 6px 16px rgba(76,175,80,0.4); }
203
- .search-box button:disabled { background: #a0a0a0; cursor: not-allowed; transform: none; box-shadow: none; }
204
- .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; margin: 20px 0; }
205
- .stat-card { background: #f8f9fa; border-radius: 12px; padding: 20px; border: 1px solid #e0e0e0; text-align: center; }
206
- .stat-value { font-size: 28px; font-weight: bold; color: #4CAF50; }
207
- .stat-label { color: #5f6368; font-size: 14px; margin-top: 5px; text-transform: uppercase; letter-spacing: 0.5px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
 
209
  /* Resultados */
210
- .result { border: 1px solid #e0e0e0; border-radius: 12px; padding: 20px; margin: 15px 0; background: white; box-shadow: 0 4px 12px rgba(0,0,0,0.05); transition: all 0.2s; }
211
- .result.acordaos { border-left: 6px solid #1a73e8; }
212
- .result.decisoes { border-left: 6px solid #7b1fa2; }
213
- .result:hover { box-shadow: 0 8px 24px rgba(0,0,0,0.1); }
214
- .result h3 { margin: 0 0 12px; color: #1a0dab; font-size: 18px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
215
- .tipo-badge { font-size: 12px; padding: 4px 10px; border-radius: 20px; font-weight: 500; }
216
- .tipo-badge.acordaos { background: #1a73e8; color: white; }
217
- .tipo-badge.decisoes { background: #7b1fa2; color: white; }
218
- .meta { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 15px; padding-bottom: 12px; border-bottom: 1px solid #eee; }
219
- .meta-item { background: #f1f3f4; padding: 5px 12px; border-radius: 30px; font-size: 13px; color: #3c4043; display: flex; align-items: center; gap: 5px; }
220
- .campo { margin: 15px 0; padding: 15px; border-radius: 8px; }
221
- .ementa { background: #e8f0fe; border-left: 4px solid #1a73e8; }
222
- .decisao { background: #f3e5f5; border-left: 4px solid #7b1fa2; }
223
- .acordao { background: #fff3e0; border-left: 4px solid #f9ab00; }
224
- .campo-label { font-weight: bold; margin-bottom: 8px; display: block; }
225
- .ementa .campo-label { color: #1a73e8; }
226
- .decisao .campo-label { color: #7b1fa2; }
227
- .acordao .campo-label { color: #f9ab00; }
228
- .campo-conteudo { font-size: 14px; line-height: 1.6; color: #202124; white-space: pre-wrap; max-height: 300px; overflow-y: auto; }
229
- .url-link { margin-top: 15px; padding: 10px; background: #f5f5f5; border-radius: 8px; }
230
- .url-link a { color: #1a73e8; text-decoration: none; display: inline-flex; align-items: center; gap: 8px; font-weight: 500; }
231
- .url-link a:hover { text-decoration: underline; }
232
-
233
- /* Botões de ação */
234
- .action-buttons { display: flex; gap: 10px; margin-top: 15px; flex-wrap: wrap; }
235
- .btn { padding: 10px 16px; border-radius: 8px; font-size: 14px; font-weight: 500; text-decoration: none; display: inline-flex; align-items: center; gap: 6px; transition: all 0.2s; cursor: pointer; border: none; }
236
- .btn-primary { background: #1a73e8; color: white; }
237
- .btn-primary:hover { background: #1557b0; }
238
- .btn-secondary { background: #5f6368; color: white; }
239
- .btn-secondary:hover { background: #3c4043; }
240
- .btn-outline { background: white; border: 1px solid #1a73e8; color: #1a73e8; }
241
- .btn-outline:hover { background: #e8f0fe; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
  /* Paginação */
244
- .pagination { display: flex; justify-content: center; align-items: center; gap: 10px; margin: 30px 0 10px; flex-wrap: wrap; }
245
- .pagination button { padding: 10px 16px; border: 1px solid #ddd; background: white; border-radius: 8px; cursor: pointer; font-weight: 500; transition: all 0.2s; }
246
- .pagination button:hover:not(:disabled) { background: #f1f3f4; border-color: #1a73e8; }
247
- .pagination button.active { background: #1a73e8; color: white; border-color: #1a73e8; }
248
- .pagination button:disabled { opacity: 0.5; cursor: not-allowed; }
249
- .page-info { margin: 0 15px; font-weight: 500; color: #5f6368; }
250
- .page-size-selector { display: flex; align-items: center; gap: 10px; margin-left: 20px; }
251
- .page-size-selector select { padding: 8px; border-radius: 6px; border: 1px solid #ddd; }
252
-
253
- /* Loading e avisos */
254
- .loading { display: inline-block; width: 24px; height: 24px; border: 3px solid rgba(76,175,80,0.2); border-top-color: #4CAF50; border-radius: 50%; animation: spin 1s linear infinite; margin-right: 10px; }
255
- @keyframes spin { to { transform: rotate(360deg); } }
256
- .error { color: #d93025; background: #fce8e6; border-left: 5px solid #ea4335; padding: 15px 20px; margin: 15px 0; border-radius: 8px; }
257
- .warning { color: #e37400; background: #fef7e0; border-left: 5px solid #f9ab00; padding: 15px 20px; margin: 15px 0; border-radius: 8px; }
258
- .footer { margin-top: 30px; text-align: center; color: #5f6368; font-size: 13px; }
259
- .highlight { background-color: #f9ab00; color: #1a1a2e; font-weight: bold; padding: 2px 4px; border-radius: 4px; }
260
- .aviso { background: #fff3e0; border-left: 4px solid #f9ab00; padding: 10px 15px; border-radius: 8px; margin: 15px 0; font-size: 14px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  </style>
262
  </head>
263
  <body>
264
  <div class="container">
265
- <h1>STF - Busca Jurisprudencial</h1>
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
  <div class="info-box">
268
- <strong>📌 Busca em múltiplas bases do STF com navegação</strong><br>
269
- • Selecione as bases, digite sua busca e navegue pelos resultados<br>
270
- • Clique nos links para ver detalhes completos ou inteiro teor
271
  </div>
272
 
273
  <div class="base-selector">
@@ -287,11 +802,28 @@ def index():
287
  </div>
288
  </div>
289
 
290
- <div class="search-box">
291
- <input type="text" id="query" placeholder="Ex: dano moral mordida cachorro, habeas corpus, liminar..." value="" autofocus>
292
- <button id="searchBtn" onclick="doSearch(1)">
293
- <span>🔍</span> Buscar
294
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  </div>
296
 
297
  <div class="stats-grid" id="stats" style="display: none;">
@@ -301,7 +833,6 @@ def index():
301
  <div class="stat-card"><div class="stat-value" id="timeMs">0</div><div class="stat-label">tempo (ms)</div></div>
302
  </div>
303
 
304
- <div id="loading" style="display: none;" class="loading"></div>
305
  <div id="results"></div>
306
 
307
  <!-- Paginação -->
@@ -312,7 +843,7 @@ def index():
312
  <button id="nextPageBtn" onclick="goToPage(currentPage + 1)" disabled>Próxima ▶</button>
313
  <button id="lastPageBtn" onclick="goToPage(totalPages)" disabled>Última ⏭️</button>
314
  <div class="page-size-selector">
315
- <label for="pageSize">Resultados por página:</label>
316
  <select id="pageSize" onchange="changePageSize()">
317
  <option value="10">10</option>
318
  <option value="20" selected>20</option>
@@ -322,7 +853,10 @@ def index():
322
  </div>
323
  </div>
324
 
325
- <div class="footer">Fonte: STF - Supremo Tribunal Federal</div>
 
 
 
326
  </div>
327
 
328
  <script>
@@ -359,7 +893,7 @@ def index():
359
  const paginationDiv = document.getElementById('pagination');
360
 
361
  btn.disabled = true;
362
- loading.style.display = 'inline-block';
363
  resultsDiv.innerHTML = '';
364
  statsDiv.style.display = 'none';
365
  paginationDiv.style.display = 'none';
@@ -527,49 +1061,215 @@ def documento_detalhe(doc_id):
527
  <!DOCTYPE html>
528
  <html>
529
  <head>
530
- <title>⚖️ STF - Documento {{ doc_id }}</title>
531
  <meta charset="utf-8">
532
  <meta name="viewport" content="width=device-width, initial-scale=1">
533
  <style>
534
- body { font-family: 'Segoe UI', Roboto, system-ui, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; background: #f0f2f5; }
535
- .container { background: white; border-radius: 20px; padding: 30px; box-shadow: 0 10px 40px rgba(0,0,0,0.1); }
536
- h1 { color: #1a1a2e; border-bottom: 3px solid #4CAF50; padding-bottom: 15px; display: flex; align-items: center; gap: 10px; }
537
- .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
538
- .back-btn { padding: 10px 20px; background: #f1f3f4; border-radius: 8px; text-decoration: none; color: #1a73e8; font-weight: 500; display: inline-flex; align-items: center; gap: 5px; }
539
- .back-btn:hover { background: #e8eaed; }
540
- .loading { text-align: center; padding: 50px; color: #5f6368; }
541
- .loading .spinner { display: inline-block; width: 40px; height: 40px; border: 4px solid rgba(76,175,80,0.2); border-top-color: #4CAF50; border-radius: 50%; animation: spin 1s linear infinite; margin-bottom: 15px; }
542
- @keyframes spin { to { transform: rotate(360deg); } }
543
- .error { color: #d93025; background: #fce8e6; border-left: 5px solid #ea4335; padding: 20px; border-radius: 8px; }
544
- .doc-header { background: #f8f9fa; border-radius: 12px; padding: 20px; margin-bottom: 20px; border: 1px solid #e0e0e0; }
545
- .doc-header h2 { margin-top: 0; color: #1a0dab; }
546
- .meta { display: flex; flex-wrap: wrap; gap: 10px; margin: 15px 0; }
547
- .meta-item { background: #f1f3f4; padding: 8px 16px; border-radius: 30px; font-size: 14px; color: #3c4043; display: flex; align-items: center; gap: 8px; }
548
- .campo { margin: 20px 0; padding: 20px; border-radius: 12px; }
549
- .ementa { background: #e8f0fe; border-left: 6px solid #1a73e8; }
550
- .decisao { background: #f3e5f5; border-left: 6px solid #7b1fa2; }
551
- .acordao { background: #fff3e0; border-left: 6px solid #f9ab00; }
552
- .campo-label { font-weight: bold; margin-bottom: 10px; display: block; font-size: 16px; }
553
- .ementa .campo-label { color: #1a73e8; }
554
- .decisao .campo-label { color: #7b1fa2; }
555
- .acordao .campo-label { color: #f9ab00; }
556
- .campo-conteudo { font-size: 15px; line-height: 1.8; color: #202124; white-space: pre-wrap; }
557
- .url-link { margin-top: 20px; padding: 15px; background: #f5f5f5; border-radius: 8px; }
558
- .url-link a { color: #1a73e8; text-decoration: none; display: inline-flex; align-items: center; gap: 8px; font-weight: 500; }
559
- .url-link a:hover { text-decoration: underline; }
560
- .highlight { background-color: #f9ab00; color: #1a1a2e; font-weight: bold; padding: 2px 4px; border-radius: 4px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
561
  </style>
562
  </head>
563
  <body>
564
  <div class="container">
565
  <div class="header">
566
- <h1>📄 Detalhes do Documento</h1>
 
 
 
 
567
  <a href="/" class="back-btn">← Voltar para busca</a>
568
  </div>
569
 
570
- <div id="loading" class="loading">
571
- <div class="spinner"></div>
572
- <p>Carregando documento...</p>
573
  </div>
574
 
575
  <div id="error" style="display: none;"></div>
@@ -622,7 +1322,7 @@ def documento_detalhe(doc_id):
622
  if (temEmenta) {
623
  html += `
624
  <div class="campo ementa">
625
- <span class="campo-label">📝 Ementa:</span>
626
  <div class="campo-conteudo">${item.ementa.replace(/\\n/g, '<br>').replace(/<em>/g, '<span class="highlight">').replace(/<\\/em>/g, '</span>')}</div>
627
  </div>
628
  `;
@@ -631,7 +1331,7 @@ def documento_detalhe(doc_id):
631
  if (temDecisao) {
632
  html += `
633
  <div class="campo decisao">
634
- <span class="campo-label">⚖️ Decisão:</span>
635
  <div class="campo-conteudo">${item.decisao_texto.replace(/\\n/g, '<br>').replace(/<em>/g, '<span class="highlight">').replace(/<\\/em>/g, '</span>')}</div>
636
  </div>
637
  `;
@@ -640,7 +1340,7 @@ def documento_detalhe(doc_id):
640
  if (temAcordao) {
641
  html += `
642
  <div class="campo acordao">
643
- <span class="campo-label">📋 Acórdão/Ata:</span>
644
  <div class="campo-conteudo">${item.acordao_ata.replace(/\\n/g, '<br>').replace(/<em>/g, '<span class="highlight">').replace(/<\\/em>/g, '</span>')}</div>
645
  </div>
646
  `;
@@ -852,9 +1552,8 @@ if __name__ == '__main__':
852
  except:
853
  pass
854
  logger.info("="*50)
855
- logger.info("🚀 Iniciando app STF - Busca Multi-base com Navegação")
856
- logger.info("📋 Bases: acordaos (acórdãos) e decisoes (decisões monocráticas)")
857
- logger.info("📑 Páginas individuais para cada documento")
858
  logger.info("="*50)
859
  port = int(os.environ.get('PORT', 7860))
860
  app.run(host='0.0.0.0', port=port, debug=False)
 
1
+
2
  import os
3
  import sys
4
  import json
 
178
  <!DOCTYPE html>
179
  <html>
180
  <head>
181
+ <title>⚖️ PARA AI - Busca STF</title>
182
  <meta charset="utf-8">
183
  <meta name="viewport" content="width=device-width, initial-scale=1">
184
  <style>
185
+ :root {
186
+ --primary: #1E3A8A; /* Azul escuro principal */
187
+ --secondary: #2563EB; /* Azul médio */
188
+ --accent: #3B82F6; /* Azul claro */
189
+ --background: #F8FAFC; /* Fundo claro */
190
+ --text: #0F172A; /* Texto escuro */
191
+ --card-bg: #FFFFFF; /* Fundo dos cards */
192
+ --border: #E2E8F0; /* Bordas suaves */
193
+ --success: #10B981; /* Verde */
194
+ --warning: #F59E0B; /* Laranja */
195
+ --error: #EF4444; /* Vermelho */
196
+ --purple: #8B5CF6; /* Roxo para decisões */
197
+ }
198
+
199
+ body {
200
+ font-family: 'Inter', 'Segoe UI', Roboto, system-ui, sans-serif;
201
+ max-width: 1400px;
202
+ margin: 0 auto;
203
+ padding: 20px;
204
+ background: var(--background);
205
+ color: var(--text);
206
+ line-height: 1.5;
207
+ }
208
+
209
+ .container {
210
+ background: var(--card-bg);
211
+ border-radius: 24px;
212
+ padding: 30px;
213
+ box-shadow: 0 20px 40px rgba(0,0,0,0.05), 0 4px 12px rgba(0,0,0,0.1);
214
+ border: 1px solid var(--border);
215
+ }
216
+
217
+ /* Logo e cabeçalho */
218
+ .header {
219
+ text-align: center;
220
+ margin-bottom: 30px;
221
+ border-bottom: 2px solid var(--border);
222
+ padding-bottom: 25px;
223
+ }
224
+
225
+ .logo-container {
226
+ display: flex;
227
+ flex-direction: column;
228
+ align-items: center;
229
+ gap: 8px;
230
+ }
231
+
232
+ .logo {
233
+ height: 60px;
234
+ width: auto;
235
+ }
236
+
237
+ .logo-text {
238
+ font-size: 28px;
239
+ font-weight: 700;
240
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
241
+ -webkit-background-clip: text;
242
+ -webkit-text-fill-color: transparent;
243
+ letter-spacing: -0.5px;
244
+ }
245
+
246
+ .tagline {
247
+ font-size: 14px;
248
+ color: #64748B;
249
+ font-weight: 400;
250
+ letter-spacing: 1px;
251
+ }
252
+
253
+ .stats-badge {
254
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
255
+ color: white;
256
+ padding: 8px 20px;
257
+ border-radius: 40px;
258
+ font-size: 16px;
259
+ font-weight: 500;
260
+ display: inline-block;
261
+ margin-top: 10px;
262
+ box-shadow: 0 4px 10px rgba(30,58,138,0.2);
263
+ }
264
+
265
+ .info-box {
266
+ background: #EFF6FF;
267
+ border-left: 6px solid var(--primary);
268
+ padding: 20px 25px;
269
+ margin: 25px 0;
270
+ border-radius: 16px;
271
+ font-size: 15px;
272
+ }
273
+
274
+ .base-selector {
275
+ background: var(--card-bg);
276
+ border-radius: 20px;
277
+ padding: 20px;
278
+ margin: 20px 0;
279
+ border: 1px solid var(--border);
280
+ }
281
+
282
+ .base-selector h3 {
283
+ margin-top: 0;
284
+ color: var(--primary);
285
+ font-size: 16px;
286
+ margin-bottom: 15px;
287
+ font-weight: 600;
288
+ }
289
+
290
+ .checkbox-group {
291
+ display: flex;
292
+ gap: 30px;
293
+ flex-wrap: wrap;
294
+ }
295
+
296
+ .checkbox-item {
297
+ display: flex;
298
+ align-items: center;
299
+ gap: 12px;
300
+ cursor: pointer;
301
+ }
302
+
303
+ .checkbox-item input[type="checkbox"] {
304
+ width: 20px;
305
+ height: 20px;
306
+ cursor: pointer;
307
+ accent-color: var(--primary);
308
+ }
309
+
310
+ .checkbox-item label {
311
+ font-size: 16px;
312
+ cursor: pointer;
313
+ font-weight: 500;
314
+ }
315
+
316
+ .badge {
317
+ background: var(--primary);
318
+ color: white;
319
+ padding: 4px 12px;
320
+ border-radius: 20px;
321
+ font-size: 13px;
322
+ font-weight: 500;
323
+ margin-left: 8px;
324
+ }
325
+
326
+ .badge.acordaos {
327
+ background: var(--secondary);
328
+ }
329
+
330
+ .badge.decisoes {
331
+ background: var(--purple);
332
+ }
333
+
334
+ /* Caixa de busca - botão abaixo */
335
+ .search-section {
336
+ margin: 30px 0;
337
+ }
338
+
339
+ .search-input {
340
+ width: 100%;
341
+ padding: 18px 20px;
342
+ font-size: 16px;
343
+ border: 2px solid var(--border);
344
+ border-radius: 16px;
345
+ transition: all 0.3s;
346
+ background: var(--card-bg);
347
+ margin-bottom: 15px;
348
+ box-sizing: border-box;
349
+ }
350
+
351
+ .search-input:focus {
352
+ outline: none;
353
+ border-color: var(--secondary);
354
+ box-shadow: 0 0 0 4px rgba(37,99,235,0.15);
355
+ }
356
+
357
+ .search-button-container {
358
+ display: flex;
359
+ justify-content: center;
360
+ }
361
+
362
+ .search-button {
363
+ padding: 16px 48px;
364
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
365
+ color: white;
366
+ border: none;
367
+ border-radius: 60px;
368
+ font-size: 18px;
369
+ font-weight: 600;
370
+ cursor: pointer;
371
+ transition: all 0.3s;
372
+ display: inline-flex;
373
+ align-items: center;
374
+ gap: 10px;
375
+ box-shadow: 0 8px 20px rgba(30,58,138,0.3);
376
+ letter-spacing: 0.5px;
377
+ }
378
+
379
+ .search-button:hover {
380
+ transform: translateY(-2px);
381
+ box-shadow: 0 12px 28px rgba(30,58,138,0.4);
382
+ }
383
+
384
+ .search-button:disabled {
385
+ opacity: 0.6;
386
+ cursor: not-allowed;
387
+ transform: none;
388
+ box-shadow: none;
389
+ }
390
+
391
+ .exemplos {
392
+ text-align: center;
393
+ color: #64748B;
394
+ font-size: 14px;
395
+ margin: 15px 0 5px;
396
+ }
397
+
398
+ .exemplos strong {
399
+ color: var(--primary);
400
+ }
401
+
402
+ .stats-grid {
403
+ display: grid;
404
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
405
+ gap: 15px;
406
+ margin: 25px 0;
407
+ }
408
+
409
+ .stat-card {
410
+ background: #F8FAFC;
411
+ border-radius: 20px;
412
+ padding: 20px;
413
+ border: 1px solid var(--border);
414
+ text-align: center;
415
+ transition: all 0.2s;
416
+ }
417
+
418
+ .stat-card:hover {
419
+ border-color: var(--secondary);
420
+ box-shadow: 0 4px 12px rgba(0,0,0,0.05);
421
+ }
422
+
423
+ .stat-value {
424
+ font-size: 32px;
425
+ font-weight: 700;
426
+ color: var(--primary);
427
+ line-height: 1.2;
428
+ }
429
+
430
+ .stat-label {
431
+ color: #64748B;
432
+ font-size: 14px;
433
+ margin-top: 5px;
434
+ text-transform: uppercase;
435
+ letter-spacing: 0.5px;
436
+ }
437
 
438
  /* Resultados */
439
+ .result {
440
+ border: 1px solid var(--border);
441
+ border-radius: 20px;
442
+ padding: 25px;
443
+ margin: 20px 0;
444
+ background: var(--card-bg);
445
+ box-shadow: 0 4px 12px rgba(0,0,0,0.03);
446
+ transition: all 0.2s;
447
+ }
448
+
449
+ .result.acordaos {
450
+ border-left: 6px solid var(--secondary);
451
+ }
452
+
453
+ .result.decisoes {
454
+ border-left: 6px solid var(--purple);
455
+ }
456
+
457
+ .result:hover {
458
+ box-shadow: 0 8px 24px rgba(0,0,0,0.08);
459
+ border-color: var(--secondary);
460
+ }
461
+
462
+ .result h3 {
463
+ margin: 0 0 15px;
464
+ color: var(--primary);
465
+ font-size: 18px;
466
+ display: flex;
467
+ align-items: center;
468
+ gap: 8px;
469
+ flex-wrap: wrap;
470
+ }
471
+
472
+ .tipo-badge {
473
+ font-size: 12px;
474
+ padding: 4px 12px;
475
+ border-radius: 30px;
476
+ font-weight: 500;
477
+ }
478
+
479
+ .tipo-badge.acordaos {
480
+ background: var(--secondary);
481
+ color: white;
482
+ }
483
+
484
+ .tipo-badge.decisoes {
485
+ background: var(--purple);
486
+ color: white;
487
+ }
488
+
489
+ .meta {
490
+ display: flex;
491
+ flex-wrap: wrap;
492
+ gap: 10px;
493
+ margin-bottom: 15px;
494
+ padding-bottom: 15px;
495
+ border-bottom: 1px solid var(--border);
496
+ }
497
+
498
+ .meta-item {
499
+ background: #F1F5F9;
500
+ padding: 6px 14px;
501
+ border-radius: 30px;
502
+ font-size: 13px;
503
+ color: var(--text);
504
+ display: flex;
505
+ align-items: center;
506
+ gap: 6px;
507
+ }
508
+
509
+ .campo {
510
+ margin: 20px 0;
511
+ padding: 20px;
512
+ border-radius: 16px;
513
+ }
514
+
515
+ .ementa {
516
+ background: #EFF6FF;
517
+ border-left: 4px solid var(--secondary);
518
+ }
519
+
520
+ .decisao {
521
+ background: #F5F3FF;
522
+ border-left: 4px solid var(--purple);
523
+ }
524
+
525
+ .acordao {
526
+ background: #FFFBEB;
527
+ border-left: 4px solid var(--warning);
528
+ }
529
+
530
+ .campo-label {
531
+ font-weight: 600;
532
+ margin-bottom: 10px;
533
+ display: block;
534
+ font-size: 14px;
535
+ text-transform: uppercase;
536
+ letter-spacing: 0.5px;
537
+ }
538
+
539
+ .ementa .campo-label {
540
+ color: var(--secondary);
541
+ }
542
+
543
+ .decisao .campo-label {
544
+ color: var(--purple);
545
+ }
546
+
547
+ .acordao .campo-label {
548
+ color: var(--warning);
549
+ }
550
+
551
+ .campo-conteudo {
552
+ font-size: 14px;
553
+ line-height: 1.7;
554
+ color: var(--text);
555
+ white-space: pre-wrap;
556
+ max-height: 300px;
557
+ overflow-y: auto;
558
+ background: rgba(255,255,255,0.5);
559
+ padding: 10px;
560
+ border-radius: 8px;
561
+ }
562
+
563
+ .url-link {
564
+ margin-top: 15px;
565
+ padding: 12px;
566
+ background: #F8FAFC;
567
+ border-radius: 12px;
568
+ border: 1px solid var(--border);
569
+ }
570
+
571
+ .url-link a {
572
+ color: var(--secondary);
573
+ text-decoration: none;
574
+ display: inline-flex;
575
+ align-items: center;
576
+ gap: 8px;
577
+ font-weight: 500;
578
+ }
579
+
580
+ .url-link a:hover {
581
+ text-decoration: underline;
582
+ }
583
+
584
+ .action-buttons {
585
+ display: flex;
586
+ gap: 12px;
587
+ margin-top: 20px;
588
+ flex-wrap: wrap;
589
+ }
590
+
591
+ .btn {
592
+ padding: 12px 24px;
593
+ border-radius: 40px;
594
+ font-size: 14px;
595
+ font-weight: 500;
596
+ text-decoration: none;
597
+ display: inline-flex;
598
+ align-items: center;
599
+ gap: 8px;
600
+ transition: all 0.2s;
601
+ cursor: pointer;
602
+ border: none;
603
+ }
604
+
605
+ .btn-primary {
606
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
607
+ color: white;
608
+ box-shadow: 0 4px 10px rgba(30,58,138,0.2);
609
+ }
610
+
611
+ .btn-primary:hover {
612
+ background: linear-gradient(135deg, var(--secondary), var(--primary));
613
+ box-shadow: 0 6px 15px rgba(30,58,138,0.3);
614
+ }
615
+
616
+ .btn-outline {
617
+ background: white;
618
+ border: 1px solid var(--border);
619
+ color: var(--primary);
620
+ }
621
+
622
+ .btn-outline:hover {
623
+ background: #F8FAFC;
624
+ border-color: var(--secondary);
625
+ }
626
+
627
+ .btn-secondary {
628
+ background: #F1F5F9;
629
+ color: var(--text);
630
+ }
631
+
632
+ .btn-secondary:hover {
633
+ background: #E2E8F0;
634
+ }
635
 
636
  /* Paginação */
637
+ .pagination {
638
+ display: flex;
639
+ justify-content: center;
640
+ align-items: center;
641
+ gap: 8px;
642
+ margin: 40px 0 20px;
643
+ flex-wrap: wrap;
644
+ }
645
+
646
+ .pagination button {
647
+ padding: 10px 16px;
648
+ border: 1px solid var(--border);
649
+ background: white;
650
+ border-radius: 40px;
651
+ cursor: pointer;
652
+ font-weight: 500;
653
+ transition: all 0.2s;
654
+ color: var(--text);
655
+ }
656
+
657
+ .pagination button:hover:not(:disabled) {
658
+ background: #F1F5F9;
659
+ border-color: var(--secondary);
660
+ color: var(--secondary);
661
+ }
662
+
663
+ .pagination button.active {
664
+ background: var(--primary);
665
+ color: white;
666
+ border-color: var(--primary);
667
+ }
668
+
669
+ .pagination button:disabled {
670
+ opacity: 0.4;
671
+ cursor: not-allowed;
672
+ }
673
+
674
+ .page-info {
675
+ margin: 0 15px;
676
+ font-weight: 500;
677
+ color: var(--text);
678
+ }
679
+
680
+ .page-size-selector {
681
+ display: flex;
682
+ align-items: center;
683
+ gap: 10px;
684
+ margin-left: 20px;
685
+ }
686
+
687
+ .page-size-selector select {
688
+ padding: 8px 16px;
689
+ border-radius: 40px;
690
+ border: 1px solid var(--border);
691
+ background: white;
692
+ color: var(--text);
693
+ font-weight: 500;
694
+ }
695
+
696
+ .loading {
697
+ display: inline-block;
698
+ width: 30px;
699
+ height: 30px;
700
+ border: 3px solid rgba(30,58,138,0.2);
701
+ border-top-color: var(--primary);
702
+ border-radius: 50%;
703
+ animation: spin 1s linear infinite;
704
+ }
705
+
706
+ @keyframes spin {
707
+ to { transform: rotate(360deg); }
708
+ }
709
+
710
+ .error {
711
+ color: var(--error);
712
+ background: #FEF2F2;
713
+ border-left: 6px solid var(--error);
714
+ padding: 20px 25px;
715
+ margin: 15px 0;
716
+ border-radius: 16px;
717
+ }
718
+
719
+ .warning {
720
+ color: #92400E;
721
+ background: #FFFBEB;
722
+ border-left: 6px solid var(--warning);
723
+ padding: 20px 25px;
724
+ margin: 15px 0;
725
+ border-radius: 16px;
726
+ }
727
+
728
+ .footer {
729
+ margin-top: 50px;
730
+ text-align: center;
731
+ color: #64748B;
732
+ font-size: 14px;
733
+ border-top: 1px solid var(--border);
734
+ padding-top: 25px;
735
+ }
736
+
737
+ .highlight {
738
+ background-color: #FEF9C3;
739
+ color: var(--text);
740
+ font-weight: 600;
741
+ padding: 2px 4px;
742
+ border-radius: 4px;
743
+ }
744
+
745
+ .aviso {
746
+ background: #FFFBEB;
747
+ border-left: 4px solid var(--warning);
748
+ padding: 12px 18px;
749
+ border-radius: 12px;
750
+ margin: 15px 0;
751
+ font-size: 14px;
752
+ }
753
+
754
+ .loading-container {
755
+ display: flex;
756
+ flex-direction: column;
757
+ align-items: center;
758
+ gap: 15px;
759
+ margin: 30px 0;
760
+ }
761
+
762
+ .loading-text {
763
+ color: var(--primary);
764
+ font-weight: 500;
765
+ }
766
  </style>
767
  </head>
768
  <body>
769
  <div class="container">
770
+ <div class="header">
771
+ <div class="logo-container">
772
+ <img src="https://huggingface.co/spaces/caarleexx/paraAI_CHATBOT/resolve/main/public/logo_dark.png"
773
+ alt="PARA AI"
774
+ class="logo"
775
+ onerror="this.style.display='none'; this.nextElementSibling.style.display='block';">
776
+ <div class="logo-text" style="display: none;">⚖️ PARA AI</div>
777
+ <div class="tagline">convergent law technologies</div>
778
+ </div>
779
+ <div class="stats-badge">
780
+ 📚 Documentos disponíveis: 2.327.484 decisões
781
+ </div>
782
+ </div>
783
 
784
  <div class="info-box">
785
+ <strong> Como funciona:</strong> Pesquise diretamente na base do STF e navegue pelos resultados
 
 
786
  </div>
787
 
788
  <div class="base-selector">
 
802
  </div>
803
  </div>
804
 
805
+ <div class="search-section">
806
+ <input type="text"
807
+ class="search-input"
808
+ id="query"
809
+ placeholder="Ex: dano moral mordida cachorro, habeas corpus, liminar..."
810
+ value=""
811
+ autofocus>
812
+
813
+ <div class="search-button-container">
814
+ <button id="searchBtn" class="search-button" onclick="doSearch(1)">
815
+ <span>🔍</span> PESQUISAR
816
+ </button>
817
+ </div>
818
+
819
+ <div class="exemplos">
820
+ <strong>Exemplos:</strong> Dano moral em atraso de voo · Agravo de instrumento · Responsabilidade civil
821
+ </div>
822
+ </div>
823
+
824
+ <div id="loading" class="loading-container" style="display: none;">
825
+ <div class="loading"></div>
826
+ <div class="loading-text">Buscando jurisprudência...</div>
827
  </div>
828
 
829
  <div class="stats-grid" id="stats" style="display: none;">
 
833
  <div class="stat-card"><div class="stat-value" id="timeMs">0</div><div class="stat-label">tempo (ms)</div></div>
834
  </div>
835
 
 
836
  <div id="results"></div>
837
 
838
  <!-- Paginação -->
 
843
  <button id="nextPageBtn" onclick="goToPage(currentPage + 1)" disabled>Próxima ▶</button>
844
  <button id="lastPageBtn" onclick="goToPage(totalPages)" disabled>Última ⏭️</button>
845
  <div class="page-size-selector">
846
+ <label for="pageSize">Itens:</label>
847
  <select id="pageSize" onchange="changePageSize()">
848
  <option value="10">10</option>
849
  <option value="20" selected>20</option>
 
853
  </div>
854
  </div>
855
 
856
+ <div class="footer">
857
+ <span>⚖️ STF - Supremo Tribunal Federal • </span>
858
+ <span>PARA AI - Pesquisa Jurisprudencial</span>
859
+ </div>
860
  </div>
861
 
862
  <script>
 
893
  const paginationDiv = document.getElementById('pagination');
894
 
895
  btn.disabled = true;
896
+ loading.style.display = 'flex';
897
  resultsDiv.innerHTML = '';
898
  statsDiv.style.display = 'none';
899
  paginationDiv.style.display = 'none';
 
1061
  <!DOCTYPE html>
1062
  <html>
1063
  <head>
1064
+ <title>⚖️ PARA AI - Documento {{ doc_id }}</title>
1065
  <meta charset="utf-8">
1066
  <meta name="viewport" content="width=device-width, initial-scale=1">
1067
  <style>
1068
+ :root {
1069
+ --primary: #1E3A8A;
1070
+ --secondary: #2563EB;
1071
+ --accent: #3B82F6;
1072
+ --background: #F8FAFC;
1073
+ --text: #0F172A;
1074
+ --card-bg: #FFFFFF;
1075
+ --border: #E2E8F0;
1076
+ --success: #10B981;
1077
+ --warning: #F59E0B;
1078
+ --purple: #8B5CF6;
1079
+ }
1080
+
1081
+ body {
1082
+ font-family: 'Inter', 'Segoe UI', Roboto, system-ui, sans-serif;
1083
+ max-width: 1200px;
1084
+ margin: 0 auto;
1085
+ padding: 20px;
1086
+ background: var(--background);
1087
+ color: var(--text);
1088
+ }
1089
+
1090
+ .container {
1091
+ background: var(--card-bg);
1092
+ border-radius: 24px;
1093
+ padding: 30px;
1094
+ box-shadow: 0 20px 40px rgba(0,0,0,0.05);
1095
+ border: 1px solid var(--border);
1096
+ }
1097
+
1098
+ .header {
1099
+ display: flex;
1100
+ justify-content: space-between;
1101
+ align-items: center;
1102
+ margin-bottom: 30px;
1103
+ border-bottom: 2px solid var(--border);
1104
+ padding-bottom: 20px;
1105
+ }
1106
+
1107
+ .logo-small {
1108
+ height: 40px;
1109
+ width: auto;
1110
+ }
1111
+
1112
+ .back-btn {
1113
+ padding: 12px 24px;
1114
+ background: #F1F5F9;
1115
+ border-radius: 40px;
1116
+ text-decoration: none;
1117
+ color: var(--primary);
1118
+ font-weight: 500;
1119
+ display: inline-flex;
1120
+ align-items: center;
1121
+ gap: 8px;
1122
+ transition: all 0.2s;
1123
+ border: 1px solid var(--border);
1124
+ }
1125
+
1126
+ .back-btn:hover {
1127
+ background: #E2E8F0;
1128
+ border-color: var(--secondary);
1129
+ }
1130
+
1131
+ .loading-container {
1132
+ display: flex;
1133
+ flex-direction: column;
1134
+ align-items: center;
1135
+ gap: 15px;
1136
+ padding: 60px;
1137
+ }
1138
+
1139
+ .loading {
1140
+ width: 50px;
1141
+ height: 50px;
1142
+ border: 4px solid rgba(30,58,138,0.2);
1143
+ border-top-color: var(--primary);
1144
+ border-radius: 50%;
1145
+ animation: spin 1s linear infinite;
1146
+ }
1147
+
1148
+ @keyframes spin {
1149
+ to { transform: rotate(360deg); }
1150
+ }
1151
+
1152
+ .error {
1153
+ color: #EF4444;
1154
+ background: #FEF2F2;
1155
+ border-left: 6px solid #EF4444;
1156
+ padding: 20px 25px;
1157
+ border-radius: 16px;
1158
+ }
1159
+
1160
+ .doc-header {
1161
+ background: #F8FAFC;
1162
+ border-radius: 20px;
1163
+ padding: 25px;
1164
+ margin-bottom: 25px;
1165
+ border: 1px solid var(--border);
1166
+ }
1167
+
1168
+ .doc-header h2 {
1169
+ margin-top: 0;
1170
+ color: var(--primary);
1171
+ }
1172
+
1173
+ .meta {
1174
+ display: flex;
1175
+ flex-wrap: wrap;
1176
+ gap: 12px;
1177
+ margin: 20px 0;
1178
+ }
1179
+
1180
+ .meta-item {
1181
+ background: #F1F5F9;
1182
+ padding: 8px 18px;
1183
+ border-radius: 40px;
1184
+ font-size: 14px;
1185
+ color: var(--text);
1186
+ display: flex;
1187
+ align-items: center;
1188
+ gap: 8px;
1189
+ }
1190
+
1191
+ .campo {
1192
+ margin: 25px 0;
1193
+ padding: 25px;
1194
+ border-radius: 20px;
1195
+ }
1196
+
1197
+ .ementa {
1198
+ background: #EFF6FF;
1199
+ border-left: 6px solid var(--secondary);
1200
+ }
1201
+
1202
+ .decisao {
1203
+ background: #F5F3FF;
1204
+ border-left: 6px solid var(--purple);
1205
+ }
1206
+
1207
+ .acordao {
1208
+ background: #FFFBEB;
1209
+ border-left: 6px solid var(--warning);
1210
+ }
1211
+
1212
+ .campo-label {
1213
+ font-weight: 600;
1214
+ margin-bottom: 15px;
1215
+ display: block;
1216
+ font-size: 16px;
1217
+ }
1218
+
1219
+ .campo-conteudo {
1220
+ font-size: 15px;
1221
+ line-height: 1.8;
1222
+ color: var(--text);
1223
+ white-space: pre-wrap;
1224
+ background: rgba(255,255,255,0.7);
1225
+ padding: 15px;
1226
+ border-radius: 12px;
1227
+ }
1228
+
1229
+ .url-link {
1230
+ margin-top: 25px;
1231
+ padding: 15px;
1232
+ background: #F8FAFC;
1233
+ border-radius: 12px;
1234
+ border: 1px solid var(--border);
1235
+ }
1236
+
1237
+ .url-link a {
1238
+ color: var(--secondary);
1239
+ text-decoration: none;
1240
+ display: inline-flex;
1241
+ align-items: center;
1242
+ gap: 8px;
1243
+ font-weight: 500;
1244
+ font-size: 16px;
1245
+ }
1246
+
1247
+ .url-link a:hover {
1248
+ text-decoration: underline;
1249
+ }
1250
+
1251
+ .highlight {
1252
+ background-color: #FEF9C3;
1253
+ font-weight: 600;
1254
+ padding: 2px 4px;
1255
+ border-radius: 4px;
1256
+ }
1257
  </style>
1258
  </head>
1259
  <body>
1260
  <div class="container">
1261
  <div class="header">
1262
+ <img src="https://huggingface.co/spaces/caarleexx/paraAI_CHATBOT/resolve/main/public/logo_dark.png"
1263
+ alt="PARA AI"
1264
+ class="logo-small"
1265
+ onerror="this.style.display='none'; this.nextElementSibling.style.display='block';">
1266
+ <div style="display: none; font-weight: 700; color: var(--primary);">⚖️ PARA AI</div>
1267
  <a href="/" class="back-btn">← Voltar para busca</a>
1268
  </div>
1269
 
1270
+ <div id="loading" class="loading-container">
1271
+ <div class="loading"></div>
1272
+ <p style="color: var(--primary); font-weight: 500;">Carregando documento...</p>
1273
  </div>
1274
 
1275
  <div id="error" style="display: none;"></div>
 
1322
  if (temEmenta) {
1323
  html += `
1324
  <div class="campo ementa">
1325
+ <span class="campo-label">📝 Ementa</span>
1326
  <div class="campo-conteudo">${item.ementa.replace(/\\n/g, '<br>').replace(/<em>/g, '<span class="highlight">').replace(/<\\/em>/g, '</span>')}</div>
1327
  </div>
1328
  `;
 
1331
  if (temDecisao) {
1332
  html += `
1333
  <div class="campo decisao">
1334
+ <span class="campo-label">⚖️ Decisão</span>
1335
  <div class="campo-conteudo">${item.decisao_texto.replace(/\\n/g, '<br>').replace(/<em>/g, '<span class="highlight">').replace(/<\\/em>/g, '</span>')}</div>
1336
  </div>
1337
  `;
 
1340
  if (temAcordao) {
1341
  html += `
1342
  <div class="campo acordao">
1343
+ <span class="campo-label">📋 Acórdão/Ata</span>
1344
  <div class="campo-conteudo">${item.acordao_ata.replace(/\\n/g, '<br>').replace(/<em>/g, '<span class="highlight">').replace(/<\\/em>/g, '</span>')}</div>
1345
  </div>
1346
  `;
 
1552
  except:
1553
  pass
1554
  logger.info("="*50)
1555
+ logger.info("🚀 Iniciando PARA AI - Busca STF")
1556
+ logger.info("📋 Bases: acordaos e decisoes")
 
1557
  logger.info("="*50)
1558
  port = int(os.environ.get('PORT', 7860))
1559
  app.run(host='0.0.0.0', port=port, debug=False)