Update app.py
Browse files
app.py
CHANGED
|
@@ -17,7 +17,12 @@ from ratelimiter import RateLimiter
|
|
| 17 |
import difflib
|
| 18 |
from html import escape
|
| 19 |
import random
|
| 20 |
-
import tempfile
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
load_dotenv()
|
| 23 |
|
|
@@ -60,6 +65,7 @@ def preprocess_image_for_ocr(img):
|
|
| 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):
|
|
@@ -95,6 +101,7 @@ def extract_text_from_pdf(file_path_or_obj):
|
|
| 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):
|
|
@@ -122,6 +129,7 @@ def extract_text_from_docx(file_path_or_obj):
|
|
| 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):
|
|
@@ -146,6 +154,7 @@ def extract_text_from_txt(file_path_or_obj):
|
|
| 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):
|
|
@@ -169,6 +178,7 @@ def process_file(file_obj):
|
|
| 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):
|
|
@@ -300,10 +310,13 @@ def chamar_api(prompt):
|
|
| 300 |
continue
|
| 301 |
return f"❌ Erro na requisição: {e}"
|
| 302 |
except Exception as e:
|
|
|
|
| 303 |
return f"❌ Erro inesperado: {str(e)}"
|
| 304 |
|
| 305 |
def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treinamento=False):
|
|
|
|
| 306 |
if not caso.strip():
|
|
|
|
| 307 |
return "⚠️ Forneça o caso da banca."
|
| 308 |
|
| 309 |
troll_triggers = [
|
|
@@ -317,6 +330,7 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 317 |
if peticao_arquivo is not None:
|
| 318 |
peticao_conteudo = process_file(peticao_arquivo)
|
| 319 |
if peticao_conteudo.startswith("❌") or peticao_conteudo.startswith("⚠️"):
|
|
|
|
| 320 |
return peticao_conteudo
|
| 321 |
else:
|
| 322 |
peticao_conteudo = peticao_texto or ""
|
|
@@ -354,9 +368,11 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 354 |
"🎮 **Nível Bônus**: 'Desbloqueie o nível bônus: escreva a petição sem ajuda e ganhe experiência!'",
|
| 355 |
"🎧 **Música de Elevador**: 'Enquanto você escreve, eu toco uma música relaxante. Boa sorte!'"
|
| 356 |
]
|
|
|
|
| 357 |
return random.choice(respostas_troll)
|
| 358 |
|
| 359 |
if not peticao_conteudo.strip():
|
|
|
|
| 360 |
return "⚠️ Forneça uma petição."
|
| 361 |
|
| 362 |
problemas = validar_peticao_basica(peticao_conteudo)
|
|
@@ -364,17 +380,20 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 364 |
|
| 365 |
cache_key = f"{caso[:50]}|{peticao_conteudo[:50]}|{modo_treinamento}"
|
| 366 |
if cache_key in CORRECAO_CACHE:
|
|
|
|
| 367 |
return aviso_validacao + CORRECAO_CACHE[cache_key]
|
| 368 |
|
| 369 |
prompt_analise = estruturar_prompt_analise(caso, peticao_conteudo, modo_treinamento)
|
| 370 |
analise = chamar_api(prompt_analise)
|
| 371 |
if "❌" in analise or "⏱️" in analise:
|
|
|
|
| 372 |
return aviso_validacao + analise
|
| 373 |
analise_formatada = formatar_correcao(analise)
|
| 374 |
|
| 375 |
prompt_peticao = estruturar_prompt_peticao_corrigida(caso, peticao_conteudo)
|
| 376 |
peticao_corrigida = chamar_api(prompt_peticao)
|
| 377 |
if "❌" in peticao_corrigida or "⏱️" in peticao_corrigida:
|
|
|
|
| 378 |
return aviso_validacao + analise_formatada + "\n\n" + peticao_corrigida
|
| 379 |
|
| 380 |
peticao_corrigida = pos_corrigir_peticao(peticao_corrigida)
|
|
@@ -389,6 +408,7 @@ def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treina
|
|
| 389 |
if len(HISTORICO) > 10:
|
| 390 |
HISTORICO.pop(0)
|
| 391 |
CORRECAO_CACHE[cache_key] = analise_formatada
|
|
|
|
| 392 |
return aviso_validacao + analise_formatada
|
| 393 |
|
| 394 |
def formatar_correcao(texto):
|
|
@@ -429,6 +449,7 @@ def extrair_peticao_corrigida(correcao_completa):
|
|
| 429 |
return peticao_texto[:fim].strip()
|
| 430 |
return "⚠️ Seção '### Petição Corrigida' não encontrada."
|
| 431 |
except Exception as e:
|
|
|
|
| 432 |
return f"❌ Erro ao extrair petição: {str(e)}"
|
| 433 |
|
| 434 |
def fornecer_dica_contextual(texto):
|
|
@@ -518,27 +539,48 @@ Diferença Líquida: {total_adicionadas - total_removidas} linhas
|
|
| 518 |
return peticao, peticao_corrigida, resumo_estatistico, criticas_texto, visualizacao_detalhada
|
| 519 |
|
| 520 |
def salvar_progresso(caso, peticao):
|
|
|
|
| 521 |
try:
|
| 522 |
# Verifica se os inputs estão vazios ou None
|
| 523 |
if not caso or not peticao:
|
|
|
|
| 524 |
return gr.File.update(visible=False), "⚠️ Caso ou petição estão vazios. Preencha ambos para salvar."
|
| 525 |
|
| 526 |
-
|
| 527 |
-
|
|
|
|
|
|
|
|
|
|
| 528 |
json.dump({"caso": caso, "peticao": peticao}, temp_file, ensure_ascii=False, indent=4)
|
| 529 |
arquivo_saida = temp_file.name
|
| 530 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 531 |
# Retorna o arquivo temporário para download e uma mensagem de sucesso
|
| 532 |
return gr.File.update(value=arquivo_saida, visible=True), "✅ Progresso salvo com sucesso!"
|
| 533 |
except Exception as e:
|
| 534 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 535 |
|
| 536 |
def carregar_progresso(arquivo_entrada):
|
|
|
|
| 537 |
try:
|
| 538 |
with open(arquivo_entrada, 'r', encoding='utf-8') as f:
|
| 539 |
dados = json.load(f)
|
|
|
|
| 540 |
return dados.get("caso", ""), dados.get("peticao", ""), "Progresso carregado com sucesso."
|
| 541 |
except Exception as e:
|
|
|
|
| 542 |
return "", "", f"❌ Erro ao carregar o progresso: {str(e)}"
|
| 543 |
|
| 544 |
def interface_gradio():
|
|
@@ -670,9 +712,17 @@ def interface_gradio():
|
|
| 670 |
visualizacao_detalhada_output]
|
| 671 |
)
|
| 672 |
salvar_btn.click(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 673 |
fn=lambda caso, peticao: salvar_progresso(caso, peticao),
|
| 674 |
inputs=[caso_input, peticao_texto],
|
| 675 |
outputs=[download_file, resultado_output]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 676 |
)
|
| 677 |
carregar_btn.click(
|
| 678 |
fn=lambda arquivo: carregar_progresso(arquivo.name),
|
|
|
|
| 17 |
import difflib
|
| 18 |
from html import escape
|
| 19 |
import random
|
| 20 |
+
import tempfile
|
| 21 |
+
import logging
|
| 22 |
+
|
| 23 |
+
# Configura o logging para depuração
|
| 24 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 25 |
+
logger = logging.getLogger(__name__)
|
| 26 |
|
| 27 |
load_dotenv()
|
| 28 |
|
|
|
|
| 65 |
_, thresh = cv2.threshold(np_img, 150, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
|
| 66 |
return Image.fromarray(thresh)
|
| 67 |
except Exception as e:
|
| 68 |
+
logger.error(f"Erro no pré-processamento da imagem: {str(e)}")
|
| 69 |
return f"❌ Erro no pré-processamento: {str(e)}"
|
| 70 |
|
| 71 |
def extract_text_from_pdf(file_path_or_obj):
|
|
|
|
| 101 |
text += f"[Erro na página {i+1}: {str(e)}]\n"
|
| 102 |
return text if text.strip() else "⚠️ Não foi possível extrair texto do PDF."
|
| 103 |
except Exception as e:
|
| 104 |
+
logger.error(f"Erro ao processar o PDF: {str(e)}")
|
| 105 |
return f"❌ Erro ao processar o PDF: {str(e)}"
|
| 106 |
|
| 107 |
def extract_text_from_docx(file_path_or_obj):
|
|
|
|
| 129 |
text += "\n"
|
| 130 |
return text if text.strip() else "⚠️ Não foi possível extrair texto do DOCX."
|
| 131 |
except Exception as e:
|
| 132 |
+
logger.error(f"Erro ao processar o DOCX: {str(e)}")
|
| 133 |
return f"❌ Erro ao processar o DOCX: {str(e)}"
|
| 134 |
|
| 135 |
def extract_text_from_txt(file_path_or_obj):
|
|
|
|
| 154 |
continue
|
| 155 |
return "❌ Não foi possível decodificar o arquivo TXT."
|
| 156 |
except Exception as e:
|
| 157 |
+
logger.error(f"Erro ao processar o TXT: {str(e)}")
|
| 158 |
return f"❌ Erro ao processar o TXT: {str(e)}"
|
| 159 |
|
| 160 |
def process_file(file_obj):
|
|
|
|
| 178 |
else:
|
| 179 |
return "❌ Erro: Objeto de arquivo inválido."
|
| 180 |
except Exception as e:
|
| 181 |
+
logger.error(f"Erro ao processar o arquivo: {str(e)}")
|
| 182 |
return f"❌ Erro ao processar o arquivo: {str(e)}"
|
| 183 |
|
| 184 |
def estruturar_prompt_analise(caso, peticao, modo_treinamento=False):
|
|
|
|
| 310 |
continue
|
| 311 |
return f"❌ Erro na requisição: {e}"
|
| 312 |
except Exception as e:
|
| 313 |
+
logger.error(f"Erro inesperado na chamada da API: {str(e)}")
|
| 314 |
return f"❌ Erro inesperado: {str(e)}"
|
| 315 |
|
| 316 |
def corrigir_peticao(caso, peticao_texto=None, peticao_arquivo=None, modo_treinamento=False):
|
| 317 |
+
logger.info("Iniciando correção de petição...")
|
| 318 |
if not caso.strip():
|
| 319 |
+
logger.warning("Caso não fornecido.")
|
| 320 |
return "⚠️ Forneça o caso da banca."
|
| 321 |
|
| 322 |
troll_triggers = [
|
|
|
|
| 330 |
if peticao_arquivo is not None:
|
| 331 |
peticao_conteudo = process_file(peticao_arquivo)
|
| 332 |
if peticao_conteudo.startswith("❌") or peticao_conteudo.startswith("⚠️"):
|
| 333 |
+
logger.error(f"Erro ao processar arquivo: {peticao_conteudo}")
|
| 334 |
return peticao_conteudo
|
| 335 |
else:
|
| 336 |
peticao_conteudo = peticao_texto or ""
|
|
|
|
| 368 |
"🎮 **Nível Bônus**: 'Desbloqueie o nível bônus: escreva a petição sem ajuda e ganhe experiência!'",
|
| 369 |
"🎧 **Música de Elevador**: 'Enquanto você escreve, eu toco uma música relaxante. Boa sorte!'"
|
| 370 |
]
|
| 371 |
+
logger.info("Detectado pedido para escrever petição. Retornando resposta troll.")
|
| 372 |
return random.choice(respostas_troll)
|
| 373 |
|
| 374 |
if not peticao_conteudo.strip():
|
| 375 |
+
logger.warning("Petição não fornecida.")
|
| 376 |
return "⚠️ Forneça uma petição."
|
| 377 |
|
| 378 |
problemas = validar_peticao_basica(peticao_conteudo)
|
|
|
|
| 380 |
|
| 381 |
cache_key = f"{caso[:50]}|{peticao_conteudo[:50]}|{modo_treinamento}"
|
| 382 |
if cache_key in CORRECAO_CACHE:
|
| 383 |
+
logger.info("Correção encontrada no cache.")
|
| 384 |
return aviso_validacao + CORRECAO_CACHE[cache_key]
|
| 385 |
|
| 386 |
prompt_analise = estruturar_prompt_analise(caso, peticao_conteudo, modo_treinamento)
|
| 387 |
analise = chamar_api(prompt_analise)
|
| 388 |
if "❌" in analise or "⏱️" in analise:
|
| 389 |
+
logger.error(f"Erro na análise da petição: {analise}")
|
| 390 |
return aviso_validacao + analise
|
| 391 |
analise_formatada = formatar_correcao(analise)
|
| 392 |
|
| 393 |
prompt_peticao = estruturar_prompt_peticao_corrigida(caso, peticao_conteudo)
|
| 394 |
peticao_corrigida = chamar_api(prompt_peticao)
|
| 395 |
if "❌" in peticao_corrigida or "⏱️" in peticao_corrigida:
|
| 396 |
+
logger.error(f"Erro ao gerar petição corrigida: {peticao_corrigida}")
|
| 397 |
return aviso_validacao + analise_formatada + "\n\n" + peticao_corrigida
|
| 398 |
|
| 399 |
peticao_corrigida = pos_corrigir_peticao(peticao_corrigida)
|
|
|
|
| 408 |
if len(HISTORICO) > 10:
|
| 409 |
HISTORICO.pop(0)
|
| 410 |
CORRECAO_CACHE[cache_key] = analise_formatada
|
| 411 |
+
logger.info("Correção de petição concluída com sucesso.")
|
| 412 |
return aviso_validacao + analise_formatada
|
| 413 |
|
| 414 |
def formatar_correcao(texto):
|
|
|
|
| 449 |
return peticao_texto[:fim].strip()
|
| 450 |
return "⚠️ Seção '### Petição Corrigida' não encontrada."
|
| 451 |
except Exception as e:
|
| 452 |
+
logger.error(f"Erro ao extrair petição corrigida: {str(e)}")
|
| 453 |
return f"❌ Erro ao extrair petição: {str(e)}"
|
| 454 |
|
| 455 |
def fornecer_dica_contextual(texto):
|
|
|
|
| 539 |
return peticao, peticao_corrigida, resumo_estatistico, criticas_texto, visualizacao_detalhada
|
| 540 |
|
| 541 |
def salvar_progresso(caso, peticao):
|
| 542 |
+
logger.info("Iniciando salvamento de progresso...")
|
| 543 |
try:
|
| 544 |
# Verifica se os inputs estão vazios ou None
|
| 545 |
if not caso or not peticao:
|
| 546 |
+
logger.warning("Inputs vazios detectados: caso ou peticao estão vazios.")
|
| 547 |
return gr.File.update(visible=False), "⚠️ Caso ou petição estão vazios. Preencha ambos para salvar."
|
| 548 |
|
| 549 |
+
logger.info("Criando arquivo temporário...")
|
| 550 |
+
# Especifica um diretório personalizado para o arquivo temporário
|
| 551 |
+
temp_dir = os.path.join(os.getcwd(), "temp_files")
|
| 552 |
+
os.makedirs(temp_dir, exist_ok=True)
|
| 553 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".json", dir=temp_dir, mode='w', encoding='utf-8') as temp_file:
|
| 554 |
json.dump({"caso": caso, "peticao": peticao}, temp_file, ensure_ascii=False, indent=4)
|
| 555 |
arquivo_saida = temp_file.name
|
| 556 |
|
| 557 |
+
# Verifica se o arquivo foi criado e é acessível
|
| 558 |
+
if not os.path.exists(arquivo_saida):
|
| 559 |
+
logger.error(f"Arquivo temporário não encontrado: {arquivo_saida}")
|
| 560 |
+
return gr.File.update(visible=False), f"❌ Erro: Arquivo temporário não foi criado."
|
| 561 |
+
|
| 562 |
+
logger.info(f"Arquivo temporário criado com sucesso: {arquivo_saida}")
|
| 563 |
# Retorna o arquivo temporário para download e uma mensagem de sucesso
|
| 564 |
return gr.File.update(value=arquivo_saida, visible=True), "✅ Progresso salvo com sucesso!"
|
| 565 |
except Exception as e:
|
| 566 |
+
logger.error(f"Erro ao salvar progresso: {str(e)}")
|
| 567 |
+
# Fallback: Retorna o conteúdo como string se o arquivo não puder ser criado
|
| 568 |
+
try:
|
| 569 |
+
json_content = json.dumps({"caso": caso, "peticao": peticao}, ensure_ascii=False, indent=4)
|
| 570 |
+
return gr.File.update(visible=False), f"✅ Progresso salvo! Copie o conteúdo abaixo:\n\n```json\n{json_content}\n```"
|
| 571 |
+
except Exception as e2:
|
| 572 |
+
logger.error(f"Erro ao gerar JSON como string: {str(e2)}")
|
| 573 |
+
return gr.File.update(visible=False), f"❌ Erro ao salvar o progresso: {str(e)}"
|
| 574 |
|
| 575 |
def carregar_progresso(arquivo_entrada):
|
| 576 |
+
logger.info("Iniciando carregamento de progresso...")
|
| 577 |
try:
|
| 578 |
with open(arquivo_entrada, 'r', encoding='utf-8') as f:
|
| 579 |
dados = json.load(f)
|
| 580 |
+
logger.info("Progresso carregado com sucesso.")
|
| 581 |
return dados.get("caso", ""), dados.get("peticao", ""), "Progresso carregado com sucesso."
|
| 582 |
except Exception as e:
|
| 583 |
+
logger.error(f"Erro ao carregar o progresso: {str(e)}")
|
| 584 |
return "", "", f"❌ Erro ao carregar o progresso: {str(e)}"
|
| 585 |
|
| 586 |
def interface_gradio():
|
|
|
|
| 712 |
visualizacao_detalhada_output]
|
| 713 |
)
|
| 714 |
salvar_btn.click(
|
| 715 |
+
fn=lambda: gr.update(value="⏳ Salvando progresso...", visible=True),
|
| 716 |
+
inputs=None,
|
| 717 |
+
outputs=[processing_message]
|
| 718 |
+
).then(
|
| 719 |
fn=lambda caso, peticao: salvar_progresso(caso, peticao),
|
| 720 |
inputs=[caso_input, peticao_texto],
|
| 721 |
outputs=[download_file, resultado_output]
|
| 722 |
+
).then(
|
| 723 |
+
fn=lambda: gr.update(value="", visible=False),
|
| 724 |
+
inputs=None,
|
| 725 |
+
outputs=[processing_message]
|
| 726 |
)
|
| 727 |
carregar_btn.click(
|
| 728 |
fn=lambda arquivo: carregar_progresso(arquivo.name),
|