GabrielGD commited on
Commit
2500185
·
verified ·
1 Parent(s): b202ede

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +103 -33
app.py CHANGED
@@ -15,6 +15,9 @@ import cv2
15
  import numpy as np
16
  from datetime import datetime
17
  from ratelimiter import RateLimiter
 
 
 
18
 
19
  load_dotenv()
20
 
@@ -186,6 +189,20 @@ def calcular_pontuacao(enderecamento, fundamentos, pedidos, fechamento):
186
  tabela_formatada = "\n".join([f"| {linha[0].ljust(60)} | {linha[1].rjust(10)} |" for linha in tabela])
187
  return f"{tabela_formatada}\n\n**Nota Final:** {nota_final:.2f} / 10,00"
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  def estruturar_prompt_correcao(caso, peticao, modo_treinamento=False):
190
  base_prompt = f"""
191
  ## Correção Rigorosa de Petição Inicial Cível (Critérios Realistas da OAB)
@@ -262,9 +279,10 @@ def estruturar_prompt_correcao(caso, peticao, modo_treinamento=False):
262
  base_prompt += f"""
263
  **Modo de Treinamento Interativo Ativado:**
264
  - Para cada item com pontuação inferior ao máximo, forneça:
265
- a) Uma explicação detalhada (mínimo 2 frases) descrevendo o erro e por que ele está errado conforme o CPC ou CDC.
266
- b) Uma sugestão de redação corrigida baseada exclusivamente no caso fornecido.
267
- c) Uma dica prática extraída do banco de dicas ({json.dumps(DICAS_OAB)}) ou uma dica personalizada se o banco não se aplicar.
 
268
  - Não resuma; detalhe cada erro de forma pedagógica e clara.
269
  """
270
  return base_prompt
@@ -341,6 +359,10 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
341
  if not peticao_conteudo.strip():
342
  return "⚠️ Forneça uma petição."
343
 
 
 
 
 
344
  cache_key = f"{caso[:50]}|{peticao_conteudo[:50]}|{modo_treinamento}"
345
  if cache_key in CORRECAO_CACHE:
346
  return CORRECAO_CACHE[cache_key]
@@ -376,7 +398,7 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
376
  analise = correção_completa.strip()
377
  correção_formatada = formatar_correção(analise)
378
  HISTORICO.append({
379
- "data": datetime.now().strftime("%Y-%-m-%d %H:%M:%S"),
380
  "caso": caso,
381
  "peticao": peticao_conteudo,
382
  "correcao_completa": correção_completa
@@ -400,11 +422,19 @@ def formatar_correção(texto):
400
  linhas = texto.split('\n')
401
  texto_formatado = ""
402
  for linha in linhas:
403
- if "Análise Geral" in linha or "Nota Final" in linha or "Pontos Positivos" in linha or "Pontos a Melhorar" in linha:
404
- texto_formatado += f"### {linha.strip()}\n\n"
 
 
 
 
 
 
 
 
405
  elif linha.strip().startswith('-') and len(linha) > 2 and any(termo in linha for termo in ["Endereçamento", "Qualificação", "Fatos", "Pedidos", "Valor", "Provas"]):
406
  texto_formatado += f"**{linha.strip()}**\n"
407
- elif "Explicação" in linha or "Sugestão" in linha or "Dica" in linha:
408
  texto_formatado += f"*{linha.strip()}*\n"
409
  else:
410
  texto_formatado += f"{linha}\n"
@@ -414,7 +444,7 @@ def formatar_correção(texto):
414
  match = re.search(nota_pattern, texto_formatado, re.DOTALL)
415
  if match:
416
  nota = match.group(1)
417
- texto_formatado = texto_formatado.replace(f"### Nota Final\n\n{nota}", f"### Nota Final: {nota}/10\n\n")
418
  return texto_formatado
419
 
420
  def extrair_peticao_corrigida(correcao_completa):
@@ -450,9 +480,6 @@ def calcular_progresso():
450
  return f"📊 Progresso: Média {media:.1f}/10 | Tentativas: {len(notas)} | Tendência: {tendencia}"
451
 
452
  def comparar_peticao_melhorada(caso, peticao_texto, correcao):
453
- import difflib
454
- from html import escape
455
-
456
  if not caso:
457
  return "⚠️ Forneça um caso antes de comparar.", "", ""
458
  peticao = peticao_texto if peticao_texto else (HISTORICO[-1]["peticao"] if HISTORICO else "")
@@ -497,6 +524,7 @@ def comparar_peticao_melhorada(caso, peticao_texto, correcao):
497
 
498
  secao_atual = "OUTROS"
499
  resultado_diff = []
 
500
  for linha in diff:
501
  if linha.startswith(' '):
502
  texto = linha[2:]
@@ -506,6 +534,8 @@ def comparar_peticao_melhorada(caso, peticao_texto, correcao):
506
  resultado_diff.append(f"<div class='linha-igual'>{escape(texto)}</div>")
507
  elif linha.startswith('- '):
508
  texto = linha[2:]
 
 
509
  resultado_diff.append(f"<div class='linha-removida'><del>{escape(texto)}</del></div>")
510
  secoes[secao_atual].append(f"- REMOVIDO: {texto}")
511
  elif linha.startswith('+ '):
@@ -513,6 +543,8 @@ def comparar_peticao_melhorada(caso, peticao_texto, correcao):
513
  nova_secao = identificar_secao(texto)
514
  if nova_secao != "OUTROS":
515
  secao_atual = nova_secao
 
 
516
  resultado_diff.append(f"<div class='linha-adicionada'><ins>{escape(texto)}</ins></div>")
517
  secoes[secao_atual].append(f"+ ADICIONADO: {texto}")
518
  elif linha.startswith('? '):
@@ -524,31 +556,56 @@ def comparar_peticao_melhorada(caso, peticao_texto, correcao):
524
  resumo_alteracoes = []
525
  for secao, alteracoes in secoes.items():
526
  if alteracoes:
527
- resumo_alteracoes.append(f"### {secao}\n")
 
 
 
 
 
 
 
 
528
  for alt in alteracoes[:5]:
529
- resumo_alteracoes.append(f" {alt}")
 
530
  if len(alteracoes) > 5:
531
- resumo_alteracoes.append(f" - ... e mais {len(alteracoes) - 5} alterações\n")
532
 
533
  resumo_estatistico = f"""
