Update app.py
Browse files
app.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import requests
|
| 3 |
import os
|
|
@@ -94,7 +95,6 @@ def extract_text_from_pdf(file_path_or_obj):
|
|
| 94 |
ocr_text_parts.append(f"[Erro OCR Página {i+1}: {str(ocr_e)}]")
|
| 95 |
pdf_reader.close()
|
| 96 |
ocr_text = "\n".join(ocr_text_parts)
|
| 97 |
-
|
| 98 |
if text.strip() and len(text) > len(ocr_text) * 0.7:
|
| 99 |
logger.info(f"Usando texto extraído do PDF ({len(text)} chars).")
|
| 100 |
return text
|
|
@@ -133,7 +133,6 @@ def extract_text_from_txt(file_path_or_obj):
|
|
| 133 |
content = file_path_or_obj.read()
|
| 134 |
else:
|
| 135 |
return "❌ Tipo de entrada TXT inválido."
|
| 136 |
-
|
| 137 |
encodings = ['utf-8', 'latin-1', 'cp1252']
|
| 138 |
for encoding in encodings:
|
| 139 |
try:
|
|
@@ -167,13 +166,9 @@ def process_file(file_obj):
|
|
| 167 |
return "⚠️ Arquivo muito grande (Máx 15MB)."
|
| 168 |
except OSError as size_e:
|
| 169 |
logger.warning(f"Não foi possível verificar o tamanho do arquivo: {size_e}")
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
elif filename.endswith('.docx'):
|
| 174 |
-
return extract_text_from_docx(file_path)
|
| 175 |
-
elif filename.endswith('.txt'):
|
| 176 |
-
return extract_text_from_txt(file_path)
|
| 177 |
else:
|
| 178 |
logger.warning(f"Formato de arquivo não suportado: {filename}")
|
| 179 |
return "⚠️ Formato de arquivo não suportado. Use PDF, DOCX ou TXT."
|
|
@@ -184,267 +179,60 @@ def process_file(file_obj):
|
|
| 184 |
def get_instrucoes_gerais_avaliacao(modo_treinamento=False):
|
| 185 |
base = """
|
| 186 |
**Estrutura da Avaliação:**
|
| 187 |
-
1. **Análise Geral:** Visão geral concisa (2-3 linhas)
|
| 188 |
-
2. **Nota Final:** 0 a 10 (uma casa decimal), com justificativa BREVE
|
| 189 |
-
3. **Pontos Positivos:** Liste
|
| 190 |
-
4. **Pontos a Melhorar:** Liste **TODOS** os problemas em ordem de gravidade
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
* **Impacto estimado na nota** (ex: -0.5, -1.0, -2.0).
|
| 194 |
-
* Sugestão de correção ou como deveria ter sido feito.
|
| 195 |
-
5. **Análise Específica dos Requisitos:** Avalie os itens chave da peça (listados abaixo para cada tipo).
|
| 196 |
-
|
| 197 |
-
**Critérios Fundamentais (Aplicáveis a Quase Todos):**
|
| 198 |
-
* **Coerência:** A peça responde ao caso/situação processual? Os argumentos são lógicos?
|
| 199 |
-
* **Fundamentação:** Usou a lei, doutrina e jurisprudência corretamente? Citou artigos relevantes?
|
| 200 |
-
* **Linguagem:** Clareza, objetividade, correção gramatical e formalidade adequada?
|
| 201 |
-
* **Pedidos:** São claros, certos, determinados e coerentes com a fundamentação?
|
| 202 |
-
* **NÃO INVENTAR FATOS:** Penalidade severa (-3.0 a -5.0) se criar fatos não presentes no caso.
|
| 203 |
-
* **NÃO SE IDENTIFICAR:** Nota ZERO se houver nome, OAB, CPF, etc., do aluno na peça (exceto nomes das partes do caso). Use "ADVOGADO(A)", "OAB/...".
|
| 204 |
-
"""
|
| 205 |
if modo_treinamento:
|
| 206 |
base += """
|
| 207 |
-
**Modo de Treinamento:**
|
| 208 |
-
* Para cada Ponto a Melhorar, detalhe AINDA MAIS:
|
| 209 |
-
a) Explicação aprofundada do erro e sua consequência prática.
|
| 210 |
-
b) Base legal/doutrinária específica.
|
| 211 |
-
c) **Exemplo de Redação Corrigida** para aquele trecho específico.
|
| 212 |
-
d) Dica prática relevante (use o banco de dicas se aplicável).
|
| 213 |
-
e) Possível estratégia alternativa.
|
| 214 |
-
* Destaque inconsistências entre a peça e o caso com citações diretas.
|
| 215 |
-
* Sugira estratégias jurídicas adicionais ou alternativas viáveis.
|
| 216 |
-
"""
|
| 217 |
return base
|
| 218 |
|
| 219 |
def estruturar_prompt_analise(caso, peticao, tipo_peticao, modo_treinamento=False):
|
| 220 |
instrucoes_gerais = get_instrucoes_gerais_avaliacao(modo_treinamento)
|
| 221 |
-
prompt_especifico = f""
|
| 222 |
-
## Análise de Peça Processual: {tipo_peticao} (Critérios OAB Simulados)
|
| 223 |
-
**Caso/Contexto Fornecido:**
|
| 224 |
-
```
|
| 225 |
-
{caso}
|
| 226 |
-
```
|
| 227 |
-
**Peça do Aluno ({tipo_peticao}):**
|
| 228 |
-
```
|
| 229 |
-
{peticao}
|
| 230 |
-
```
|
| 231 |
-
{instrucoes_gerais}
|
| 232 |
-
**Requisitos Específicos para {tipo_peticao}:**
|
| 233 |
-
"""
|
| 234 |
if tipo_peticao == "Petição Inicial":
|
| 235 |
-
prompt_especifico += ""
|
| 236 |
-
- Endereçamento e competência (Art. 319, I, CPC; leis especiais como CDC Art. 101, I).
|
| 237 |
-
- Qualificação completa das partes (Art. 319, II, CPC).
|
| 238 |
-
- Exposição clara e lógica dos fatos (causa de pedir remota).
|
| 239 |
-
- Fundamentação jurídica pertinente (causa de pedir próxima - Art. 319, III, CPC).
|
| 240 |
-
- Pedidos certos, determinados e líquidos (se possível) (Art. 319, IV, CPC).
|
| 241 |
-
- Valor da causa correto e justificado (Art. 291-292, 319, V, CPC).
|
| 242 |
-
- Indicação das provas pretendidas (Art. 319, VI, CPC).
|
| 243 |
-
- Opção pela audiência de conciliação/mediação (Art. 319, VII, CPC).
|
| 244 |
-
- Pedido de citação do réu (forma específica se necessário).
|
| 245 |
-
- Requerimento de juntada de documentos essenciais (procuração, custas/JG).
|
| 246 |
-
- Fechamento formal ("Nestes termos pede deferimento", Local, data, Advogado, OAB).
|
| 247 |
-
**Critérios Adicionais (Inicial):**
|
| 248 |
-
* Uso de "XXX" para dados ausentes. Penalizar invenção (-0.5 por ocorrência).
|
| 249 |
-
* Falta de pedido de juntada de custas/JG: -1.0 ponto.
|
| 250 |
-
* Erro em "Nestes termos, pede deferimento" (com vírgula): -0.2 ponto.
|
| 251 |
-
* Analisar foro (Art. 46 CPC vs. Art. 101 CDC): Escolha do foro do consumidor é válida se aplicável; não penalizar, apenas comentar se gerar dificuldades práticas.
|
| 252 |
-
"""
|
| 253 |
elif tipo_peticao == "Contestação":
|
| 254 |
-
prompt_especifico += ""
|
| 255 |
-
- Endereçamento ao juízo correto onde tramita a ação.
|
| 256 |
-
- Qualificação completa do réu (se já não constante nos autos, referenciar).
|
| 257 |
-
- Indicação do processo (número).
|
| 258 |
-
- Tempestividade (menção implícita ou explícita de que está no prazo).
|
| 259 |
-
- **Preliminares (Art. 337, CPC):** Alegar TODAS as aplicáveis (inexistência/nulidade citação, incompetência, inépcia, perempção, litispendência, coisa julgada, conexão, incapacidade, convenção de arbitragem, ausência de legitimidade/interesse, falta de caução, indevida concessão de JG).
|
| 260 |
-
- **Impugnação Específica dos Fatos:** Rebater PONTO A PONTO os fatos alegados na inicial (Art. 341, CPC). A falta de impugnação específica torna o fato incontroverso!
|
| 261 |
-
- **Mérito:** Apresentar a versão do réu sobre os fatos; apresentar a defesa de mérito direta (negando direito do autor) e/ou indireta (fatos impeditivos, modificativos, extintivos do direito do autor - ex: pagamento, prescrição, compensação).
|
| 262 |
-
- Fundamentação jurídica da defesa.
|
| 263 |
-
- **Pedidos:** Requerer acolhimento das preliminares (com extinção ou remessa); NO MÉRITO, requerer a IMPROCEDÊNCIA TOTAL dos pedidos do autor; Requerer a condenação do autor nas custas e honorários advocatícios (Art. 85, CPC).
|
| 264 |
-
- Indicação das provas que pretende produzir.
|
| 265 |
-
- Fechamento formal.
|
| 266 |
-
**Critérios Adicionais (Contestação):**
|
| 267 |
-
* A não alegação de preliminar arguível (exceto incompetência absoluta, conexão, convenção de arbitragem) preclui? Avaliar impacto.
|
| 268 |
-
* Falha grave na impugnação específica: -2.0 a -4.0 pontos.
|
| 269 |
-
* Ausência de pedido de improcedência: -1.5 pontos.
|
| 270 |
-
"""
|
| 271 |
elif tipo_peticao == "Reconvenção":
|
| 272 |
-
prompt_especifico += ""
|
| 273 |
-
- Apresentada NA MESMA PEÇA da Contestação (Art. 343, CPC).
|
| 274 |
-
- Endereçamento ao mesmo juízo.
|
| 275 |
-
- Indica�o do processo.
|
| 276 |
-
- Qualificação completa do réu-reconvinte e do autor-reconvindo (podem ser referenciadas se já completas).
|
| 277 |
-
- **Conexão com a Ação Principal ou Fundamento de Defesa:** O pedido da reconvenção deve ser conexo (Art. 343, caput).
|
| 278 |
-
- **Estrutura Similar à Petição Inicial:** Fatos, Fundamentação, Pedidos específicos, Valor da causa, Provas.
|
| 279 |
-
- Pedido de intimação do autor-reconvindo para contestar a reconvenção (na pessoa de seu advogado - Art. 343, §1º).
|
| 280 |
-
- Fechamento formal (pode ser conjunto com a contestação).
|
| 281 |
-
**Critérios Adicionais (Reconvenção):**
|
| 282 |
-
* Ausência de conexão clara: -2.0 pontos. Falta de pedido/valor da causa/provas específicos: -1.0 por item. Apresentada em peça separada (erro formal grave): -3.0 pontos.
|
| 283 |
-
"""
|
| 284 |
elif tipo_peticao == "Impugnação à Contestação":
|
| 285 |
-
prompt_especifico += ""
|
| 286 |
-
- Endereçamento ao juízo correto. Indicação do processo. Qualificação do autor (impugnante). Tempestividade (15 dias - Art. 350/351 CPC).
|
| 287 |
-
- **Resposta às Preliminares:** Rebater cada preliminar arguida.
|
| 288 |
-
- **Resposta a Fatos Impeditivos/Modificativos/Extintivos:** Manifestar-se sobre fatos novos (Art. 350).
|
| 289 |
-
- **Resposta a Documentos Novos:** Manifestar-se sobre documentos juntados (Art. 437 CPC).
|
| 290 |
-
- **Ratificação da Inicial:** Reiterar os termos e pedidos da inicial.
|
| 291 |
-
- **Especificação de Provas:** Indicar provas para contrapor defesa indireta/preliminares (Art. 350/351).
|
| 292 |
-
- Pedidos: Rejeição das preliminares, refutação da defesa, procedência dos pedidos da inicial. Fechamento formal.
|
| 293 |
-
**Critérios Adicionais (Impugnação):**
|
| 294 |
-
* Não responder a preliminar relevante: -1.5 pontos. Não se manifestar sobre fato novo: -2.0 pontos. Não ratificar a inicial: -0.5 pontos.
|
| 295 |
-
"""
|
| 296 |
elif tipo_peticao == "Embargos de Declaração":
|
| 297 |
-
prompt_especifico += ""
|
| 298 |
-
- **Contra Decisão Específica:** Indicar claramente qual decisão está sendo embargada. Endereçamento ao PRÓPRIO juízo prolator. Indicação do processo. Qualificação das partes. Tempestividade (5 dias - Art. 1023 CPC).
|
| 299 |
-
- **Cabimento (Art. 1022, CPC):** Apontar **PRECISAMENTE** e **FUNDAMENTADAMENTE** a ocorrência de: Omissão, Contradição, Obscuridade, Erro Material.
|
| 300 |
-
- **NÃO PODE REJULGAR A CAUSA:** Objetivo é sanar vício, não modificar o mérito (salvo efeitos infringentes excepcionais).
|
| 301 |
-
- **Pedido:** Requerer o conhecimento e ACOLHIMENTO para sanar o vício (com ou sem efeitos infringentes, se for o caso). Fechamento formal.
|
| 302 |
-
**Critérios Adicionais (Embargos):**
|
| 303 |
-
* Usar para rediscutir mérito (erro grave): -4.0 pontos. Não apontar vício claramente: -3.0 pontos. Endereçar ao tribunal (erro): -1.0 ponto.
|
| 304 |
-
"""
|
| 305 |
elif tipo_peticao == "Recurso de Apelação":
|
| 306 |
-
prompt_especifico += ""
|
| 307 |
-
- **Peça de Interposição:** Endereçamento ao juízo a quo. Indicação do processo. Qualificação das partes. Pressupostos (cabimento - Art. 1009; tempestividade - 15 dias Art. 1003, §5º; preparo/JG; regularidade). Pedido de recebimento e remessa ao Tribunal.
|
| 308 |
-
- **Razões Recursais:** Endereçamento ao TRIBUNAL competente. Exposição dos fatos e da sentença. **Fundamentos para Reforma/Anulação (Art. 1010, II e III):** Error in procedendo (anulação) ou Error in judicando (reforma). **Princípio da Dialeticidade:** Impugnar ESPECIFICAMENTE os fundamentos da sentença.
|
| 309 |
-
- **Pedidos:** Conhecimento; PROVIMENTO para ANULAR ou REFORMAR (especificar); inversão da sucumbência. Fechamento formal.
|
| 310 |
-
**Critérios Adicionais (Apelação):**
|
| 311 |
-
* Falta de interposição ou razões: Nota zero. Endereçamento incorreto das razões: -1.0. Ausência de dialeticidade: -3.0 a -5.0. Não pedir anulação/reforma: -1.5. Falta de preparo/JG: -2.0.
|
| 312 |
-
"""
|
| 313 |
elif tipo_peticao == "Agravo de Instrumento":
|
| 314 |
-
prompt_especifico += ""
|
| 315 |
-
- **Peça Única:** Endereçamento direto ao TRIBUNAL. Indicação processo origem. Qualificação partes e advogados (com endereços - Art. 1016, IV). Cópia da decisão agravada (OBRIGATÓRIA - Art. 1017, I).
|
| 316 |
-
- **Cabimento (Art. 1015 ou taxatividade mitigada):** Demonstrar hipótese legal ou urgência (Tema 988 STJ). Tempestividade (15 dias). Preparo/JG.
|
| 317 |
-
- **Peças Obrigatórias (Art. 1017, I):** Decisão agravada, certidão de intimação, procurações. Peças Facultativas (Art. 1017, III).
|
| 318 |
-
- **Razões (Art. 1016, II e III):** Exposição do fato e direito; razões para reforma/invalidação da decisão interlocutória.
|
| 319 |
-
- **Pedido de Efeito Suspensivo ou Tutela Antecipada Recursal (Art. 1019, I):** Se houver risco, pedir fundamentadamente.
|
| 320 |
-
- **Pedidos Finais:** Conhecimento; (se aplicável) efeito suspensivo/tutela antecipada; PROVIMENTO para reformar/invalidar; comunicação ao juiz (Art. 1018 - opcional se eletrônico). Fechamento formal.
|
| 321 |
-
**Critérios Adicionais (Agravo):**
|
| 322 |
-
* Ausência de peça obrigatória: Inadmissibilidade (-4.0). Não demonstrar cabimento: -3.0. Endereçar ao juiz a quo: -1.0. Não indicar advogados: -0.5.
|
| 323 |
-
"""
|
| 324 |
elif tipo_peticao == "Petição de Tutela Provisória":
|
| 325 |
-
prompt_especifico += ""
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
- **Tutela de Evidência (Art. 311):** Demonstrar uma das hipóteses (I a IV). **NÃO precisa periculum in mora.**
|
| 329 |
-
- **Pedido Específico:** Indicar CLARAMENTE a medida liminar solicitada.
|
| 330 |
-
- **Se Antecedente (Art. 303 ou 305):** Indicar pedido final ou aditar/apresentar inicial no prazo. Valor da Causa.
|
| 331 |
-
- **Pedidos:** Concessão da tutela (liminar/justificação prévia); citação/intimação; (se antecedente) indicação da ação principal/aditamento. Fechamento formal.
|
| 332 |
-
**Critérios Adicionais (Tutela):**
|
| 333 |
-
* Não demonstrar Fumus/Periculum (Urgência): -3.0 a -5.0. Não enquadrar na Evidência: -3.0. Pedido genérico: -2.0. Confundir requisitos: -1.5.
|
| 334 |
-
"""
|
| 335 |
-
else:
|
| 336 |
-
prompt_especifico += """
|
| 337 |
-
- **Adequação ao Tipo:** A peça corresponde à estrutura e finalidade do tipo?
|
| 338 |
-
- **Clareza:** É possível entender a pretensão?
|
| 339 |
-
- **Fundamentação Mínima:** Tentativa de basear em lei ou fatos?
|
| 340 |
-
- **Pedido:** Existe um pedido?
|
| 341 |
-
"""
|
| 342 |
-
prompt_especifico += "\n\n**Instruções Finais:** Analise a peça do aluno estritamente com base no caso/contexto fornecido e nos critérios acima. Seja rigoroso como um examinador da OAB, mas forneça feedback construtivo e detalhado. Gere a resposta **exclusivamente** no formato solicitado."
|
| 343 |
return prompt_especifico
|
| 344 |
|
| 345 |
def estruturar_prompt_peticao_corrigida(caso, peticao_original, tipo_peticao):
|
| 346 |
-
prompt = f""
|
| 347 |
-
**Caso/Contexto Fornecido:**
|
| 348 |
-
```
|
| 349 |
-
{caso}
|
| 350 |
-
```
|
| 351 |
-
**Peça Original do Aluno ({tipo_peticao}):**
|
| 352 |
-
```
|
| 353 |
-
{peticao_original}
|
| 354 |
-
```
|
| 355 |
-
**Tarefa:** Com base no caso e nos problemas da peça original, **gere uma versão corrigida e aprimorada** da peça ({tipo_peticao}). Siga **rigorosamente** as melhores práticas e requisitos formais/materiais para este tipo de peça no exame da OAB.
|
| 356 |
-
**Instruções Específicas para a Peça Corrigida ({tipo_peticao}):**
|
| 357 |
-
"""
|
| 358 |
if tipo_peticao == "Petição Inicial":
|
| 359 |
-
prompt += ""
|
| 360 |
-
1. **Endereçamento:** Correto e fundamentado (Art. 46 CPC ou Art. 101 CDC se aplicável).
|
| 361 |
-
2. **Qualificação:** Completa (Art. 319, II), usando "XXX" para dados ausentes.
|
| 362 |
-
3. **Fatos:** Narre de forma cronológica, clara e fiel ao caso.
|
| 363 |
-
4. **Fundamentação:** Cite artigos pertinentes (CC, CDC, CPC) e súmulas/jurisprudência, se aplicável.
|
| 364 |
-
5. **Pedidos:** Claros, certos, determinados (quantificar danos se possível). Cumulados se cabível.
|
| 365 |
-
6. **Valor da Causa:** Correto (soma dos benefícios - Art. 292).
|
| 366 |
-
7. **Provas:** Indicar ("protesta provar o alegado por todos os meios...").
|
| 367 |
-
8. **Audiência:** Indicar opção (Art. 319, VII).
|
| 368 |
-
9. **Citação:** Pedido de citação (ex: "via postal, Art. 246, I, CPC").
|
| 369 |
-
10. **Custas:** Requerimento expresso de juntada da guia OU pedido de gratuidade (com pedido de declaração). **NUNCA OMITIR.**
|
| 370 |
-
11. **Fechamento:** "Nestes termos pede deferimento." (SEM vírgula). Seguido de "Local, data.", "ADVOGADO(A)", "OAB/...". **NUNCA identificar.**
|
| 371 |
-
"""
|
| 372 |
elif tipo_peticao == "Contestação":
|
| 373 |
-
prompt += ""
|
| 374 |
-
1. **Endereçamento:** Ao juízo da ação.
|
| 375 |
-
2. **Identificação:** Número do processo, qualificação do réu.
|
| 376 |
-
3. **Tempestividade:** Mencionar ("A presente contestação é tempestiva...").
|
| 377 |
-
4. **Estrutura:** Síntese da Inicial; Preliminares (Art. 337, fundamentadas); Mérito (Impugnação Específica + Defesa de Mérito Direta/Indireta com fundamentos); Reconvenção (Se houver, ANTES dos pedidos da contestação).
|
| 378 |
-
5. **Pedidos da Contestação:** Acolhimento das preliminares (com consequência); **IMPROCEDÊNCIA TOTAL** dos pedidos do autor; Condenação em custas e honorários.
|
| 379 |
-
6. **Provas:** Indicar as provas do réu.
|
| 380 |
-
7. **Fechamento:** Padrão OAB.
|
| 381 |
-
"""
|
| 382 |
elif tipo_peticao == "Reconvenção":
|
| 383 |
-
prompt += ""
|
| 384 |
-
**IMPORTANTE:** Gere a Reconvenção como parte da Contestação.
|
| 385 |
-
1. **Após a defesa de mérito da Contestação e ANTES dos pedidos da Contestação**, insira: "DA RECONVENÇÃO".
|
| 386 |
-
2. **Qualificação:** Réu-Reconvinte e Autor-Reconvindo.
|
| 387 |
-
3. **Conexão:** Justifique brevemente.
|
| 388 |
-
4. **Fatos e Direito Reconvencionais:** Narre e fundamente o pedido do reconvinte.
|
| 389 |
-
5. **Pedidos da Reconvenção:** Claros e específicos contra o autor-reconvindo.
|
| 390 |
-
6. **Valor da Causa e Provas da Reconvenção:** Específicos.
|
| 391 |
-
7. **Intimação:** Peça a intimação do autor-reconvindo para contestar.
|
| 392 |
-
8. **Continue com os Pedidos da Contestação**.
|
| 393 |
-
9. **Fechamento:** Padrão OAB.
|
| 394 |
-
"""
|
| 395 |
elif tipo_peticao == "Impugnação à Contestação":
|
| 396 |
-
prompt += ""
|
| 397 |
-
1. Endereçamento, processo, qualificação autor, tempestividade.
|
| 398 |
-
2. Tópico: **DA(S) PRELIMINAR(ES) ARGUIDA(S)** - Rebater cada uma.
|
| 399 |
-
3. Tópico: **DO MÉRITO E DOS FATOS NOVOS** - Manifestar-se sobre fatos impeditivos/modificativos/extintivos e documentos.
|
| 400 |
-
4. Tópico: **DA RATIFICAÇÃO DA INICIAL** - Reiterar termos e pedidos.
|
| 401 |
-
5. Tópico: **DAS PROVAS** - Especificar provas contrapostas.
|
| 402 |
-
6. **Pedidos:** Rejeição das preliminares, refutação da defesa, procedência dos pedidos da inicial.
|
| 403 |
-
7. Fechamento padrão OAB.
|
| 404 |
-
"""
|
| 405 |
elif tipo_peticao == "Embargos de Declaração":
|
| 406 |
-
prompt += ""
|
| 407 |
-
1. Endereçamento ao juízo prolator. Processo, Embargante, Embargado. Decisão embargada identificada. Tempestividade (5 dias).
|
| 408 |
-
2. Tópico para cada vício (Art. 1022): **DA OMISSÃO / DA CONTRADIÇÃO / DA OBSCURIDADE / DO ERRO MATERIAL**.
|
| 409 |
-
3. Dentro de cada tópico: **Transcrever trecho relevante da decisão** e explicar **objetivamente** o vício. NÃO REJULGAR.
|
| 410 |
-
4. **Pedido:** Conhecimento e ACOLHIMENTO para sanar o(s) vício(s) apontado(s), especificando o que se espera. Pedir efeitos infringentes se cabível e fundamentado.
|
| 411 |
-
5. Fechamento padrão OAB.
|
| 412 |
-
"""
|
| 413 |
elif tipo_peticao == "Recurso de Apelação":
|
| 414 |
-
prompt += ""
|
| 415 |
-
1. **Peça de Interposição:** Endereçamento ao juízo a quo. Processo, Apelante, Apelado. Pressupostos (cabimento, tempestividade, preparo/JG). Pedido de recebimento e remessa.
|
| 416 |
-
2. **Razões Recursais:** Endereçamento ao Tribunal. Breve relato. **DOS FUNDAMENTOS PARA REFORMA/ANULAÇÃO:** Error in procedendo ou Error in judicando. Impugnar especificamente a sentença (dialeticidade).
|
| 417 |
-
3. **Pedidos:** Conhecimento; PROVIMENTO para ANULAR ou REFORMAR (especificar); inversão sucumbência.
|
| 418 |
-
4. Fechamento padrão OAB.
|
| 419 |
-
"""
|
| 420 |
elif tipo_peticao == "Agravo de Instrumento":
|
| 421 |
-
prompt += ""
|
| 422 |
-
1. Peça única ao Tribunal. Processo origem, Agravante, Agravado, Advogados (com endereços). Decisão agravada identificada (juntar cópia).
|
| 423 |
-
2. **DO CABIMENTO:** Demonstrar hipótese Art. 1015 ou mitigação. **DA TEMPESTIVIDADE.** **DO PREPARO/JG.** **DAS PEÇAS OBRIGATÓRIAS E FACULTATIVAS.**
|
| 424 |
-
3. **DAS RAZÕES RECURSAIS:** Exposição fato/direito, motivos para reforma/invalidação da interlocutória.
|
| 425 |
-
4. **DO PEDIDO DE EFEITO SUSPENSIVO / TUTELA ANTECIPADA RECURSAL** (se cabível e fundamentado).
|
| 426 |
-
5. **Pedidos:** Conhecimento; (se aplicável) efeito suspensivo/tutela; PROVIMENTO para reformar/invalidar; comunicação ao juiz.
|
| 427 |
-
6. Fechamento padrão OAB.
|
| 428 |
-
"""
|
| 429 |
elif tipo_peticao == "Petição de Tutela Provisória":
|
| 430 |
-
prompt += ""
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
* **Urgência:** Tópico **DA PROBABILIDADE DO DIREITO (FUMUS BONI IURIS)** e tópico **DO PERIGO DE DANO OU RISCO AO RESULTADO ÚTIL (PERICULUM IN MORA)**. Se possível, **DA REVERSIBILIDADE**.
|
| 434 |
-
* **Evidência:** Tópico **DA HIPÓTESE DE EVIDÊNCIA (ART. 311, INCISO __)** - Demonstrar o enquadramento.
|
| 435 |
-
3. **DO PEDIDO LIMINAR:** Descrever CLARAMENTE a medida solicitada.
|
| 436 |
-
4. **Se Antecedente:** Indicar pedido final ou aditamento/inicial completa. Valor da Causa.
|
| 437 |
-
5. **Pedidos:** Concessão da tutela; citação/intimação; (se antecedente) indicação ação principal/aditamento.
|
| 438 |
-
6. Fechamento padrão OAB.
|
| 439 |
-
"""
|
| 440 |
-
else:
|
| 441 |
-
prompt += """
|
| 442 |
-
1. Estrutura Lógica: Começo, meio, fim.
|
| 443 |
-
2. Argumentos Claros.
|
| 444 |
-
3. Pedido Claro.
|
| 445 |
-
4. Formalidades: Linguagem adequada, fechamento OAB.
|
| 446 |
-
"""
|
| 447 |
-
prompt += "\n\n**Instrução Final:** Gere **APENAS** o texto completo da peça corrigida abaixo, começando pelo endereçamento e terminando com 'OAB/...'. Não inclua NENHUM comentário, introdução ou explicação ANTES ou DEPOIS do texto da peça."
|
| 448 |
return prompt
|
| 449 |
|
| 450 |
def pos_corrigir_peticao(peticao_corrigida, tipo_peticao):
|
|
@@ -454,24 +242,17 @@ def pos_corrigir_peticao(peticao_corrigida, tipo_peticao):
|
|
| 454 |
peticao_lower = peticao_corrigida.lower()
|
| 455 |
if "juntada da guia de custas" not in peticao_lower and "gratuidade de justiça" not in peticao_lower:
|
| 456 |
partes = peticao_corrigida.split("Nestes termos pede deferimento")
|
| 457 |
-
if len(partes) == 2:
|
| 458 |
-
|
| 459 |
-
else:
|
| 460 |
-
peticao_corrigida = peticao_corrigida.replace("Local, data.", "Requer, ainda, a juntada da guia de custas devidamente recolhida.\n\nLocal, data.")
|
| 461 |
if "audiência de conciliação" not in peticao_lower and "audiência de mediação" not in peticao_lower:
|
| 462 |
partes = peticao_corrigida.split("Nestes termos pede deferimento")
|
| 463 |
-
if len(partes) == 2:
|
| 464 |
-
|
| 465 |
-
else:
|
| 466 |
-
peticao_corrigida = peticao_corrigida.replace("Local, data.", "Opta o Autor pela realização da audiência de conciliação ou mediação (Art. 319, VII, CPC).\n\nLocal, data.")
|
| 467 |
-
|
| 468 |
linhas = [l.strip() for l in peticao_corrigida.strip().split('\n') if l.strip()]
|
| 469 |
fechamento_padrao = ["Local, data.", "ADVOGADO(A)", "OAB/..."]
|
| 470 |
-
while linhas and any(term in linhas[-1] for term in ["ADVOGADO", "OAB", "Local", "data"]):
|
| 471 |
-
linhas.pop()
|
| 472 |
linhas.extend(fechamento_padrao)
|
| 473 |
-
|
| 474 |
-
return peticao_corrigida
|
| 475 |
|
| 476 |
def chamar_api(prompt):
|
| 477 |
payload = {"contents": [{"parts": [{"text": prompt}]}],"generationConfig": {"temperature": CONFIG["temperatura"],"maxOutputTokens": CONFIG["max_tokens"],"topP": 0.95,}}
|
|
@@ -483,71 +264,58 @@ def chamar_api(prompt):
|
|
| 483 |
logger.debug(f"API Call - Tentativa {tentativa + 1}/{CONFIG['max_retry_attempts']}")
|
| 484 |
response = requests.post(GEMINI_API_URL, headers=headers, data=json.dumps(payload), timeout=CONFIG["timeout"])
|
| 485 |
logger.debug(f"API Response - Status: {response.status_code}")
|
| 486 |
-
|
| 487 |
if response.status_code == 429:
|
| 488 |
retry_after = int(response.headers.get("Retry-After", CONFIG["retry_delay"] * (tentativa + 1)))
|
| 489 |
-
logger.warning(f"Erro 429
|
| 490 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(retry_after); continue
|
| 491 |
-
else: return "❌ Erro 429: Muitas requisições.
|
| 492 |
-
|
| 493 |
if response.status_code != 200:
|
| 494 |
-
error_msg = "Erro
|
| 495 |
-
try:
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
except json.JSONDecodeError:
|
| 499 |
-
error_msg = f"Erro {response.status_code}: {response.text[:200]}" # Mostra início do erro não-JSON
|
| 500 |
-
logger.error(f"API Error (Status {response.status_code}): {error_msg}")
|
| 501 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 502 |
-
return f"❌ Erro
|
| 503 |
-
|
| 504 |
response_data = response.json()
|
| 505 |
-
|
| 506 |
if not response_data.get("candidates"):
|
| 507 |
prompt_feedback = response_data.get("promptFeedback", {})
|
| 508 |
block_reason = prompt_feedback.get("blockReason")
|
| 509 |
logger.error(f"API Response sem 'candidates'. Block Reason: {block_reason}")
|
| 510 |
-
if block_reason: return f"❌
|
| 511 |
-
else: return "❌ Resposta
|
| 512 |
-
|
| 513 |
candidate = response_data["candidates"][0]
|
| 514 |
finish_reason = candidate.get("finishReason")
|
| 515 |
-
|
| 516 |
if finish_reason and finish_reason not in ["STOP", "MAX_TOKENS", "FINISH_REASON_UNSPECIFIED"]:
|
| 517 |
-
logger.error(f"Geração
|
| 518 |
safety_ratings = candidate.get("safetyRatings", [])
|
| 519 |
harm_categories = [r['category'] for r in safety_ratings if r['probability'] not in ['NEGLIGIBLE', 'LOW']]
|
| 520 |
-
if harm_categories: return f"❌
|
| 521 |
-
else: return f"❌ Geração interrompida
|
| 522 |
-
|
| 523 |
if not candidate.get("content") or not candidate["content"].get("parts"):
|
| 524 |
-
logger.error("Estrutura
|
| 525 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 526 |
-
return "❌ Resposta
|
| 527 |
-
|
| 528 |
texto_gerado = candidate["content"]["parts"][0]["text"].strip()
|
| 529 |
-
logger.info(f"API retornou com sucesso ({len(texto_gerado)} chars). Finish
|
| 530 |
return texto_gerado
|
| 531 |
-
|
| 532 |
except requests.Timeout:
|
| 533 |
-
logger.warning(f"Timeout
|
| 534 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 535 |
-
return "⏱️ Tempo esgotado
|
| 536 |
except requests.RequestException as e:
|
| 537 |
-
logger.error(f"Erro
|
| 538 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 539 |
-
return f"❌ Erro
|
| 540 |
except json.JSONDecodeError as e:
|
| 541 |
-
logger.error(f"Erro
|
| 542 |
logger.debug(f"Resposta não-JSON: {response.text[:500]}")
|
| 543 |
-
return f"❌ Erro
|
| 544 |
except Exception as e:
|
| 545 |
-
logger.exception(f"Erro inesperado
|
| 546 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 547 |
-
return f"❌ Erro inesperado
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
return "❌ Falha ao comunicar com a API após múltiplas tentativas."
|
| 551 |
|
| 552 |
def corrigir_peticao(caso, tipo_peticao, peticao_texto=None, peticao_arquivo=None, modo_treinamento=False):
|
| 553 |
logger.info(f"Iniciando correção. Tipo={tipo_peticao}, Treinamento={modo_treinamento}")
|
|
@@ -555,60 +323,32 @@ def corrigir_peticao(caso, tipo_peticao, peticao_texto=None, peticao_arquivo=Non
|
|
| 555 |
analise_formatada, peticao_corrigida_final, resumo_diff, criticas_diff, diff_html = "", "", "", "", ""
|
| 556 |
peticao_conteudo = ""
|
| 557 |
try:
|
| 558 |
-
if not caso or not caso.strip():
|
| 559 |
-
|
| 560 |
-
return "⚠️ Forneça o caso/contexto da peça.", "", "", "", ""
|
| 561 |
-
if not tipo_peticao or tipo_peticao not in TIPOS_DE_PETICAO:
|
| 562 |
-
logger.warning(f"Tipo de petição inválido ou não fornecido: {tipo_peticao}")
|
| 563 |
-
return "⚠️ Selecione um tipo de petição válido.", "", "", "", ""
|
| 564 |
-
|
| 565 |
if peticao_arquivo is not None:
|
| 566 |
-
logger.info("Processando arquivo de petição...")
|
| 567 |
peticao_conteudo = process_file(peticao_arquivo)
|
| 568 |
-
if peticao_conteudo.startswith("❌"
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
elif peticao_texto and peticao_texto.strip():
|
| 572 |
-
peticao_conteudo = peticao_texto
|
| 573 |
-
else:
|
| 574 |
-
logger.warning("Nenhuma petição fornecida (texto ou arquivo).")
|
| 575 |
-
return "⚠️ Forneça a petição (em texto ou arquivo).", "", "", "", ""
|
| 576 |
logger.info(f"Petição recebida ({len(peticao_conteudo)} chars).")
|
| 577 |
-
|
| 578 |
troll_triggers = ["escreva a petição", "faça a petição", "redija a petição", "elabore a petição", "crie a petição", "gere a petição", "faça para mim", "faça por mim"]
|
| 579 |
if any(trigger in peticao_conteudo.lower() for trigger in troll_triggers):
|
| 580 |
logger.info("Detectado pedido para escrever petição.")
|
| 581 |
-
return random.choice([
|
| 582 |
-
"Hummm... Parece que você quer que *eu* faça o trabalho, né? 😉 Que tal você tentar escrever a peça e *eu* te ajudo a corrigir?",
|
| 583 |
-
"🚫 Opa! Meu trabalho é *corrigir* e *ensinar*, não fazer a peça do zero. Mostre o que você fez e eu te dou o feedback!",
|
| 584 |
-
]), "", "", "", ""
|
| 585 |
-
|
| 586 |
cache_key = f"{tipo_peticao}|{caso[:100]}|{peticao_conteudo[:100]}|{modo_treinamento}"
|
| 587 |
if cache_key in CORRECAO_CACHE:
|
| 588 |
logger.info("Correção encontrada no cache.")
|
| 589 |
-
|
| 590 |
-
return
|
| 591 |
-
|
| 592 |
-
logger.info("Estruturando prompt de análise...")
|
| 593 |
prompt_analise = estruturar_prompt_analise(caso, peticao_conteudo, tipo_peticao, modo_treinamento)
|
| 594 |
-
logger.info("Chamando API para análise...")
|
| 595 |
analise_bruta = chamar_api(prompt_analise)
|
| 596 |
-
if analise_bruta.startswith(("❌", "⏱️", "⚠️")):
|
| 597 |
-
logger.error(f"Erro retornado pela API (Análise): {analise_bruta}")
|
| 598 |
-
return analise_bruta, "", "", "", ""
|
| 599 |
-
logger.info("Análise recebida. Formatando...")
|
| 600 |
analise_formatada = formatar_correcao(analise_bruta)
|
| 601 |
-
|
| 602 |
-
logger.info("Estruturando prompt para peça corrigida...")
|
| 603 |
prompt_peticao = estruturar_prompt_peticao_corrigida(caso, peticao_conteudo, tipo_peticao)
|
| 604 |
-
logger.info("Chamando API para gerar peça corrigida...")
|
| 605 |
peticao_corrigida_bruta = chamar_api(prompt_peticao)
|
| 606 |
-
|
| 607 |
if peticao_corrigida_bruta.startswith(("❌", "⏱️", "⚠️")):
|
| 608 |
-
|
| 609 |
-
peticao_corrigida_final = f"⚠️ Falha ao gerar a versão corrigida:\n{peticao_corrigida_bruta}"
|
| 610 |
else:
|
| 611 |
-
logger.info("Peça corrigida recebida. Aplicando pós-correção...")
|
| 612 |
start_markers = ["excelentíssimo", "eméritos julgadores", "meritíssimo juízo"]
|
| 613 |
start_index = -1
|
| 614 |
peticao_lower_corr = peticao_corrigida_bruta.lower()
|
|
@@ -617,390 +357,268 @@ def corrigir_peticao(caso, tipo_peticao, peticao_texto=None, peticao_arquivo=Non
|
|
| 617 |
if idx != -1: start_index = idx; break
|
| 618 |
peticao_extraida = peticao_corrigida_bruta[start_index:] if start_index != -1 else peticao_corrigida_bruta
|
| 619 |
peticao_corrigida_final = pos_corrigir_peticao(peticao_extraida, tipo_peticao)
|
| 620 |
-
logger.info("Pós-correção aplicada.")
|
| 621 |
-
|
| 622 |
-
logger.info("Calculando diferenças...")
|
| 623 |
diff_html, resumo_diff, criticas_diff = calcular_diff_interno(peticao_conteudo, peticao_corrigida_final)
|
| 624 |
-
logger.info("Diferenças calculadas.")
|
| 625 |
-
|
| 626 |
resultado_cache = {"analise_formatada": analise_formatada,"peticao_corrigida": peticao_corrigida_final,"resumo_diff": resumo_diff,"criticas_diff": criticas_diff,"diff_html": diff_html}
|
| 627 |
CORRECAO_CACHE[cache_key] = resultado_cache
|
| 628 |
HISTORICO.append({"data": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),"tipo_peticao": tipo_peticao,"caso": caso,"peticao_original": peticao_conteudo,**resultado_cache})
|
| 629 |
if len(HISTORICO) > 10: HISTORICO.pop(0)
|
| 630 |
-
|
| 631 |
end_time = time.time()
|
| 632 |
logger.info(f"Correção concluída em {end_time - start_time:.2f} segundos.")
|
| 633 |
return analise_formatada, peticao_corrigida_final, resumo_diff, criticas_diff, diff_html
|
| 634 |
-
|
| 635 |
except Exception as e:
|
| 636 |
logger.exception("Erro GERAL inesperado dentro de corrigir_peticao:")
|
| 637 |
-
|
| 638 |
-
return error_message, "", "", "", ""
|
| 639 |
|
| 640 |
def formatar_correcao(texto):
|
| 641 |
texto = texto.replace("### Análise Geral", "## 📝 Análise Geral")
|
| 642 |
texto = texto.replace("### Nota Final", "## ⭐ Nota Final")
|
| 643 |
texto = texto.replace("### Pontos Positivos", "## ✅ Pontos Positivos")
|
| 644 |
texto = texto.replace("### Pontos a Melhorar", "## ⚠️ Pontos a Melhorar")
|
| 645 |
-
texto = texto.replace("### Análise Específica dos Requisitos", "## 🔎 Análise Específica
|
| 646 |
-
linhas = texto.split('\n')
|
| 647 |
-
linhas_formatadas = []
|
| 648 |
in_list = False
|
| 649 |
for linha in linhas:
|
| 650 |
-
|
| 651 |
-
if
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
prefix = " * " if in_list else "* "
|
| 656 |
-
linhas_formatadas.append(prefix + linha_strip[2:])
|
| 657 |
-
in_list = True
|
| 658 |
-
elif linha_strip.startswith(("a)","b)","c)","d)","e)")):
|
| 659 |
-
linhas_formatadas.append(f" * {linha_strip}")
|
| 660 |
-
in_list = True
|
| 661 |
-
else:
|
| 662 |
-
linhas_formatadas.append(linha)
|
| 663 |
-
if not linha_strip.startswith(("*", "- ", "a)", "b)", "c)", "d)", "e)"," ")):
|
| 664 |
-
in_list = False
|
| 665 |
texto_final = "\n".join(linhas_formatadas)
|
| 666 |
-
|
| 667 |
-
|
| 668 |
-
if match:
|
| 669 |
-
nota = match.group(2).replace(",",".")
|
| 670 |
-
texto_final = re.sub(nota_pattern, f"\\1**{nota}/10**", texto_final, count=1, flags=re.IGNORECASE)
|
| 671 |
return texto_final
|
| 672 |
|
| 673 |
def fornecer_dica_contextual(texto_peticao, tipo_peticao):
|
| 674 |
-
if not texto_peticao or not texto_peticao.strip():
|
| 675 |
-
return "*Digite algo na peça para receber dicas...*"
|
| 676 |
dicas_relevantes = []
|
| 677 |
texto_lower = texto_peticao.lower()
|
| 678 |
for chave in ["Clareza e Concisão", "Fundamentação Legal", "Revisão Ortográfica"]:
|
| 679 |
-
if chave in DICAS_OAB_MELHORADO:
|
| 680 |
-
dicas_relevantes.append(f"💡 **{chave}:** {DICAS_OAB_MELHORADO[chave]}")
|
| 681 |
keywords_por_tipo = {
|
| 682 |
-
"Petição Inicial": ["endereçamento",
|
| 683 |
-
"Contestação": ["preliminar",
|
| 684 |
-
"
|
| 685 |
-
"
|
| 686 |
-
"
|
| 687 |
-
"
|
| 688 |
-
"Agravo de Instrumento": ["interlocutória", "cabimento", "urgência", "efeito suspensivo", "art. 1015", "art. 1017"],
|
| 689 |
-
"Petição de Tutela Provisória": ["urgência", "evidência", "liminar", "periculum", "fumus boni", "art. 300", "art. 311"],
|
| 690 |
}
|
| 691 |
if tipo_peticao in keywords_por_tipo:
|
| 692 |
for chave, dica in DICAS_OAB_MELHORADO.items():
|
| 693 |
-
|
| 694 |
-
if f"({tipo_peticao.split()[0].lower()})" in
|
| 695 |
-
|
| 696 |
-
|
| 697 |
-
|
| 698 |
-
dicas_relevantes.append(dica_formatada)
|
| 699 |
-
if not dicas_relevantes:
|
| 700 |
-
return "*Continue escrevendo ou selecione o tipo de peça para dicas mais específicas.*"
|
| 701 |
return "\n\n".join(dicas_relevantes[:4])
|
| 702 |
|
| 703 |
def calcular_diff_interno(texto_original, texto_corrigido):
|
| 704 |
-
if not texto_original or not texto_corrigido or texto_corrigido.startswith(("⚠️","❌")):
|
| 705 |
-
|
| 706 |
-
orig_lines = texto_original.splitlines()
|
| 707 |
-
corr_lines = texto_corrigido.splitlines()
|
| 708 |
diff = difflib.ndiff(orig_lines, corr_lines)
|
| 709 |
-
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
linhas_adicionadas = 0
|
| 713 |
-
keywords_criticas_removidas = ["invenção", "identificação", "erro crasso", "incorreto", "prazo"]
|
| 714 |
-
keywords_criticas_adicionadas = ["custas", "art. 319", "art. 337", "art. 1022", "art. 1015", "art. 300", "fumus", "periculum", "essencial", "preliminar", "tempestividade", "cabimento"]
|
| 715 |
for linha in diff:
|
| 716 |
-
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
resumo_estatistico = f"**Resumo:**\n* Removidas: {linhas_removidas}\n* Adicionadas: {linhas_adicionadas}\n* **Saldo:** {linhas_adicionadas - linhas_removidas} linhas"
|
| 728 |
-
criticas_texto = "### 🚨 Mudanças Críticas / Essenciais:\n" + "\n".join(criticas) if criticas else "*Nenhuma mudança crítica/essencial detectada.*"
|
| 729 |
-
css = """<style>.diff-container { font-family: monospace; white-space: pre-wrap; border: 1px solid #ccc; padding: 10px; background-color: #f9f9f9; max-height: 600px; overflow-y: auto;} .linha-igual { color: #555; margin: 1px 0; } .linha-removida { background-color: #ffebee; color: #c62828; margin: 1px 0; } .linha-adicionada { background-color: #e8f5e9; color: #2e7d32; margin: 1px 0; } .linha-removida del, .linha-adicionada ins { text-decoration: none; padding: 0 2px; border-radius: 2px; } .linha-removida del { background-color: #ffcdd2; } .linha-adicionada ins { background-color: #c8e6c9; }</style>"""
|
| 730 |
-
visualizacao_detalhada_html = f"{css}<div class='diff-container'>{''.join(resultado_diff_html)}</div>"
|
| 731 |
-
return visualizacao_detalhada_html, resumo_estatistico, criticas_texto
|
| 732 |
|
| 733 |
def calcular_progresso():
|
| 734 |
-
if not HISTORICO: return "📊 Nenhum progresso
|
| 735 |
-
notas = []
|
| 736 |
-
tipos_corrigidos = set()
|
| 737 |
for entry in HISTORICO:
|
| 738 |
-
|
| 739 |
-
|
| 740 |
-
if
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
|
| 744 |
-
|
| 745 |
-
tendencia = ""
|
| 746 |
-
if len(notas) > 1:
|
| 747 |
-
if notas[-1] > notas[-2]: tendencia = "⬆️ Melhorando"
|
| 748 |
-
elif notas[-1] < notas[-2]: tendencia = "⬇️ Piorando"
|
| 749 |
-
else: tendencia = "↔️ Estável"
|
| 750 |
-
progresso_texto = f"**📊 Resumo:**\n* Correções: {total_corridas}\n* Tipos: {', '.join(sorted(list(tipos_corrigidos)))}\n* Média: {media:.1f}/10 ({len(notas)} válidas)\n* Tendência: {tendencia if tendencia else 'N/A'}"
|
| 751 |
-
return progresso_texto
|
| 752 |
|
| 753 |
def mostrar_historico():
|
| 754 |
if not HISTORICO: return "📜 Histórico vazio."
|
| 755 |
-
|
| 756 |
for i, entry in enumerate(reversed(HISTORICO)):
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
return historico_md
|
| 763 |
|
| 764 |
def salvar_progresso(caso, peticao, tipo_peticao):
|
| 765 |
-
logger.info("
|
| 766 |
try:
|
| 767 |
-
if not caso or not peticao or not tipo_peticao:
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
|
| 777 |
-
logger.info(f"Progresso salvo com sucesso em: {temp_file_path}")
|
| 778 |
-
success_message = f"✅ Progresso salvo! Baixe `{filename}`."
|
| 779 |
-
return json_content, success_message, temp_file_path
|
| 780 |
-
except Exception as e:
|
| 781 |
-
logger.error(f"Erro ao salvar progresso: {str(e)}", exc_info=True)
|
| 782 |
-
return "", f"❌ Erro ao salvar: {str(e)}", None
|
| 783 |
|
| 784 |
def carregar_progresso(arquivo_entrada):
|
| 785 |
-
logger.info("
|
| 786 |
-
if arquivo_entrada is None: return "", "", "", "⚠️ Nenhum arquivo
|
| 787 |
try:
|
| 788 |
-
|
| 789 |
-
logger.info(f"Carregando
|
| 790 |
-
with open(
|
| 791 |
-
caso = dados.get("caso")
|
| 792 |
-
|
| 793 |
-
|
| 794 |
-
|
| 795 |
-
|
| 796 |
-
|
| 797 |
-
if tipo_peticao not in TIPOS_DE_PETICAO:
|
| 798 |
-
logger.warning(f"Tipo de petição '{tipo_peticao}' do arquivo não é válido.")
|
| 799 |
-
return caso, peticao, "", f"⚠️ Tipo '{tipo_peticao}' inválido. Selecione manualmente."
|
| 800 |
-
logger.info("Progresso carregado com sucesso.")
|
| 801 |
-
return tipo_peticao, caso, peticao, "✅ Progresso carregado!"
|
| 802 |
-
except json.JSONDecodeError:
|
| 803 |
-
logger.error(f"Erro ao decodificar JSON do arquivo: {file_path}")
|
| 804 |
-
return "", "", "", "❌ Erro: Arquivo não é JSON válido."
|
| 805 |
-
except Exception as e:
|
| 806 |
-
logger.error(f"Erro ao carregar o progresso: {str(e)}", exc_info=True)
|
| 807 |
-
return "", "", "", f"❌ Erro inesperado ao carregar: {str(e)}"
|
| 808 |
|
| 809 |
def estruturar_prompt_geracao_caso(tipo_peticao="Petição Inicial"):
|
| 810 |
-
prompt = f""
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
|
| 818 |
-
"""
|
| 819 |
-
|
| 820 |
-
|
| 821 |
-
elif tipo_peticao == "Contestação":
|
| 822 |
-
prompt += """* **PRIMEIRO:** Resumo da Petição Inicial recebida pelo réu (autor, alegações, pedidos). * **DEPOIS:** Versão dos fatos do RÉU, incluindo informações para: Alegar preliminares; Impugnar fatos; Apresentar defesa de mérito (pagamento, prescrição, etc.). * Forneça dados qualificação réu."""
|
| 823 |
-
elif tipo_peticao == "Reconvenção":
|
| 824 |
-
prompt += """* Siga estrutura **Contestação**: Resumo Petição Inicial + Versão Réu. * **ADICIONE fatos/fundamentos** para RÉU fazer pedido PRÓPRIO contra AUTOR ORIGINAL (CONEXO com ação/defesa). * **Exemplo:** Cobrança -> Réu contesta e reconvém pedindo indenização por danos no mesmo negócio."""
|
| 825 |
-
elif tipo_peticao == "Impugnação à Contestação":
|
| 826 |
-
prompt += """* Resumo Petição Inicial do Autor. * **Resumo Contestação** do réu, destacando: Preliminares arguidas; Fatos novos (impeditivos/modificativos/extintivos); Documentos juntados. * Objetivo: fornecer elementos para Autor rebater contestação."""
|
| 827 |
-
elif tipo_peticao == "Embargos de Declaração":
|
| 828 |
-
prompt += """* Breve descrição caso original. * **Apresente DISPOSITIVO ou TRECHO FUNDAMENTAL de DECISÃO JUDICIAL** (sentença/acórdão). * **INDIQUE CLARAMENTE vício** (omissão, contradição, obscuridade, erro material) NESSA DECISÃO, dando contexto. * **Exemplo:** "Sentença julgou X, mas omissa quanto a Y." OU "Acórdão afirmou X e concluiu Y (contradição)." """
|
| 829 |
-
elif tipo_peticao == "Recurso de Apelação":
|
| 830 |
-
prompt += """* Descrição caso original. * **Resumo da SENTENÇA** (procedente/improcedente/parcial, fundamentos juiz). * **FORNEÇA ELEMENTOS indicando ERRO na sentença** (in judicando/in procedendo) que justifiquem reforma/anulação. * **Exemplo:** "Sentença ignorou prova X." OU "Juiz indeferiu testemunha chave Y (cerceamento)." * Indique cliente (apelante)."""
|
| 831 |
-
elif tipo_peticao == "Agravo de Instrumento":
|
| 832 |
-
prompt += """* Descrição caso em andamento. * **Apresente DECISÃO INTERLOCUTÓRIA específica**. * Decisão DEVE se enquadrar no Art. 1015 ou justificar mitigação. * **FORNEÇA ELEMENTOS indicando ERRO** na decisão E, se possível, **URGÊNCIA**. * **Exemplo:** "Juiz indeferiu JG apesar de prova." OU "Deferiu liminar sem comprovação mora." * Indique cliente (agravante)."""
|
| 833 |
-
elif tipo_peticao == "Petição de Tutela Provisória":
|
| 834 |
-
prompt += """* Situação de conflito com **urgência** (risco iminente) ou direito **evidente**. * **FORNEÇA ELEMENTOS claros demonstrando:** **Urgência:** Probabilidade do direito (fumus) E Perigo de dano (periculum). **Evidência:** Hipótese do Art. 311 (abuso defesa, repetitivo, etc.). * Indique medida específica desejada. * Especifique se antecedente ou incidental."""
|
| 835 |
-
else:
|
| 836 |
-
prompt += "* Crie cenário jurídico cível com conflito claro."
|
| 837 |
-
prompt += """
|
| 838 |
-
**Finalize o caso com:**
|
| 839 |
-
"**Situação-Problema:** Na qualidade de advogado(a) de [Nome do Cliente], elabore a peça processual cabível ({tipo_peticao})."
|
| 840 |
-
**Importante:** Evite casos muito específicos. Foque em temas comuns. Seja criativo!
|
| 841 |
-
"""
|
| 842 |
return prompt
|
| 843 |
|
| 844 |
def gerar_caso_ficticio(tipo_peticao="Petição Inicial"):
|
| 845 |
-
logger.info(f"
|
| 846 |
try:
|
| 847 |
-
if not tipo_peticao or tipo_peticao not in TIPOS_DE_PETICAO:
|
| 848 |
-
logger.warning(f"Tentativa de gerar caso com tipo inválido: {tipo_peticao}")
|
| 849 |
-
return "⚠️ Erro: Selecione um tipo de petição válido antes de gerar o caso."
|
| 850 |
-
logger.info("Estruturando prompt para geração de caso...")
|
| 851 |
prompt = estruturar_prompt_geracao_caso(tipo_peticao)
|
| 852 |
-
logger.info("Chamando API para gerar caso...")
|
| 853 |
caso_gerado = chamar_api(prompt)
|
| 854 |
-
if caso_gerado.startswith(("❌","⏱️","⚠️")):
|
| 855 |
-
|
| 856 |
-
|
| 857 |
-
|
| 858 |
-
|
| 859 |
-
|
| 860 |
-
|
| 861 |
-
|
| 862 |
-
caso_gerado += f"\n\n**Situação-Problema:** Na qualidade de advogado(a) de {cliente_nome}, elabore a peça processual cabível ({tipo_peticao})."
|
| 863 |
-
logger.info("Caso fictício gerado com sucesso.")
|
| 864 |
return caso_gerado
|
| 865 |
-
except Exception as e:
|
| 866 |
-
|
| 867 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 868 |
|
| 869 |
def interface_gradio():
|
| 870 |
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="orange")) as demo:
|
| 871 |
-
gr.Markdown("# ⚖️ Corretor Jurídico OAB Master ⚖️")
|
| 872 |
-
gr.Markdown("Analise e aprimore suas peças processuais!")
|
| 873 |
with gr.Row():
|
| 874 |
with gr.Column(scale=1):
|
| 875 |
gr.Markdown("### ⚙️ Configurações")
|
| 876 |
-
tipo_peticao_input = gr.Dropdown(label="1. Selecione o Tipo
|
| 877 |
modo_treinamento = gr.Checkbox(label="🎓 Modo Treinamento", value=False)
|
| 878 |
-
with gr.Accordion("🛠️ Opções Avançadas
|
| 879 |
-
temperatura_slider = gr.Slider(
|
| 880 |
-
timeout_slider = gr.Slider(
|
| 881 |
-
max_tokens_slider = gr.Slider(
|
| 882 |
config_update_btn = gr.Button("💾 Salvar Configs")
|
| 883 |
config_status = gr.Textbox(label="Status", interactive=False, lines=1)
|
| 884 |
with gr.Accordion("📊 Dashboard", open=False):
|
| 885 |
-
progresso_output = gr.Markdown("*Atualize para ver
|
| 886 |
progresso_btn = gr.Button("🔄 Atualizar Progresso")
|
| 887 |
with gr.Accordion("📜 Histórico", open=False):
|
| 888 |
-
historico_output = gr.Markdown("*Atualize para ver
|
| 889 |
historico_btn = gr.Button("🔄 Ver Histórico")
|
| 890 |
with gr.Accordion("💾📂 Salvar/Carregar", open=False):
|
| 891 |
-
salvar_btn = gr.Button("💾 Salvar
|
| 892 |
-
carregar_btn = gr.Button("📂 Carregar
|
| 893 |
-
arquivo_progresso_upload = gr.File(label="Selecione .json", file_types=[".json"]
|
| 894 |
progresso_download_file = gr.File(label="Baixar Progresso", interactive=False)
|
| 895 |
with gr.Column(scale=3):
|
| 896 |
-
gr.Markdown("### 1.
|
| 897 |
with gr.Row():
|
| 898 |
-
caso_input = gr.Textbox(label="📋 Caso
|
| 899 |
-
caso_btn = gr.Button("🎲 Gerar
|
| 900 |
-
gr.Markdown("### 2.
|
| 901 |
with gr.Tabs():
|
| 902 |
-
with gr.TabItem("✏️
|
| 903 |
-
peticao_texto_input = gr.Textbox(label="Texto da Peça", lines=12, placeholder="Cole ou digite
|
| 904 |
-
dica_contextual_output = gr.Markdown(
|
| 905 |
-
btn_corrigir = gr.Button("🚀 CORRIGIR
|
| 906 |
-
with gr.TabItem("📎
|
| 907 |
-
peticao_arquivo_input = gr.File(label="Arquivo (.pdf,
|
| 908 |
-
arquivo_preview_output = gr.Textbox(label="🔍 Prévia
|
| 909 |
-
btn_corrigir_arquivo = gr.Button("🚀 CORRIGIR
|
| 910 |
|
| 911 |
processing_message = gr.Markdown("", visible=False)
|
| 912 |
-
|
| 913 |
-
gr.Markdown("--- \n ### 3. Resultados da Correção")
|
| 914 |
with gr.Tabs():
|
| 915 |
-
with gr.TabItem("📊 Análise e Correção
|
| 916 |
-
resultado_analise_output = gr.Markdown(label="Análise
|
| 917 |
resultado_peticao_corrigida_output = gr.Textbox(label="✨ Versão Sugerida", lines=18, show_copy_button=True)
|
| 918 |
-
with gr.TabItem("⚖️ Comparativo
|
| 919 |
-
gr.Markdown("### ↔️ Comparativo
|
| 920 |
with gr.Row():
|
| 921 |
-
with gr.Column(scale=1):
|
| 922 |
-
|
| 923 |
-
|
| 924 |
-
with gr.Column(scale=3):
|
| 925 |
-
visualizacao_detalhada_output = gr.HTML(label="Alterações Detalhadas")
|
| 926 |
-
|
| 927 |
-
clear_btn = gr.Button("🗑️ Limpar Campos e Resultados")
|
| 928 |
|
| 929 |
-
|
| 930 |
-
|
| 931 |
-
).then(
|
| 932 |
fn=gerar_caso_ficticio, inputs=[tipo_peticao_input], outputs=[caso_input]
|
| 933 |
-
).then(
|
| 934 |
-
fn=lambda: gr.update(value="", visible=False), outputs=processing_message
|
| 935 |
-
)
|
| 936 |
|
| 937 |
-
peticao_texto_input.change(
|
| 938 |
-
tipo_peticao_input.change(
|
| 939 |
-
peticao_arquivo_input.change(
|
| 940 |
|
| 941 |
-
btn_corrigir.click(
|
| 942 |
-
fn=lambda: gr.update(value="⏳ Processando texto... Gerando análise e correção...", visible=True),
|
| 943 |
-
outputs=processing_message
|
| 944 |
-
).then(
|
| 945 |
fn=corrigir_peticao,
|
| 946 |
inputs=[caso_input, tipo_peticao_input, peticao_texto_input, gr.State(None), modo_treinamento],
|
| 947 |
-
outputs=[resultado_analise_output, resultado_peticao_corrigida_output,
|
| 948 |
-
resumo_alteracoes_output, criticas_output, visualizacao_detalhada_output],
|
| 949 |
concurrency_limit=1
|
| 950 |
-
).then(
|
| 951 |
-
fn=lambda: gr.update(value="", visible=False),
|
| 952 |
-
outputs=processing_message
|
| 953 |
-
)
|
| 954 |
|
| 955 |
-
btn_corrigir_arquivo.click(
|
| 956 |
-
fn=lambda: gr.update(value="⏳ Processando arquivo... Gerando análise e correção...", visible=True),
|
| 957 |
-
outputs=processing_message
|
| 958 |
-
).then(
|
| 959 |
fn=corrigir_peticao,
|
| 960 |
inputs=[caso_input, tipo_peticao_input, gr.State(None), peticao_arquivo_input, modo_treinamento],
|
| 961 |
-
outputs=[resultado_analise_output, resultado_peticao_corrigida_output,
|
| 962 |
-
resumo_alteracoes_output, criticas_output, visualizacao_detalhada_output],
|
| 963 |
concurrency_limit=1
|
| 964 |
-
).then(
|
| 965 |
-
fn=lambda: gr.update(value="", visible=False),
|
| 966 |
-
outputs=processing_message
|
| 967 |
-
)
|
| 968 |
|
| 969 |
-
config_update_btn.click(atualizar_config,
|
| 970 |
-
progresso_btn.click(
|
| 971 |
-
historico_btn.click(
|
| 972 |
|
| 973 |
-
salvar_btn.click(
|
| 974 |
-
fn=lambda: gr.update(value="⏳ Salvando...", visible=True), outputs=processing_message
|
| 975 |
-
).then(
|
| 976 |
fn=salvar_progresso, inputs=[caso_input, peticao_texto_input, tipo_peticao_input],
|
| 977 |
outputs=[gr.Textbox(visible=False), config_status, progresso_download_file]
|
| 978 |
-
).then(
|
| 979 |
-
|
| 980 |
-
).then(
|
| 981 |
-
lambda: gr.update(value="", visible=False), None, processing_message
|
| 982 |
-
)
|
| 983 |
|
| 984 |
-
carregar_btn.click(
|
| 985 |
-
fn=lambda: gr.update(value="⏳ Carregando...", visible=True), outputs=processing_message
|
| 986 |
-
).then(
|
| 987 |
fn=carregar_progresso, inputs=[arquivo_progresso_upload],
|
| 988 |
outputs=[tipo_peticao_input, caso_input, peticao_texto_input, config_status]
|
| 989 |
-
).then(
|
| 990 |
-
lambda: gr.update(value="", visible=False), None, processing_message
|
| 991 |
-
)
|
| 992 |
|
| 993 |
clear_btn.click(
|
| 994 |
-
fn=lambda: ["Petição Inicial", False, None, None, None, None, "*Dicas
|
| 995 |
-
outputs=[
|
| 996 |
-
|
| 997 |
-
|
| 998 |
-
|
| 999 |
-
resumo_alteracoes_output, criticas_output, visualizacao_detalhada_output,
|
| 1000 |
-
arquivo_progresso_upload, progresso_download_file, config_status
|
| 1001 |
-
]
|
| 1002 |
)
|
| 1003 |
-
|
| 1004 |
return demo
|
| 1005 |
|
| 1006 |
if __name__ == "__main__":
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
import gradio as gr
|
| 3 |
import requests
|
| 4 |
import os
|
|
|
|
| 95 |
ocr_text_parts.append(f"[Erro OCR Página {i+1}: {str(ocr_e)}]")
|
| 96 |
pdf_reader.close()
|
| 97 |
ocr_text = "\n".join(ocr_text_parts)
|
|
|
|
| 98 |
if text.strip() and len(text) > len(ocr_text) * 0.7:
|
| 99 |
logger.info(f"Usando texto extraído do PDF ({len(text)} chars).")
|
| 100 |
return text
|
|
|
|
| 133 |
content = file_path_or_obj.read()
|
| 134 |
else:
|
| 135 |
return "❌ Tipo de entrada TXT inválido."
|
|
|
|
| 136 |
encodings = ['utf-8', 'latin-1', 'cp1252']
|
| 137 |
for encoding in encodings:
|
| 138 |
try:
|
|
|
|
| 166 |
return "⚠️ Arquivo muito grande (Máx 15MB)."
|
| 167 |
except OSError as size_e:
|
| 168 |
logger.warning(f"Não foi possível verificar o tamanho do arquivo: {size_e}")
|
| 169 |
+
if filename.endswith('.pdf'): return extract_text_from_pdf(file_path)
|
| 170 |
+
elif filename.endswith('.docx'): return extract_text_from_docx(file_path)
|
| 171 |
+
elif filename.endswith('.txt'): return extract_text_from_txt(file_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
else:
|
| 173 |
logger.warning(f"Formato de arquivo não suportado: {filename}")
|
| 174 |
return "⚠️ Formato de arquivo não suportado. Use PDF, DOCX ou TXT."
|
|
|
|
| 179 |
def get_instrucoes_gerais_avaliacao(modo_treinamento=False):
|
| 180 |
base = """
|
| 181 |
**Estrutura da Avaliação:**
|
| 182 |
+
1. **Análise Geral:** Visão geral concisa (2-3 linhas).
|
| 183 |
+
2. **Nota Final:** 0 a 10 (uma casa decimal), com justificativa BREVE.
|
| 184 |
+
3. **Pontos Positivos:** Liste 2-3 aspectos bem executados, com justificativa.
|
| 185 |
+
4. **Pontos a Melhorar:** Liste **TODOS** os problemas em ordem de gravidade. Para cada: Descrição, Fundamentação legal, Impacto na nota, Sugestão.
|
| 186 |
+
5. **Análise Específica dos Requisitos:** Avalie os itens chave da peça.
|
| 187 |
+
**Critérios Fundamentais:** Coerência, Fundamentação, Linguagem, Pedidos. **NÃO INVENTAR FATOS** (-3 a -5). **NÃO SE IDENTIFICAR** (Nota ZERO)."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
if modo_treinamento:
|
| 189 |
base += """
|
| 190 |
+
**Modo de Treinamento:** Para cada Ponto a Melhorar: a) Explicação aprofundada. b) Base legal. c) Exemplo Redação Corrigida. d) Dica prática. e) Estratégia alternativa. Destaque inconsistências. Sugira estratégias adicionais."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
return base
|
| 192 |
|
| 193 |
def estruturar_prompt_analise(caso, peticao, tipo_peticao, modo_treinamento=False):
|
| 194 |
instrucoes_gerais = get_instrucoes_gerais_avaliacao(modo_treinamento)
|
| 195 |
+
prompt_especifico = f"## Análise: {tipo_peticao}\n**Caso:**\n```\n{caso}\n```\n**Peça Aluno:**\n```\n{peticao}\n```\n{instrucoes_gerais}\n**Requisitos Específicos ({tipo_peticao}):**\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
if tipo_peticao == "Petição Inicial":
|
| 197 |
+
prompt_especifico += "- Endereçamento/competência (Art. 319, I; CDC 101, I).\n- Qualificação (Art. 319, II).\n- Fatos.\n- Fundamentação (Art. 319, III).\n- Pedidos (Art. 319, IV).\n- Valor causa (Art. 291-292, 319, V).\n- Provas (Art. 319, VI).\n- Audiência (Art. 319, VII).\n- Citação.\n- Docs essenciais (procuração, custas/JG).\n- Fechamento.\n**Critérios Adicionais:** Usar 'XXX'. Falta custas/JG (-1.0). Vírgula em 'pede deferimento' (-0.2). Foro consumidor OK."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
elif tipo_peticao == "Contestação":
|
| 199 |
+
prompt_especifico += "- Endereçamento. Qualificação réu. Processo nº. Tempestividade.\n- **Preliminares (Art. 337):** TODAS aplicáveis.\n- **Impugnação Específica Fatos (Art. 341):** PONTO A PONTO.\n- **Mérito:** Versão réu; defesa direta/indireta (fatos impeditivos/modificativos/extintivos).\n- Fundamentação defesa.\n- **Pedidos:** Acolher preliminares; IMPROCEDÊNCIA TOTAL; Condenação sucumbência (Art. 85).\n- Provas. Fechamento.\n**Critérios Adicionais:** Preliminar não arguida preclui? Falha grave impugnação (-2 a -4). Ausência pedido improcedência (-1.5)."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
elif tipo_peticao == "Reconvenção":
|
| 201 |
+
prompt_especifico += "- NA MESMA PEÇA da Contestação (Art. 343). Endereçamento. Processo nº.\n- Qualificação réu-reconvinte e autor-reconvindo.\n- **Conexão** (Art. 343).\n- **Estrutura PI:** Fatos, Fundamentos, Pedidos específicos, Valor causa, Provas (da reconvenção).\n- Pedido intimação autor-reconvindo (Art. 343, §1º).\n**Critérios Adicionais:** Sem conexão (-2.0). Falta pedido/valor/provas reconv. (-1.0/item). Peça separada (-3.0)."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
elif tipo_peticao == "Impugnação à Contestação":
|
| 203 |
+
prompt_especifico += "- Endereçamento. Processo nº. Qualificação autor. Tempestividade (15d - Art. 350/351).\n- **Resposta Preliminares.**\n- **Resposta Fatos Novos** (Art. 350).\n- **Resposta Documentos** (Art. 437).\n- **Ratificação Inicial.**\n- **Especificação Provas** (contra defesa indireta/preliminares).\n- Pedidos: Rejeitar preliminares; refutar defesa; proceder inicial.\n**Critérios Adicionais:** Não responder preliminar (-1.5). Não manifestar fato novo (-2.0). Não ratificar (-0.5)."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 204 |
elif tipo_peticao == "Embargos de Declaração":
|
| 205 |
+
prompt_especifico += "- **Contra Decisão Específica.** Endereçamento ao juízo prolator. Processo nº. Partes. Tempestividade (5d - Art. 1023).\n- **Cabimento (Art. 1022):** Apontar PRECISAMENTE: Omissão, Contradição, Obscuridade ou Erro Material.\n- **NÃO REJULGAR CAUSA.**\n- **Pedido:** Conhecimento e ACOLHIMENTO para sanar vício.\n**Critérios Adicionais:** Rediscutir mérito (-4.0). Não apontar vício (-3.0). Endereçar tribunal (-1.0)."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
elif tipo_peticao == "Recurso de Apelação":
|
| 207 |
+
prompt_especifico += "- **Interposição:** Ao juízo a quo. Processo nº. Partes. Pressupostos (cabimento Art. 1009; tempestividade 15d; preparo/JG). Pedido recebimento/remessa.\n- **Razões:** Ao TRIBUNAL. Relato. **Fundamentos Reforma/Anulação (Art. 1010):** Error in procedendo/judicando. **Dialeticidade.**\n- **Pedidos:** Conhecimento; PROVIMENTO (anular/reformar); Inversão sucumbência.\n**Critérios Adicionais:** Falta peça (-10). Endereço razões (-1.0). Sem dialeticidade (-3 a -5). Sem pedido reforma/anulação (-1.5). Falta preparo/JG (-2.0)."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
elif tipo_peticao == "Agravo de Instrumento":
|
| 209 |
+
prompt_especifico += "- Peça única ao TRIBUNAL. Processo origem. Partes e Advogados (endereços Art. 1016, IV). Cópia decisão agravada (Art. 1017, I).\n- **Cabimento (Art. 1015 / mitigada).** Tempestividade (15d). Preparo/JG.\n- **Peças Obrigatórias (Art. 1017, I):** Decisão, Intimação, Procurações. Facultativas (III).\n- **Razões (Art. 1016):** Motivos reforma/invalidação.\n- **Efeito Suspensivo / Tutela Antecipada Recursal (Art. 1019, I)** (se risco).\n- **Pedidos Finais:** Conhecimento; Efeito/Tutela (se aplicável); PROVIMENTO; Comunicação juiz.\n**Critérios Adicionais:** Falta peça obrigatória (-4.0). Sem cabimento (-3.0). Endereço juiz (-1.0). Sem advogados (-0.5)."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
elif tipo_peticao == "Petição de Tutela Provisória":
|
| 211 |
+
prompt_especifico += "- Tipo (Urgência/Evidência). Caráter (Antecedente/Incidental). Endereçamento. Qualificação. Processo (se incidental).\n- **Tutela Urgência (Art. 300):** **Fumus Boni Iuris** E **Periculum in Mora**. **Reversibilidade** (Art. 300, §3º).\n- **Tutela Evidência (Art. 311):** Hipótese I a IV. **NÃO precisa periculum.**\n- **Pedido Específico:** Medida liminar CLARA.\n- **Se Antecedente (Art. 303/305):** Indicar pedido final ou aditar/apresentar inicial. Valor Causa.\n- **Pedidos:** Concessão tutela; citação/intimação; indicação ação/aditamento.\n**Critérios Adicionais:** Sem Fumus/Periculum (-3 a -5). Erro hipótese Evidência (-3.0). Pedido genérico (-2.0)."
|
| 212 |
+
else: prompt_especifico += "- Adequação ao tipo? Clareza? Fundamentação Mínima? Pedido?"
|
| 213 |
+
prompt_especifico += "\n\n**Instruções Finais:** Analise estritamente com base no caso e critérios. Seja rigoroso mas construtivo. Gere **exclusivamente** no formato solicitado."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
return prompt_especifico
|
| 215 |
|
| 216 |
def estruturar_prompt_peticao_corrigida(caso, peticao_original, tipo_peticao):
|
| 217 |
+
prompt = f"**Caso:**\n```\n{caso}\n```\n**Peça Original ({tipo_peticao}):**\n```\n{peticao_original}\n```\n**Tarefa:** Gere versão corrigida da peça ({tipo_peticao}), seguindo rigorosamente práticas OAB.\n**Instruções Específicas ({tipo_peticao}):**\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
if tipo_peticao == "Petição Inicial":
|
| 219 |
+
prompt += "1.Endereçamento correto/fundamentado. 2.Qualificação completa (Art.319,II,'XXX'). 3.Fatos cronológicos/fiéis. 4.Fundamentação (artigos, súmulas). 5.Pedidos certos/determinados (quantificar). 6.Valor causa (Art.292). 7.Provas ('protesta provar...'). 8.Audiência (Art.319,VII). 9.Citação (Art.246,I). 10.Custas/JG (NÃO OMITIR). 11.Fechamento ('Nestes termos pede deferimento.', Local, data., ADVOGADO(A), OAB/...). NUNCA identificar."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
elif tipo_peticao == "Contestação":
|
| 221 |
+
prompt += "1.Endereçamento juízo ação. 2.Identificação (proc. nº, réu). 3.Tempestividade. 4.Estrutura: Síntese Inicial; Preliminares (Art.337, fund.); Mérito (Impug. Específica + Defesa fund.); Reconvenção (se houver, antes pedidos cont.). 5.Pedidos Cont.: Acolher prelim.; IMPROCEDÊNCIA TOTAL; Sucumbência. 6.Provas réu. 7.Fechamento OAB."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
elif tipo_peticao == "Reconvenção":
|
| 223 |
+
prompt += "**IMPORTANTE:** Gere como parte da Contestação.\n1.Após defesa mérito cont., ANTES pedidos cont.: Tópico 'DA RECONVENÇÃO'. 2.Qualificação Reconvinte/Reconvindo. 3.Conexão. 4.Fatos e Direito Reconvencionais. 5.Pedidos Reconv.: Claros contra autor-reconvindo. 6.Valor Causa e Provas Reconv. 7.Intimação autor-reconvindo. 8.Continue com Pedidos Contestação. 9.Fechamento OAB."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
elif tipo_peticao == "Impugnação à Contestação":
|
| 225 |
+
prompt += "1.Endereçamento, proc, autor, tempestividade. 2.Tópico: DA(S) PRELIMINAR(ES) - Rebater. 3.Tópico: DO MÉRITO E FATOS NOVOS - Manifestar. 4.Tópico: DA RATIFICAÇÃO INICIAL. 5.Tópico: DAS PROVAS - Especificar. 6.Pedidos: Rejeitar prelim., refutar defesa, proceder inicial. 7.Fechamento OAB."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
elif tipo_peticao == "Embargos de Declaração":
|
| 227 |
+
prompt += "1.Endereçamento juízo prolator. Proc, Partes. Decisão embargada ID. Tempestividade (5d). 2.Tópico para cada vício (Art.1022): DA OMISSÃO/CONTRADIÇÃO/OBSCURIDADE/ERRO MATERIAL. 3.Dentro: Transcrever trecho + explicar vício OBJETIVAMENTE. NÃO REJULGAR. 4.Pedido: Conhecimento e ACOLHIMENTO p/ sanar vício(s). 5.Fechamento OAB."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
elif tipo_peticao == "Recurso de Apelação":
|
| 229 |
+
prompt += "1.Interposição: Juízo a quo. Proc, Partes. Pressupostos (cabim., temp., prep./JG). Pedido receb./remessa. 2.Razões: Tribunal. Relato. FUNDAMENTOS REFORMA/ANULAÇÃO (Error in proc./judic.). DIALETICIDADE. 3.Pedidos: Conhec.; PROVIMENTO (anular/reformar); Inversão sucumb. 4.Fechamento OAB."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
elif tipo_peticao == "Agravo de Instrumento":
|
| 231 |
+
prompt += "1.Peça única Tribunal. Proc. origem, Partes, Advogados (endereços). Decisão agravada ID (juntar cópia). 2.CABIMENTO (Art.1015/mitig.). TEMPESTIVIDADE. PREPARO/JG. PEÇAS OBRIG./FACULT. 3.RAZÕES RECURSAIS: Motivos reforma/invalidação. 4.EFEITO SUSPENSIVO/TUTELA ANTECIPADA (se cabível). 5.PEDIDOS: Conhec.; Efeito/Tutela; PROVIMENTO; Comunicação juiz. 6.Fechamento OAB."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
elif tipo_peticao == "Petição de Tutela Provisória":
|
| 233 |
+
prompt += "1.Indicar TIPO(Urg/Evid) e CARÁTER(Antec/Incid). Endereç. Qualif. Proc(se incid). 2.REQUISITOS: Urgência=Fumus+Periculum(+Reversib.). Evidência=Hipótese Art.311. 3.PEDIDO LIMINAR: Medida CLARA. 4.Se Antec.: Indicar pedido final/aditar. Valor Causa. 5.PEDIDOS: Concessão tutela; citação/intim.; indic. ação/adit. 6.Fechamento OAB."
|
| 234 |
+
else: prompt += "1.Estrutura Lógica. 2.Argumentos Claros. 3.Pedido Claro. 4.Formalidades OAB."
|
| 235 |
+
prompt += "\n\n**Instrução Final:** Gere **APENAS** o texto completo da peça corrigida abaixo, começando pelo endereçamento e terminando com 'OAB/...'. Sem comentários extras."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
return prompt
|
| 237 |
|
| 238 |
def pos_corrigir_peticao(peticao_corrigida, tipo_peticao):
|
|
|
|
| 242 |
peticao_lower = peticao_corrigida.lower()
|
| 243 |
if "juntada da guia de custas" not in peticao_lower and "gratuidade de justiça" not in peticao_lower:
|
| 244 |
partes = peticao_corrigida.split("Nestes termos pede deferimento")
|
| 245 |
+
if len(partes) == 2: peticao_corrigida = partes[0].strip() + "\nRequer, ainda, a juntada da guia de custas devidamente recolhida.\nNestes termos pede deferimento" + partes[1]
|
| 246 |
+
else: peticao_corrigida = peticao_corrigida.replace("Local, data.", "Requer, ainda, a juntada da guia de custas devidamente recolhida.\n\nLocal, data.")
|
|
|
|
|
|
|
| 247 |
if "audiência de conciliação" not in peticao_lower and "audiência de mediação" not in peticao_lower:
|
| 248 |
partes = peticao_corrigida.split("Nestes termos pede deferimento")
|
| 249 |
+
if len(partes) == 2: peticao_corrigida = partes[0].strip() + "\nOpta o Autor pela realização da audiência de conciliação ou mediação (Art. 319, VII, CPC).\nNestes termos pede deferimento" + partes[1]
|
| 250 |
+
else: peticao_corrigida = peticao_corrigida.replace("Local, data.", "Opta o Autor pela realização da audiência de conciliação ou mediação (Art. 319, VII, CPC).\n\nLocal, data.")
|
|
|
|
|
|
|
|
|
|
| 251 |
linhas = [l.strip() for l in peticao_corrigida.strip().split('\n') if l.strip()]
|
| 252 |
fechamento_padrao = ["Local, data.", "ADVOGADO(A)", "OAB/..."]
|
| 253 |
+
while linhas and any(term in linhas[-1] for term in ["ADVOGADO", "OAB", "Local", "data"]): linhas.pop()
|
|
|
|
| 254 |
linhas.extend(fechamento_padrao)
|
| 255 |
+
return "\n".join(linhas)
|
|
|
|
| 256 |
|
| 257 |
def chamar_api(prompt):
|
| 258 |
payload = {"contents": [{"parts": [{"text": prompt}]}],"generationConfig": {"temperature": CONFIG["temperatura"],"maxOutputTokens": CONFIG["max_tokens"],"topP": 0.95,}}
|
|
|
|
| 264 |
logger.debug(f"API Call - Tentativa {tentativa + 1}/{CONFIG['max_retry_attempts']}")
|
| 265 |
response = requests.post(GEMINI_API_URL, headers=headers, data=json.dumps(payload), timeout=CONFIG["timeout"])
|
| 266 |
logger.debug(f"API Response - Status: {response.status_code}")
|
|
|
|
| 267 |
if response.status_code == 429:
|
| 268 |
retry_after = int(response.headers.get("Retry-After", CONFIG["retry_delay"] * (tentativa + 1)))
|
| 269 |
+
logger.warning(f"Erro 429. Aguardando {retry_after}s...")
|
| 270 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(retry_after); continue
|
| 271 |
+
else: return "❌ Erro 429: Muitas requisições."
|
|
|
|
| 272 |
if response.status_code != 200:
|
| 273 |
+
error_msg = f"Erro {response.status_code}"
|
| 274 |
+
try: error_msg = response.json().get("error", {}).get("message", error_msg)
|
| 275 |
+
except json.JSONDecodeError: error_msg = f"Erro {response.status_code}: {response.text[:200]}"
|
| 276 |
+
logger.error(f"API Error: {error_msg}")
|
|
|
|
|
|
|
|
|
|
| 277 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 278 |
+
return f"❌ Erro API ({response.status_code}): {error_msg}"
|
|
|
|
| 279 |
response_data = response.json()
|
|
|
|
| 280 |
if not response_data.get("candidates"):
|
| 281 |
prompt_feedback = response_data.get("promptFeedback", {})
|
| 282 |
block_reason = prompt_feedback.get("blockReason")
|
| 283 |
logger.error(f"API Response sem 'candidates'. Block Reason: {block_reason}")
|
| 284 |
+
if block_reason: return f"❌ Bloqueado pela API: {block_reason}."
|
| 285 |
+
else: return "❌ Resposta API vazia (sem 'candidates')."
|
|
|
|
| 286 |
candidate = response_data["candidates"][0]
|
| 287 |
finish_reason = candidate.get("finishReason")
|
|
|
|
| 288 |
if finish_reason and finish_reason not in ["STOP", "MAX_TOKENS", "FINISH_REASON_UNSPECIFIED"]:
|
| 289 |
+
logger.error(f"Geração API interrompida: {finish_reason}")
|
| 290 |
safety_ratings = candidate.get("safetyRatings", [])
|
| 291 |
harm_categories = [r['category'] for r in safety_ratings if r['probability'] not in ['NEGLIGIBLE', 'LOW']]
|
| 292 |
+
if harm_categories: return f"❌ Bloqueado por segurança: {finish_reason} ({','.join(harm_categories)})."
|
| 293 |
+
else: return f"❌ Geração interrompida: {finish_reason}."
|
|
|
|
| 294 |
if not candidate.get("content") or not candidate["content"].get("parts"):
|
| 295 |
+
logger.error("Estrutura resposta API inesperada.")
|
| 296 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 297 |
+
return "❌ Resposta API inválida (estrutura)."
|
|
|
|
| 298 |
texto_gerado = candidate["content"]["parts"][0]["text"].strip()
|
| 299 |
+
logger.info(f"API retornou com sucesso ({len(texto_gerado)} chars). Finish: {finish_reason}")
|
| 300 |
return texto_gerado
|
|
|
|
| 301 |
except requests.Timeout:
|
| 302 |
+
logger.warning(f"Timeout API - Tentativa {tentativa + 1}.")
|
| 303 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 304 |
+
return "⏱️ Tempo esgotado API."
|
| 305 |
except requests.RequestException as e:
|
| 306 |
+
logger.error(f"Erro Rede/Requisição API - Tentativa {tentativa + 1}: {e}")
|
| 307 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 308 |
+
return f"❌ Erro conexão API: {e}"
|
| 309 |
except json.JSONDecodeError as e:
|
| 310 |
+
logger.error(f"Erro JSON API: {e}")
|
| 311 |
logger.debug(f"Resposta não-JSON: {response.text[:500]}")
|
| 312 |
+
return f"❌ Erro processar resposta API (JSON inválido)."
|
| 313 |
except Exception as e:
|
| 314 |
+
logger.exception(f"Erro inesperado API - Tentativa {tentativa + 1}: {str(e)}")
|
| 315 |
if tentativa < CONFIG["max_retry_attempts"] - 1: time.sleep(CONFIG['retry_delay'] * (tentativa + 1)); continue
|
| 316 |
+
return f"❌ Erro inesperado API: {str(e)}"
|
| 317 |
+
logger.error("Falha API após todas as tentativas.")
|
| 318 |
+
return "❌ Falha API após múltiplas tentativas."
|
|
|
|
| 319 |
|
| 320 |
def corrigir_peticao(caso, tipo_peticao, peticao_texto=None, peticao_arquivo=None, modo_treinamento=False):
|
| 321 |
logger.info(f"Iniciando correção. Tipo={tipo_peticao}, Treinamento={modo_treinamento}")
|
|
|
|
| 323 |
analise_formatada, peticao_corrigida_final, resumo_diff, criticas_diff, diff_html = "", "", "", "", ""
|
| 324 |
peticao_conteudo = ""
|
| 325 |
try:
|
| 326 |
+
if not caso or not caso.strip(): return "⚠️ Forneça o caso.", "", "", "", ""
|
| 327 |
+
if not tipo_peticao or tipo_peticao not in TIPOS_DE_PETICAO: return "⚠️ Selecione tipo.", "", "", "", ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
if peticao_arquivo is not None:
|
|
|
|
| 329 |
peticao_conteudo = process_file(peticao_arquivo)
|
| 330 |
+
if peticao_conteudo.startswith(("❌", "⚠️")): return peticao_conteudo, "", "", "", ""
|
| 331 |
+
elif peticao_texto and peticao_texto.strip(): peticao_conteudo = peticao_texto
|
| 332 |
+
else: return "⚠️ Forneça a petição.", "", "", "", ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 333 |
logger.info(f"Petição recebida ({len(peticao_conteudo)} chars).")
|
|
|
|
| 334 |
troll_triggers = ["escreva a petição", "faça a petição", "redija a petição", "elabore a petição", "crie a petição", "gere a petição", "faça para mim", "faça por mim"]
|
| 335 |
if any(trigger in peticao_conteudo.lower() for trigger in troll_triggers):
|
| 336 |
logger.info("Detectado pedido para escrever petição.")
|
| 337 |
+
return random.choice(["Hummm... 😉", "🚫 Opa! Corrijo, não crio."]), "", "", "", ""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 338 |
cache_key = f"{tipo_peticao}|{caso[:100]}|{peticao_conteudo[:100]}|{modo_treinamento}"
|
| 339 |
if cache_key in CORRECAO_CACHE:
|
| 340 |
logger.info("Correção encontrada no cache.")
|
| 341 |
+
cached = CORRECAO_CACHE[cache_key]
|
| 342 |
+
return cached["analise_formatada"], cached["peticao_corrigida"], cached["resumo_diff"], cached["criticas_diff"], cached["diff_html"]
|
|
|
|
|
|
|
| 343 |
prompt_analise = estruturar_prompt_analise(caso, peticao_conteudo, tipo_peticao, modo_treinamento)
|
|
|
|
| 344 |
analise_bruta = chamar_api(prompt_analise)
|
| 345 |
+
if analise_bruta.startswith(("❌", "⏱️", "⚠️")): return analise_bruta, "", "", "", ""
|
|
|
|
|
|
|
|
|
|
| 346 |
analise_formatada = formatar_correcao(analise_bruta)
|
|
|
|
|
|
|
| 347 |
prompt_peticao = estruturar_prompt_peticao_corrigida(caso, peticao_conteudo, tipo_peticao)
|
|
|
|
| 348 |
peticao_corrigida_bruta = chamar_api(prompt_peticao)
|
|
|
|
| 349 |
if peticao_corrigida_bruta.startswith(("❌", "⏱️", "⚠️")):
|
| 350 |
+
peticao_corrigida_final = f"⚠️ Falha ao gerar versão corrigida:\n{peticao_corrigida_bruta}"
|
|
|
|
| 351 |
else:
|
|
|
|
| 352 |
start_markers = ["excelentíssimo", "eméritos julgadores", "meritíssimo juízo"]
|
| 353 |
start_index = -1
|
| 354 |
peticao_lower_corr = peticao_corrigida_bruta.lower()
|
|
|
|
| 357 |
if idx != -1: start_index = idx; break
|
| 358 |
peticao_extraida = peticao_corrigida_bruta[start_index:] if start_index != -1 else peticao_corrigida_bruta
|
| 359 |
peticao_corrigida_final = pos_corrigir_peticao(peticao_extraida, tipo_peticao)
|
|
|
|
|
|
|
|
|
|
| 360 |
diff_html, resumo_diff, criticas_diff = calcular_diff_interno(peticao_conteudo, peticao_corrigida_final)
|
|
|
|
|
|
|
| 361 |
resultado_cache = {"analise_formatada": analise_formatada,"peticao_corrigida": peticao_corrigida_final,"resumo_diff": resumo_diff,"criticas_diff": criticas_diff,"diff_html": diff_html}
|
| 362 |
CORRECAO_CACHE[cache_key] = resultado_cache
|
| 363 |
HISTORICO.append({"data": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),"tipo_peticao": tipo_peticao,"caso": caso,"peticao_original": peticao_conteudo,**resultado_cache})
|
| 364 |
if len(HISTORICO) > 10: HISTORICO.pop(0)
|
|
|
|
| 365 |
end_time = time.time()
|
| 366 |
logger.info(f"Correção concluída em {end_time - start_time:.2f} segundos.")
|
| 367 |
return analise_formatada, peticao_corrigida_final, resumo_diff, criticas_diff, diff_html
|
|
|
|
| 368 |
except Exception as e:
|
| 369 |
logger.exception("Erro GERAL inesperado dentro de corrigir_peticao:")
|
| 370 |
+
return f"❌ Erro inesperado correção: {str(e)}", "", "", "", ""
|
|
|
|
| 371 |
|
| 372 |
def formatar_correcao(texto):
|
| 373 |
texto = texto.replace("### Análise Geral", "## 📝 Análise Geral")
|
| 374 |
texto = texto.replace("### Nota Final", "## ⭐ Nota Final")
|
| 375 |
texto = texto.replace("### Pontos Positivos", "## ✅ Pontos Positivos")
|
| 376 |
texto = texto.replace("### Pontos a Melhorar", "## ⚠️ Pontos a Melhorar")
|
| 377 |
+
texto = texto.replace("### Análise Específica dos Requisitos", "## 🔎 Análise Específica")
|
| 378 |
+
linhas = texto.split('\n'); linhas_formatadas = []
|
|
|
|
| 379 |
in_list = False
|
| 380 |
for linha in linhas:
|
| 381 |
+
ls = linha.strip()
|
| 382 |
+
if ls.startswith(("1.","2.","3.","4.","5.")): linhas_formatadas.append(f"\n**{ls}**"); in_list = False
|
| 383 |
+
elif ls.startswith(("- ","* ")): prefix = " * " if in_list else "* "; linhas_formatadas.append(prefix + ls[2:]); in_list = True
|
| 384 |
+
elif ls.startswith(("a)","b)","c)","d)","e)")): linhas_formatadas.append(f" * {ls}"); in_list = True
|
| 385 |
+
else: linhas_formatadas.append(linha); in_list = False if not ls.startswith(("*","- ","a)","b)","c)","d)","e)"," ")) else in_list
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 386 |
texto_final = "\n".join(linhas_formatadas)
|
| 387 |
+
m = re.search(r"(\*\*Nota Final:?\*\*\s*)(\d{1,2}[,.]\d{1}|\d{1,2})", texto_final, re.I)
|
| 388 |
+
if m: nota = m.group(2).replace(",","."); texto_final = re.sub(r"(\*\*Nota Final:?\*\*\s*)(\d{1,2}[,.]\d{1}|\d{1,2})", f"\\1**{nota}/10**", texto_final, count=1, flags=re.I)
|
|
|
|
|
|
|
|
|
|
| 389 |
return texto_final
|
| 390 |
|
| 391 |
def fornecer_dica_contextual(texto_peticao, tipo_peticao):
|
| 392 |
+
if not texto_peticao or not texto_peticao.strip(): return "*Digite para dicas...*"
|
|
|
|
| 393 |
dicas_relevantes = []
|
| 394 |
texto_lower = texto_peticao.lower()
|
| 395 |
for chave in ["Clareza e Concisão", "Fundamentação Legal", "Revisão Ortográfica"]:
|
| 396 |
+
if chave in DICAS_OAB_MELHORADO: dicas_relevantes.append(f"💡 **{chave}:** {DICAS_OAB_MELHORADO[chave]}")
|
|
|
|
| 397 |
keywords_por_tipo = {
|
| 398 |
+
"Petição Inicial": ["endereçamento","qualificação","fatos","fundamentos","pedidos","valor","provas","audiência","citação","custas"],
|
| 399 |
+
"Contestação": ["preliminar","mérito","impugnação","improcedência","honorários","art. 337","art. 341"],
|
| 400 |
+
"Embargos de Declaração": ["omissão","contradição","obscuridade","erro material","art. 1022"],
|
| 401 |
+
"Recurso de Apelação": ["sentença","reforma","anulação","dialeticidade","preparo","tribunal","art. 1009"],
|
| 402 |
+
"Agravo de Instrumento": ["interlocutória","cabimento","urgência","efeito suspensivo","art. 1015"],
|
| 403 |
+
"Petição de Tutela Provisória": ["urgência","evidência","liminar","periculum","fumus boni","art. 300"],
|
|
|
|
|
|
|
| 404 |
}
|
| 405 |
if tipo_peticao in keywords_por_tipo:
|
| 406 |
for chave, dica in DICAS_OAB_MELHORADO.items():
|
| 407 |
+
cl = chave.lower()
|
| 408 |
+
if f"({tipo_peticao.split()[0].lower()})" in cl or any(kw in cl for kw in keywords_por_tipo[tipo_peticao] if kw in texto_lower):
|
| 409 |
+
dica_fmt = f"💡 **{chave}:** {dica}"
|
| 410 |
+
if dica_fmt not in dicas_relevantes: dicas_relevantes.append(dica_fmt)
|
| 411 |
+
if not dicas_relevantes: return "*Continue escrevendo para dicas...*"
|
|
|
|
|
|
|
|
|
|
| 412 |
return "\n\n".join(dicas_relevantes[:4])
|
| 413 |
|
| 414 |
def calcular_diff_interno(texto_original, texto_corrigido):
|
| 415 |
+
if not texto_original or not texto_corrigido or texto_corrigido.startswith(("⚠️","❌")): return "","",""
|
| 416 |
+
orig_lines = texto_original.splitlines(); corr_lines = texto_corrigido.splitlines()
|
|
|
|
|
|
|
| 417 |
diff = difflib.ndiff(orig_lines, corr_lines)
|
| 418 |
+
res_html, crit, l_rem, l_add = [], [], 0, 0
|
| 419 |
+
kw_rem = ["invenção", "identificação", "erro crasso", "incorreto", "prazo"]
|
| 420 |
+
kw_add = ["custas", "art. 319", "art. 337", "art. 1022", "art. 1015", "art. 300", "fumus", "periculum", "essencial", "preliminar", "tempestividade", "cabimento"]
|
|
|
|
|
|
|
|
|
|
| 421 |
for linha in diff:
|
| 422 |
+
txt = linha[2:]; txt_esc = escape(txt)
|
| 423 |
+
if linha.startswith(' '): res_html.append(f"<div class='linha-igual'>{txt_esc}</div>")
|
| 424 |
+
elif linha.startswith('- '): l_rem += 1; res_html.append(f"<div class='linha-removida'><del>{txt_esc}</del></div>"); \
|
| 425 |
+
if txt.strip() and any(kw in txt.lower() for kw in kw_rem): crit.append(f"<span style='color:red'>🔴 REMOVIDO:</span> {txt_esc}")
|
| 426 |
+
elif linha.startswith('+ '): l_add += 1; res_html.append(f"<div class='linha-adicionada'><ins>{txt_esc}</ins></div>"); \
|
| 427 |
+
if txt.strip() and any(kw in txt.lower() for kw in kw_add): crit.append(f"<span style='color:green'>🟢 ADICIONADO:</span> {txt_esc}")
|
| 428 |
+
resumo = f"**Resumo:** Rem={l_rem}, Add={l_add}, Saldo={l_add - l_rem}"
|
| 429 |
+
crit_txt = "### 🚨 Mudanças Críticas:\n" + "\n".join(crit) if crit else "*Nenhuma mudança crítica detectada.*"
|
| 430 |
+
css = "<style>.diff-container{font-family:monospace;white-space:pre-wrap;border:1px solid #ccc;padding:10px;background-color:#f9f9f9;max-height:600px;overflow-y:auto}.linha-igual{color:#555}.linha-removida{background-color:#ffebee;color:#c62828}.linha-adicionada{background-color:#e8f5e9;color:#2e7d32}.linha-removida del,.linha-adicionada ins{text-decoration:none;padding:0 2px;border-radius:2px}.linha-removida del{background-color:#ffcdd2}.linha-adicionada ins{background-color:#c8e6c9}</style>"
|
| 431 |
+
html_diff = f"{css}<div class='diff-container'>{''.join(res_html)}</div>"
|
| 432 |
+
return html_diff, resumo, crit_txt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
|
| 434 |
def calcular_progresso():
|
| 435 |
+
if not HISTORICO: return "📊 Nenhum progresso."
|
| 436 |
+
notas, tipos = [], set()
|
|
|
|
| 437 |
for entry in HISTORICO:
|
| 438 |
+
tipos.add(entry["tipo_peticao"])
|
| 439 |
+
m = re.search(r"Nota Final:?\s*\**(\d{1,2}[,.]\d{1}|\d{1,2})\s*/\s*10", entry["analise_formatada"], re.I)
|
| 440 |
+
if m: try: notas.append(float(m.group(1).replace(",", "."))) except ValueError: pass
|
| 441 |
+
tot = len(HISTORICO); media = sum(notas)/len(notas) if notas else 0
|
| 442 |
+
tend = ""
|
| 443 |
+
if len(notas) > 1: tend = "⬆️" if notas[-1] > notas[-2] else ("⬇️" if notas[-1] < notas[-2] else "↔️")
|
| 444 |
+
return f"**📊 Resumo:** Corrs:{tot}, Tipos:{len(tipos)}, Média:{media:.1f}/10 ({len(notas)} val), Tend:{tend if tend else 'N/A'}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 445 |
|
| 446 |
def mostrar_historico():
|
| 447 |
if not HISTORICO: return "📜 Histórico vazio."
|
| 448 |
+
md = "### 📜 Histórico (Últimas 10)\n---\n"
|
| 449 |
for i, entry in enumerate(reversed(HISTORICO)):
|
| 450 |
+
caso = (entry['caso'][:70] + '...') if len(entry['caso']) > 70 else entry['caso']
|
| 451 |
+
nota = "N/A"; m = re.search(r"Nota Final:?\s*\**(\d{1,2}[,.]\d{1}|\d{1,2})\s*/\s*10", entry["analise_formatada"], re.I)
|
| 452 |
+
if m: nota = f"{m.group(1).replace(',', '.')}/10"
|
| 453 |
+
md += f"**{len(HISTORICO)-i}.** {entry['data']} | **{entry['tipo_peticao']}** | **Nota:{nota}**\n **Caso:** _{caso}_\n---\n"
|
| 454 |
+
return md
|
|
|
|
| 455 |
|
| 456 |
def salvar_progresso(caso, peticao, tipo_peticao):
|
| 457 |
+
logger.info("Salvando progresso...")
|
| 458 |
try:
|
| 459 |
+
if not caso or not peticao or not tipo_peticao: return "", "⚠️ Inputs necessários.", None
|
| 460 |
+
dados = {"tipo_peticao": tipo_peticao, "caso": caso, "peticao": peticao, "timestamp": datetime.now().isoformat()}
|
| 461 |
+
json_cont = json.dumps(dados, ensure_ascii=False, indent=4)
|
| 462 |
+
fname = f"progresso_peticao_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
| 463 |
+
fpath = os.path.join(tempfile.gettempdir(), fname)
|
| 464 |
+
with open(fpath, 'w', encoding='utf-8') as f: f.write(json_cont)
|
| 465 |
+
logger.info(f"Progresso salvo: {fpath}")
|
| 466 |
+
msg = f"✅ Salvo! Baixe `{fname}`."
|
| 467 |
+
return json_cont, msg, fpath
|
| 468 |
+
except Exception as e: logger.error(f"Erro salvar: {e}", exc_info=True); return "", f"❌ Erro salvar: {e}", None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
|
| 470 |
def carregar_progresso(arquivo_entrada):
|
| 471 |
+
logger.info("Carregando progresso...")
|
| 472 |
+
if arquivo_entrada is None: return "", "", "", "⚠️ Nenhum arquivo."
|
| 473 |
try:
|
| 474 |
+
fpath = arquivo_entrada.name
|
| 475 |
+
logger.info(f"Carregando: {fpath}")
|
| 476 |
+
with open(fpath, 'r', encoding='utf-8') as f: dados = json.load(f)
|
| 477 |
+
caso, peticao, tipo = dados.get("caso"), dados.get("peticao"), dados.get("tipo_peticao")
|
| 478 |
+
if not all([caso, peticao, tipo]): return "", "", "", "❌ Arquivo inválido."
|
| 479 |
+
if tipo not in TIPOS_DE_PETICAO: return caso, peticao, "", f"⚠️ Tipo '{tipo}' inválido."
|
| 480 |
+
logger.info("Progresso carregado.")
|
| 481 |
+
return tipo, caso, peticao, "✅ Progresso carregado!"
|
| 482 |
+
except Exception as e: logger.error(f"Erro carregar: {e}", exc_info=True); return "", "", "", f"❌ Erro carregar: {e}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
|
| 484 |
def estruturar_prompt_geracao_caso(tipo_peticao="Petição Inicial"):
|
| 485 |
+
prompt = f"Crie caso fictício **detalhado e realista** p/ peça **'{tipo_peticao}'** (simulado OAB).\n**Geral:**\n1.Complexidade adequada (15-25l).\n2.Dados Essenciais (nomes,locais,datas,valores,relação,conflito).\n3.Coerência.\n4.Foco no Tipo Peça.\n**Específico '{tipo_peticao}':**\n"
|
| 486 |
+
if tipo_peticao == "Petição Inicial": prompt += "* Descreva violação direitos. * Inclua danos. * Dados qualificação. * Tema: Consumo, Contrato, etc."
|
| 487 |
+
elif tipo_peticao == "Contestação": prompt += "* Resumo PI recebida. * Versão Réu (p/ preliminares, impugnação, mérito). * Dados qualificação réu."
|
| 488 |
+
elif tipo_peticao == "Reconvenção": prompt += "* Estrutura Contestação + Fatos/Fundamentos p/ pedido PRÓPRIO CONEXO do Réu contra Autor."
|
| 489 |
+
elif tipo_peticao == "Impugnação à Contestação": prompt += "* Resumo PI Autor. * Resumo Contestação Réu (preliminares, fatos novos, docs). * Objetivo: Rebater contestação."
|
| 490 |
+
elif tipo_peticao == "Embargos de Declaração": prompt += "* Breve caso. * TRECHO DECISÃO JUDICIAL. * INDIQUE VÍCIO (omissão/contradição/obscuridade/erro material) NESSA DECISÃO."
|
| 491 |
+
elif tipo_peticao == "Recurso de Apelação": prompt += "* Caso original. * Resumo SENTENÇA. * ELEMENTOS indicando ERRO (in judicando/procedendo). * Indique cliente (apelante)."
|
| 492 |
+
elif tipo_peticao == "Agravo de Instrumento": prompt += "* Caso em andamento. * DECISÃO INTERLOCUTÓRIA. * Enquadrar Art.1015/mitigação. * ELEMENTOS indicando ERRO + URGÊNCIA. * Indique cliente (agravante)."
|
| 493 |
+
elif tipo_peticao == "Petição de Tutela Provisória": prompt += "* Situação URGENTE ou EVIDENTE. * ELEMENTOS: Urgência=Fumus+Periculum; Evidência=Hipótese Art.311. * Medida específica. * Antecedente ou Incidental."
|
| 494 |
+
else: prompt += "* Crie cenário cível com conflito claro."
|
| 495 |
+
prompt += f'\n**Finalize:**\n"**Situação-Problema:** Advogado(a) de [Nome Cliente], elabore a peça cabível ({tipo_peticao})."\n**Importante:** Temas comuns. Seja criativo!'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 496 |
return prompt
|
| 497 |
|
| 498 |
def gerar_caso_ficticio(tipo_peticao="Petição Inicial"):
|
| 499 |
+
logger.info(f"Gerando caso para: {tipo_peticao}")
|
| 500 |
try:
|
| 501 |
+
if not tipo_peticao or tipo_peticao not in TIPOS_DE_PETICAO: return "⚠️ Selecione tipo válido."
|
|
|
|
|
|
|
|
|
|
| 502 |
prompt = estruturar_prompt_geracao_caso(tipo_peticao)
|
|
|
|
| 503 |
caso_gerado = chamar_api(prompt)
|
| 504 |
+
if caso_gerado.startswith(("❌","⏱️","⚠️")): return f"⚠️ Falha gerar caso:\n{caso_gerado}"
|
| 505 |
+
frase_final = "**Situação-Problema:** Na qualidade de advogado(a) de"
|
| 506 |
+
if frase_final.lower() not in caso_gerado.lower():
|
| 507 |
+
logger.warning("Frase final não encontrada. Adicionando.")
|
| 508 |
+
nomes = re.findall(r"[A-Z][a-z]+(?:\s[A-Z][a-z]+)+", caso_gerado)
|
| 509 |
+
cliente = nomes[0] if nomes else "[Cliente]"
|
| 510 |
+
caso_gerado += f"\n\n**Situação-Problema:** Na qualidade de advogado(a) de {cliente}, elabore a peça processual cabível ({tipo_peticao})."
|
| 511 |
+
logger.info("Caso gerado.")
|
|
|
|
|
|
|
| 512 |
return caso_gerado
|
| 513 |
+
except Exception as e: logger.exception("Erro gerar_caso:"); return f"❌ Erro gerar caso: {e}"
|
| 514 |
+
|
| 515 |
+
# Função para atualizar config (faltante no traceback anterior)
|
| 516 |
+
def atualizar_config(temp, timeout, tokens):
|
| 517 |
+
CONFIG["temperatura"] = temp
|
| 518 |
+
CONFIG["timeout"] = timeout
|
| 519 |
+
CONFIG["max_tokens"] = tokens
|
| 520 |
+
logger.info(f"Configs atualizadas: Temp={temp}, Timeout={timeout}, Tokens={tokens}")
|
| 521 |
+
return "✅ Configs Atualizadas!"
|
| 522 |
|
| 523 |
def interface_gradio():
|
| 524 |
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="orange")) as demo:
|
| 525 |
+
gr.Markdown("# ⚖️ Corretor Jurídico OAB Master ⚖️\nAnalise e aprimore suas peças processuais!")
|
|
|
|
| 526 |
with gr.Row():
|
| 527 |
with gr.Column(scale=1):
|
| 528 |
gr.Markdown("### ⚙️ Configurações")
|
| 529 |
+
tipo_peticao_input = gr.Dropdown(label="1. Selecione o Tipo", choices=TIPOS_DE_PETICAO, value="Petição Inicial")
|
| 530 |
modo_treinamento = gr.Checkbox(label="🎓 Modo Treinamento", value=False)
|
| 531 |
+
with gr.Accordion("🛠️ Opções Avançadas", open=False):
|
| 532 |
+
temperatura_slider = gr.Slider(0.0, 1.0, value=CONFIG["temperatura"], step=0.1, label="Criatividade")
|
| 533 |
+
timeout_slider = gr.Slider(30, 180, value=CONFIG["timeout"], step=10, label="Timeout (s)")
|
| 534 |
+
max_tokens_slider = gr.Slider(2048, 8192, value=CONFIG["max_tokens"], step=256, label="Max Tokens")
|
| 535 |
config_update_btn = gr.Button("💾 Salvar Configs")
|
| 536 |
config_status = gr.Textbox(label="Status", interactive=False, lines=1)
|
| 537 |
with gr.Accordion("📊 Dashboard", open=False):
|
| 538 |
+
progresso_output = gr.Markdown("*Atualize para ver.*")
|
| 539 |
progresso_btn = gr.Button("🔄 Atualizar Progresso")
|
| 540 |
with gr.Accordion("📜 Histórico", open=False):
|
| 541 |
+
historico_output = gr.Markdown("*Atualize para ver.*")
|
| 542 |
historico_btn = gr.Button("🔄 Ver Histórico")
|
| 543 |
with gr.Accordion("💾📂 Salvar/Carregar", open=False):
|
| 544 |
+
salvar_btn = gr.Button("💾 Salvar")
|
| 545 |
+
carregar_btn = gr.Button("📂 Carregar")
|
| 546 |
+
arquivo_progresso_upload = gr.File(label="Selecione .json", file_types=[".json"])
|
| 547 |
progresso_download_file = gr.File(label="Baixar Progresso", interactive=False)
|
| 548 |
with gr.Column(scale=3):
|
| 549 |
+
gr.Markdown("### 1. Caso / Contexto")
|
| 550 |
with gr.Row():
|
| 551 |
+
caso_input = gr.Textbox(label="📋 Caso", lines=8, placeholder="Insira o texto do caso...")
|
| 552 |
+
caso_btn = gr.Button("🎲 Gerar", variant="secondary", scale=0)
|
| 553 |
+
gr.Markdown("### 2. Sua Peça")
|
| 554 |
with gr.Tabs():
|
| 555 |
+
with gr.TabItem("✏️ Texto"):
|
| 556 |
+
peticao_texto_input = gr.Textbox(label="Texto da Peça", lines=12, placeholder="Cole ou digite...")
|
| 557 |
+
dica_contextual_output = gr.Markdown("*Dicas...*")
|
| 558 |
+
btn_corrigir = gr.Button("🚀 CORRIGIR!", variant="primary")
|
| 559 |
+
with gr.TabItem("📎 Arquivo"):
|
| 560 |
+
peticao_arquivo_input = gr.File(label="Arquivo (.pdf,.docx,.txt)", file_types=[".pdf",".docx",".txt"])
|
| 561 |
+
arquivo_preview_output = gr.Textbox(label="🔍 Prévia", lines=4, interactive=False)
|
| 562 |
+
btn_corrigir_arquivo = gr.Button("🚀 CORRIGIR ARQUIVO!", variant="primary")
|
| 563 |
|
| 564 |
processing_message = gr.Markdown("", visible=False)
|
| 565 |
+
gr.Markdown("--- \n ### 3. Resultados")
|
|
|
|
| 566 |
with gr.Tabs():
|
| 567 |
+
with gr.TabItem("📊 Análise e Correção"):
|
| 568 |
+
resultado_analise_output = gr.Markdown(label="Análise e Nota")
|
| 569 |
resultado_peticao_corrigida_output = gr.Textbox(label="✨ Versão Sugerida", lines=18, show_copy_button=True)
|
| 570 |
+
with gr.TabItem("⚖️ Comparativo"):
|
| 571 |
+
gr.Markdown("### ↔️ Comparativo (Diff)")
|
| 572 |
with gr.Row():
|
| 573 |
+
with gr.Column(scale=1): resumo_alteracoes_output = gr.Markdown(label="Resumo"); criticas_output = gr.Markdown(label="Críticas")
|
| 574 |
+
with gr.Column(scale=3): visualizacao_detalhada_output = gr.HTML(label="Detalhes")
|
| 575 |
+
clear_btn = gr.Button("🗑️ Limpar Tudo")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 576 |
|
| 577 |
+
# --- Eventos ---
|
| 578 |
+
caso_btn.click(lambda: gr.update(value="⏳ Gerando...", visible=True), outputs=processing_message).then(
|
|
|
|
| 579 |
fn=gerar_caso_ficticio, inputs=[tipo_peticao_input], outputs=[caso_input]
|
| 580 |
+
).then(lambda: gr.update(value="", visible=False), outputs=processing_message)
|
|
|
|
|
|
|
| 581 |
|
| 582 |
+
peticao_texto_input.change(fornecer_dica_contextual, [peticao_texto_input, tipo_peticao_input], dica_contextual_output)
|
| 583 |
+
tipo_peticao_input.change(fornecer_dica_contextual, [peticao_texto_input, tipo_peticao_input], dica_contextual_output)
|
| 584 |
+
peticao_arquivo_input.change(process_file, [peticao_arquivo_input], [arquivo_preview_output])
|
| 585 |
|
| 586 |
+
btn_corrigir.click(lambda: gr.update(value="⏳ Processando texto...", visible=True), outputs=processing_message).then(
|
|
|
|
|
|
|
|
|
|
| 587 |
fn=corrigir_peticao,
|
| 588 |
inputs=[caso_input, tipo_peticao_input, peticao_texto_input, gr.State(None), modo_treinamento],
|
| 589 |
+
outputs=[resultado_analise_output, resultado_peticao_corrigida_output, resumo_alteracoes_output, criticas_output, visualizacao_detalhada_output],
|
|
|
|
| 590 |
concurrency_limit=1
|
| 591 |
+
).then(lambda: gr.update(value="", visible=False), outputs=processing_message)
|
|
|
|
|
|
|
|
|
|
| 592 |
|
| 593 |
+
btn_corrigir_arquivo.click(lambda: gr.update(value="⏳ Processando arquivo...", visible=True), outputs=processing_message).then(
|
|
|
|
|
|
|
|
|
|
| 594 |
fn=corrigir_peticao,
|
| 595 |
inputs=[caso_input, tipo_peticao_input, gr.State(None), peticao_arquivo_input, modo_treinamento],
|
| 596 |
+
outputs=[resultado_analise_output, resultado_peticao_corrigida_output, resumo_alteracoes_output, criticas_output, visualizacao_detalhada_output],
|
|
|
|
| 597 |
concurrency_limit=1
|
| 598 |
+
).then(lambda: gr.update(value="", visible=False), outputs=processing_message)
|
|
|
|
|
|
|
|
|
|
| 599 |
|
| 600 |
+
config_update_btn.click(atualizar_config, [temperatura_slider, timeout_slider, max_tokens_slider], config_status)
|
| 601 |
+
progresso_btn.click(calcular_progresso, outputs=progresso_output)
|
| 602 |
+
historico_btn.click(mostrar_historico, outputs=historico_output)
|
| 603 |
|
| 604 |
+
salvar_btn.click(lambda: gr.update(value="⏳ Salvando...", visible=True), outputs=processing_message).then(
|
|
|
|
|
|
|
| 605 |
fn=salvar_progresso, inputs=[caso_input, peticao_texto_input, tipo_peticao_input],
|
| 606 |
outputs=[gr.Textbox(visible=False), config_status, progresso_download_file]
|
| 607 |
+
).then(lambda x: gr.update(visible=bool(x)), [progresso_download_file], [progresso_download_file]
|
| 608 |
+
).then(lambda: gr.update(value="", visible=False), None, processing_message)
|
|
|
|
|
|
|
|
|
|
| 609 |
|
| 610 |
+
carregar_btn.click(lambda: gr.update(value="⏳ Carregando...", visible=True), outputs=processing_message).then(
|
|
|
|
|
|
|
| 611 |
fn=carregar_progresso, inputs=[arquivo_progresso_upload],
|
| 612 |
outputs=[tipo_peticao_input, caso_input, peticao_texto_input, config_status]
|
| 613 |
+
).then(lambda: gr.update(value="", visible=False), None, processing_message)
|
|
|
|
|
|
|
| 614 |
|
| 615 |
clear_btn.click(
|
| 616 |
+
fn=lambda: ["Petição Inicial", False, None, None, None, None, "*Dicas...*", "", "", "", "", "", None, None, ""],
|
| 617 |
+
outputs=[tipo_peticao_input, modo_treinamento, caso_input, peticao_texto_input, peticao_arquivo_input,
|
| 618 |
+
arquivo_preview_output, dica_contextual_output, resultado_analise_output, resultado_peticao_corrigida_output,
|
| 619 |
+
resumo_alteracoes_output, criticas_output, visualizacao_detalhada_output,
|
| 620 |
+
arquivo_progresso_upload, progresso_download_file, config_status]
|
|
|
|
|
|
|
|
|
|
| 621 |
)
|
|
|
|
| 622 |
return demo
|
| 623 |
|
| 624 |
if __name__ == "__main__":
|