Update app.py
Browse files
app.py
CHANGED
|
@@ -17,7 +17,6 @@ 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 |
|
|
@@ -228,12 +227,13 @@ def estruturar_prompt_correcao(caso, peticao, modo_treinamento=False):
|
|
| 228 |
- Juntada da guia de custas
|
| 229 |
- Fechamento formal da petição
|
| 230 |
**Critérios Fundamentais:**
|
| 231 |
-
1. Identificação do candidato resulta em nota máxima de 3,0
|
| 232 |
2. Invenção de fatos não constantes no caso resulta em penalização grave (-5,0 pontos)
|
| 233 |
3. Falta de pedido de juntada de custas resulta em perda de 1,0 ponto
|
| 234 |
4. Use marcadores para dados não fornecidos (ex: "Rua XXX", "CPF XXX")
|
| 235 |
5. Não penalize por informações ausentes no caso original
|
| 236 |
-
6. A frase "Nestes termos, pede deferimento" com vírgula é incorreta; corrija para "Nestes termos pede deferimento" e destaque o erro na análise
|
|
|
|
| 237 |
**Instruções Especiais para Endereçamento:**
|
| 238 |
- CPC (art. 46): foro competente é o domicílio do réu; CDC (art. 101, I): em relação de consumo, foro do autor é correto.
|
| 239 |
- Avalie o contexto: priorize o foro do autor em casos consumeristas.
|
|
@@ -258,7 +258,7 @@ def estruturar_prompt_correcao(caso, peticao, modo_treinamento=False):
|
|
| 258 |
**Fechamento** | |
|
| 259 |
12. Fechamento formal adequado (0,10) | / 0,10 |
|
| 260 |
**Nota Final:**
|
| 261 |
-
Calcule a nota final somando os pontos.
|
| 262 |
---
|
| 263 |
|
| 264 |
### Petição Corrigida
|
|
@@ -273,7 +273,7 @@ def estruturar_prompt_correcao(caso, peticao, modo_treinamento=False):
|
|
| 273 |
8. Opção por audiência (Art. 319, VII, CPC)
|
| 274 |
9. Pedido de citação
|
| 275 |
10. Juntada da guia de custas
|
| 276 |
-
11. Fechamento formal
|
| 277 |
"""
|
| 278 |
if modo_treinamento:
|
| 279 |
base_prompt += f"""
|
|
@@ -359,7 +359,6 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 359 |
if not peticao_conteudo.strip():
|
| 360 |
return "⚠️ Forneça uma petição."
|
| 361 |
|
| 362 |
-
# Validação preliminar como aviso, não como bloqueio
|
| 363 |
problemas = validar_peticao_basica(peticao_conteudo)
|
| 364 |
aviso_validacao = f"### Validação Inicial\n\n" + "\n".join(problemas) + "\n\n" if problemas else ""
|
| 365 |
|
|
@@ -481,15 +480,15 @@ def calcular_progresso():
|
|
| 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 "")
|
| 486 |
if not peticao:
|
| 487 |
-
return "⚠️ Forneça uma petição para comparar ou corrija uma antes.", "", ""
|
| 488 |
if not correcao:
|
| 489 |
-
return "⚠️ Corrija a petição antes de comparar.", "", ""
|
| 490 |
ultima_correcao = HISTORICO[-1]["correcao_completa"] if HISTORICO else ""
|
| 491 |
if not ultima_correcao:
|
| 492 |
-
return "⚠️ Nenhuma correção disponível no histórico.", "", ""
|
| 493 |
peticao_corrigida = extrair_peticao_corrigida(ultima_correcao)
|
| 494 |
|
| 495 |
orig_lines = peticao.split('\n')
|
|
@@ -572,18 +571,14 @@ def comparar_peticao_melhorada(caso, peticao_texto, correcao):
|
|
| 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 |
-
|
| 581 |
-
|
| 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; }}
|
|
@@ -591,20 +586,7 @@ def comparar_peticao_melhorada(caso, peticao_texto, correcao):
|
|
| 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:
|
|
@@ -628,6 +610,7 @@ def interface_gradio():
|
|
| 628 |
- ❌ Identificação do candidato: nota máxima 3,0
|
| 629 |
- ❌ Invenção de fatos: -5,0 pontos
|
| 630 |
- ❌ Sem pedido de custas: -1,0 ponto
|
|
|
|
| 631 |
""")
|
| 632 |
modo_treinamento = gr.Checkbox(label="Modo de Treinamento Interativo", value=False)
|
| 633 |
with gr.Accordion("⚙️ Configurações", open=False):
|
|
@@ -674,9 +657,11 @@ def interface_gradio():
|
|
| 674 |
peticao_corrigida_output = gr.Textbox(label="Petição Corrigida", lines=15, interactive=False)
|
| 675 |
|
| 676 |
with gr.Row():
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
|
|
|
|
|
|
|
| 680 |
|
| 681 |
with gr.Accordion("📜 Histórico de Correções", open=False):
|
| 682 |
historico_output = gr.Markdown()
|
|
@@ -698,25 +683,17 @@ def interface_gradio():
|
|
| 698 |
outputs=[resultado_output]
|
| 699 |
)
|
| 700 |
clear_btn.click(
|
| 701 |
-
fn=lambda: [None, None, None, None, "", "", "", "",
|
| 702 |
inputs=None,
|
| 703 |
-
outputs=[caso_input, peticao_texto, peticao_arquivo, arquivo_preview, resultado_output, dica_contextual,
|
|
|
|
|
|
|
| 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,
|
| 709 |
-
|
| 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):
|
|
@@ -729,9 +706,12 @@ def interface_gradio():
|
|
| 729 |
- ✅ CORRETO: Pedir citação conforme dados do caso
|
| 730 |
#### 3. Pedidos Obrigatórios
|
| 731 |
- ✅ OBRIGATÓRIO: Incluir "a juntada da guia de custas"
|
| 732 |
-
#### 4.
|
| 733 |
-
-
|
|
|
|
|
|
|
| 734 |
- ❌ INCORRETO: Invenção de fatos
|
|
|
|
| 735 |
""")
|
| 736 |
gr.Markdown("""
|
| 737 |
### ℹ️ Modo de Treinamento Interativo
|
|
|
|
| 17 |
from ratelimiter import RateLimiter
|
| 18 |
import difflib
|
| 19 |
from html import escape
|
|
|
|
| 20 |
|
| 21 |
load_dotenv()
|
| 22 |
|
|
|
|
| 227 |
- Juntada da guia de custas
|
| 228 |
- Fechamento formal da petição
|
| 229 |
**Critérios Fundamentais:**
|
| 230 |
+
1. Identificação do candidato (nome ou número real na seção final) resulta em nota máxima de 3,0
|
| 231 |
2. Invenção de fatos não constantes no caso resulta em penalização grave (-5,0 pontos)
|
| 232 |
3. Falta de pedido de juntada de custas resulta em perda de 1,0 ponto
|
| 233 |
4. Use marcadores para dados não fornecidos (ex: "Rua XXX", "CPF XXX")
|
| 234 |
5. Não penalize por informações ausentes no caso original
|
| 235 |
+
6. A frase "Nestes termos, pede deferimento" com vírgula é incorreta; corrija para "Nestes termos pede deferimento" e destaque o erro na análise
|
| 236 |
+
7. A petição deve finalizar com "Local e data.\nADVOGADO.\nOAB." sem identificação do aluno (nome, número ou estado na OAB); se houver identificação específica (ex.: número ou estado), zere a nota (0,0)
|
| 237 |
**Instruções Especiais para Endereçamento:**
|
| 238 |
- CPC (art. 46): foro competente é o domicílio do réu; CDC (art. 101, I): em relação de consumo, foro do autor é correto.
|
| 239 |
- Avalie o contexto: priorize o foro do autor em casos consumeristas.
|
|
|
|
| 258 |
**Fechamento** | |
|
| 259 |
12. Fechamento formal adequado (0,10) | / 0,10 |
|
| 260 |
**Nota Final:**
|
| 261 |
+
Calcule a nota final somando os pontos, exceto se houver identificação específica na OAB, que zera a nota.
|
| 262 |
---
|
| 263 |
|
| 264 |
### Petição Corrigida
|
|
|
|
| 273 |
8. Opção por audiência (Art. 319, VII, CPC)
|
| 274 |
9. Pedido de citação
|
| 275 |
10. Juntada da guia de custas
|
| 276 |
+
11. Fechamento formal com "Local e data.\nADVOGADO.\nOAB." sem identificação específica
|
| 277 |
"""
|
| 278 |
if modo_treinamento:
|
| 279 |
base_prompt += f"""
|
|
|
|
| 359 |
if not peticao_conteudo.strip():
|
| 360 |
return "⚠️ Forneça uma petição."
|
| 361 |
|
|
|
|
| 362 |
problemas = validar_peticao_basica(peticao_conteudo)
|
| 363 |
aviso_validacao = f"### Validação Inicial\n\n" + "\n".join(problemas) + "\n\n" if problemas else ""
|
| 364 |
|
|
|
|
| 480 |
|
| 481 |
def comparar_peticao_melhorada(caso, peticao_texto, correcao):
|
| 482 |
if not caso:
|
| 483 |
+
return "⚠️ Forneça um caso antes de comparar.", "", "", ""
|
| 484 |
peticao = peticao_texto if peticao_texto else (HISTORICO[-1]["peticao"] if HISTORICO else "")
|
| 485 |
if not peticao:
|
| 486 |
+
return "⚠️ Forneça uma petição para comparar ou corrija uma antes.", "", "", ""
|
| 487 |
if not correcao:
|
| 488 |
+
return "⚠️ Corrija a petição antes de comparar.", "", "", ""
|
| 489 |
ultima_correcao = HISTORICO[-1]["correcao_completa"] if HISTORICO else ""
|
| 490 |
if not ultima_correcao:
|
| 491 |
+
return "⚠️ Nenhuma correção disponível no histórico.", "", "", ""
|
| 492 |
peticao_corrigida = extrair_peticao_corrigida(ultima_correcao)
|
| 493 |
|
| 494 |
orig_lines = peticao.split('\n')
|
|
|
|
| 571 |
resumo_alteracoes.append(f" - ... e mais {len(alteracoes) - 5} alterações")
|
| 572 |
|
| 573 |
resumo_estatistico = f"""
|
|
|
|
| 574 |
- **Linhas Removidas:** {total_removidas}
|
| 575 |
- **Linhas Adicionadas:** {total_adicionadas}
|
| 576 |
- **Diferença Líquida:** {total_adicionadas - total_removidas} linhas
|
| 577 |
+
"""
|
| 578 |
|
| 579 |
+
criticas_texto = "\n".join(criticas) if criticas else "Nenhuma mudança crítica detectada."
|
| 580 |
+
alteracoes_texto = "".join(resumo_alteracoes)
|
| 581 |
+
visualizacao_detalhada = f"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 582 |
<style>
|
| 583 |
.linha-igual {{ color: #000000; margin: 2px 0; }}
|
| 584 |
.linha-removida {{ color: #ffffff; background-color: #b30000; margin: 2px 0; padding: 2px; }}
|
|
|
|
| 586 |
</style>
|
| 587 |
{"".join(resultado_diff)}
|
| 588 |
"""
|
| 589 |
+
return peticao, peticao_corrigida, resumo_estatistico, criticas_texto, alteracoes_texto, visualizacao_detalhada
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 590 |
|
| 591 |
def interface_gradio():
|
| 592 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
|
|
| 610 |
- ❌ Identificação do candidato: nota máxima 3,0
|
| 611 |
- ❌ Invenção de fatos: -5,0 pontos
|
| 612 |
- ❌ Sem pedido de custas: -1,0 ponto
|
| 613 |
+
- ❌ Identificação específica na OAB (nome, número ou estado): nota 0,0
|
| 614 |
""")
|
| 615 |
modo_treinamento = gr.Checkbox(label="Modo de Treinamento Interativo", value=False)
|
| 616 |
with gr.Accordion("⚙️ Configurações", open=False):
|
|
|
|
| 657 |
peticao_corrigida_output = gr.Textbox(label="Petição Corrigida", lines=15, interactive=False)
|
| 658 |
|
| 659 |
with gr.Row():
|
| 660 |
+
with gr.Column(scale=1):
|
| 661 |
+
resumo_alteracoes_output = gr.Markdown(label="📊 Resumo das Alterações")
|
| 662 |
+
criticas_output = gr.Markdown(label="🚨 Mudanças Críticas")
|
| 663 |
+
with gr.Column(scale=2):
|
| 664 |
+
visualizacao_detalhada_output = gr.Markdown(label="📝 Alterações Detalhadas")
|
| 665 |
|
| 666 |
with gr.Accordion("📜 Histórico de Correções", open=False):
|
| 667 |
historico_output = gr.Markdown()
|
|
|
|
| 683 |
outputs=[resultado_output]
|
| 684 |
)
|
| 685 |
clear_btn.click(
|
| 686 |
+
fn=lambda: [None, None, None, None, "", "", "", "", "", "", ""],
|
| 687 |
inputs=None,
|
| 688 |
+
outputs=[caso_input, peticao_texto, peticao_arquivo, arquivo_preview, resultado_output, dica_contextual,
|
| 689 |
+
peticao_aluno_output, peticao_corrigida_output, resumo_alteracoes_output, criticas_output,
|
| 690 |
+
visualizacao_detalhada_output]
|
| 691 |
)
|
| 692 |
comparar_btn.click(
|
| 693 |
fn=comparar_peticao_melhorada,
|
| 694 |
inputs=[caso_input, peticao_texto, resultado_output],
|
| 695 |
+
outputs=[peticao_aluno_output, peticao_corrigida_output, resumo_alteracoes_output, criticas_output,
|
| 696 |
+
visualizacao_detalhada_output]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 697 |
)
|
| 698 |
|
| 699 |
with gr.Accordion("📘 Critérios Detalhados", open=False):
|
|
|
|
| 706 |
- ✅ CORRETO: Pedir citação conforme dados do caso
|
| 707 |
#### 3. Pedidos Obrigatórios
|
| 708 |
- ✅ OBRIGATÓRIO: Incluir "a juntada da guia de custas"
|
| 709 |
+
#### 4. Fechamento Formal
|
| 710 |
+
- ✅ OBRIGATÓRIO: Finalizar com "Local e data.\nADVOGADO.\nOAB." sem identificação específica
|
| 711 |
+
#### 5. Penalização Grave
|
| 712 |
+
- ❌ INCORRETO: Identificação do candidato (nome ou número)
|
| 713 |
- ❌ INCORRETO: Invenção de fatos
|
| 714 |
+
- ❌ INCORRETO: Identificação na OAB (número ou estado)
|
| 715 |
""")
|
| 716 |
gr.Markdown("""
|
| 717 |
### ℹ️ Modo de Treinamento Interativo
|