534
- ## 📊 Resumo das Alterações
535
- - **Linhas Removidas:** {total_removidas}
536
- - **Linhas Adicionadas:** {total_adicionadas}
537
- - **Diferença Líquida:** {total_adicionadas - total_removidas} linhas
538
-
539
- ## 🔍 Alterações por Seção
540
- {''.join(resumo_alteracoes)}
541
-
542
- ## 📝 Visualização Detalhada
543
- <style>
544
- .linha-igual {{ color: #000000; margin: 2px 0; }}
545
- .linha-removida {{ color: #ffffff; background-color: #b30000; margin: 2px 0; padding: 2px; }}
546
- .linha-adicionada {{ color: #ffffff; background-color: #006600; margin: 2px 0; padding: 2px; }}
547
- </style>
548
- {"".join(resultado_diff)}
549
- """
 
 
 
550
  return peticao, peticao_corrigida, resumo_estatistico
551
 
 
 
 
 
 
 
 
 
 
 
 
 
 
552
  def interface_gradio():
553
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
554
  gr.Markdown("# 📝 Corretor Avançado de Petições Iniciais (Critérios OAB)")
@@ -592,7 +649,7 @@ def interface_gradio():
592
  with gr.Row():
593
  gr.Markdown("### 🧩 Gerar Caso Fictício")
594
  caso_btn = gr.Button("🔄 Gerar Novo Caso Fictício", variant="secondary")
595
- caso_input = gr.Textbox(label="� - 📋 Caso Fornecido pela Banca", lines=8, placeholder="Insira o texto COMPLETO do caso...")
596
  with gr.Tabs():
597
  with gr.TabItem("✏️ Inserir Texto"):
598
  peticao_texto = gr.Textbox(label="Texto da Petição do Aluno", lines=15, placeholder="Insira a petição completa...")
@@ -618,6 +675,8 @@ def interface_gradio():
618
 
619
  with gr.Row():
620
  comparacao_diferencas = gr.HTML(label="Diferenças Destacadas")
 
 
621
 
622
  with gr.Accordion("📜 Histórico de Correções", open=False):
623
  historico_output = gr.Markdown()
@@ -639,14 +698,25 @@ def interface_gradio():
639
  outputs=[resultado_output]
640
  )
641
  clear_btn.click(
642
- fn=lambda: [None, None, None, None, "", "", "", ""],
643
  inputs=None,
644
- outputs=[caso_input, peticao_texto, peticao_arquivo, arquivo_preview, resultado_output, dica_contextual, peticao_aluno_output, peticao_corrigida_output]
645
  )
646
  comparar_btn.click(
647
  fn=comparar_peticao_melhorada,
648
  inputs=[caso_input, peticao_texto, resultado_output],
649
  outputs=[peticao_aluno_output, peticao_corrigida_output, comparacao_diferencas]
 
 
 
 
 
 
 
 
 
 
 
650
  )
651
 
652
  with gr.Accordion("📘 Critérios Detalhados", open=False):
 
15
  import numpy as np
16
  from datetime import datetime
17
  from ratelimiter import RateLimiter
18
+ import difflib
19
+ from html import escape
20
+ import pdfkit # Requer wkhtmltopdf instalado
21
 
22
  load_dotenv()
23
 
 
189
  tabela_formatada = "\n".join([f"| {linha[0].ljust(60)} | {linha[1].rjust(10)} |" for linha in tabela])
190
  return f"{tabela_formatada}\n\n**Nota Final:** {nota_final:.2f} / 10,00"
191
 
192
+ def validar_peticao_basica(peticao):
193
+ problemas = []
194
+ if "EXCELENTÍSSIMO" not in peticao.upper():
195
+ problemas.append("⚠️ Endereçamento ausente ou incompleto.")
196
+ if "Art. 319" not in peticao and "CPC" not in peticao:
197
+ problemas.append("⚠️ Fundamentação jurídica não menciona o CPC.")
198
+ if "Dá-se à causa o valor" not in peticao:
199
+ problemas.append("⚠️ Valor da causa não especificado (Art. 319, V, CPC).")
200
+ if "juntada da guia de custas" not in peticao.lower():
201
+ problemas.append("⚠️ Pedido de juntada da guia de custas ausente.")
202
+ if "Nestes termos" not in peticao:
203
+ problemas.append("⚠️ Fechamento formal ausente.")
204
+ return problemas
205
+
206
  def estruturar_prompt_correcao(caso, peticao, modo_treinamento=False):
207
  base_prompt = f"""
208
  ## Correção Rigorosa de Petição Inicial Cível (Critérios Realistas da OAB)
 
279
  base_prompt += f"""
280
  **Modo de Treinamento Interativo Ativado:**
281
  - Para cada item com pontuação inferior ao máximo, forneça:
282
+ a) Uma explicação detalhada (mínimo 2 frases) descrevendo o erro e sua base legal (ex.: Art. 319, CPC).
283
+ b) Uma sugestão de redação corrigida baseada no caso.
284
+ c) Um exemplo prático de redação correta em outro contexto (ex.: "Em uma ação de dano moral, poderia ser: 'Requer a condenação ao pagamento de R$ 10.000,00 por danos morais, conforme Súmula 387 do STJ.'").
285
+ d) Uma dica prática do banco ({json.dumps(DICAS_OAB)}) ou personalizada.
286
  - Não resuma; detalhe cada erro de forma pedagógica e clara.
287
  """
288
  return base_prompt
 
359
  if not peticao_conteudo.strip():
360
  return "⚠️ Forneça uma petição."
361
 
362
+ problemas = validar_peticao_basica(peticao_conteudo)
363
+ if problemas:
364
+ return f"### Validação Inicial\n\n" + "\n".join(problemas) + "\n\nCorrija os itens acima antes de prosseguir."
365
+
366
  cache_key = f"{caso[:50]}|{peticao_conteudo[:50]}|{modo_treinamento}"
367
  if cache_key in CORRECAO_CACHE:
368
  return CORRECAO_CACHE[cache_key]
 
398
  analise = correção_completa.strip()
399
  correção_formatada = formatar_correção(analise)
400
  HISTORICO.append({
401
+ "data": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
402
  "caso": caso,
403
  "peticao": peticao_conteudo,
404
  "correcao_completa": correção_completa
 
422
  linhas = texto.split('\n')
423
  texto_formatado = ""
424
  for linha in linhas:
425
+ if "Análise Geral" in linha:
426
+ texto_formatado += f"### ℹ️ {linha.strip()}\n\n"
427
+ elif "Nota Final" in linha:
428
+ texto_formatado += f"### ⭐ {linha.strip()}\n\n"
429
+ elif "Pontos Positivos" in linha:
430
+ texto_formatado += f"### ✅ {linha.strip()}\n\n"
431
+ elif "Pontos a Melhorar" in linha:
432
+ texto_formatado += f"### ⚠️ {linha.strip()}\n\n"
433
+ elif "- Invenção de fatos" in linha:
434
+ texto_formatado += f"**🔴 {linha.strip()}**\n"
435
  elif linha.strip().startswith('-') and len(linha) > 2 and any(termo in linha for termo in ["Endereçamento", "Qualificação", "Fatos", "Pedidos", "Valor", "Provas"]):
436
  texto_formatado += f"**{linha.strip()}**\n"
437
+ elif "Explicação" in linha or "Sugestão" in linha or "Dica" in linha or "Exemplo" in linha:
438
  texto_formatado += f"*{linha.strip()}*\n"
439
  else:
440
  texto_formatado += f"{linha}\n"
 
444
  match = re.search(nota_pattern, texto_formatado, re.DOTALL)
445
  if match:
446
  nota = match.group(1)
447
+ texto_formatado = texto_formatado.replace(f"### ⭐ Nota Final\n\n{nota}", f"### ⭐ Nota Final: {nota}/10\n\n")
448
  return texto_formatado
449
 
450
  def extrair_peticao_corrigida(correcao_completa):
 
480
  return f"📊 Progresso: Média {media:.1f}/10 | Tentativas: {len(notas)} | Tendência: {tendencia}"
481
 
482
  def comparar_peticao_melhorada(caso, peticao_texto, correcao):
 
 
 
483
  if not caso:
484
  return "⚠️ Forneça um caso antes de comparar.", "", ""
485
  peticao = peticao_texto if peticao_texto else (HISTORICO[-1]["peticao"] if HISTORICO else "")
 
524
 
525
  secao_atual = "OUTROS"
526
  resultado_diff = []
527
+ criticas = []
528
  for linha in diff:
529
  if linha.startswith(' '):
530
  texto = linha[2:]
 
534
  resultado_diff.append(f"<div class='linha-igual'>{escape(texto)}</div>")
535
  elif linha.startswith('- '):
536
  texto = linha[2:]
537
+ if any(kw in texto.lower() for kw in ["invenção", "custas", "art. 319"]):
538
+ criticas.append(f"🔴 REMOVIDO: {texto}")
539
  resultado_diff.append(f"<div class='linha-removida'><del>{escape(texto)}</del></div>")
540
  secoes[secao_atual].append(f"- REMOVIDO: {texto}")
541
  elif linha.startswith('+ '):
 
543
  nova_secao = identificar_secao(texto)
544
  if nova_secao != "OUTROS":
545
  secao_atual = nova_secao
546
+ if any(kw in texto.lower() for kw in ["custas", "art. 319"]):
547
+ criticas.append(f"🟢 ADICIONADO: {texto}")
548
  resultado_diff.append(f"<div class='linha-adicionada'><ins>{escape(texto)}</ins></div>")
549
  secoes[secao_atual].append(f"+ ADICIONADO: {texto}")
550
  elif linha.startswith('? '):
 
556
  resumo_alteracoes = []
557
  for secao, alteracoes in secoes.items():
558
  if alteracoes:
559
+ adicionadas = sum(1 for alt in alteracoes if alt.startswith("+"))
560
+ removidas = sum(1 for alt in alteracoes if alt.startswith("-"))
561
+ resumo_alteracoes.append(f"""
562
+ ### {secao}
563
+ | Tipo | Quantidade |
564
+ |--------------|------------|
565
+ | Adicionadas | {adicionadas} |
566
+ | Removidas | {removidas} |
567
+ """)
568
  for alt in alteracoes[:5]:
569
+ texto = alt[:60] + "..." if len(alt) > 60 else alt
570
+ resumo_alteracoes.append(f" {texto}")
571
  if len(alteracoes) > 5:
572
+ resumo_alteracoes.append(f" - ... e mais {len(alteracoes) - 5} alterações")
573
 
574
  resumo_estatistico = f"""
575
+ ## 📊 Resumo das Alterações
576
+ - **Linhas Removidas:** {total_removidas}
577
+ - **Linhas Adicionadas:** {total_adicionadas}
578
+ - **Diferença Líquida:** {total_adicionadas - total_removidas} linhas
579
+
580
+ ## 🚨 Mudanças Críticas
581
+ {''.join(criticas) if criticas else 'Nenhuma mudança crítica detectada.'}
582
+
583
+ ## 🔍 Alterações por Seção
584
+ {''.join(resumo_alteracoes)}
585
+
586
+ ## 📝 Visualização Detalhada
587
+ <style>
588
+ .linha-igual {{ color: #000000; margin: 2px 0; }}
589
+ .linha-removida {{ color: #ffffff; background-color: #b30000; margin: 2px 0; padding: 2px; }}
590
+ .linha-adicionada {{ color: #ffffff; background-color: #006600; margin: 2px 0; padding: 2px; }}
591
+ </style>
592
+ {"".join(resultado_diff)}
593
+ """
594
  return peticao, peticao_corrigida, resumo_estatistico
595
 
596
+ def exportar_diferencas(caso, peticao_texto, correcao):
597
+ _, _, resumo_estatistico = comparar_peticao_melhorada(caso, peticao_texto, correcao)
598
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".html") as tmp:
599
+ tmp.write(resumo_estatistico.encode('utf-8'))
600
+ pdf_path = tmp.name.replace(".html", ".pdf")
601
+ try:
602
+ pdfkit.from_file(tmp.name, pdf_path)
603
+ return pdf_path
604
+ except Exception as e:
605
+ return f"❌ Erro ao gerar PDF: {str(e)}"
606
+ finally:
607
+ os.unlink(tmp.name)
608
+
609
  def interface_gradio():
610
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
611
  gr.Markdown("# 📝 Corretor Avançado de Petições Iniciais (Critérios OAB)")
 
649
  with gr.Row():
650
  gr.Markdown("### 🧩 Gerar Caso Fictício")
651
  caso_btn = gr.Button("🔄 Gerar Novo Caso Fictício", variant="secondary")
652
+ caso_input = gr.Textbox(label="📋 Caso Fornecido pela Banca", lines=8, placeholder="Insira o texto COMPLETO do caso...")
653
  with gr.Tabs():
654
  with gr.TabItem("✏️ Inserir Texto"):
655
  peticao_texto = gr.Textbox(label="Texto da Petição do Aluno", lines=15, placeholder="Insira a petição completa...")
 
675
 
676
  with gr.Row():
677
  comparacao_diferencas = gr.HTML(label="Diferenças Destacadas")
678
+ export_btn = gr.Button("📥 Exportar Diferenças", visible=False)
679
+ export_file = gr.File(label="Baixar Diferenças", visible=False)
680
 
681
  with gr.Accordion("📜 Histórico de Correções", open=False):
682
  historico_output = gr.Markdown()
 
698
  outputs=[resultado_output]
699
  )
700
  clear_btn.click(
701
+ fn=lambda: [None, None, None, None, "", "", "", "", gr.update(visible=False), gr.update(visible=False)],
702
  inputs=None,
703
+ outputs=[caso_input, peticao_texto, peticao_arquivo, arquivo_preview, resultado_output, dica_contextual, peticao_aluno_output, peticao_corrigida_output, export_btn, export_file]
704
  )
705
  comparar_btn.click(
706
  fn=comparar_peticao_melhorada,
707
  inputs=[caso_input, peticao_texto, resultado_output],
708
  outputs=[peticao_aluno_output, peticao_corrigida_output, comparacao_diferencas]
709
+ ).then(
710
+ fn=lambda: [gr.update(visible=True), gr.update(visible=False)],
711
+ outputs=[export_btn, export_file]
712
+ )
713
+ export_btn.click(
714
+ fn=exportar_diferencas,
715
+ inputs=[caso_input, peticao_texto, resultado_output],
716
+ outputs=export_file
717
+ ).then(
718
+ fn=lambda x: [gr.update(visible=True, value=x), gr.update(visible=True)],
719
+ outputs=[export_file, export_btn]
720
  )
721
 
722
  with gr.Accordion("📘 Critérios Detalhados", open=False):