Update app.py
Browse files
app.py
CHANGED
|
@@ -18,9 +18,26 @@ from ratelimiter import RateLimiter
|
|
| 18 |
import difflib
|
| 19 |
from html import escape
|
| 20 |
from weasyprint import HTML # Para gerar PDF com cores
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
load_dotenv()
|
| 23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
| 25 |
if not GEMINI_API_KEY:
|
| 26 |
raise ValueError("❌ A chave GEMINI_API_KEY não foi encontrada. Configure-a como Secret no Hugging Face Spaces.")
|
|
@@ -38,47 +55,30 @@ CONFIG = {
|
|
| 38 |
rate_limiter = RateLimiter(max_calls=60, period=60)
|
| 39 |
|
| 40 |
DICAS_OAB_MELHORADO = {
|
| 41 |
-
"Endereçamento": "Em relações de consumo, prefira o foro do domicílio do autor (Art. 101, I, CDC). "
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
"
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
"
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
"
|
| 51 |
-
"Dica: Inclua pedidos de danos morais e materiais, se aplicável, com base em precedentes.",
|
| 52 |
-
|
| 53 |
-
"Custas": "Inclua 'Requer a juntada da guia de custas devidamente recolhida'. "
|
| 54 |
-
"Dica: Nunca se esqueça de mencionar o recolhimento das custas para evitar a extinção do processo.",
|
| 55 |
-
|
| 56 |
-
"Fundamentação": "Baseie-se em artigos do CPC ou CDC e, se possível, em súmulas do STJ (ex.: Súmula 387 para danos morais). "
|
| 57 |
-
"Exemplo: 'Conforme o artigo 186 do Código Civil, a responsabilidade civil pode ser caracterizada'.",
|
| 58 |
-
|
| 59 |
-
"Fechamento": "Finalize com 'Nestes termos pede deferimento', sem vírgula. "
|
| 60 |
-
"Dica: Evite erros de pontuação que podem comprometer a formalidade do documento.",
|
| 61 |
-
|
| 62 |
-
"Estratégia Jurídica": "Utilize precedentes e súmulas para fortalecer sua argumentação. "
|
| 63 |
-
"Exemplo: 'Conforme a Súmula 387 do STJ, os danos morais devem ser comprovados e quantificados'.",
|
| 64 |
-
|
| 65 |
-
"Provas": "Especifique as provas que pretende produzir. "
|
| 66 |
-
"Dica: Inclua testemunhas, documentos e perícias, se necessário, para comprovar os fatos alegados.",
|
| 67 |
-
|
| 68 |
-
"Contra-argumentação": "Antecipe possíveis defesas da parte contrária e prepare respostas. "
|
| 69 |
-
"Dica: Considere os argumentos que a outra parte pode usar e esteja preparado para refutá-los."
|
| 70 |
}
|
| 71 |
|
| 72 |
HISTORICO = []
|
| 73 |
-
CORRECAO_CACHE = {}
|
| 74 |
|
| 75 |
def preprocess_image_for_ocr(img):
|
| 76 |
try:
|
| 77 |
gray = img.convert('L')
|
| 78 |
np_img = np.array(gray)
|
| 79 |
-
|
|
|
|
|
|
|
| 80 |
return Image.fromarray(thresh)
|
| 81 |
except Exception as e:
|
|
|
|
| 82 |
return f"❌ Erro no pré-processamento: {str(e)}"
|
| 83 |
|
| 84 |
def extract_text_from_pdf(file_path_or_obj):
|
|
@@ -114,6 +114,7 @@ def extract_text_from_pdf(file_path_or_obj):
|
|
| 114 |
text += f"[Erro na página {i+1}: {str(e)}]\n"
|
| 115 |
return text if text.strip() else "⚠️ Não foi possível extrair texto do PDF."
|
| 116 |
except Exception as e:
|
|
|
|
| 117 |
return f"❌ Erro ao processar o PDF: {str(e)}"
|
| 118 |
|
| 119 |
def extract_text_from_docx(file_path_or_obj):
|
|
@@ -141,6 +142,7 @@ def extract_text_from_docx(file_path_or_obj):
|
|
| 141 |
text += "\n"
|
| 142 |
return text if text.strip() else "⚠️ Não foi possível extrair texto do DOCX."
|
| 143 |
except Exception as e:
|
|
|
|
| 144 |
return f"❌ Erro ao processar o DOCX: {str(e)}"
|
| 145 |
|
| 146 |
def extract_text_from_txt(file_path_or_obj):
|
|
@@ -165,9 +167,11 @@ def extract_text_from_txt(file_path_or_obj):
|
|
| 165 |
continue
|
| 166 |
return "❌ Não foi possível decodificar o arquivo TXT."
|
| 167 |
except Exception as e:
|
|
|
|
| 168 |
return f"❌ Erro ao processar o TXT: {str(e)}"
|
| 169 |
|
| 170 |
def process_file(file_obj):
|
|
|
|
| 171 |
if file_obj is None:
|
| 172 |
return "Nenhum arquivo enviado."
|
| 173 |
try:
|
|
@@ -188,6 +192,7 @@ def process_file(file_obj):
|
|
| 188 |
else:
|
| 189 |
return "❌ Erro: Objeto de arquivo inválido."
|
| 190 |
except Exception as e:
|
|
|
|
| 191 |
return f"❌ Erro ao processar o arquivo: {str(e)}"
|
| 192 |
|
| 193 |
def calcular_pontuacao(enderecamento, fundamentos, pedidos, fechamento):
|
|
@@ -214,105 +219,175 @@ def calcular_pontuacao(enderecamento, fundamentos, pedidos, fechamento):
|
|
| 214 |
return f"{tabela_formatada}\n\n**Nota Final:** {nota_final:.2f} / 10,00"
|
| 215 |
|
| 216 |
def validar_peticao_basica(peticao):
|
|
|
|
| 217 |
problemas = []
|
| 218 |
-
|
|
|
|
|
|
|
|
|
|
| 219 |
problemas.append("⚠️ Endereçamento ausente ou incompleto (Art. 319, I, CPC).")
|
| 220 |
-
if "
|
| 221 |
-
problemas.append("⚠️
|
| 222 |
-
if "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
problemas.append("⚠️ Valor da causa não especificado (Art. 319, V, CPC).")
|
| 224 |
-
if "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
problemas.append("⚠️ Pedido de juntada da guia de custas ausente (-1,0 ponto).")
|
| 226 |
-
if "
|
| 227 |
-
problemas.append("⚠️ Fechamento formal ausente.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
return problemas
|
| 229 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
def estruturar_prompt_correcao(caso, peticao, modo_treinamento=False):
|
|
|
|
| 231 |
base_prompt = f"""
|
| 232 |
-
## Correção Avançada de Petição Inicial Cível (Critérios Realistas da OAB)
|
| 233 |
**Caso Fornecido:**
|
| 234 |
{caso}
|
| 235 |
**Petição do Aluno:**
|
| 236 |
{peticao}
|
| 237 |
**Estrutura da Avaliação:**
|
| 238 |
### Análise da Petição
|
| 239 |
-
1. Análise Geral (Visão geral sobre a petição - máximo 3 linhas)
|
| 240 |
-
2. Nota Final (0 a 10 com uma casa decimal)
|
| 241 |
-
3. Pontos Positivos (Liste pelo menos 3 aspectos bem executados com justificativa legal)
|
| 242 |
-
4. Pontos a Melhorar (Liste os problemas encontrados em ordem de gravidade com explicação
|
| 243 |
5. Análise Específica dos Requisitos:
|
| 244 |
-
- Endereçamento e qualificação do juízo (Art. 319, I, CPC; Art. 101, I, CDC se aplicável)
|
| 245 |
-
- Qualificação das partes (Art. 319, II, CPC)
|
| 246 |
-
- Fatos e fundamentos jurídicos (Art. 319, III, CPC; Art. 186, CC)
|
| 247 |
-
- Pedidos com especificações (Art. 319, IV, CPC)
|
| 248 |
-
- Valor da causa (Art. 319, V, CPC)
|
| 249 |
-
- Provas com que o autor pretende demonstrar a verdade dos fatos (Art. 319, VI, CPC)
|
| 250 |
-
- Opção pela realização ou não de audiência de conciliação (Art. 319, VII, CPC)
|
| 251 |
-
- Pedido de citação do réu
|
| 252 |
-
- Juntada da guia de custas
|
| 253 |
-
- Fechamento formal da petição
|
|
|
|
| 254 |
**Critérios Fundamentais:**
|
| 255 |
-
1. Identificação do candidato (nome ou número real na seção final) resulta em nota máxima de 3,0
|
| 256 |
-
2. Invenção de fatos não constantes no caso resulta em penalização grave (-5,0 pontos)
|
| 257 |
-
3. Falta de pedido de juntada de custas resulta em perda de 1,0 ponto
|
| 258 |
-
4. Use marcadores para dados não fornecidos (ex: "Rua XXX", "CPF XXX")
|
| 259 |
-
5. Não penalize por informações ausentes no caso original
|
| 260 |
-
6. A frase "Nestes termos, pede deferimento" com vírgula é incorreta; corrija para "Nestes termos pede deferimento" e
|
| 261 |
-
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.:
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
- Avalie o
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 265 |
**Pontuação Detalhada:**
|
| 266 |
Inclua uma tabela com:
|
| 267 |
-
| ITEM | PONTUAÇÃO |
|
| 268 |
-
|-------------------------------------------|-----------|
|
| 269 |
-
**Endereçamento** | |
|
| 270 |
-
1. Correto endereçamento ao juízo competente (0,10) | / 0,10 |
|
| 271 |
-
2. Qualificação das partes conforme Art. 319, II, CPC (0,20) | / 0,20 |
|
| 272 |
-
**Fundamentos** | |
|
| 273 |
-
3. Exposição clara dos fatos (0,20) | / 0,20 |
|
| 274 |
-
4. Fundamentação jurídica adequada (0,25)
|
| 275 |
-
5. Demonstração de ilícito e dano (0,25) | / 0,25 |
|
| 276 |
-
**Pedidos** | |
|
| 277 |
-
6. Pedidos claros e específicos (0,30) | / 0,30 |
|
| 278 |
-
7. Valor da causa indicado (0,10) | / 0,10 |
|
| 279 |
-
8. Provas pretendidas especificadas (0,10)
|
| 280 |
-
9. Opção sobre audiência de conciliação (0,10) | / 0,10 |
|
| 281 |
-
10. Pedido de citação do réu (0,10) | / 0,10 |
|
| 282 |
-
11. Juntada da guia de custas (0,10)
|
| 283 |
-
**Fechamento** | |
|
| 284 |
-
12. Fechamento formal adequado (0,10) | / 0,10 |
|
| 285 |
-
**Nota Final:**
|
| 286 |
-
Calcule a nota final somando os pontos, exceto se houver identificação específica na OAB, que zera a nota.
|
| 287 |
-
---
|
| 288 |
|
| 289 |
### Petição Corrigida
|
| 290 |
-
Forneça a petição do aluno reescrita com todas as correções aplicadas, incluindo partes omitidas (como pedidos ou custas) e ajustando erros identificados
|
| 291 |
-
1. Endereçamento correto
|
| 292 |
-
2. Qualificação completa (Art. 319, II, CPC)
|
| 293 |
-
3. Fatos claros (Art. 319, III, CPC)
|
| 294 |
-
4. Fundamentação jurídica (
|
| 295 |
-
5. Pedidos específicos (Art. 319, IV, CPC)
|
| 296 |
-
6. Valor da causa (Art. 319, V, CPC)
|
| 297 |
-
7. Provas (Art. 319, VI, CPC)
|
| 298 |
-
8. Opção por audiência (Art. 319, VII, CPC)
|
| 299 |
-
9. Pedido de citação
|
| 300 |
-
10. Juntada da guia de custas
|
| 301 |
-
11. Fechamento formal com "Local e data.\nADVOGADO.\nOAB." sem identificação específica
|
| 302 |
"""
|
| 303 |
if modo_treinamento:
|
| 304 |
base_prompt += f"""
|
| 305 |
**Modo de Treinamento Interativo Avançado:**
|
| 306 |
- Para cada item com pontuação inferior ao máximo, forneça:
|
| 307 |
-
a)
|
| 308 |
-
b)
|
| 309 |
-
c)
|
| 310 |
-
d)
|
| 311 |
-
e)
|
| 312 |
-
- Verifique a coerência entre os fatos do caso e a petição,
|
| 313 |
-
- Sugira estratégias
|
| 314 |
-
-
|
| 315 |
-
-
|
| 316 |
"""
|
| 317 |
return base_prompt
|
| 318 |
|
|
@@ -374,9 +449,33 @@ def gerar_caso_ficticio():
|
|
| 374 |
continue
|
| 375 |
return f"❌ Erro ao chamar a API: {e}"
|
| 376 |
except Exception as e:
|
|
|
|
| 377 |
return f"❌ Erro inesperado: {str(e)}"
|
| 378 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treinamento=False):
|
|
|
|
|
|
|
| 380 |
if not caso.strip():
|
| 381 |
return "⚠️ Forneça o caso da banca."
|
| 382 |
if peticao_arquivo is not None:
|
|
@@ -384,16 +483,20 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 384 |
if peticao_conteudo.startswith("❌") or peticao_conteudo.startswith("⚠️"):
|
| 385 |
return peticao_conteudo
|
| 386 |
else:
|
| 387 |
-
peticao_conteudo = peticao_texto or ""
|
| 388 |
if not peticao_conteudo.strip():
|
| 389 |
return "⚠️ Forneça uma petição."
|
| 390 |
|
| 391 |
problemas = validar_peticao_basica(peticao_conteudo)
|
|
|
|
| 392 |
aviso_validacao = f"### Validação Inicial\n\n" + "\n".join(problemas) + "\n\n" if problemas else ""
|
|
|
|
|
|
|
| 393 |
|
| 394 |
cache_key = f"{caso[:50]}|{peticao_conteudo[:50]}|{modo_treinamento}"
|
| 395 |
-
|
| 396 |
-
|
|
|
|
| 397 |
|
| 398 |
prompt = estruturar_prompt_correcao(caso, peticao_conteudo, modo_treinamento)
|
| 399 |
payload = {
|
|
@@ -419,6 +522,9 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 419 |
continue
|
| 420 |
return aviso_validacao + "❌ A API retornou uma resposta vazia. Tente novamente."
|
| 421 |
correcao_completa = response_data["candidates"][0]["content"]["parts"][0]["text"]
|
|
|
|
|
|
|
|
|
|
| 422 |
if "### Peti�o Corrigida" in correcao_completa:
|
| 423 |
analise_fim = correcao_completa.index("### Petição Corrigida")
|
| 424 |
analise = correcao_completa[:analise_fim].strip()
|
|
@@ -431,9 +537,9 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 431 |
"peticao": peticao_conteudo,
|
| 432 |
"correcao_completa": correcao_completa
|
| 433 |
})
|
| 434 |
-
if len(HISTORICO) > 10:
|
| 435 |
HISTORICO.pop(0)
|
| 436 |
-
|
| 437 |
return aviso_validacao + correcao_formatada
|
| 438 |
except requests.Timeout:
|
| 439 |
if tentativa < CONFIG["max_retry_attempts"] - 1:
|
|
@@ -446,6 +552,7 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 446 |
continue
|
| 447 |
return aviso_validacao + f"❌ Erro ao chamar a API: {e}"
|
| 448 |
except Exception as e:
|
|
|
|
| 449 |
return aviso_validacao + f"❌ Erro inesperado: {str(e)}"
|
| 450 |
|
| 451 |
def formatar_correcao(texto):
|
|
@@ -469,7 +576,6 @@ def formatar_correcao(texto):
|
|
| 469 |
else:
|
| 470 |
texto_formatado += f"{linha}\n"
|
| 471 |
if "Nota Final" in texto_formatado:
|
| 472 |
-
import re
|
| 473 |
nota_pattern = r"### Nota Final.*?(\d+[.,]\d+|\d+)"
|
| 474 |
match = re.search(nota_pattern, texto_formatado, re.DOTALL)
|
| 475 |
if match:
|
|
@@ -479,20 +585,15 @@ def formatar_correcao(texto):
|
|
| 479 |
|
| 480 |
def extrair_peticao_corrigida(correcao_completa):
|
| 481 |
try:
|
| 482 |
-
# Verifica se a seção "### Petição Corrigida" está presente na resposta
|
| 483 |
if "### Petição Corrigida" in correcao_completa:
|
| 484 |
inicio = correcao_completa.index("### Petição Corrigida") + len("### Petição Corrigida")
|
| 485 |
peticao_texto = correcao_completa[inicio:].strip()
|
| 486 |
-
# Encontra o final da petição corrigida, caso haja outra seção marcada com "###"
|
| 487 |
fim = peticao_texto.find("###") if "###" in peticao_texto else len(peticao_texto)
|
| 488 |
peticao_texto = peticao_texto[:fim].strip()
|
| 489 |
return peticao_texto
|
| 490 |
-
|
| 491 |
-
# Se a seção não for encontrada, tenta extrair a petição corrigida de outra forma
|
| 492 |
-
# Aqui, você pode adicionar lógica adicional para tentar localizar a petição corrigida
|
| 493 |
-
# de outras maneiras, se necessário.
|
| 494 |
-
return "⚠️ A seção '### Petição Corrigida' não foi encontrada na resposta da API. Verifique a resposta e tente novamente."
|
| 495 |
except Exception as e:
|
|
|
|
| 496 |
return f"❌ Erro ao extrair petição corrigida: {str(e)}"
|
| 497 |
|
| 498 |
def fornecer_dica_contextual(texto):
|
|
@@ -527,7 +628,6 @@ def comparar_peticao_melhorada(caso, peticao_texto, correcao):
|
|
| 527 |
if not ultima_correcao:
|
| 528 |
return "⚠️ Nenhuma correção disponível no histórico.", "", "", "", ""
|
| 529 |
|
| 530 |
-
# Tenta extrair a petição corrigida da última correção
|
| 531 |
peticao_corrigida = extrair_peticao_corrigida(ultima_correcao)
|
| 532 |
if "⚠️" in peticao_corrigida or "❌" in peticao_corrigida:
|
| 533 |
return peticao_corrigida, "", "", "", ""
|
|
@@ -613,6 +713,7 @@ def exportar_diferencas_html(caso, peticao_texto, correcao):
|
|
| 613 |
HTML(string=html_content).write_pdf(temp_path)
|
| 614 |
return temp_path
|
| 615 |
except Exception as e:
|
|
|
|
| 616 |
return f"❌ Erro ao gerar PDF: {str(e)}"
|
| 617 |
finally:
|
| 618 |
if 'temp_path' in locals() and os.path.exists(temp_path):
|
|
@@ -737,7 +838,7 @@ def interface_gradio():
|
|
| 737 |
inputs=[caso_input, peticao_texto, resultado_output],
|
| 738 |
outputs=[download_file]
|
| 739 |
).then(
|
| 740 |
-
fn=lambda x: [gr.update(visible=True, value=x
|
| 741 |
outputs=[download_file, download_btn]
|
| 742 |
)
|
| 743 |
|
|
@@ -774,4 +875,4 @@ def interface_gradio():
|
|
| 774 |
return demo
|
| 775 |
|
| 776 |
app = interface_gradio()
|
| 777 |
-
app.launch()
|
|
|
|
| 18 |
import difflib
|
| 19 |
from html import escape
|
| 20 |
from weasyprint import HTML # Para gerar PDF com cores
|
| 21 |
+
import shelve
|
| 22 |
+
import logging
|
| 23 |
+
import re
|
| 24 |
+
|
| 25 |
+
# Configuração de logging
|
| 26 |
+
logging.basicConfig(filename='app.log', level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 27 |
|
| 28 |
load_dotenv()
|
| 29 |
|
| 30 |
+
# Verificação de dependências
|
| 31 |
+
def verificar_dependencias():
|
| 32 |
+
dependencias = {
|
| 33 |
+
"gradio": gr, "requests": requests, "pdfplumber": pdfplumber_open,
|
| 34 |
+
"pytesseract": pytesseract, "cv2": cv2, "weasyprint": HTML
|
| 35 |
+
}
|
| 36 |
+
for nome, modulo in dependencias.items():
|
| 37 |
+
if modulo is None:
|
| 38 |
+
raise ImportError(f"❌ Módulo {nome} não encontrado. Instale com 'pip install {nome}'.")
|
| 39 |
+
verificar_dependencias()
|
| 40 |
+
|
| 41 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
| 42 |
if not GEMINI_API_KEY:
|
| 43 |
raise ValueError("❌ A chave GEMINI_API_KEY não foi encontrada. Configure-a como Secret no Hugging Face Spaces.")
|
|
|
|
| 55 |
rate_limiter = RateLimiter(max_calls=60, period=60)
|
| 56 |
|
| 57 |
DICAS_OAB_MELHORADO = {
|
| 58 |
+
"Endereçamento": "Em relações de consumo, prefira o foro do domicílio do autor (Art. 101, I, CDC). Exemplo: 'Excelentíssimo Senhor Juiz de Direito da Vara Cível da Comarca de [Cidade do Autor]'.",
|
| 59 |
+
"Qualificação": "Mencione nome, estado civil (se informado), endereço (use 'Rua XXX' se não fornecido). Dica: Sempre verifique se todos os dados das partes estão corretos e completos.",
|
| 60 |
+
"Fatos": "Descreva os fatos cronologicamente, sem inventar informações. Exemplo: 'Em [data], o autor celebrou contrato com o réu para a prestação de serviços de [descrição]'.",
|
| 61 |
+
"Pedidos": "Seja específico nos pedidos (ex.: 'condenação ao pagamento de R$ X'). Dica: Inclua pedidos de danos morais e materiais, se aplicável, com base em precedentes.",
|
| 62 |
+
"Custas": "Inclua 'Requer a juntada da guia de custas devidamente recolhida'. Dica: Nunca se esqueça de mencionar o recolhimento das custas para evitar a extinção do processo.",
|
| 63 |
+
"Fundamentação": "Baseie-se em artigos do CPC ou CDC e, se possível, em súmulas do STJ (ex.: Súmula 387 para danos morais). Exemplo: 'Conforme o artigo 186 do Código Civil, a responsabilidade civil pode ser caracterizada'.",
|
| 64 |
+
"Fechamento": "Finalize com 'Nestes termos pede deferimento', sem vírgula. Dica: Evite erros de pontuação que podem comprometer a formalidade do documento.",
|
| 65 |
+
"Estratégia Jurídica": "Utilize precedentes e súmulas para fortalecer sua argumentação. Exemplo: 'Conforme a Súmula 387 do STJ, os danos morais devem ser comprovados e quantificados'.",
|
| 66 |
+
"Provas": "Especifique as provas que pretende produzir. Dica: Inclua testemunhas, documentos e perícias, se necessário, para comprovar os fatos alegados.",
|
| 67 |
+
"Contra-argumentação": "Antecipe possíveis defesas da parte contrária e prepare respostas. Dica: Considere os argumentos que a outra parte pode usar e esteja preparado para refutá-los."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
}
|
| 69 |
|
| 70 |
HISTORICO = []
|
|
|
|
| 71 |
|
| 72 |
def preprocess_image_for_ocr(img):
|
| 73 |
try:
|
| 74 |
gray = img.convert('L')
|
| 75 |
np_img = np.array(gray)
|
| 76 |
+
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
|
| 77 |
+
enhanced = clahe.apply(np_img)
|
| 78 |
+
_, thresh = cv2.threshold(enhanced, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
|
| 79 |
return Image.fromarray(thresh)
|
| 80 |
except Exception as e:
|
| 81 |
+
logging.error(f"Erro no pré-processamento de imagem: {str(e)}")
|
| 82 |
return f"❌ Erro no pré-processamento: {str(e)}"
|
| 83 |
|
| 84 |
def extract_text_from_pdf(file_path_or_obj):
|
|
|
|
| 114 |
text += f"[Erro na página {i+1}: {str(e)}]\n"
|
| 115 |
return text if text.strip() else "⚠️ Não foi possível extrair texto do PDF."
|
| 116 |
except Exception as e:
|
| 117 |
+
logging.error(f"Erro ao processar PDF: {str(e)}")
|
| 118 |
return f"❌ Erro ao processar o PDF: {str(e)}"
|
| 119 |
|
| 120 |
def extract_text_from_docx(file_path_or_obj):
|
|
|
|
| 142 |
text += "\n"
|
| 143 |
return text if text.strip() else "⚠️ Não foi possível extrair texto do DOCX."
|
| 144 |
except Exception as e:
|
| 145 |
+
logging.error(f"Erro ao processar DOCX: {str(e)}")
|
| 146 |
return f"❌ Erro ao processar o DOCX: {str(e)}"
|
| 147 |
|
| 148 |
def extract_text_from_txt(file_path_or_obj):
|
|
|
|
| 167 |
continue
|
| 168 |
return "❌ Não foi possível decodificar o arquivo TXT."
|
| 169 |
except Exception as e:
|
| 170 |
+
logging.error(f"Erro ao processar TXT: {str(e)}")
|
| 171 |
return f"❌ Erro ao processar o TXT: {str(e)}"
|
| 172 |
|
| 173 |
def process_file(file_obj):
|
| 174 |
+
"""Processa arquivos PDF, DOCX ou TXT e extrai texto."""
|
| 175 |
if file_obj is None:
|
| 176 |
return "Nenhum arquivo enviado."
|
| 177 |
try:
|
|
|
|
| 192 |
else:
|
| 193 |
return "❌ Erro: Objeto de arquivo inválido."
|
| 194 |
except Exception as e:
|
| 195 |
+
logging.error(f"Erro ao processar arquivo: {str(e)}")
|
| 196 |
return f"❌ Erro ao processar o arquivo: {str(e)}"
|
| 197 |
|
| 198 |
def calcular_pontuacao(enderecamento, fundamentos, pedidos, fechamento):
|
|
|
|
| 219 |
return f"{tabela_formatada}\n\n**Nota Final:** {nota_final:.2f} / 10,00"
|
| 220 |
|
| 221 |
def validar_peticao_basica(peticao):
|
| 222 |
+
"""Valida os elementos básicos da petição com base no Art. 319 do CPC e critérios OAB."""
|
| 223 |
problemas = []
|
| 224 |
+
peticao_upper = peticao.upper()
|
| 225 |
+
peticao_lower = peticao.lower()
|
| 226 |
+
|
| 227 |
+
if "EXCELENTÍSSIMO" not in peticao_upper or "JUIZ" not in peticao_upper:
|
| 228 |
problemas.append("⚠️ Endereçamento ausente ou incompleto (Art. 319, I, CPC).")
|
| 229 |
+
if "AUTOR" not in peticao_upper or "RÉU" not in peticao_upper:
|
| 230 |
+
problemas.append("⚠️ Qualificação incompleta: 'autor' ou 'réu' não mencionados (Art. 319, II, CPC).")
|
| 231 |
+
if "FATO" not in peticao_upper and "FUNDAMENTO" not in peticao_upper:
|
| 232 |
+
problemas.append("⚠️ Exposição de fatos ou fundamentos ausente (Art. 319, III, CPC).")
|
| 233 |
+
if "ART." not in peticao_upper or "CPC" not in peticao_upper:
|
| 234 |
+
problemas.append("⚠️ Fundamentação jurídica não menciona artigos ou CPC (Art. 319, III, CPC).")
|
| 235 |
+
if "REQUER" not in peticao_upper and "PEDE" not in peticao_upper:
|
| 236 |
+
problemas.append("⚠️ Pedidos não especificados ou ausentes (Art. 319, IV, CPC).")
|
| 237 |
+
if "DÁ-SE À CAUSA O VALOR" not in peticao_upper:
|
| 238 |
problemas.append("⚠️ Valor da causa não especificado (Art. 319, V, CPC).")
|
| 239 |
+
if "R$" not in peticao_upper and "VALOR" not in peticao_upper:
|
| 240 |
+
problemas.append("⚠️ Valor da causa sem quantia monetária explícita (Art. 319, V, CPC).")
|
| 241 |
+
if "PROVA" not in peticao_upper and "TESTEMUNHA" not in peticao_upper and "DOCUMENTO" not in peticao_upper:
|
| 242 |
+
problemas.append("⚠️ Provas pretendidas não especificadas (Art. 319, VI, CPC).")
|
| 243 |
+
if "AUDIÊNCIA" not in peticao_upper and "CONCILIAÇÃO" not in peticao_upper:
|
| 244 |
+
problemas.append("⚠️ Opção sobre audiência de conciliação não mencionada (Art. 319, VII, CPC).")
|
| 245 |
+
if "CITAÇÃO" not in peticao_upper:
|
| 246 |
+
problemas.append("⚠️ Pedido de citação do réu ausente.")
|
| 247 |
+
if "juntada da guia de custas" not in peticao_lower:
|
| 248 |
problemas.append("⚠️ Pedido de juntada da guia de custas ausente (-1,0 ponto).")
|
| 249 |
+
if "NESTES TERMOS" not in peticao_upper:
|
| 250 |
+
problemas.append("⚠️ Fechamento formal 'Nestes termos pede deferimento' ausente.")
|
| 251 |
+
if "NESTES TERMOS," in peticao_upper:
|
| 252 |
+
problemas.append("⚠️ Uso incorreto de vírgula em 'Nestes termos, pede deferimento'.")
|
| 253 |
+
if "ADVOGADO" not in peticao_upper or "OAB" not in peticao_upper:
|
| 254 |
+
problemas.append("⚠️ Fechamento sem 'ADVOGADO' ou 'OAB'.")
|
| 255 |
+
if "LOCAL E DATA" not in peticao_upper:
|
| 256 |
+
problemas.append("⚠️ Fechamento sem 'Local e data'.")
|
| 257 |
+
if any(id in peticao_upper for id in ["CPF", "RG", "MATRÍCULA"]):
|
| 258 |
+
problemas.append("⚠️ Identificação indevida do candidato detectada (nota máxima 3,0).")
|
| 259 |
+
if "OAB/" in peticao_upper or any(char.isdigit() for char in peticao.split("OAB")[-1] if "OAB" in peticao_upper):
|
| 260 |
+
problemas.append("⚠️ Identificação específica na OAB (ex.: número ou estado) detectada (nota 0,0).")
|
| 261 |
+
|
| 262 |
return problemas
|
| 263 |
|
| 264 |
+
def verificar_coerencia_caso_peticao(caso, peticao):
|
| 265 |
+
"""Verifica coerência entre o caso e a petição, detectando omissões e invenções."""
|
| 266 |
+
incoerencias = []
|
| 267 |
+
caso_lower = caso.lower()
|
| 268 |
+
peticao_lower = peticao.lower()
|
| 269 |
+
|
| 270 |
+
nomes_caso = [word for word in caso.split() if word.istitle() and len(word) > 2]
|
| 271 |
+
nomes_peticao = [word for word in peticao.split() if word.istitle() and len(word) > 2]
|
| 272 |
+
for nome in nomes_caso:
|
| 273 |
+
if nome.lower() not in peticao_lower:
|
| 274 |
+
incoerencias.append(f"⚠️ Nome '{nome}' do caso não mencionado na petição (suspeita de omissão).")
|
| 275 |
+
for frase in peticao.split("."):
|
| 276 |
+
if frase.strip() and not any(palavra.lower() in caso_lower for palavra in frase.split() if len(palavra) > 3):
|
| 277 |
+
incoerencias.append(f"⚠️ Frase suspeita de invenção: '{frase.strip()}' (não consta no caso).")
|
| 278 |
+
valores_caso = re.findall(r"R\$\s*\d+(?:\.\d+)?(?:,\d+)?", caso)
|
| 279 |
+
valores_peticao = re.findall(r"R\$\s*\d+(?:\.\d+)?(?:,\d+)?", peticao)
|
| 280 |
+
for valor in valores_peticao:
|
| 281 |
+
if valor not in valores_caso:
|
| 282 |
+
incoerencias.append(f"⚠️ Valor '{valor}' na petição não consta no caso (suspeita de invenção).")
|
| 283 |
+
|
| 284 |
+
return incoerencias
|
| 285 |
+
|
| 286 |
+
def validar_resposta_api(correcao_completa):
|
| 287 |
+
"""Valida a qualidade da resposta da API."""
|
| 288 |
+
problemas_api = []
|
| 289 |
+
if "Nota Final" not in correcao_completa:
|
| 290 |
+
problemas_api.append("⚠️ Resposta da API sem 'Nota Final'.")
|
| 291 |
+
if "Pontos a Melhorar" not in correcao_completa:
|
| 292 |
+
problemas_api.append("⚠️ Resposta da API sem 'Pontos a Melhorar'.")
|
| 293 |
+
if "Análise Específica dos Requisitos" not in correcao_completa:
|
| 294 |
+
problemas_api.append("⚠️ Resposta da API sem 'Análise Específica dos Requisitos'.")
|
| 295 |
+
if "### Petição Corrigida" not in correcao_completa:
|
| 296 |
+
problemas_api.append("⚠️ Resposta da API sem 'Petição Corrigida'.")
|
| 297 |
+
return problemas_api
|
| 298 |
+
|
| 299 |
def estruturar_prompt_correcao(caso, peticao, modo_treinamento=False):
|
| 300 |
+
"""Estrutura um prompt avançado e especializado para correção de petições."""
|
| 301 |
base_prompt = f"""
|
| 302 |
+
## Correção Avançada de Petição Inicial Cível (Critérios Realistas da OAB com Análise Especializada)
|
| 303 |
**Caso Fornecido:**
|
| 304 |
{caso}
|
| 305 |
**Petição do Aluno:**
|
| 306 |
{peticao}
|
| 307 |
**Estrutura da Avaliação:**
|
| 308 |
### Análise da Petição
|
| 309 |
+
1. Análise Geral (Visão geral sobre a petição - máximo 3 linhas, destacando adequação ao caso e consistência jurídica)
|
| 310 |
+
2. Nota Final (0 a 10 com uma casa decimal, justificando brevemente a pontuação total)
|
| 311 |
+
3. Pontos Positivos (Liste pelo menos 3 aspectos bem executados com justificativa legal detalhada, incluindo artigos, súmulas ou precedentes aplicáveis)
|
| 312 |
+
4. Pontos a Melhorar (Liste todos os problemas encontrados em ordem de gravidade, com explicação detalhada, base legal e impacto na nota; não omita erros menores)
|
| 313 |
5. Análise Específica dos Requisitos:
|
| 314 |
+
- Endereçamento e qualificação do juízo (Art. 319, I, CPC; Art. 101, I, CDC se aplicável): Verifique a competência territorial e material com precisão.
|
| 315 |
+
- Qualificação das partes (Art. 319, II, CPC): Avalie nomes, estado civil, endereço e consistência com o caso.
|
| 316 |
+
- Fatos e fundamentos jurídicos (Art. 319, III, CPC; Art. 186, CC): Compare os fatos narrados com o caso e analise a pertinência dos fundamentos legais.
|
| 317 |
+
- Pedidos com especificações (Art. 319, IV, CPC): Examine clareza, especificidade e adequação dos pedidos ao caso.
|
| 318 |
+
- Valor da causa (Art. 319, V, CPC): Confirme se o valor é realista e compatível com os danos alegados.
|
| 319 |
+
- Provas com que o autor pretende demonstrar a verdade dos fatos (Art. 319, VI, CPC): Avalie a suficiência e relevância das provas indicadas.
|
| 320 |
+
- Opção pela realização ou não de audiência de conciliação (Art. 319, VII, CPC): Verifique a menção explícita e sua coerência com o caso.
|
| 321 |
+
- Pedido de citação do réu: Analise se está claro e conforme os meios legais (ex.: Art. 246, CPC).
|
| 322 |
+
- Juntada da guia de custas: Confirme a presença literal do pedido e sua redação formal.
|
| 323 |
+
- Fechamento formal da petição: Certifique-se da estrutura exata "Local e data.\nADVOGADO.\nOAB." sem variações ou identificação indevida.
|
| 324 |
+
|
| 325 |
**Critérios Fundamentais:**
|
| 326 |
+
1. Identificação do candidato (nome, CPF, RG ou número real na seção final) resulta em nota máxima de 3,0; forneça exemplo do trecho problemático.
|
| 327 |
+
2. Invenção de fatos não constantes no caso resulta em penalização grave (-5,0 pontos); identifique cada fato inventado e compare com o caso.
|
| 328 |
+
3. Falta de pedido de juntada de custas resulta em perda de 1,0 ponto; verifique a ausência ou redação inadequada.
|
| 329 |
+
4. Use marcadores para dados não fornecidos (ex.: "Rua XXX", "CPF XXX"); penalize invenção de dados específicos (-0,5 por ocorrência).
|
| 330 |
+
5. Não penalize por informações ausentes no caso original, mas alerte se a omissão compromete a petição.
|
| 331 |
+
6. A frase "Nestes termos, pede deferimento" com vírgula é incorreta; corrija para "Nestes termos pede deferimento" e penalize com -0,2 ponto, destacando o erro formal.
|
| 332 |
+
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.: "OAB/SP" ou "12345"), zere a nota (0,0) e explique o motivo.
|
| 333 |
+
|
| 334 |
+
**Instruções Especiais para Análise Avançada:**
|
| 335 |
+
- **Competência**: Avalie o foro indicado com base no Art. 46 do CPC (domicílio do réu) ou Art. 101, I do CDC (domicílio do autor em relações de consumo); penalize erros com -0,10 ponto e justifique com jurisprudência (ex.: STJ, REsp 1.234.567).
|
| 336 |
+
- **Consistência Fática**: Compare cada fato narrado na petição com o caso; destaque omissões ou distorções com base no Art. 319, III, CPC.
|
| 337 |
+
- **Fundamentação Jurídica**: Exija citação de pelo menos um artigo específico (ex.: Art. 186, CC para responsabilidade civil) e avalie a pertinência; penalize generalidades com -0,15 ponto por item vago.
|
| 338 |
+
- **Danos Morais e Materiais**: Se o caso sugerir danos, verifique se os pedidos estão quantificados e fundamentados (ex.: Súmula 387/STJ para danos morais); penalize omissões com -0,20 ponto.
|
| 339 |
+
- **Linguagem Técnica**: Avalie a formalidade e precisão do vocabulário jurídico; penalize informalidades ou erros gramaticais (ex.: "vossa excelência" em minúsculas) com -0,05 ponto por ocorrência.
|
| 340 |
+
- **Precedentes**: Inclua referências a súmulas ou decisões relevantes (ex.: Súmula 297/STJ para CDC) quando aplicável no caso.
|
| 341 |
+
|
| 342 |
**Pontuação Detalhada:**
|
| 343 |
Inclua uma tabela com:
|
| 344 |
+
| ITEM | PONTUAÇÃO | JUSTIFICATIVA |
|
| 345 |
+
|-------------------------------------------|-----------|---------------|
|
| 346 |
+
**Endereçamento** | | |
|
| 347 |
+
1. Correto endereçamento ao juízo competente (0,10) | / 0,10 | [Explique erro ou acerto] |
|
| 348 |
+
2. Qualificação das partes conforme Art. 319, II, CPC (0,20) | / 0,20 | [Explique erro ou acerto] |
|
| 349 |
+
**Fundamentos** | | |
|
| 350 |
+
3. Exposição clara dos fatos (0,20) | / 0,20 | [Explique erro ou acerto] |
|
| 351 |
+
4. Fundamentação jurídica adequada (0,25) | / 0,25 | [Explique erro ou acerto] |
|
| 352 |
+
5. Demonstração de ilícito e dano (0,25) | / 0,25 | [Explique erro ou acerto] |
|
| 353 |
+
**Pedidos** | | |
|
| 354 |
+
6. Pedidos claros e específicos (0,30) | / 0,30 | [Explique erro ou acerto] |
|
| 355 |
+
7. Valor da causa indicado (0,10) | / 0,10 | [Explique erro ou acerto] |
|
| 356 |
+
8. Provas pretendidas especificadas (0,10)| / 0,10 | [Explique erro ou acerto] |
|
| 357 |
+
9. Opção sobre audiência de conciliação (0,10) | / 0,10 | [Explique erro ou acerto] |
|
| 358 |
+
10. Pedido de citação do réu (0,10) | / 0,10 | [Explique erro ou acerto] |
|
| 359 |
+
11. Juntada da guia de custas (0,10) | / 0,10 | [Explique erro ou acerto] |
|
| 360 |
+
**Fechamento** | | |
|
| 361 |
+
12. Fechamento formal adequado (0,10) | / 0,10 | [Explique erro ou acerto] |
|
| 362 |
+
**Nota Final:** Calcule a soma dos pontos, aplicando penalizações cumulativas conforme os critérios fundamentais; justifique qualquer desconto adicional.
|
|
|
|
|
|
|
| 363 |
|
| 364 |
### Petição Corrigida
|
| 365 |
+
Forneça a petição do aluno reescrita com todas as correções aplicadas, incluindo partes omitidas (como pedidos ou custas) e ajustando erros identificados. Siga rigorosamente:
|
| 366 |
+
1. Endereçamento correto (com foro justificado por CPC ou CDC).
|
| 367 |
+
2. Qualificação completa (Art. 319, II, CPC; use "XXX" para dados ausentes).
|
| 368 |
+
3. Fatos claros e fiéis ao caso (Art. 319, III, CPC).
|
| 369 |
+
4. Fundamentação jurídica robusta (cite CPC, CDC, CC e súmulas aplicáveis, como Súmula 387/STJ para danos morais).
|
| 370 |
+
5. Pedidos específicos e quantificados (Art. 319, IV, CPC).
|
| 371 |
+
6. Valor da causa realista (Art. 319, V, CPC).
|
| 372 |
+
7. Provas detalhadas (Art. 319, VI, CPC; ex.: "prova documental e testemunhal").
|
| 373 |
+
8. Opção por audiência explícita (Art. 319, VII, CPC).
|
| 374 |
+
9. Pedido de citação formal (ex.: "via postal, nos termos do Art. 246, I, CPC").
|
| 375 |
+
10. Juntada da guia de custas com redação precisa.
|
| 376 |
+
11. Fechamento formal com "Local e data.\nADVOGADO.\nOAB." sem identificação específica.
|
| 377 |
"""
|
| 378 |
if modo_treinamento:
|
| 379 |
base_prompt += f"""
|
| 380 |
**Modo de Treinamento Interativo Avançado:**
|
| 381 |
- Para cada item com pontuação inferior ao máximo, forneça:
|
| 382 |
+
a) Explicação detalhada (mínimo 3 frases) com base legal (ex.: Art. 319, CPC) e análise do impacto processual.
|
| 383 |
+
b) Sugestão de redação corrigida baseada no caso, com linguagem técnica exemplar.
|
| 384 |
+
c) Exemplo prático em outro contexto (ex.: "Em ação consumerista, ‘Requer a inversão do ônus da prova, nos termos do Art. 6º, VIII, CDC.’").
|
| 385 |
+
d) Dica prática do banco ({json.dumps(DICAS_OAB_MELHORADO, ensure_ascii=False)}) ou personalizada, com enfoque pedagógico.
|
| 386 |
+
e) Estratégia jurídica avançada (ex.: "Cite o Art. 944, CC para quantificar danos ou peça tutela antecipada com base no Art. 300, CPC").
|
| 387 |
+
- Verifique a coerência entre os fatos do caso e a petição, listando todas as inconsistências com trechos específicos.
|
| 388 |
+
- Sugira estratégias adicionais baseadas no caso (ex.: cumulação de pedidos, Art. 327, CPC; ou danos morais com Súmula 387/STJ).
|
| 389 |
+
- Detalhe cada erro pedagogicamente, com referências a leis, súmulas (ex.: Súmula 54/STJ para lucros cessantes), e doutrina (ex.: Nelson Nery Jr. sobre Art. 319, CPC).
|
| 390 |
+
- Avalie a viabilidade processual da petição (ex.: risco de indeferimento por inépcia, Art. 330, CPC).
|
| 391 |
"""
|
| 392 |
return base_prompt
|
| 393 |
|
|
|
|
| 449 |
continue
|
| 450 |
return f"❌ Erro ao chamar a API: {e}"
|
| 451 |
except Exception as e:
|
| 452 |
+
logging.error(f"Erro inesperado ao gerar caso: {str(e)}")
|
| 453 |
return f"❌ Erro inesperado: {str(e)}"
|
| 454 |
|
| 455 |
+
def sanitize_input(text):
|
| 456 |
+
"""Sanitiza entradas para evitar injeção."""
|
| 457 |
+
return escape(text.strip()) if text else ""
|
| 458 |
+
|
| 459 |
+
def salvar_cache(chave, valor):
|
| 460 |
+
"""Salva correção no cache persistente."""
|
| 461 |
+
try:
|
| 462 |
+
with shelve.open("correcao_cache.db") as db:
|
| 463 |
+
db[chave] = valor
|
| 464 |
+
except Exception as e:
|
| 465 |
+
logging.error(f"Erro ao salvar no cache: {str(e)}")
|
| 466 |
+
|
| 467 |
+
def carregar_cache(chave):
|
| 468 |
+
"""Carrega correção do cache persistente."""
|
| 469 |
+
try:
|
| 470 |
+
with shelve.open("correcao_cache.db") as db:
|
| 471 |
+
return db.get(chave)
|
| 472 |
+
except Exception as e:
|
| 473 |
+
logging.error(f"Erro ao carregar do cache: {str(e)}")
|
| 474 |
+
return None
|
| 475 |
+
|
| 476 |
def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treinamento=False):
|
| 477 |
+
"""Corrige uma petição inicial cível com base em critérios da OAB."""
|
| 478 |
+
caso = sanitize_input(caso)
|
| 479 |
if not caso.strip():
|
| 480 |
return "⚠️ Forneça o caso da banca."
|
| 481 |
if peticao_arquivo is not None:
|
|
|
|
| 483 |
if peticao_conteudo.startswith("❌") or peticao_conteudo.startswith("⚠️"):
|
| 484 |
return peticao_conteudo
|
| 485 |
else:
|
| 486 |
+
peticao_conteudo = sanitize_input(peticao_texto) or ""
|
| 487 |
if not peticao_conteudo.strip():
|
| 488 |
return "⚠️ Forneça uma petição."
|
| 489 |
|
| 490 |
problemas = validar_peticao_basica(peticao_conteudo)
|
| 491 |
+
incoerencias = verificar_coerencia_caso_peticao(caso, peticao_conteudo)
|
| 492 |
aviso_validacao = f"### Validação Inicial\n\n" + "\n".join(problemas) + "\n\n" if problemas else ""
|
| 493 |
+
if incoerencias:
|
| 494 |
+
aviso_validacao += f"### Verificação de Coerência\n\n" + "\n".join(incoerencias) + "\n\n"
|
| 495 |
|
| 496 |
cache_key = f"{caso[:50]}|{peticao_conteudo[:50]}|{modo_treinamento}"
|
| 497 |
+
cached_result = carregar_cache(cache_key)
|
| 498 |
+
if cached_result:
|
| 499 |
+
return aviso_validacao + cached_result
|
| 500 |
|
| 501 |
prompt = estruturar_prompt_correcao(caso, peticao_conteudo, modo_treinamento)
|
| 502 |
payload = {
|
|
|
|
| 522 |
continue
|
| 523 |
return aviso_validacao + "❌ A API retornou uma resposta vazia. Tente novamente."
|
| 524 |
correcao_completa = response_data["candidates"][0]["content"]["parts"][0]["text"]
|
| 525 |
+
problemas_api = validar_resposta_api(correcao_completa)
|
| 526 |
+
if problemas_api:
|
| 527 |
+
return aviso_validacao + f"### Problemas na Resposta da API\n\n" + "\n".join(problemas_api) + "\n\n⚠️ Tente novamente."
|
| 528 |
if "### Peti�o Corrigida" in correcao_completa:
|
| 529 |
analise_fim = correcao_completa.index("### Petição Corrigida")
|
| 530 |
analise = correcao_completa[:analise_fim].strip()
|
|
|
|
| 537 |
"peticao": peticao_conteudo,
|
| 538 |
"correcao_completa": correcao_completa
|
| 539 |
})
|
| 540 |
+
if len(HISTORICO) > 10:
|
| 541 |
HISTORICO.pop(0)
|
| 542 |
+
salvar_cache(cache_key, correcao_formatada)
|
| 543 |
return aviso_validacao + correcao_formatada
|
| 544 |
except requests.Timeout:
|
| 545 |
if tentativa < CONFIG["max_retry_attempts"] - 1:
|
|
|
|
| 552 |
continue
|
| 553 |
return aviso_validacao + f"❌ Erro ao chamar a API: {e}"
|
| 554 |
except Exception as e:
|
| 555 |
+
logging.error(f"Erro inesperado ao corrigir petição: {str(e)}")
|
| 556 |
return aviso_validacao + f"❌ Erro inesperado: {str(e)}"
|
| 557 |
|
| 558 |
def formatar_correcao(texto):
|
|
|
|
| 576 |
else:
|
| 577 |
texto_formatado += f"{linha}\n"
|
| 578 |
if "Nota Final" in texto_formatado:
|
|
|
|
| 579 |
nota_pattern = r"### Nota Final.*?(\d+[.,]\d+|\d+)"
|
| 580 |
match = re.search(nota_pattern, texto_formatado, re.DOTALL)
|
| 581 |
if match:
|
|
|
|
| 585 |
|
| 586 |
def extrair_peticao_corrigida(correcao_completa):
|
| 587 |
try:
|
|
|
|
| 588 |
if "### Petição Corrigida" in correcao_completa:
|
| 589 |
inicio = correcao_completa.index("### Petição Corrigida") + len("### Petição Corrigida")
|
| 590 |
peticao_texto = correcao_completa[inicio:].strip()
|
|
|
|
| 591 |
fim = peticao_texto.find("###") if "###" in peticao_texto else len(peticao_texto)
|
| 592 |
peticao_texto = peticao_texto[:fim].strip()
|
| 593 |
return peticao_texto
|
| 594 |
+
return "⚠️ A seção '### Petição Corrigida' não foi encontrada na resposta da API."
|
|
|
|
|
|
|
|
|
|
|
|
|
| 595 |
except Exception as e:
|
| 596 |
+
logging.error(f"Erro ao extrair petição corrigida: {str(e)}")
|
| 597 |
return f"❌ Erro ao extrair petição corrigida: {str(e)}"
|
| 598 |
|
| 599 |
def fornecer_dica_contextual(texto):
|
|
|
|
| 628 |
if not ultima_correcao:
|
| 629 |
return "⚠️ Nenhuma correção disponível no histórico.", "", "", "", ""
|
| 630 |
|
|
|
|
| 631 |
peticao_corrigida = extrair_peticao_corrigida(ultima_correcao)
|
| 632 |
if "⚠️" in peticao_corrigida or "❌" in peticao_corrigida:
|
| 633 |
return peticao_corrigida, "", "", "", ""
|
|
|
|
| 713 |
HTML(string=html_content).write_pdf(temp_path)
|
| 714 |
return temp_path
|
| 715 |
except Exception as e:
|
| 716 |
+
logging.error(f"Erro ao gerar PDF: {str(e)}")
|
| 717 |
return f"❌ Erro ao gerar PDF: {str(e)}"
|
| 718 |
finally:
|
| 719 |
if 'temp_path' in locals() and os.path.exists(temp_path):
|
|
|
|
| 838 |
inputs=[caso_input, peticao_texto, resultado_output],
|
| 839 |
outputs=[download_file]
|
| 840 |
).then(
|
| 841 |
+
fn=lambda x: [gr.update(visible=True, value=x if not x.startswith("❌") else None), gr.update(visible=True)],
|
| 842 |
outputs=[download_file, download_btn]
|
| 843 |
)
|
| 844 |
|
|
|
|
| 875 |
return demo
|
| 876 |
|
| 877 |
app = interface_gradio()
|
| 878 |
+
app.launch()
|