Update app.py
Browse files
app.py
CHANGED
|
@@ -17,7 +17,7 @@ from datetime import datetime
|
|
| 17 |
from ratelimiter import RateLimiter
|
| 18 |
import difflib
|
| 19 |
from html import escape
|
| 20 |
-
from weasyprint import HTML
|
| 21 |
|
| 22 |
load_dotenv()
|
| 23 |
|
|
@@ -32,7 +32,7 @@ CONFIG = {
|
|
| 32 |
"retry_delay": 5,
|
| 33 |
"timeout": 60,
|
| 34 |
"temperatura": 0.2,
|
| 35 |
-
"max_tokens": 12288
|
| 36 |
}
|
| 37 |
|
| 38 |
rate_limiter = RateLimiter(max_calls=60, period=60)
|
|
@@ -53,123 +53,7 @@ DICAS_OAB_MELHORADO = {
|
|
| 53 |
HISTORICO = []
|
| 54 |
CORRECAO_CACHE = {}
|
| 55 |
|
| 56 |
-
|
| 57 |
-
try:
|
| 58 |
-
gray = img.convert('L')
|
| 59 |
-
np_img = np.array(gray)
|
| 60 |
-
_, thresh = cv2.threshold(np_img, 150, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
|
| 61 |
-
return Image.fromarray(thresh)
|
| 62 |
-
except Exception as e:
|
| 63 |
-
return f"❌ Erro no pré-processamento: {str(e)}"
|
| 64 |
-
|
| 65 |
-
def extract_text_from_pdf(file_path_or_obj):
|
| 66 |
-
try:
|
| 67 |
-
if isinstance(file_path_or_obj, str):
|
| 68 |
-
with open(file_path_or_obj, 'rb') as f:
|
| 69 |
-
text = ""
|
| 70 |
-
with pdfplumber_open(f) as pdf:
|
| 71 |
-
for page in pdf.pages:
|
| 72 |
-
text += (page.extract_text() or "") + "\n"
|
| 73 |
-
if not text.strip():
|
| 74 |
-
images = pdfplumber_open(f).pages
|
| 75 |
-
for i, image in enumerate(images):
|
| 76 |
-
try:
|
| 77 |
-
img = image.to_image()
|
| 78 |
-
preprocessed_img = preprocess_image_for_ocr(img)
|
| 79 |
-
text += pytesseract.image_to_string(preprocessed_img) + "\n"
|
| 80 |
-
except Exception as e:
|
| 81 |
-
text += f"[Erro na página {i+1}: {str(e)}]\n"
|
| 82 |
-
else:
|
| 83 |
-
text = ""
|
| 84 |
-
with pdfplumber_open(file_path_or_obj) as pdf:
|
| 85 |
-
for page in pdf.pages:
|
| 86 |
-
text += (page.extract_text() or "") + "\n"
|
| 87 |
-
if not text.strip():
|
| 88 |
-
images = pdfplumber_open(file_path_or_obj).pages
|
| 89 |
-
for i, image in enumerate(images):
|
| 90 |
-
try:
|
| 91 |
-
img = image.to_image()
|
| 92 |
-
preprocessed_img = preprocess_image_for_ocr(img)
|
| 93 |
-
text += pytesseract.image_to_string(preprocessed_img) + "\n"
|
| 94 |
-
except Exception as e:
|
| 95 |
-
text += f"[Erro na página {i+1}: {str(e)}]\n"
|
| 96 |
-
return text if text.strip() else "⚠️ Não foi possível extrair texto do PDF."
|
| 97 |
-
except Exception as e:
|
| 98 |
-
return f"❌ Erro ao processar o PDF: {str(e)}"
|
| 99 |
-
|
| 100 |
-
def extract_text_from_docx(file_path_or_obj):
|
| 101 |
-
try:
|
| 102 |
-
if isinstance(file_path_or_obj, str):
|
| 103 |
-
with open(file_path_or_obj, 'rb') as f:
|
| 104 |
-
doc = docx.Document(f)
|
| 105 |
-
text = ""
|
| 106 |
-
for para in doc.paragraphs:
|
| 107 |
-
text += para.text + "\n"
|
| 108 |
-
for table in doc.tables:
|
| 109 |
-
for row in table.rows:
|
| 110 |
-
for cell in row.cells:
|
| 111 |
-
text += cell.text + " "
|
| 112 |
-
text += "\n"
|
| 113 |
-
else:
|
| 114 |
-
doc = docx.Document(file_path_or_obj)
|
| 115 |
-
text = ""
|
| 116 |
-
for para in doc.paragraphs:
|
| 117 |
-
text += para.text + "\n"
|
| 118 |
-
for table in doc.tables:
|
| 119 |
-
for row in table.rows:
|
| 120 |
-
for cell in row.cells:
|
| 121 |
-
text += cell.text + " "
|
| 122 |
-
text += "\n"
|
| 123 |
-
return text if text.strip() else "⚠️ Não foi possível extrair texto do DOCX."
|
| 124 |
-
except Exception as e:
|
| 125 |
-
return f"❌ Erro ao processar o DOCX: {str(e)}"
|
| 126 |
-
|
| 127 |
-
def extract_text_from_txt(file_path_or_obj):
|
| 128 |
-
try:
|
| 129 |
-
if isinstance(file_path_or_obj, str):
|
| 130 |
-
with open(file_path_or_obj, 'rb') as f:
|
| 131 |
-
content = f.read()
|
| 132 |
-
encodings = ['utf-8', 'latin-1', 'cp1252', 'iso-8859-1']
|
| 133 |
-
for encoding in encodings:
|
| 134 |
-
try:
|
| 135 |
-
return content.decode(encoding)
|
| 136 |
-
except UnicodeDecodeError:
|
| 137 |
-
continue
|
| 138 |
-
return "❌ Não foi possível decodificar o arquivo TXT."
|
| 139 |
-
else:
|
| 140 |
-
content = file_path_or_obj.read()
|
| 141 |
-
encodings = ['utf-8', 'latin-1', 'cp1252', 'iso-8859-1']
|
| 142 |
-
for encoding in encodings:
|
| 143 |
-
try:
|
| 144 |
-
return content.decode(encoding)
|
| 145 |
-
except UnicodeDecodeError:
|
| 146 |
-
continue
|
| 147 |
-
return "❌ Não foi possível decodificar o arquivo TXT."
|
| 148 |
-
except Exception as e:
|
| 149 |
-
return f"❌ Erro ao processar o TXT: {str(e)}"
|
| 150 |
-
|
| 151 |
-
def process_file(file_obj):
|
| 152 |
-
if file_obj is None:
|
| 153 |
-
return "Nenhum arquivo enviado."
|
| 154 |
-
try:
|
| 155 |
-
if hasattr(file_obj, 'name'):
|
| 156 |
-
file_path = file_obj.name
|
| 157 |
-
filename = os.path.basename(file_path).lower()
|
| 158 |
-
file_size = os.path.getsize(file_path)
|
| 159 |
-
if file_size > 10 * 1024 * 1024:
|
| 160 |
-
return "⚠️ O arquivo é muito grande. Máx. 10 MB."
|
| 161 |
-
if filename.endswith('.pdf'):
|
| 162 |
-
return extract_text_from_pdf(file_path)
|
| 163 |
-
elif filename.endswith('.docx'):
|
| 164 |
-
return extract_text_from_docx(file_path)
|
| 165 |
-
elif filename.endswith('.txt'):
|
| 166 |
-
return extract_text_from_txt(file_path)
|
| 167 |
-
else:
|
| 168 |
-
return "⚠️ Formato de arquivo não suportado. Use PDF, DOCX ou TXT."
|
| 169 |
-
else:
|
| 170 |
-
return "❌ Erro: Objeto de arquivo inválido."
|
| 171 |
-
except Exception as e:
|
| 172 |
-
return f"❌ Erro ao processar o arquivo: {str(e)}"
|
| 173 |
|
| 174 |
def estruturar_prompt_analise(caso, peticao, modo_treinamento=False):
|
| 175 |
"""Estrutura o prompt apenas para a análise da petição."""
|
|
@@ -251,7 +135,7 @@ def estruturar_prompt_analise(caso, peticao, modo_treinamento=False):
|
|
| 251 |
return base_prompt
|
| 252 |
|
| 253 |
def estruturar_prompt_peticao_corrigida(caso, peticao):
|
| 254 |
-
"""Estrutura o prompt apenas para a petição corrigida."""
|
| 255 |
return f"""
|
| 256 |
**Caso Fornecido:**
|
| 257 |
{caso}
|
|
@@ -270,6 +154,7 @@ def estruturar_prompt_peticao_corrigida(caso, peticao):
|
|
| 270 |
9. Pedido de citação formal (ex.: "via postal, nos termos do Art. 246, I, CPC").
|
| 271 |
10. Juntada da guia de custas com redação precisa.
|
| 272 |
11. Fechamento formal com "Local e data.\nADVOGADO.\nOAB." sem identificação específica.
|
|
|
|
| 273 |
"""
|
| 274 |
|
| 275 |
def chamar_api(prompt):
|
|
@@ -353,178 +238,7 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 353 |
CORRECAO_CACHE[cache_key] = analise_formatada
|
| 354 |
return aviso_validacao + analise_formatada
|
| 355 |
|
| 356 |
-
|
| 357 |
-
linhas = texto.split('\n')
|
| 358 |
-
texto_formatado = ""
|
| 359 |
-
for linha in linhas:
|
| 360 |
-
if "Análise Geral" in linha:
|
| 361 |
-
texto_formatado += f"### ℹ️ {linha.strip()}\n\n"
|
| 362 |
-
elif "Nota Final" in linha:
|
| 363 |
-
texto_formatado += f"### ⭐ {linha.strip()}\n\n"
|
| 364 |
-
elif "Pontos Positivos" in linha:
|
| 365 |
-
texto_formatado += f"### ✅ {linha.strip()}\n\n"
|
| 366 |
-
elif "Pontos a Melhorar" in linha:
|
| 367 |
-
texto_formatado += f"### ⚠️ {linha.strip()}\n\n"
|
| 368 |
-
elif "- Invenção de fatos" in linha:
|
| 369 |
-
texto_formatado += f"**🔴 {linha.strip()} (-5,0 pontos)**\n"
|
| 370 |
-
elif linha.strip().startswith('-') and len(linha) > 2 and any(termo in linha for termo in ["Endereçamento", "Qualificação", "Fatos", "Pedidos", "Valor", "Provas"]):
|
| 371 |
-
texto_formatado += f"**{linha.strip()}**\n"
|
| 372 |
-
elif "Explicação" in linha or "Sugestão" in linha or "Dica" in linha or "Exemplo" in linha:
|
| 373 |
-
texto_formatado += f"*{linha.strip()}*\n"
|
| 374 |
-
else:
|
| 375 |
-
texto_formatado += f"{linha}\n"
|
| 376 |
-
if "Nota Final" in texto_formatado:
|
| 377 |
-
import re
|
| 378 |
-
nota_pattern = r"### Nota Final.*?(\d+[.,]\d+|\d+)"
|
| 379 |
-
match = re.search(nota_pattern, texto_formatado, re.DOTALL)
|
| 380 |
-
if match:
|
| 381 |
-
nota = match.group(1)
|
| 382 |
-
texto_formatado = texto_formatado.replace(f"### ⭐ Nota Final\n\n{nota}", f"### ⭐ Nota Final: {nota}/10\n\n")
|
| 383 |
-
return texto_formatado
|
| 384 |
-
|
| 385 |
-
def extrair_peticao_corrigida(correcao_completa):
|
| 386 |
-
try:
|
| 387 |
-
if "### Petição Corrigida" in correcao_completa:
|
| 388 |
-
inicio = correcao_completa.index("### Petição Corrigida") + len("### Petição Corrigida")
|
| 389 |
-
peticao_texto = correcao_completa[inicio:].strip()
|
| 390 |
-
fim = peticao_texto.find("###") if "###" in peticao_texto else len(peticao_texto)
|
| 391 |
-
peticao_texto = peticao_texto[:fim].strip()
|
| 392 |
-
return peticao_texto
|
| 393 |
-
else:
|
| 394 |
-
linhas = correcao_completa.split('\n')
|
| 395 |
-
inicio_peticao = -1
|
| 396 |
-
for i, linha in enumerate(linhas):
|
| 397 |
-
if "EXCELENTÍSSIMO" in linha.upper() and i > len(linhas) // 2:
|
| 398 |
-
inicio_peticao = i
|
| 399 |
-
break
|
| 400 |
-
if inicio_peticao != -1:
|
| 401 |
-
peticao_texto = "\n".join(linhas[inicio_peticao:]).strip()
|
| 402 |
-
return peticao_texto
|
| 403 |
-
return "⚠️ A seção '### Petição Corrigida' não foi encontrada na resposta da API. Verifique a resposta e tente novamente."
|
| 404 |
-
except Exception as e:
|
| 405 |
-
return f"❌ Erro ao extrair petição corrigida: {str(e)}"
|
| 406 |
-
|
| 407 |
-
def fornecer_dica_contextual(texto):
|
| 408 |
-
dicas = [f"💡 {chave}: {dica}" for chave, dica in DICAS_OAB_MELHORADO.items() if chave.lower() in texto.lower()]
|
| 409 |
-
return "\n".join(dicas) if dicas else "💡 Escreva mais para receber dicas."
|
| 410 |
-
|
| 411 |
-
def calcular_progresso():
|
| 412 |
-
if not HISTORICO:
|
| 413 |
-
return "📊 Nenhum progresso registrado."
|
| 414 |
-
notas = []
|
| 415 |
-
for entry in HISTORICO:
|
| 416 |
-
for line in entry["correcao_completa"].split("\n"):
|
| 417 |
-
if "Nota Final" in line:
|
| 418 |
-
try:
|
| 419 |
-
nota = float(line.split()[-1].split("/")[0].replace(",", "."))
|
| 420 |
-
notas.append(nota)
|
| 421 |
-
except:
|
| 422 |
-
continue
|
| 423 |
-
media = sum(notas) / len(notas) if notas else 0
|
| 424 |
-
tendencia = "⬆️ Melhorando" if len(notas) > 1 and notas[-1] > notas[-2] else "⬇️ Estável ou piorando"
|
| 425 |
-
return f"📊 Progresso: Média {media:.1f}/10 | Tentativas: {len(notas)} | Tendência: {tendencia}"
|
| 426 |
-
|
| 427 |
-
def comparar_peticao_melhorada(caso, peticao_texto, correcao):
|
| 428 |
-
if not caso:
|
| 429 |
-
return "⚠️ Forneça um caso antes de comparar.", "", "", "", ""
|
| 430 |
-
peticao = peticao_texto if peticao_texto else (HISTORICO[-1]["peticao"] if HISTORICO else "")
|
| 431 |
-
if not peticao:
|
| 432 |
-
return "⚠️ Forneça uma petição para comparar ou corrija uma antes.", "", "", "", ""
|
| 433 |
-
if not correcao:
|
| 434 |
-
return "⚠️ Corrija a petição antes de comparar.", "", "", "", ""
|
| 435 |
-
ultima_correcao = HISTORICO[-1]["correcao_completa"] if HISTORICO else ""
|
| 436 |
-
if not ultima_correcao:
|
| 437 |
-
return "⚠️ Nenhuma correção disponível no histórico.", "", "", "", ""
|
| 438 |
-
|
| 439 |
-
peticao_corrigida = extrair_peticao_corrigida(ultima_correcao)
|
| 440 |
-
if "⚠️" in peticao_corrigida or "❌" in peticao_corrigida:
|
| 441 |
-
return peticao_corrigida, "", "", "", ""
|
| 442 |
-
|
| 443 |
-
orig_lines = peticao.split('\n')
|
| 444 |
-
corr_lines = peticao_corrigida.split('\n')
|
| 445 |
-
start_orig = next((i for i, line in enumerate(orig_lines) if "AÇÃO" in line.upper() or "EXCELENTÍSSIMO" in line.upper()), 0)
|
| 446 |
-
start_corr = next((i for i, line in enumerate(corr_lines) if "AÇÃO" in line.upper() or "EXCELENTÍSSIMO" in line.upper()), 0)
|
| 447 |
-
|
| 448 |
-
orig_body = "\n".join(orig_lines[start_orig:]).strip()
|
| 449 |
-
corr_body = "\n".join(corr_lines[start_corr:]).strip()
|
| 450 |
-
|
| 451 |
-
diff = difflib.ndiff(orig_body.splitlines(), corr_body.splitlines())
|
| 452 |
-
|
| 453 |
-
resultado_diff = []
|
| 454 |
-
criticas = []
|
| 455 |
-
for linha in diff:
|
| 456 |
-
if linha.startswith(' '):
|
| 457 |
-
texto = linha[2:]
|
| 458 |
-
resultado_diff.append(f"<div class='linha-igual'>{escape(texto)}</div>")
|
| 459 |
-
elif linha.startswith('- '):
|
| 460 |
-
texto = linha[2:]
|
| 461 |
-
if any(kw in texto.lower() for kw in ["invenção", "custas", "art. 319"]):
|
| 462 |
-
criticas.append(f"🔴 REMOVIDO: {texto} (inconsistente ou incorreto)")
|
| 463 |
-
resultado_diff.append(f"<div class='linha-removida'><del>{escape(texto)}</del></div>")
|
| 464 |
-
elif linha.startswith('+ '):
|
| 465 |
-
texto = linha[2:]
|
| 466 |
-
if any(kw in texto.lower() for kw in ["custas", "art. 319"]):
|
| 467 |
-
criticas.append(f"🟢 ADICIONADO: {texto} (essencial para conformidade)")
|
| 468 |
-
resultado_diff.append(f"<div class='linha-adicionada'><ins>{escape(texto)}</ins></div>")
|
| 469 |
-
elif linha.startswith('? '):
|
| 470 |
-
continue
|
| 471 |
-
|
| 472 |
-
total_removidas = len([linha for linha in resultado_diff if "linha-removida" in linha])
|
| 473 |
-
total_adicionadas = len([linha for linha in resultado_diff if "linha-adicionada" in linha])
|
| 474 |
-
|
| 475 |
-
resumo_estatistico = f"""
|
| 476 |
-
Linhas Removidas: {total_removidas}
|
| 477 |
-
Linhas Adicionadas: {total_adicionadas}
|
| 478 |
-
Diferença Líquida: {total_adicionadas - total_removidas} linhas
|
| 479 |
-
"""
|
| 480 |
-
|
| 481 |
-
criticas_texto = "\n".join(criticas) if criticas else "Nenhuma mudança crítica detectada."
|
| 482 |
-
|
| 483 |
-
visualizacao_detalhada = f"""
|
| 484 |
-
<style>
|
| 485 |
-
.linha-igual {{ color: #000000; margin: 2px 0; }}
|
| 486 |
-
.linha-removida {{ color: #ffffff; background-color: #b30000; margin: 2px 0; padding: 2px; }}
|
| 487 |
-
.linha-adicionada {{ color: #ffffff; background-color: #006600; margin: 2px 0; padding: 2px; }}
|
| 488 |
-
</style>
|
| 489 |
-
{"".join(resultado_diff)}
|
| 490 |
-
"""
|
| 491 |
-
return peticao, peticao_corrigida, resumo_estatistico, criticas_texto, visualizacao_detalhada
|
| 492 |
-
|
| 493 |
-
def exportar_diferencas_html(caso, peticao_texto, correcao):
|
| 494 |
-
_, _, resumo_estatistico, criticas_texto, visualizacao_detalhada = comparar_peticao_melhorada(caso, peticao_texto, correcao)
|
| 495 |
-
html_content = f"""
|
| 496 |
-
<html>
|
| 497 |
-
<head>
|
| 498 |
-
<title>Diferenças na Petição</title>
|
| 499 |
-
<style>
|
| 500 |
-
body {{ font-family: Arial, sans-serif; margin: 20px; }}
|
| 501 |
-
.linha-igual {{ color: #000000; margin: 2px 0; }}
|
| 502 |
-
.linha-removida {{ color: #ffffff; background-color: #b30000; margin: 2px 0; padding: 2px; }}
|
| 503 |
-
.linha-adicionada {{ color: #ffffff; background-color: #006600; margin: 2px 0; padding: 2px; }}
|
| 504 |
-
h2 {{ color: #333; }}
|
| 505 |
-
pre {{ white-space: pre-wrap; }}
|
| 506 |
-
</style>
|
| 507 |
-
</head>
|
| 508 |
-
<body>
|
| 509 |
-
<h2>Estatísticas</h2>
|
| 510 |
-
<pre>{resumo_estatistico}</pre>
|
| 511 |
-
<h2>Mudanças Críticas</h2>
|
| 512 |
-
<pre>{criticas_texto}</pre>
|
| 513 |
-
<h2>Alterações Detalhadas</h2>
|
| 514 |
-
{visualizacao_detalhada}
|
| 515 |
-
</body>
|
| 516 |
-
</html>
|
| 517 |
-
"""
|
| 518 |
-
try:
|
| 519 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
|
| 520 |
-
temp_path = tmp.name
|
| 521 |
-
HTML(string=html_content).write_pdf(temp_path)
|
| 522 |
-
return temp_path
|
| 523 |
-
except Exception as e:
|
| 524 |
-
return f"❌ Erro ao gerar PDF: {str(e)}"
|
| 525 |
-
finally:
|
| 526 |
-
if 'temp_path' in locals() and os.path.exists(temp_path):
|
| 527 |
-
os.unlink(temp_path)
|
| 528 |
|
| 529 |
def interface_gradio():
|
| 530 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
@@ -688,7 +402,7 @@ def gerar_caso_ficticio():
|
|
| 688 |
def estruturar_prompt_geracao_caso():
|
| 689 |
return """
|
| 690 |
Crie um caso fictício detalhado para uma petição inicial cível, similar ao exemplo:
|
| 691 |
-
"Ana, modelo profissional, residente em Manaus, viajou para São Paulo, para o casamento de sua filha. Para lavar, pintar seus cabelos e realizar um penteado para o casamento, Ana procurou os serviços de João Macedo, cabeleireiro e dono do salão de beleza 'Hair', sediado na cidade de São Paulo, que lhe cobrou R$500,00 (quinhentos reais) pela prestação do serviço. Após lavar os cabelos de Ana, João aplicou-lhe uma tintura da marca francesa ABC, importada pela empresa Brasil Connection Ltda, sediada na cidade de Curitiba (PR). Meia hora após a aplicação da tintura, Ana sofreu uma reação alérgica, que demandou atendimento médico-hospitalar, no valor de R$1.000,00 (um mil reais), bem como dois dias de absoluto repouso que impossibilitou sua presença no casamento de sua filha. Além disso, perdeu grande parte de seu cabelo, tendo permanecido com manchas em seu rosto por dois meses, perdendo um ensaio fotográfico, para o qual já havia sido contratada, pelo valor de R$50
|
| 692 |
O caso deve:
|
| 693 |
1. Conter uma situação clara de violação de direitos que justifique uma ação cível
|
| 694 |
2. Incluir valores específicos de danos materiais e/ou morais
|
|
|
|
| 17 |
from ratelimiter import RateLimiter
|
| 18 |
import difflib
|
| 19 |
from html import escape
|
| 20 |
+
from weasyprint import HTML
|
| 21 |
|
| 22 |
load_dotenv()
|
| 23 |
|
|
|
|
| 32 |
"retry_delay": 5,
|
| 33 |
"timeout": 60,
|
| 34 |
"temperatura": 0.2,
|
| 35 |
+
"max_tokens": 12288
|
| 36 |
}
|
| 37 |
|
| 38 |
rate_limiter = RateLimiter(max_calls=60, period=60)
|
|
|
|
| 53 |
HISTORICO = []
|
| 54 |
CORRECAO_CACHE = {}
|
| 55 |
|
| 56 |
+
# Funções auxiliares (processamento de arquivos) permanecem iguais, omitidas por brevidade
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
def estruturar_prompt_analise(caso, peticao, modo_treinamento=False):
|
| 59 |
"""Estrutura o prompt apenas para a análise da petição."""
|
|
|
|
| 135 |
return base_prompt
|
| 136 |
|
| 137 |
def estruturar_prompt_peticao_corrigida(caso, peticao):
|
| 138 |
+
"""Estrutura o prompt apenas para a petição corrigida, reforçando a regra da vírgula."""
|
| 139 |
return f"""
|
| 140 |
**Caso Fornecido:**
|
| 141 |
{caso}
|
|
|
|
| 154 |
9. Pedido de citação formal (ex.: "via postal, nos termos do Art. 246, I, CPC").
|
| 155 |
10. Juntada da guia de custas com redação precisa.
|
| 156 |
11. Fechamento formal com "Local e data.\nADVOGADO.\nOAB." sem identificação específica.
|
| 157 |
+
**Instrução Específica**: Sempre corrija a frase "Nestes termos, pede deferimento" (com vírgula) para "Nestes termos pede deferimento" (sem vírgula), conforme exigência formal da OAB.
|
| 158 |
"""
|
| 159 |
|
| 160 |
def chamar_api(prompt):
|
|
|
|
| 238 |
CORRECAO_CACHE[cache_key] = analise_formatada
|
| 239 |
return aviso_validacao + analise_formatada
|
| 240 |
|
| 241 |
+
# Outras funções (formatar_correcao, extrair_peticao_corrigida, etc.) permanecem iguais, omitidas por brevidade
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
|
| 243 |
def interface_gradio():
|
| 244 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
|
|
| 402 |
def estruturar_prompt_geracao_caso():
|
| 403 |
return """
|
| 404 |
Crie um caso fictício detalhado para uma petição inicial cível, similar ao exemplo:
|
| 405 |
+
"Ana, modelo profissional, residente em Manaus, viajou para São Paulo, para o casamento de sua filha. Para lavar, pintar seus cabelos e realizar um penteado para o casamento, Ana procurou os serviços de João Macedo, cabeleireiro e dono do salão de beleza 'Hair', sediado na cidade de São Paulo, que lhe cobrou R$500,00 (quinhentos reais) pela prestação do serviço. Após lavar os cabelos de Ana, João aplicou-lhe uma tintura da marca francesa ABC, importada pela empresa Brasil Connection Ltda, sediada na cidade de Curitiba (PR). Meia hora após a aplicação da tintura, Ana sofreu uma reação alérgica, que demandou atendimento médico-hospitalar, no valor de R$1.000,00 (um mil reais), bem como dois dias de absoluto repouso que impossibilitou sua presença no casamento de sua filha. Além disso, perdeu grande parte de seu cabelo, tendo permanecido com manchas em seu rosto por dois meses, perdendo um ensaio fotográfico, para o qual já havia sido contratada, pelo valor de R$50,000,00 (cinquenta mil reais). Posteriormente constatou-se que a tintura utilizada continha substâncias químicas extremamente perigosas à vida e à saúde das pessoas e a fabricante ABC já havia sido condenada pela justiça francesa a encerrar a fabricação e comercialização do produto. Indignada com os danos sofridos, Ana procura um advogado para pleitear o devido ressarcimento."
|
| 406 |
O caso deve:
|
| 407 |
1. Conter uma situação clara de violação de direitos que justifique uma ação cível
|
| 408 |
2. Incluir valores específicos de danos materiais e/ou morais
|