GabrielGD commited on
Commit
94872c6
·
verified ·
1 Parent(s): a564bb4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +277 -2
app.py CHANGED
@@ -53,7 +53,123 @@ DICAS_OAB_MELHORADO = {
53
  HISTORICO = []
54
  CORRECAO_CACHE = {}
55
 
56
- # Funções auxiliares (processamento de arquivos) permanecem iguais, omitidas aqui 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."""
@@ -288,7 +404,127 @@ def extrair_peticao_corrigida(correcao_completa):
288
  except Exception as e:
289
  return f"❌ Erro ao extrair petição corrigida: {str(e)}"
290
 
291
- # Outras funções (comparar_peticao_melhorada, interface_gradio, etc.) permanecem iguais, omitidas por brevidade
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
 
293
  def interface_gradio():
294
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
@@ -445,5 +681,44 @@ def interface_gradio():
445
 
446
  return demo
447
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  app = interface_gradio()
449
  app.launch()
 
53
  HISTORICO = []
54
  CORRECAO_CACHE = {}
55
 
56
+ def preprocess_image_for_ocr(img):
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."""
 
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:
 
681
 
682
  return demo
683
 
684
+ def gerar_caso_ficticio():
685
+ prompt = estruturar_prompt_geracao_caso()
686
+ return chamar_api(prompt)
687
+
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.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."
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
695
+ 3. Mencionar nomes completos, cidades e informações suficientes para identificar as partes
696
+ 4. Estabelecer relação entre as partes (contratual, extracontratual, consumo, etc.)
697
+ 5. Ter complexidade adequada para uma petição inicial de nível OAB
698
+ 6. Ter entre 15-25 linhas de texto
699
+ 7. Focar em um dos seguintes temas (escolha APENAS UM aleatoriamente):
700
+ - Responsabilidade civil por acidente de consumo
701
+ - Inadimplemento contratual com danos
702
+ - Responsabilidade civil por dano ambiental
703
+ - Violação de direitos da personalidade
704
+ - Relação de consumo com vício de produto/serviço
705
+ - Reparação por danos patrimoniais
706
+ Termine com: "Situação problema: Como advogado(a) de [NOME DO CLIENTE], promova a demanda cabível."
707
+ """
708
+
709
+ def validar_peticao_basica(peticao):
710
+ problemas = []
711
+ if "EXCELENTÍSSIMO" not in peticao.upper():
712
+ problemas.append("⚠️ Endereçamento ausente ou incompleto (Art. 319, I, CPC).")
713
+ if "Art. 319" not in peticao and "CPC" not in peticao:
714
+ problemas.append("⚠️ Fundamentação jurídica não menciona o CPC (Art. 319).")
715
+ if "Dá-se à causa o valor" not in peticao:
716
+ problemas.append("⚠️ Valor da causa não especificado (Art. 319, V, CPC).")
717
+ if "juntada da guia de custas" not in peticao.lower():
718
+ problemas.append("⚠️ Pedido de juntada da guia de custas ausente (-1,0 ponto).")
719
+ if "Nestes termos" not in peticao:
720
+ problemas.append("⚠️ Fechamento formal ausente.")
721
+ return problemas
722
+
723
  app = interface_gradio()
724
  app.launch()