SimuladorAIJ2 / app.py
GabrielGD's picture
Update app.py
0366775 verified
Raw
History Blame
25.2 kB
import gradio as gr
import os
import copy
import re
import requests
import json
import logging
from typing import Dict, List, Optional, Union, Tuple, Any
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
logger = logging.getLogger(__name__)
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
MODEL_NAME = "gemini-1.5-flash-latest"
API_URL_BASE = f"https://generativelanguage.googleapis.com/v1beta/models/{MODEL_NAME}:generateContent"
class Config:
MAX_RETRIES = 1
REQUEST_TIMEOUT = 360
DEFAULT_TEMPERATURE = 0.75
PETICAO_MAX_TOKENS = 2200 # Aumentado
CONTESTACAO_MAX_TOKENS = 2200 # Aumentado
AIJ_MAX_TOKENS = 6000 # Aumentado significativamente para AIJ completa e detalhada
PETICAO_MARKERS_MAP = {
"fatos_autor": "### DOS FATOS (Narrativa do Autor)",
"direito_autor": "### DO DIREITO (Principais Fundamentos Jurídicos)",
"pedidos_autor": "### DOS PEDIDOS",
"estrategias_autor": "### PONTOS ESTRATÉGICOS ADICIONAIS PARA O AUTOR"
}
CONTESTACAO_MARKERS_MAP = {
"sintese_reu": "### SÍNTESE DA DEFESA",
"preliminares_reu": "### PRELIMINARES", # Adicionado para parsing explícito
"fatos_reu": "### DA REALIDADE DOS FATOS (Narrativa do Réu e Impugnação Específica)",
"direito_reu": "### DO DIREITO (Principais Fundamentos da Defesa)",
"pedidos_reu": "### DOS PEDIDOS (Contrapedidos/Impugnações)",
"estrategias_reu": "### PONTOS ESTRATÉGICOS ADICIONAIS PARA O RÉU"
}
AIJ_MARKERS_MAP = {
"1_abertura": "### 1. ABERTURA E TENTATIVA DE CONCILIAÇÃO",
"2_dep_autor": "### 2. DEPOIMENTO PESSOAL DO AUTOR (Resumido)",
"3_dep_reu": "### 3. DEPOIMENTO PESSOAL DO RÉU (Preposto do Jornal - Resumido)",
"4_test_autor": "### 4. OITIVA DAS TESTEMUNHAS DO AUTOR",
"5_test_reu": "### 5. OITIVA DAS TESTEMUNHAS DO RÉU",
"6_aleg_autor": "### 6. ALEGAÇÕES FINAIS DO AUTOR (Resumido)",
"7_aleg_reu": "### 7. ALEGAÇÕES FINAIS DO RÉU (Resumido)",
"8_conc_juiz": "### 8. CONCLUSÃO DO JUIZ PARA SENTENÇA (Simulada)",
"9_cenarios": "### 9. ANÁLISE DE CENÁRIOS E PONTOS DE INFLEXÃO"
}
class CasoPadrao:
RESUMO = """Carlos Alberto Mendes processou o jornal "A Verdade Diária" por violação do direito ao esquecimento. Há 15 anos, Carlos foi absolvido de fraude. Recentemente, o jornal revisitou o caso numa matéria retrospectiva, mencionando a absolvição. Carlos alega danos (reputação, emprego, emocional) e pede remoção e indenização. O jornal defende liberdade de imprensa, interesse público histórico e veracidade."""
AUTOR_PONTOS = """1. Dano à honra e imagem. Prova: Laudo psicológico. 2. Sofrimento social. Prova: Depoimentos. 3. Prejuízo profissional. 4. Direito ao esquecimento (Art. 5º, X, CF; Enunciado 531). 5. Irrelevância atual da notícia."""
REU_PONTOS = """1. Liberdade de imprensa (Art. 5º, IX, XIV, 220 CF). 2. Interesse público histórico. 3. Menção à absolvição. 4. Animus narrandi. 5. Precedente STF (RE 1.010.606). Provas: Cópia da matéria, docs. processo original."""
_peticao_completa_exportar = ""
_contestacao_completa_exportar = ""
_aij_texto_completo_para_exportar = ""
class GeminiAPI:
@staticmethod
def chamar_api(prompt_text: str, temperature: float = Config.DEFAULT_TEMPERATURE,
max_output_tokens: int = 1500, retries: int = Config.MAX_RETRIES) -> str:
if not GEMINI_API_KEY:
logger.error("ERRO_FATAL: API Key do Gemini não configurada.")
return "ERRO_FATAL: API Key do Gemini não configurada."
api_url_com_chave = f"{API_URL_BASE}?key={GEMINI_API_KEY}"
headers = {'Content-Type': 'application/json'}
data = {"contents": [{"parts": [{"text": prompt_text}]}],
"generationConfig": {"temperature": temperature, "maxOutputTokens": max_output_tokens, "topP": 0.95, "topK": 40},
"safetySettings": [{"category": f"HARM_CATEGORY_{cat}", "threshold": "BLOCK_NONE"} for cat in ["HARASSMENT", "HATE_SPEECH", "SEXUALLY_EXPLICIT", "DANGEROUS_CONTENT"]]}
for attempt in range(retries + 1):
try:
logger.info(f"API Gemini: Tentativa {attempt+1}/{retries+1}, Prompt: {len(prompt_text)} chars, Max Tokens: {max_output_tokens}")
response = requests.post(api_url_com_chave, headers=headers, json=data, timeout=Config.REQUEST_TIMEOUT)
response.raise_for_status()
response_json = response.json()
if response_json.get("candidates") and response_json["candidates"][0].get("content"):
generated_text = response_json["candidates"][0]["content"]["parts"][0].get("text", "").strip()
logger.info(f"API Gemini retornou {len(generated_text)} caracteres.")
finish_reason = response_json["candidates"][0].get("finishReason", "")
if finish_reason == "MAX_TOKENS":
logger.warning("Geração da API interrompida por MAX_TOKENS.")
generated_text += "\n\n[AVISO: Geração interrompida por limite de tokens.]"
elif finish_reason not in ["STOP", "OTHER", None]:
logger.warning(f"Geração da API terminou com razão: {finish_reason}")
return generated_text
elif response_json.get("promptFeedback"):
feedback = response_json["promptFeedback"]
error_detail = f"Bloqueio: {feedback.get('blockReason', 'N/A')}. Safety: {feedback.get('safetyRatings', 'N/A')}"
logger.error(f"API: Conteúdo bloqueado. {error_detail}")
return f"ERRO_API: Conteúdo bloqueado. {error_detail}"
logger.error(f"API: Resposta inesperada/vazia. JSON: {response_json}")
return "ERRO_API: Resposta inesperada/vazia da API."
except requests.exceptions.Timeout:
logger.error(f"API: Timeout na tentativa {attempt+1}.")
if attempt == retries: return "ERRO_CONEXAO: Timeout excedido."
except requests.exceptions.RequestException as e:
logger.error(f"API: Erro na requisição (tentativa {attempt+1}): {e}", exc_info=True)
if attempt == retries: return f"ERRO_CONEXAO: {e}"
except Exception as e:
logger.exception(f"API: Erro desconhecido (tentativa {attempt+1}): {e}")
if attempt == retries: return f"ERRO_DESCONHECIDO: {e}"
return "ERRO_API: Todas as tentativas falharam."
class GeradorDocumentos:
@staticmethod
def gerar_peticao_inicial(resumo_caso: str, pontos_autor: str, modificacao_fato: Optional[str], abordagem_autor: str) -> str:
mod_prompt = f"\n**Modificação Fato:** {modificacao_fato}\n" if modificacao_fato else ""
ab_prompt = f"\n**Abordagem Autor:** {abordagem_autor}\n"
prompt = f"""**Persona:** Advogado experiente (Direitos da Personalidade), redigindo Petição Inicial (Esquecimento vs. Imprensa).
{mod_prompt}{ab_prompt}**Caso Base:** {resumo_caso}
**Pontos Autor:** {pontos_autor or "Inferir do resumo e abordagem."}
**Tarefa:** Gere Petição Inicial com seções detalhadas (Fatos, Direito, Pedidos, Estratégias Adicionais), adaptando à modificação do fato e abordagem. Para o Direito, cite 3-4 fundamentos (Dignidade, Privacidade, Esquecimento, Resp. Civil) e explique sua aplicação. Nos Pedidos, seja específico (tutela, remoção, indenização, retratação). Em Estratégias, sugira argumentos/provas alternativas e riscos a antecipar.
**Formato Saída (marcadores exatos):**
`{Config.PETICAO_MARKERS_MAP["fatos_autor"]}`
[Conteúdo]
`{Config.PETICAO_MARKERS_MAP["direito_autor"]}`
[Conteúdo]
`{Config.PETICAO_MARKERS_MAP["pedidos_autor"]}`
[Conteúdo]
`{Config.PETICAO_MARKERS_MAP["estrategias_autor"]}`
[Conteúdo]"""
return GeminiAPI.chamar_api(prompt, max_output_tokens=Config.PETICAO_MAX_TOKENS)
@staticmethod
def gerar_contestacao(resumo_caso: str, pontos_reu: str, peticao_autor: str, tom_defesa: str, modificacao_fato: Optional[str]) -> str:
mod_prompt = f"\n**Modificação Fato (do caso original):** {modificacao_fato}\n" if modificacao_fato else ""
prompt = f"""**Persona:** Advogado experiente (Liberdade de Imprensa), redigindo Contestação (Esquecimento vs. Imprensa).
**Tom Defesa:** {tom_defesa}
{mod_prompt}**Caso Base:** {resumo_caso}
**Pontos Réu:** {pontos_reu or "Inferir do resumo."}
**Petição Autor:** ```{peticao_autor}```
**Tarefa:** Gere Contestação com seções (Síntese, Preliminares (se houver), Fatos (com impugnação), Direito, Pedidos, Estratégias Adicionais), adaptando ao tom e modificação do fato. No Direito, cite 3-4 fundamentos (Liberdade Imprensa/Info, Art. 5/220 CF, Ausência Ilicitude, Verdade, Animus Narrandi, Precedentes STF RE 1.010.606/ADPF 130). Nos Pedidos, peça improcedência total, impugne danos, peça custas/honorários. Em Estratégias, sugira teses/provas e pontos fracos da petição.
**Formato Saída (marcadores exatos):**
`{Config.CONTESTACAO_MARKERS_MAP["sintese_reu"]}`
[Conteúdo]
(Se houver preliminares: `{Config.CONTESTACAO_MARKERS_MAP["preliminares_reu"]}`\n[Conteúdo])
`{Config.CONTESTACAO_MARKERS_MAP["fatos_reu"]}`
[Conteúdo]
`{Config.CONTESTACAO_MARKERS_MAP["direito_reu"]}`
[Conteúdo]
`{Config.CONTESTACAO_MARKERS_MAP["pedidos_reu"]}`
[Conteúdo]
`{Config.CONTESTACAO_MARKERS_MAP["estrategias_reu"]}`
[Conteúdo]"""
return GeminiAPI.chamar_api(prompt, max_output_tokens=Config.CONTESTACAO_MAX_TOKENS)
@staticmethod
def simular_aij(resumo_caso: str, peticao_autor: str, contestacao_reu: str,
pontos_autor: str, pontos_reu: str, tom_defesa_reu: str,
modificacao_fato: Optional[str], abordagem_autor: str) -> str:
mod_prompt = f"\n**Modificação Fato (para AIJ):** {modificacao_fato}\n" if modificacao_fato else ""
ab_prompt = f"\n**Abordagem Autor (para AIJ):** {abordagem_autor}\n"
prompt = f"""**Persona:** Narrador Jurídico imparcial simulando AIJ (Esquecimento vs. Imprensa).
{mod_prompt}{ab_prompt}**Contexto Caso Original:** {resumo_caso}
**Petição Autor:** ```{peticao_autor}``` {("Pontos Autor: " + pontos_autor) if pontos_autor else ""}
**Contestação Réu (Tom: {tom_defesa_reu}):** ```{contestacao_reu}``` {("Pontos Réu: " + pontos_reu) if pontos_reu else ""}
**Tarefa:** Narre a AIJ. Advogados devem refletir abordagens/tons. Fato modificado deve influenciar depoimentos/perguntas/análise. Inferir 1-2 testemunhas relevantes (Autor: psicólogo, amigo; Réu: editor, jornalista) e seus depoimentos/contraditas no contexto do caso (esquecimento, dano, interesse público, veracidade). Juiz deve ponderar direitos conflitantes na conclusão. Seção de Cenários deve explorar 1 reviravolta, 1 estratégia alternativa, 1 fator externo.
**Formato Saída (marcadores exatos):**
`{Config.AIJ_MARKERS_MAP["1_abertura"]}` \n[Conteúdo]
`{Config.AIJ_MARKERS_MAP["2_dep_autor"]}` \n[Conteúdo]
`{Config.AIJ_MARKERS_MAP["3_dep_reu"]}` \n[Conteúdo]
`{Config.AIJ_MARKERS_MAP["4_test_autor"]}` \n[Formato Testemunha: - Testemunha: [Nome/Papel]\n - Ponto Chave: [Depoimento]\n - Contradita: [Foco da pergunta do Adv. Réu e resposta]]
`{Config.AIJ_MARKERS_MAP["5_test_reu"]}` \n[Formato Testemunha: - Testemunha: [Nome/Papel]\n - Ponto Chave: [Depoimento]\n - Contradita: [Foco da pergunta do Adv. Autor e resposta]]
`{Config.AIJ_MARKERS_MAP["6_aleg_autor"]}` \n[Conteúdo]
`{Config.AIJ_MARKERS_MAP["7_aleg_reu"]}` \n[Conteúdo]
`{Config.AIJ_MARKERS_MAP["8_conc_juiz"]}` \n[Conteúdo]
`{Config.AIJ_MARKERS_MAP["9_cenarios"]}` \n[a) Ponto de Virada: ... b) Estratégia Alternativa: ... c) Fator Externo: ...]"""
return GeminiAPI.chamar_api(prompt, temperature=0.8, max_output_tokens=Config.AIJ_MAX_TOKENS)
class ProcessadorTexto:
@staticmethod
def _extrair_secao(texto_completo: str, texto_lower: str, marcador_inicio: str, marcadores_subsequentes: List[str]) -> Optional[str]:
start_idx = texto_lower.find(marcador_inicio.lower())
if start_idx == -1: return None
content_start_idx = start_idx + len(marcador_inicio)
end_idx = len(texto_completo)
for next_marcador in marcadores_subsequentes:
next_marker_idx_found = texto_lower.find(next_marcador.lower(), content_start_idx)
if next_marker_idx_found != -1:
end_idx = min(end_idx, next_marker_idx_found)
return texto_completo[content_start_idx:end_idx].strip()
@staticmethod
def processar_documento(texto_completo: str, markers_map: Dict[str, str]) -> Dict[str, str]:
global _peticao_completa_exportar, _contestacao_completa_exportar, _aij_texto_completo_para_exportar
if markers_map == Config.PETICAO_MARKERS_MAP: _peticao_completa_exportar = texto_completo
elif markers_map == Config.CONTESTACAO_MARKERS_MAP: _contestacao_completa_exportar = texto_completo
elif markers_map == Config.AIJ_MARKERS_MAP: _aij_texto_completo_para_exportar = texto_completo
if not texto_completo or "ERRO_" in texto_completo:
logger.error(f"Erro na entrada do processador: {texto_completo}")
return {key: f"Erro ao gerar/processar seção: {texto_completo}" for key in markers_map.keys()}
partes_documento = {key: f"Seção '{marker_text}' não encontrada." for key, marker_text in markers_map.items()}
texto_lower = texto_completo.lower()
sorted_marcadores_list = list(markers_map.items())
for i, (key, marcador_inicio) in enumerate(sorted_marcadores_list):
marcadores_subsequentes_text = [m_text for _, m_text in sorted_marcadores_list[i+1:]]
conteudo_secao = ProcessadorTexto._extrair_secao(texto_completo, texto_lower, marcador_inicio, marcadores_subsequentes_text)
if conteudo_secao is not None: partes_documento[key] = conteudo_secao
else: logger.warning(f"Marcador não encontrado ao processar: '{marcador_inicio}' para '{key}'")
return partes_documento
class InterfaceProcesso:
@staticmethod
def simular_processo_completo_ui_generator(resumo_caso_input: str, pontos_autor_input: str,
pontos_reu_input: str, tom_defesa_reu_input: str,
modificacao_fato_input: Optional[str],
abordagem_autor_input: Optional[str]):
global _peticao_completa_exportar, _contestacao_completa_exportar, _aij_texto_completo_para_exportar
_peticao_completa_exportar = _contestacao_completa_exportar = _aij_texto_completo_para_exportar = ""
num_aij_outputs = len(Config.AIJ_MARKERS_MAP)
total_outputs = 2 + num_aij_outputs + 1 # Pet, Cont, AIJ_parts, Status
outputs_tuple_list = [""] * total_outputs
def create_error_tuple(base_error_msg: str):
err_list = [base_error_msg] * (total_outputs -1)
err_list.append(gr.update(value=base_error_msg))
return tuple(err_list)
if not GEMINI_API_KEY:
yield create_error_tuple("ERRO FATAL: API Key do Gemini não configurada.")
return
if not resumo_caso_input:
yield create_error_tuple("Erro: O resumo do caso é obrigatório.")
return
outputs_tuple_list[total_outputs - 1] = gr.update(value="Iniciando: Gerando Petição Inicial...")
outputs_tuple_list[0] = "Gerando..."
yield tuple(outputs_tuple_list)
peticao_autor_txt = GeradorDocumentos.gerar_peticao_inicial(resumo_caso_input, pontos_autor_input, modificacao_fato_input, abordagem_autor_input)
outputs_tuple_list[0] = peticao_autor_txt
_peticao_completa_exportar = peticao_autor_txt
if "ERRO_" in peticao_autor_txt:
logger.error(f"Falha Petição: {peticao_autor_txt}")
outputs_tuple_list[total_outputs-1] = gr.update(value=f"Erro Petição: {peticao_autor_txt[:100]}...")
for i in range(1, total_outputs -1) : outputs_tuple_list[i] = peticao_autor_txt
yield tuple(outputs_tuple_list)
return
outputs_tuple_list[1] = "Gerando Contestação..."
outputs_tuple_list[total_outputs -1] = gr.update(value="Gerando Contestação...")
yield tuple(outputs_tuple_list)
contestacao_reu_txt = GeradorDocumentos.gerar_contestacao(resumo_caso_input, pontos_reu_input, peticao_autor_txt, tom_defesa_reu_input, modificacao_fato_input)
outputs_tuple_list[1] = contestacao_reu_txt
_contestacao_completa_exportar = contestacao_reu_txt
if "ERRO_" in contestacao_reu_txt:
logger.error(f"Falha Contestação: {contestacao_reu_txt}")
outputs_tuple_list[total_outputs-1] = gr.update(value=f"Erro Contestação: {contestacao_reu_txt[:100]}...")
for i in range(2, total_outputs -1) : outputs_tuple_list[i] = contestacao_reu_txt
yield tuple(outputs_tuple_list)
return
for i in range(num_aij_outputs): outputs_tuple_list[2+i] = "Gerando AIJ..."
outputs_tuple_list[total_outputs -1] = gr.update(value="Simulando AIJ...")
yield tuple(outputs_tuple_list)
aij_simulacao_txt_completa = GeradorDocumentos.simular_aij(resumo_caso_input, peticao_autor_txt, contestacao_reu_txt, pontos_autor_input, pontos_reu_input, tom_defesa_reu_input, modificacao_fato_input, abordagem_autor_input)
if "ERRO_" in aij_simulacao_txt_completa:
logger.error(f"Falha AIJ: {aij_simulacao_txt_completa}")
for i in range(num_aij_outputs): outputs_tuple_list[2+i] = aij_simulacao_txt_completa
outputs_tuple_list[total_outputs-1] = gr.update(value=f"Erro AIJ: {aij_simulacao_txt_completa[:100]}...")
yield tuple(outputs_tuple_list)
return
aij_partes_dict = ProcessadorTexto.processar_aij(aij_simulacao_txt_completa)
for i, key in enumerate(Config.AIJ_MARKERS_MAP.keys()):
outputs_tuple_list[2+i] = aij_partes_dict.get(key, f"Falha ao processar seção AIJ: {key}")
outputs_tuple_list[total_outputs-1] = gr.update(value="Simulação concluída com sucesso.")
logger.info("Simulação completa e UI atualizada.")
yield tuple(outputs_tuple_list)
@staticmethod
def limpar_interface_fn():
num_aij_outputs = len(Config.AIJ_MARKERS_MAP)
return ("", "", "", "Padrão", "", "Técnica e Legalista", # Entradas
"", "", # Petição, Contestação
*[""] * num_aij_outputs, # AIJ parts
gr.update(value="Campos e saídas limpos."), # Status
"" # AIJ export box
)
@staticmethod
def restaurar_padrao_fn():
num_aij_outputs = len(Config.AIJ_MARKERS_MAP)
return (CasoPadrao.RESUMO, "", CasoPadrao.AUTOR_PONTOS, "Padrão", CasoPadrao.REU_PONTOS, "Técnica e Legalista",
"", "", *[""] * num_aij_outputs,
gr.update(value="Caso padrão restaurado. Modifique e simule."), ""
)
@staticmethod
def criar_interface() -> gr.Blocks:
with gr.Blocks(theme=gr.themes.Soft(primary_hue="teal", secondary_hue="amber"), title="Simulador de Fluxo Processual Avançado") as demo:
gr.Markdown("# ⚖️ Simulador Avançado de Fluxo Processual e AIJ (IA-Powered)")
gr.Markdown("Forneça um caso, modifique fatos, escolha abordagens e veja a IA simular o processo.")
if not GEMINI_API_KEY: gr.Warning("ALERTA: GEMINI_API_KEY não configurada!")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("## Configuração do Caso e Variações")
resumo_caso_input = gr.Textbox(lines=8, label="Resumo Detalhado do Caso Base:", value=CasoPadrao.RESUMO)
modificacao_fato_input = gr.Textbox(lines=3, label="Modificação de Fato Chave (Opcional):", placeholder="Ex: A matéria foi publicada há apenas 1 ano.")
with gr.Row():
with gr.Column():
pontos_autor_input = gr.Textbox(lines=4, label="Pontos/Provas do AUTOR (Opcional):", value=CasoPadrao.AUTOR_PONTOS)
abordagem_autor_input = gr.Radio(choices=["Padrão", "Foco Máximo em Danos Morais", "Busca Principal pela Remoção", "Postura Conciliadora Inicial"], label="Abordagem Estratégica do Autor:", value="Padrão")
with gr.Column():
pontos_reu_input = gr.Textbox(lines=4, label="Pontos/Provas do RÉU (Opcional):", value=CasoPadrao.REU_PONTOS)
tom_defesa_reu_input = gr.Radio(choices=["Combativa e Firme", "Técnica e Legalista", "Ponderada/Buscando Acordo Sutil"], label="Tom da Defesa do Réu:", value="Técnica e Legalista")
btn_simular = gr.Button("🚀 Simular Processo com Variações", variant="primary")
status_output = gr.Label(value="Aguardando simulação...")
with gr.Row():
btn_limpar_entradas = gr.Button("🧹 Limpar Tudo", variant="secondary", size="sm")
btn_restaurar_padrao = gr.Button("🔄 Restaurar Caso Padrão", variant="secondary", size="sm")
with gr.Column(scale=2):
gr.Markdown("## Resultados da Simulação")
with gr.Tabs():
with gr.TabItem("📜 Petição Inicial (Autor)"):
output_peticao_inicial = gr.Markdown(show_copy_button=True)
with gr.TabItem("🛡️ Contestação (Réu)"):
output_contestacao = gr.Markdown(show_copy_button=True)
with gr.TabItem("🎤 Audiência (AIJ)"):
output_aij_export_box = gr.Textbox(label="AIJ Completa (para copiar):", lines=1, info="Texto completo da AIJ após simulação.", interactive=False, show_copy_button=True)
aij_outputs_ui = {}
for key, title in Config.AIJ_MARKERS_MAP.items():
accordion_title = re.sub(r"### \d+\.\s*", "", title)
is_open = key in ["1_abertura", "9_cenarios"]
with gr.Accordion(accordion_title, open=is_open):
aij_outputs_ui[key] = gr.Markdown()
all_inputs = [resumo_caso_input, modificacao_fato_input, pontos_autor_input, abordagem_autor_input, pontos_reu_input, tom_defesa_reu_input]
# Construir lista de outputs na ordem correta
outputs_simulacao_list = [output_peticao_inicial, output_contestacao]
for key_aij in Config.AIJ_MARKERS_MAP.keys(): outputs_simulacao_list.append(aij_outputs_ui[key_aij])
outputs_simulacao_list.append(status_output)
# Saídas para limpar/restaurar (inclui a caixa de exportação da AIJ)
outputs_to_clear_restore = [output_peticao_inicial, output_contestacao]
for key_aij_clear in Config.AIJ_MARKERS_MAP.keys(): outputs_to_clear_restore.append(aij_outputs_ui[key_aij_clear])
outputs_to_clear_restore.extend([status_output, output_aij_export_box])
def update_export_box_after_sim():
global _aij_texto_completo_para_exportar
return _aij_texto_completo_para_exportar
btn_simular.click(
InterfaceProcesso.simular_processo_completo_ui_generator,
inputs=all_inputs, outputs=outputs_simulacao_list
).then(update_export_box_after_sim, outputs=[output_aij_export_box])
btn_limpar_entradas.click(
InterfaceProcesso.limpar_interface_fn,
inputs=None,
outputs=all_inputs + outputs_to_clear_restore
)
btn_restaurar_padrao.click(
InterfaceProcesso.restaurar_padrao_fn,
inputs=None,
outputs=all_inputs + outputs_to_clear_restore
)
return demo
if __name__ == '__main__':
if not GEMINI_API_KEY:
logger.critical("A API Key do Gemini não está configurada. A aplicação não pode iniciar.")
with gr.Blocks(theme=gr.themes.Soft(primary_hue="red")) as demo_erro:
gr.Markdown("# ERRO DE CONFIGURAÇÃO CRÍTICO")
gr.Markdown("A chave `GEMINI_API_KEY` não foi configurada corretamente...") # Mensagem completa
logger.info("Lançando interface de erro.")
demo_erro.launch(debug=True)
else:
logger.info("Iniciando a interface Gradio do Simulador de Fluxo Processual Avançado...")
simulador_interface = InterfaceProcesso.criar_interface()
simulador_interface.queue().launch(debug=True)