SimuladorAIJ / app.py
GabrielGD's picture
Update app.py
cad4f1e verified
Raw
History Blame
79.5 kB
import gradio as gr
import requests
import json
import os
import copy
# --- Configuration from Script 1 & 2 (merged) ---
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
if not GEMINI_API_KEY:
print("ALERTA: GEMINI_API_KEY não encontrada como Secret no Hugging Face Space. O app não funcionará.")
# Para teste local, descomente e cole sua chave, mas NÃO FAÇA COMMIT DISSO COM A CHAVE.
# GEMINI_API_KEY = "SUA_CHAVE_AQUI_PARA_TESTE_LOCAL_APENAS"
MODEL_NAME = "gemini-1.5-flash-latest" # Consistent model name
API_URL_BASE = f"https://generativelanguage.googleapis.com/v1beta/models/{MODEL_NAME}:generateContent"
# --- Fases da AIJ (from Script 1) ---
FASE_INICIAL_CONFIG = "CONFIGURACAO"
FASE_ABERTURA_CONCILIACAO = "ABERTURA_E_CONCILIACAO"
FASE_TESTEMUNHAS_AUTOR_INICIO = "TESTEMUNHAS_AUTOR_INICIO"
FASE_TESTEMUNHAS_AUTOR_PERGUNTAS_AUTOR = "TESTEMUNHAS_AUTOR_PERGUNTAS_AUTOR"
FASE_TESTEMUNHAS_AUTOR_CONTRADITA_REU = "TESTEMUNHAS_AUTOR_CONTRADITA_REU"
FASE_TESTEMUNHAS_REU_INICIO = "TESTEMUNHAS_REU_INICIO"
FASE_TESTEMUNHAS_REU_PERGUNTAS_REU = "TESTEMUNHAS_REU_PERGUNTAS_REU"
FASE_TESTEMUNHAS_REU_INQUIRICAO_AUTOR = "TESTEMUNHAS_REU_INQUIRICAO_AUTOR"
FASE_ALEGACOES_FINAIS_AUTOR = "ALEGACOES_FINAIS_AUTOR"
FASE_ALEGACOES_FINAIS_REU = "ALEGACOES_FINAIS_REU"
FASE_ANALISE_FINAL_PROFESSOR = "ANALISE_FINAL_PROFESSOR"
FASE_CONCLUIDA = "AIJ_CONCLUIDA"
# --- Predefined Case Data (from Script 2, adapted for Script 1 structure) ---
CASO_TITULO_PREDEFINIDO = "O Caso da Reportagem Revisitada"
CASO_PARTES_PREDEFINIDO = "Autor: Carlos Alberto Mendes\nRéu: Jornal 'A Verdade Diária'"
CASO_DESCRICAO_PREDEFINIDO = """
Uma pessoa (Carlos Alberto Mendes) processou um jornal (A Verdade Diária) alegando violação do direito ao esquecimento.
O jornal publicou uma matéria relembrando um crime ocorrido há 15 anos, no qual o autor foi
acusado de fraude, mas posteriormente absolvido por falta de provas. A matéria original foi publicada na época dos fatos
e a nova matéria, parte de uma série "Crimes que Marcaram a Cidade", revisitou o caso, mencionando a absolvição.
O autor alega que a republicação da história, mesmo com a menção da absolvição, causou-lhe
constrangimentos sociais, dificuldades em obter novo emprego e reacendeu traumas passados,
afetando sua vida familiar. Ele requer a remoção da matéria do site do jornal e uma indenização
por danos morais.
O jornal (réu) defende a liberdade de imprensa e o direito à informação, argumentando que
a matéria tem interesse público histórico, é factualmente correta (inclusive quanto à absolvição)
e faz parte do acervo jornalístico que documenta a história da comunidade.
"""
CASO_FATOS_COMPLETO_PREDEFINIDO = f"Título: {CASO_TITULO_PREDEFINIDO}\nPartes:\n{CASO_PARTES_PREDEFINIDO}\n\n---INÍCIO DOS FATOS---\n{CASO_DESCRICAO_PREDEFINIDO.strip()}"
ARGUMENTOS_AUTOR_PREDEFINIDOS = [
"Argumento: A matéria publicada reabriu feridas do passado e causou danos psicológicos e sociais ao autor. Prova: Laudo psicológico atestando abalo emocional e depoimentos sobre constrangimento social.",
"Argumento: O autor já foi absolvido judicialmente e tem direito a reconstruir sua vida sem o estigma do passado. Prova: Cópia da sentença absolutória.",
"Argumento: O tempo transcorrido (15 anos) torna o caso desatualizado e sem relevância pública atual que justifique a exposição. Prova: Irrelevância pública atual, foco no dano individual.",
"Argumento: A publicação violou o direito à privacidade e à honra do autor. Prova: Doutrina e jurisprudência sobre direitos da personalidade."
]
PROVAS_AUTOR_SUPPOSTAS_TEXTO_PREDEFINIDO = "\n".join(ARGUMENTOS_AUTOR_PREDEFINIDOS)
CONTRA_ARGUMENTOS_REU_PREDEFINIDOS = [
"Argumento: A liberdade de imprensa é um direito fundamental e a matéria é de interesse público histórico. Prova: Art. 5º, IX e XIV da CF/88; Doutrina sobre liberdade de imprensa.",
"Argumento: A matéria baseia-se inteiramente em informações verídicas e de acesso público (processo judicial). Prova: Cópia da matéria original e da recente, certidão do processo.",
"Argumento: O STF (RE 1.010.606) não reconheceu o direito ao esquecimento de forma absoluta, ponderando-o com a liberdade de informação. Prova: Inteiro teor do acórdão do RE 1.010.606.",
"Argumento: A matéria destacou a absolvição do autor, não havendo intenção de difamar. Prova: Conteúdo da própria matéria."
]
PROVAS_REU_TEXTO_PREDEFINIDO = "\n".join(CONTRA_ARGUMENTOS_REU_PREDEFINIDOS)
TESTEMUNHAS_REU_PREDEFINIDAS = [
{"nome": "João Silva", "pontos_chave": "Editor-chefe do jornal. Confirmará o processo editorial, o interesse público da série de reportagens e a ausência de intenção de prejudicar o autor."},
{"nome": "Dra. Maria Santos", "pontos_chave": "Historiadora local. Atestará a relevância histórica do caso para a comunidade e a importância de preservar a memória de tais eventos."},
{"nome": "Roberto Almeida", "pontos_chave": "Jornalista responsável pela matéria. Detalhará a pesquisa, a verificação dos fatos e a menção explícita à absolvição do autor."}
]
TESTEMUNHAS_REU_TEXTO_PREDEFINIDO = "\n".join([f"{t['nome']}: {t['pontos_chave']}" for t in TESTEMUNHAS_REU_PREDEFINIDAS])
# Para o caso padrão, precisamos de testemunhas do autor também.
TESTEMUNHAS_AUTOR_SUPPOSTAS_PREDEFINIDAS_TEXTO = """
Dr. Felipe Antunes: Psicólogo do autor. Relatará o impacto emocional da nova reportagem na vida do autor.
Sra. Clara Dias: Vizinha do autor. Comentará sobre as mudanças no tratamento social que o autor recebeu após a reportagem.
"""
LEGISLACAO_PRECEDENTES_PREDEFINIDO = {
"favoraveis_ao_reu": [
"Art. 5º, IV, IX e XIV da Constituição Federal - garantia da liberdade de expressão e acesso à informação",
"ADPF 130 (STF) - declarou a Lei de Imprensa incompatível com a ordem constitucional atual",
"RE 1.010.606 (STF) - não reconheceu o direito ao esquecimento na esfera civil de forma irrestrita",
"Pacto de San José da Costa Rica - proteção à liberdade de expressão",
],
"favoraveis_ao_autor": [
"Art. 5º, X da Constituição Federal - inviolabilidade da intimidade, vida privada e honra",
"Art. 21 do Código Civil - proteção à vida privada",
"Enunciado 531 da VI Jornada de Direito Civil - reconhece o direito ao esquecimento",
"LGPD (Lei Geral de Proteção de Dados) - embora não diretamente, reforça a proteção a dados pessoais."
]
}
# --- Funções de Estado e API (from Script 1) ---
def estado_inicial_simulacao():
return {
"fase_aij": FASE_INICIAL_CONFIG, "caso_fatos": "", "provas_reu_texto": "",
"provas_autor_supostas_texto": "", "testemunhas_reu_defs": [],
"testemunhas_autor_supostas_defs": [], "testemunha_autor_atual_idx": -1,
"testemunha_reu_atual_idx": -1, "testemunha_em_depoimento": None,
"transcricao_chat": [], "transcricao_logica": [],
"feedback_para_usuario": "Aguardando início da simulação.",
"instrucao_para_usuario": "Configure os detalhes do caso na aba 'Configuração' ou carregue o caso padrão."
}
def chamar_gemini_api(prompt_text, temperature=0.7, max_output_tokens=800):
if not GEMINI_API_KEY:
return "ERRO_FATAL: API Key do Gemini não configurada (verifique os Secrets do Space)."
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},
"safetySettings": [
{"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
{"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
{"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"},
{"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"}
]
}
try:
response = requests.post(api_url_com_chave, headers=headers, data=json.dumps(data), timeout=180) # Increased timeout
response.raise_for_status()
response_json = response.json()
if response_json.get("candidates") and response_json["candidates"][0].get("content"):
return response_json["candidates"][0]["content"]["parts"][0]["text"].strip()
elif response_json.get("promptFeedback") and response_json["promptFeedback"].get("blockReason"):
return f"ERRO_API: Conteúdo bloqueado. Razão: {response_json['promptFeedback']['blockReason']}"
return "ERRO_API: Resposta inesperada da API."
except requests.exceptions.Timeout:
return "ERRO_CONEXAO: Timeout ao chamar a API Gemini. Tente novamente."
except requests.exceptions.RequestException as e:
error_msg = f"ERRO_CONEXAO: {e}"
if e.response is not None:
try: error_msg += f" - Detalhes: {e.response.json().get('error', {}).get('message', e.response.text)}"
except json.JSONDecodeError: error_msg += f" - Resposta não JSON: {e.response.text}"
print(error_msg)
return error_msg
except Exception as e:
print(f"Erro desconhecido na API: {e}")
return f"ERRO_DESCONHECIDO: {e}"
def formatar_historico_para_prompt(transcricao_logica, max_turns=15):
historico_formatado = "\nContexto da Audiência (últimas interações):\n"
for ator, fala in transcricao_logica[-max_turns:]:
historico_formatado += f"- {ator}: {fala}\n"
return historico_formatado
# --- Funções de Geração de Conteúdo IA (from Script 1, some new) ---
def gerar_caso_ficticio_com_ia():
# (Função mantida como no Script 1 original)
prompt_geracao_caso = """
**Instrução de Persona:** Você é um roteirista jurídico criativo e experiente, especializado em criar casos simulados realistas para treinamento de advogados.
**Tarefa:** Crie um caso fictício detalhado para uma simulação de Audiência de Instrução e Julgamento (AIJ) sobre o tema "Direito ao Esquecimento vs. Liberdade de Imprensa".
**Elementos Obrigatórios a Serem Gerados:**
1. **Título do Caso Fictício:** (Ex: "O Caso da Notícia Ressurgida")
2. **Partes:** (Autor: Nome; Réu: Nome do veículo)
3. **Resumo Detalhado dos Fatos (Mínimo 250 palavras):** (Detalhes da publicação, lapso temporal, motivos do autor)
4. **Argumentos e "Provas" Hipotéticas da Parte AUTORA (mínimo 3):** (Formato: `Argumento: [Descrição]. Prova: [Descrição].`)
5. **Argumentos e "Provas" Hipotéticas da Parte RÉ (Jornal - mínimo 3):** (Formato: `Argumento: [Descrição]. Prova: [Descrição].`)
6. **Testemunhas Hipotéticas da Parte AUTORA (Pelo menos 1, idealmente 2):** (Formato: `[Nome]: [Pontos Chave]`)
7. **Testemunhas Hipotéticas da Parte RÉ (Pelo menos 1, idealmente 2):** (Formato: `[Nome]: [Pontos Chave]`)
**Formato da Saída:** Use os seguintes marcadores exatos para cada seção (iniciando em nova linha):
`## Título do Caso Fictício`
`## Partes`
`## Resumo Detalhado dos Fatos`
`## Argumentos e "Provas" Hipotéticas da Parte AUTORA`
`## Argumentos e "Provas" Hipotéticas da Parte RÉ (Jornal)`
`## Testemunhas Hipotéticas da Parte AUTORA`
`## Testemunhas Hipotéticas da Parte RÉ`
O conteúdo de cada seção deve vir após o marcador. Para Argumentos/Provas e Testemunhas, liste cada item em uma nova linha.
"""
texto_caso_completo = chamar_gemini_api(prompt_geracao_caso, temperature=0.75, max_output_tokens=2500) # Increased tokens
if "ERRO_" in texto_caso_completo:
return {"fatos": f"Falha ao gerar caso com IA: {texto_caso_completo}", "provas_autor": "", "provas_reu": "", "testemunhas_autor": "", "testemunhas_reu": ""}
return parse_caso_gerado(texto_caso_completo)
def parse_caso_gerado(texto_completo_caso):
# (Função mantida como no Script 1 original)
dados_caso = {"fatos": "Falha parsing: Fatos", "provas_autor": "Falha parsing: Provas Autor", "provas_reu": "Falha parsing: Provas Réu", "testemunhas_autor": "Falha parsing: Testemunhas Autor", "testemunhas_reu": "Falha parsing: Testemunhas Réu"}
secoes = {"fatos": "## Resumo Detalhado dos Fatos", "provas_autor": "## Argumentos e \"Provas\" Hipotéticas da Parte AUTORA", "provas_reu": "## Argumentos e \"Provas\" Hipotéticas da Parte RÉ (Jornal)", "testemunhas_autor": "## Testemunhas Hipotéticas da Parte AUTORA", "testemunhas_reu": "## Testemunhas Hipotéticas da Parte RÉ"}
fatos_prefix = ""
try:
titulo_match = texto_completo_caso.split("## Título do Caso Fictício")[1].split("## Partes")[0].strip()
partes_match_text = texto_completo_caso.split("## Partes")[1].split(secoes["fatos"])[0].strip()
fatos_prefix = f"Título: {titulo_match}\nPartes:\n{partes_match_text}\n\n---INÍCIO DOS FATOS---\n"
except IndexError: pass
texto_lower = texto_completo_caso.lower()
chaves_ordenadas = ["fatos", "provas_autor", "provas_reu", "testemunhas_autor", "testemunhas_reu"]
marcadores_lower = {k: secoes[k].lower() for k in secoes}
current_pos = 0
for i, chave_atual in enumerate(chaves_ordenadas):
marcador_atual_lower = marcadores_lower[chave_atual]
inicio_secao = texto_lower.find(marcador_atual_lower, current_pos)
if inicio_secao == -1: continue
inicio_conteudo = texto_completo_caso.find("\n", inicio_secao) + 1 if texto_completo_caso.find("\n", inicio_secao) != -1 else inicio_secao + len(secoes[chave_atual])
fim_conteudo = len(texto_completo_caso)
if i + 1 < len(chaves_ordenadas):
marcador_proximo_lower = marcadores_lower[chaves_ordenadas[i+1]]
fim_conteudo_temp = texto_lower.find(marcador_proximo_lower, inicio_conteudo)
if fim_conteudo_temp != -1: fim_conteudo = fim_conteudo_temp
conteudo_secao = texto_completo_caso[inicio_conteudo:fim_conteudo].strip()
dados_caso[chave_atual] = fatos_prefix + conteudo_secao if chave_atual == "fatos" and fatos_prefix else conteudo_secao
current_pos = fim_conteudo
for key_testemunha in ["testemunhas_autor", "testemunhas_reu"]:
if "Falha no parsing" not in dados_caso[key_testemunha] and dados_caso[key_testemunha]: # Check if not empty
linhas = dados_caso[key_testemunha].split('\n')
linhas_formatadas = []
for linha in linhas:
if linha.strip():
partes = linha.split(':', 1)
if len(partes) == 2:
linhas_formatadas.append(f"{partes[0].strip()}: {partes[1].strip()}")
else:
linhas_formatadas.append(partes[0].strip()) # Handle lines without colon if necessary
dados_caso[key_testemunha] = "\n".join(linhas_formatadas)
return dados_caso
def acao_gerar_caso_ficticio_ui():
gr.Info("Gerando caso fictício com IA... Isso pode levar um momento.")
dados_gerados = gerar_caso_ficticio_com_ia()
return [dados_gerados["fatos"], dados_gerados["provas_reu"], dados_gerados["provas_autor"], dados_gerados["testemunhas_reu"], dados_gerados["testemunhas_autor"], "Caso fictício gerado. Revise e salve."]
def acao_carregar_caso_padrao_ui():
gr.Info("Carregando caso padrão...")
return [
CASO_FATOS_COMPLETO_PREDEFINIDO,
PROVAS_REU_TEXTO_PREDEFINIDO,
PROVAS_AUTOR_SUPPOSTAS_TEXTO_PREDEFINIDO,
TESTEMUNHAS_REU_TEXTO_PREDEFINIDO,
TESTEMUNHAS_AUTOR_SUPPOSTAS_PREDEFINIDAS_TEXTO,
"Caso padrão carregado. Revise e salve."
]
def gerar_resposta_juiz_ia(estado_simulacao, acao_especifica=""):
# (Função mantida como no Script 1 original)
fase = estado_simulacao["fase_aij"]
historico = formatar_historico_para_prompt(estado_simulacao["transcricao_logica"])
prompt = f"**Persona:** Juiz(a) experiente em AIJ (Direito Esquecimento vs Liberdade Imprensa).\n**Fatos:** {estado_simulacao['caso_fatos'] or 'Não detalhado.'}\n{historico}**Fase Atual:** {fase}\n"
if fase == FASE_ABERTURA_CONCILIACAO: prompt += "**Tarefa:** Declare audiência aberta, pergunte sobre conciliação. Se já houve manifestação e sem acordo, anuncie prosseguimento para testemunhas do autor."
elif fase == FASE_TESTEMUNHAS_AUTOR_INICIO: prompt += f"**Tarefa:** Anuncie oitiva testemunhas do Autor. Peça ao Adv. Autor (IA) para qualificar e inquirir a primeira. (Supostas test. Autor: {', '.join([t['nome'] for t in estado_simulacao['testemunhas_autor_supostas_defs']]) or 'Nenhuma'})"
elif fase == FASE_TESTEMUNHAS_REU_INICIO: prompt += f"**Tarefa:** Anuncie oitiva testemunhas do Réu. Peça ao Adv. Réu (Usuário) para indicar a primeira. (Test. Réu: {', '.join([t['nome'] for t in estado_simulacao['testemunhas_reu_defs']]) or 'Nenhuma'})"
elif fase == FASE_ALEGACOES_FINAIS_AUTOR: prompt += "**Tarefa:** Anuncie encerramento instrução. Conceda palavra ao Adv. Autor (IA) para alegações finais."
elif fase == FASE_ALEGACOES_FINAIS_REU: prompt += "**Tarefa:** Após alegações do Autor, conceda palavra ao Adv. Réu (Usuário) para suas alegações."
elif fase == FASE_ANALISE_FINAL_PROFESSOR: prompt += "**Tarefa:** Declare audiência encerrada para julgamento (simulado)."
else: prompt += f"**Tarefa:** Conduza a audiência. Ação específica: {acao_especifica or 'Nenhuma'}. Mantenha ordem e fluxo."
prompt += "\n**Sua Fala (Juiz):**"
return chamar_gemini_api(prompt, temperature=0.6, max_output_tokens=300)
def gerar_resposta_advogado_autor_ia(estado_simulacao, fala_adv_reu=""):
# (Função mantida como no Script 1 original)
fase = estado_simulacao["fase_aij"]
historico = formatar_historico_para_prompt(estado_simulacao["transcricao_logica"])
prompt = f"**Persona:** Advogado(a) do AUTOR em AIJ (Direito Esquecimento vs Liberdade Imprensa). Cliente busca esquecimento/reparação.\n**Réu:** Jornal.\n**Fatos:** {estado_simulacao['caso_fatos'] or 'Não detalhado.'}\n**Provas/Argumentos Autor:** {estado_simulacao['provas_autor_supostas_texto'] or 'Passagem tempo, desinteresse público, dano vida privada.'}\n{historico}**Fase Atual:** {fase}\n"
if fase == FASE_ABERTURA_CONCILIACAO: prompt += f"**Tarefa:** Juiz perguntou sobre conciliação. Apresente proposta ou declare desinteresse. Se Réu já falou (\"{fala_adv_reu}\"), responda."
elif fase == FASE_TESTEMUNHAS_AUTOR_INICIO:
if estado_simulacao["testemunhas_autor_supostas_defs"]:
proxima_testemunha_idx = estado_simulacao["testemunha_autor_atual_idx"] + 1
if proxima_testemunha_idx < len(estado_simulacao["testemunhas_autor_supostas_defs"]):
testemunha_nome = estado_simulacao["testemunhas_autor_supostas_defs"][proxima_testemunha_idx]["nome"]
prompt += f"**Tarefa:** Juiz pediu para chamar testemunha. Chame {testemunha_nome}. Faça 1-2 perguntas iniciais (Ex: 'Sra. {testemunha_nome}, confirme conhecimento sobre X?')."
else: return "Advogado do Autor (IA): Não tenho mais testemunhas a apresentar, Excelência."
else: return "Advogado do Autor (IA): Não arrolei testemunhas, Excelência."
elif fase == FASE_TESTEMUNHAS_REU_INQUIRICAO_AUTOR:
testemunha_reu_obj = estado_simulacao.get("testemunha_em_depoimento")
if testemunha_reu_obj and testemunha_reu_obj["parte"] == "REU":
prompt += f"**Tarefa:** Testemunha do Réu ({testemunha_reu_obj['nome']}) depôs. Formule 1-2 perguntas incisivas. (Pontos chave dela: {testemunha_reu_obj.get('pontos_chave', 'Não informado')})"
else: return "Advogado do Autor (IA): (Erro interno - sem testemunha do réu para inquirir)"
elif fase == FASE_ALEGACOES_FINAIS_AUTOR: prompt += "**Tarefa:** Juiz concedeu palavra para alegações finais. Apresente resumo persuasivo e reitere pedidos."
else: prompt += f"**Contexto:** Adv. Réu (Usuário) disse: \"{fala_adv_reu}\"\n**Tarefa:** Responda estrategicamente."
prompt += "\n**Sua Resposta (Advogado Autor):**"
return chamar_gemini_api(prompt, temperature=0.75, max_output_tokens=450)
def gerar_resposta_testemunha_autor_ia(estado_simulacao, pergunta_feita):
# (Função mantida como no Script 1 original)
testemunha_obj = estado_simulacao.get("testemunha_em_depoimento")
if not testemunha_obj or testemunha_obj["parte"] != "AUTOR": return "Testemunha do Autor (IA): (Erro interno - Nenhuma testemunha do autor em depoimento)"
historico = formatar_historico_para_prompt(estado_simulacao["transcricao_logica"])
prompt = f"**Persona:** Testemunha {testemunha_obj['nome']} (AUTOR).\n**Caso:** Direito Esquecimento vs Liberdade Imprensa.\n**Fatos:** {estado_simulacao['caso_fatos'] or 'Não detalhado.'}\n**Seus Pontos Chave:** {testemunha_obj['pontos_chave'] or 'Conhecimento geral sobre autor e impactos.'}\n{historico}**Pergunta Feita:** \"{pergunta_feita}\"\n**Tarefa:** Responda claro, conciso, baseado nos seus pontos. Se Adv. Réu, seja cauteloso(a).\n**Sua Resposta (Testemunha {testemunha_obj['nome']}):**"
return chamar_gemini_api(prompt, temperature=0.6, max_output_tokens=250)
def analisar_atuacao_defesa_ia(estado_simulacao, ultima_fala_reu=""):
# (Função mantida como no Script 1 original)
historico_completo_dialogo = formatar_historico_para_prompt(estado_simulacao["transcricao_logica"], max_turns=len(estado_simulacao["transcricao_logica"]))
prompt_analise = f"**Persona:** Professor(a) de Prática Jurídica experiente.\n**Tarefa:** Feedback construtivo para aluno (Adv. RÉU - Jornal) em AIJ (Direito Esquecimento vs Liberdade Imprensa).\n**Fatos:** {estado_simulacao['caso_fatos'] or 'Não detalhado.'}\n**Provas/Argumentos Réu:** {estado_simulacao['provas_reu_texto'] or 'Não detalhado.'}\n**Transcrição AIJ:** {historico_completo_dialogo}\n**Última Intervenção Réu:** \"{ultima_fala_reu}\"\n**Feedback Detalhado (Pontos Fortes, Melhorias, Sugestões, Fundamentação, Estratégia):**"
return chamar_gemini_api(prompt_analise, temperature=0.65, max_output_tokens=1200)
# --- Novas Funções de IA para Treinamento (inspiradas em Script 2) ---
def avaliar_argumentos_defesa_ia(fatos_caso, provas_reu, tipo_argumento, argumento_usuario):
if not argumento_usuario.strip():
return "Por favor, insira seus argumentos para avaliação."
contexto_caso = f"""
Você está avaliando argumentos no contexto de um caso jurídico no Brasil sobre direito ao esquecimento vs. liberdade de imprensa.
O usuário representa a defesa (jornal).
**Fatos do Caso:** {fatos_caso if fatos_caso else CASO_DESCRICAO_PREDEFINIDO}
**Principais Argumentos/Provas da Defesa (Jornal):** {provas_reu if provas_reu else "\n".join(CONTRA_ARGUMENTOS_REU_PREDEFINIDOS)}
"""
prompt = f"""
{contexto_caso}
**Persona:** Você é um Juiz experiente em um tribunal brasileiro, com especialidade em casos de liberdade de imprensa e direitos da personalidade.
**Tarefa:** Avalie o seguinte argumento apresentado pelo advogado de defesa (jornal) para a peça/momento processual: "{tipo_argumento}".
Forneça feedback detalhado e construtivo em português brasileiro, incluindo:
1. **Pontos Fortes:** Destaque aspectos positivos (ex: fundamentação legal sólida, coerência lógica, clareza, persuasão, uso de fatos).
2. **Pontos a Melhorar:** Identifique fraquezas (ex: falta de aprofundamento, generalizações, omissão de contrapontos importantes, linguagem inadequada, falta de nexo com os fatos/provas do réu).
3. **Sugestões Específicas:** Ofereça conselhos práticos para aprimoramento (ex: citar precedentes específicos como o RE 1.010.606/STF, refutar explicitamente possíveis argumentos do autor, conectar melhor o argumento às provas do réu, sugerir redação alternativa).
4. **Nota Geral (0 a 5):** Atribua uma nota considerando:
* Fundamentação Legal/Jurisprudencial (Peso 3)
* Coerência e Lógica (Peso 2)
* Persuasão e Clareza (Peso 2)
* Adequação ao tipo de peça/momento (Peso 1)
* Conexão com os fatos/provas do caso (Peso 2)
Formato da Resposta: Utilize linguagem formal e jurídica. Estruture a resposta rigorosamente com os títulos:
`### Pontos Fortes`
`### Pontos a Melhorar`
`### Sugestões Específicas`
`### Nota Geral`
**Argumento do Advogado de Defesa (Jornal):**
"{argumento_usuario}"
**Sua Avaliação:**
"""
return chamar_gemini_api(prompt, temperature=0.6, max_output_tokens=1000)
def gerar_resposta_testemunha_defesa_para_treino_ia(fatos_caso, nome_testemunha, pontos_chave_testemunha, historico_perguntas_respostas, pergunta_atual_adv_defesa):
contexto_caso = f"""
Você está simulando o depoimento de uma testemunha de DEFESA (Jornal) em uma Audiência de Instrução e Julgamento (AIJ) no Brasil.
O caso envolve Direito ao Esquecimento vs. Liberdade de Imprensa. O jornal (réu) é processado por relembrar um crime antigo (com absolvição) do autor.
**Fatos do Caso:** {fatos_caso if fatos_caso else CASO_DESCRICAO_PREDEFINIDO}
"""
historico_formatado = "\nDepoimento até agora:\n"
for p, r in historico_perguntas_respostas:
historico_formatado += f"- Advogado Defesa: {p}\n- {nome_testemunha}: {r}\n"
prompt = f"""
{contexto_caso}
**Persona:** Você é {nome_testemunha}, testemunha arrolada pela DEFESA (Jornal).
**Seus Pontos Chave a Defender/Explicar:** {pontos_chave_testemunha}
Você deve responder às perguntas do advogado de defesa de forma consistente com esses pontos e com a tese da defesa (liberdade de imprensa, interesse público, veracidade, ausência de dolo/culpa, destaque à absolvição do autor no caso original).
Use linguagem formal, mas acessível para uma testemunha. Seja objetivo e direto. Evite admitir qualquer falha ou negligência por parte do jornal.
{historico_formatado if historico_perguntas_respostas else "Este é o início do seu depoimento."}
**Pergunta do Advogado de Defesa (Jornal):** "{pergunta_atual_adv_defesa}"
**Sua Resposta ({nome_testemunha}):**
"""
return chamar_gemini_api(prompt, temperature=0.5, max_output_tokens=300)
# --- Funções de Lógica da Simulação e UI (from Script 1, adaptadas e com novas) ---
def adicionar_fala_transcricao(estado_simulacao, ator, fala):
# (Função mantida como no Script 1 original)
estado_simulacao["transcricao_logica"].append((ator, fala))
if ator == "Advogado do Réu (Você)": estado_simulacao["transcricao_chat"].append((fala, None))
else:
if estado_simulacao["transcricao_chat"] and estado_simulacao["transcricao_chat"][-1][1] is None:
estado_simulacao["transcricao_chat"][-1] = (estado_simulacao["transcricao_chat"][-1][0], fala)
else: estado_simulacao["transcricao_chat"].append((None, fala))
return estado_simulacao
def mostrar_botoes_corretos(fase_atual):
# (Função mantida como no Script 1 original)
vis = {
"btn_responder_conciliacao": fase_atual == FASE_ABERTURA_CONCILIACAO,
"btn_chamar_testemunha_reu": fase_atual == FASE_TESTEMUNHAS_REU_INICIO,
"dropdown_testemunhas_reu": fase_atual == FASE_TESTEMUNHAS_REU_INICIO,
"btn_perguntar_testemunha_autor": fase_atual == FASE_TESTEMUNHAS_AUTOR_CONTRADITA_REU,
"btn_adv_reu_pergunta_sua_testemunha": fase_atual == FASE_TESTEMUNHAS_REU_PERGUNTAS_REU,
"btn_adv_reu_responde_pela_sua_testemunha": fase_atual == FASE_TESTEMUNHAS_REU_INQUIRICAO_AUTOR,
"btn_apresentar_alegacoes_finais_reu": fase_atual == FASE_ALEGACOES_FINAIS_REU,
"btn_juiz_avancar_fase": fase_atual not in [FASE_INICIAL_CONFIG, FASE_CONCLUIDA] and fase_atual != FASE_ALEGACOES_FINAIS_REU
}
return [gr.update(visible=vis[k]) for k in sorted(vis.keys())]
def configurar_e_iniciar_simulacao(estado_s, fatos, p_reu, p_autor, t_reu_str, t_autor_str):
# (Função adaptada do Script 1)
novo_estado = estado_inicial_simulacao()
if not fatos or not p_reu or not p_autor: # Basic validation
gr.Warning("Por favor, preencha todos os campos de configuração do caso ou carregue o caso padrão.")
return [novo_estado, novo_estado["transcricao_chat"], "Erro: Configuração incompleta.", "Preencha a configuração.", gr.Dropdown(choices=[], value=None)] + mostrar_botoes_corretos(novo_estado["fase_aij"])
novo_estado["caso_fatos"], novo_estado["provas_reu_texto"], novo_estado["provas_autor_supostas_texto"] = fatos, p_reu, p_autor
def parse_testemunhas(t_str):
defs = []
if t_str and t_str.strip():
for linha in t_str.strip().split('\n'):
if linha.strip():
partes = linha.split(':', 1)
if len(partes) == 2:
defs.append({"nome": partes[0].strip(), "pontos_chave": partes[1].strip()})
elif len(partes) == 1 and partes[0].strip(): # Testemunha sem pontos chave explícitos
defs.append({"nome": partes[0].strip(), "pontos_chave": "Não especificado."})
return defs
novo_estado["testemunhas_reu_defs"] = parse_testemunhas(t_reu_str)
novo_estado["testemunhas_autor_supostas_defs"] = parse_testemunhas(t_autor_str)
novo_estado["fase_aij"] = FASE_ABERTURA_CONCILIACAO
novo_estado = adicionar_fala_transcricao(novo_estado, "Sistema", "Configuração salva. Iniciando simulação...")
gr.Info("Iniciando simulação... Gerando falas iniciais da IA.")
fala_juiz = gerar_resposta_juiz_ia(novo_estado)
novo_estado = adicionar_fala_transcricao(novo_estado, "Juiz (IA)", fala_juiz)
fala_adv_autor = gerar_resposta_advogado_autor_ia(novo_estado)
novo_estado = adicionar_fala_transcricao(novo_estado, "Advogado do Autor (IA)", fala_adv_autor)
novo_estado["instrucao_para_usuario"] = "Responda à proposta de conciliação do Autor ou declare sua posição."
novo_estado["feedback_para_usuario"] = analisar_atuacao_defesa_ia(novo_estado)
nomes_testemunhas_reu = [t["nome"] for t in novo_estado["testemunhas_reu_defs"]] if novo_estado["testemunhas_reu_defs"] else []
botoes_vis = mostrar_botoes_corretos(novo_estado["fase_aij"])
gr.Info("Simulação iniciada.")
return [novo_estado, novo_estado["transcricao_chat"], novo_estado["feedback_para_usuario"], novo_estado["instrucao_para_usuario"], gr.Dropdown(choices=nomes_testemunhas_reu, value=None, interactive=True)] + botoes_vis
def lidar_com_fala_usuario(estado_s, fala_usuario_txt):
# (Função mantida como no Script 1 original, com pequenas adaptações)
if not fala_usuario_txt and estado_s["fase_aij"] not in [FASE_TESTEMUNHAS_REU_INICIO]:
estado_s["instrucao_para_usuario"] = "Por favor, digite sua fala ou selecione uma ação."
return [estado_s, estado_s["transcricao_chat"], estado_s["feedback_para_usuario"], estado_s["instrucao_para_usuario"], gr.Textbox(value="")] + mostrar_botoes_corretos(estado_s["fase_aij"])
estado_s = copy.deepcopy(estado_s)
ator_usuario = "Advogado do Réu (Você)"
if estado_s["fase_aij"] == FASE_TESTEMUNHAS_REU_PERGUNTAS_REU and estado_s.get("testemunha_em_depoimento"):
ator_usuario = f"Advogado do Réu (Você) perguntando a {estado_s['testemunha_em_depoimento']['nome']}"
elif estado_s["fase_aij"] == FASE_TESTEMUNHAS_REU_INQUIRICAO_AUTOR and estado_s.get("testemunha_em_depoimento"):
ator_usuario = f"Testemunha {estado_s['testemunha_em_depoimento']['nome']} (Réu) respondendo"
if fala_usuario_txt:
estado_s = adicionar_fala_transcricao(estado_s, ator_usuario, fala_usuario_txt)
gr.Info(f"Sua fala registrada. Aguardando respostas da IA...")
# Lógica de transição de fases e respostas da IA
if estado_s["fase_aij"] == FASE_ABERTURA_CONCILIACAO:
fala_adv_autor = gerar_resposta_advogado_autor_ia(estado_s, fala_adv_reu=fala_usuario_txt)
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_adv_autor)
fala_juiz = gerar_resposta_juiz_ia(estado_s, acao_especifica="Partes se manifestaram sobre conciliação. Decida o prosseguimento.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
if any(k in fala_juiz.lower() for k in ["testemunha", "instrução", "prossegu", "oitiva"]):
if estado_s["testemunhas_autor_supostas_defs"]:
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_TESTEMUNHAS_AUTOR_INICIO, "Aguarde Juiz/Adv.Autor chamarem testemunha."
# Adicionar fala do Adv. Autor chamando a testemunha
fala_adv_autor_chamando = gerar_resposta_advogado_autor_ia(estado_s)
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_adv_autor_chamando)
if not ("Não tenho mais testemunhas" in fala_adv_autor_chamando or "Não arrolei testemunhas" in fala_adv_autor_chamando):
estado_s["testemunha_autor_atual_idx"] += 1
idx = estado_s["testemunha_autor_atual_idx"]
if idx < len(estado_s["testemunhas_autor_supostas_defs"]):
t_info = estado_s["testemunhas_autor_supostas_defs"][idx]
estado_s["testemunha_em_depoimento"] = {"nome": t_info["nome"], "pontos_chave": t_info["pontos_chave"], "parte": "AUTOR"}
fala_test_autor = gerar_resposta_testemunha_autor_ia(estado_s, pergunta_feita=fala_adv_autor_chamando)
estado_s = adicionar_fala_transcricao(estado_s, f"Testemunha {t_info['nome']} (Autor - IA)", fala_test_autor)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_TESTEMUNHAS_AUTOR_CONTRADITA_REU, f"Contradite/pergunte à testemunha {t_info['nome']} (Autor)."
elif estado_s["testemunhas_reu_defs"]:
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_TESTEMUNHAS_REU_INICIO, "Selecione sua testemunha para chamar."
else:
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_ALEGACOES_FINAIS_AUTOR, "Aguarde Juiz iniciar Alegações Finais."
# Se for para alegações do autor, o juiz deve dar a palavra e o adv. autor falar
fala_juiz_aleg = gerar_resposta_juiz_ia(estado_s)
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz_aleg)
fala_aleg_autor = gerar_resposta_advogado_autor_ia(estado_s)
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_aleg_autor)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_ALEGACOES_FINAIS_REU, "Apresente suas Alegações Finais."
else:
estado_s["instrucao_para_usuario"] = "Responda ao Juiz ou Adv. Autor sobre conciliação."
elif estado_s["fase_aij"] == FASE_TESTEMUNHAS_AUTOR_CONTRADITA_REU:
fala_test_autor = gerar_resposta_testemunha_autor_ia(estado_s, pergunta_feita=fala_usuario_txt)
estado_s = adicionar_fala_transcricao(estado_s, f"Testemunha {estado_s['testemunha_em_depoimento']['nome']} (Autor - IA)", fala_test_autor)
estado_s["instrucao_para_usuario"] = f"Faça outra pergunta à testemunha {estado_s['testemunha_em_depoimento']['nome']} (Autor) ou clique 'Juiz Avançar'."
elif estado_s["fase_aij"] == FASE_TESTEMUNHAS_REU_PERGUNTAS_REU: # Usuário (Adv Réu) perguntou à sua testemunha
# Aqui, o usuário está *atuando* como sua testemunha para responder à sua própria pergunta.
# A IA do Adv. Autor fará perguntas à testemunha do Réu.
# O usuário deve então responder como se fosse sua testemunha.
# Após a pergunta do usuário à sua testemunha, e a resposta simulada (pelo usuário mesmo, no chat),
# o Adv. Autor (IA) deve ter a chance de inquirir.
estado_s["fase_aij"] = FASE_TESTEMUNHAS_REU_INQUIRICAO_AUTOR
fala_adv_autor_ia = gerar_resposta_advogado_autor_ia(estado_s) # Adv. Autor IA pergunta à testemunha do Réu
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_adv_autor_ia)
estado_s["instrucao_para_usuario"] = f"Como testemunha {estado_s['testemunha_em_depoimento']['nome']}, responda à pergunta do Adv. Autor."
elif estado_s["fase_aij"] == FASE_TESTEMUNHAS_REU_INQUIRICAO_AUTOR: # Usuário respondeu como sua testemunha à pergunta do Adv. Autor
# Advogado do Autor (IA) pode fazer mais perguntas ou encerrar.
fala_adv_autor_ia = gerar_resposta_advogado_autor_ia(estado_s, fala_adv_reu=fala_usuario_txt) # Passa a resposta da testemunha do réu
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_adv_autor_ia)
if "pergunta" in fala_adv_autor_ia.lower() or "?" in fala_adv_autor_ia and "não tenho mais perguntas" not in fala_adv_autor_ia.lower():
estado_s["instrucao_para_usuario"] = f"Como testemunha {estado_s['testemunha_em_depoimento']['nome']}, responda à nova pergunta do Adv. Autor."
else: # Adv. Autor não tem mais perguntas
fala_juiz = gerar_resposta_juiz_ia(estado_s, acao_especifica=f"Adv. Autor encerrou inquirição da testemunha {estado_s['testemunha_em_depoimento']['nome']}. Adv. Réu pode fazer mais perguntas ou dispensar.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
estado_s["fase_aij"] = FASE_TESTEMUNHAS_REU_PERGUNTAS_REU # Volta para Adv. Réu perguntar
estado_s["instrucao_para_usuario"] = f"Faça mais perguntas à sua testemunha {estado_s['testemunha_em_depoimento']['nome']}, ou clique 'Juiz Avançar' para dispensá-la."
elif estado_s["fase_aij"] == FASE_ALEGACOES_FINAIS_REU:
estado_s["fase_aij"] = FASE_ANALISE_FINAL_PROFESSOR
fala_juiz = gerar_resposta_juiz_ia(estado_s)
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
estado_s["instrucao_para_usuario"] = "Audiência encerrada para sentença (simulada). Veja o feedback final do Professor IA."
# Analise final é chamada abaixo
estado_s["feedback_para_usuario"] = analisar_atuacao_defesa_ia(estado_s, ultima_fala_reu=fala_usuario_txt if ator_usuario == "Advogado do Réu (Você)" else "")
gr.Info("Respostas da IA geradas.")
return [estado_s, estado_s["transcricao_chat"], estado_s["feedback_para_usuario"], estado_s["instrucao_para_usuario"], gr.Textbox(value="")] + mostrar_botoes_corretos(estado_s["fase_aij"])
def acao_botao_juiz_avancar(estado_s):
# (Função mantida e adaptada do Script 1)
estado_s = copy.deepcopy(estado_s)
fase_atual = estado_s["fase_aij"]
gr.Info(f"Avançando fase a partir de: {fase_atual}. Aguarde IA...")
if fase_atual == FASE_ABERTURA_CONCILIACAO:
# Se partes não chegaram a acordo, ou se o usuário pulou a conciliação.
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", "Considerando frustrada a tentativa de conciliação, passaremos à instrução.")
if estado_s["testemunhas_autor_supostas_defs"]:
estado_s["fase_aij"] = FASE_TESTEMUNHAS_AUTOR_INICIO
fala_juiz = gerar_resposta_juiz_ia(estado_s)
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
fala_adv_autor = gerar_resposta_advogado_autor_ia(estado_s) # Adv Autor chama/pergunta
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_adv_autor)
if not ("Não tenho mais testemunhas" in fala_adv_autor or "Não arrolei testemunhas" in fala_adv_autor):
estado_s["testemunha_autor_atual_idx"] += 1
idx = estado_s["testemunha_autor_atual_idx"]
if idx < len(estado_s["testemunhas_autor_supostas_defs"]):
t_info = estado_s["testemunhas_autor_supostas_defs"][idx]
estado_s["testemunha_em_depoimento"] = {"nome": t_info["nome"], "pontos_chave": t_info["pontos_chave"], "parte": "AUTOR"}
fala_test_autor = gerar_resposta_testemunha_autor_ia(estado_s, pergunta_feita=fala_adv_autor) # Testemunha responde à pergunta inicial
estado_s = adicionar_fala_transcricao(estado_s, f"Testemunha {t_info['nome']} (Autor - IA)", fala_test_autor)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_TESTEMUNHAS_AUTOR_CONTRADITA_REU, f"Contradite ou faça perguntas à testemunha {t_info['nome']} (Autor)."
else: # Adv Autor não tem testemunhas, mesmo que tenha sido definido
if estado_s["testemunhas_reu_defs"]: estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_TESTEMUNHAS_REU_INICIO, "Selecione sua testemunha para chamar."
else: estado_s["fase_aij"] = FASE_ALEGACOES_FINAIS_AUTOR # Pula para alegações finais
elif estado_s["testemunhas_reu_defs"]:
estado_s["fase_aij"] = FASE_TESTEMUNHAS_REU_INICIO
fala_juiz = gerar_resposta_juiz_ia(estado_s)
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
estado_s["instrucao_para_usuario"] = "Selecione sua testemunha para chamar."
else: # Sem testemunhas de nenhuma parte
estado_s["fase_aij"] = FASE_ALEGACOES_FINAIS_AUTOR
fala_juiz = gerar_resposta_juiz_ia(estado_s) # Juiz anuncia alegações
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
fala_adv_autor = gerar_resposta_advogado_autor_ia(estado_s) # Adv Autor faz alegações
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_adv_autor)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_ALEGACOES_FINAIS_REU, "Apresente suas Alegações Finais."
elif fase_atual == FASE_TESTEMUNHAS_AUTOR_INICIO or fase_atual == FASE_TESTEMUNHAS_AUTOR_PERGUNTAS_AUTOR:
# Juiz pede ao Adv. Autor para chamar a *próxima* testemunha ou encerrar
fala_juiz = gerar_resposta_juiz_ia(estado_s, acao_especifica="Verificar se há mais testemunhas do Autor ou encerrar esta fase.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
fala_adv_autor = gerar_resposta_advogado_autor_ia(estado_s) # Adv. Autor chama próxima ou diz que não tem mais
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_adv_autor)
if "Não tenho mais testemunhas" in fala_adv_autor or "Não arrolei testemunhas" in fala_adv_autor or estado_s["testemunha_autor_atual_idx"] +1 >= len(estado_s["testemunhas_autor_supostas_defs"]):
estado_s["testemunha_em_depoimento"] = None
if estado_s["testemunhas_reu_defs"]:
estado_s["fase_aij"] = FASE_TESTEMUNHAS_REU_INICIO
fala_juiz_trans = gerar_resposta_juiz_ia(estado_s) # Juiz anuncia oitiva das testemunhas do Réu
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz_trans)
estado_s["instrucao_para_usuario"] = "Selecione sua testemunha para chamar."
else: # Sem testemunhas do Réu, vai para alegações finais
estado_s["fase_aij"] = FASE_ALEGACOES_FINAIS_AUTOR
fala_juiz_trans = gerar_resposta_juiz_ia(estado_s) # Juiz anuncia alegações
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz_trans)
fala_aleg_autor = gerar_resposta_advogado_autor_ia(estado_s) # Adv Autor faz alegações
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_aleg_autor)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_ALEGACOES_FINAIS_REU, "Apresente suas Alegações Finais."
else: # Adv Autor chamou próxima testemunha
estado_s["testemunha_autor_atual_idx"] += 1
idx = estado_s["testemunha_autor_atual_idx"]
# Garantir que o índice é válido
if idx < len(estado_s["testemunhas_autor_supostas_defs"]):
t_info = estado_s["testemunhas_autor_supostas_defs"][idx]
estado_s["testemunha_em_depoimento"] = {"nome": t_info["nome"], "pontos_chave": t_info["pontos_chave"], "parte": "AUTOR"}
fala_test_autor = gerar_resposta_testemunha_autor_ia(estado_s, pergunta_feita=fala_adv_autor) # Testemunha responde à pergunta inicial do Adv. Autor
estado_s = adicionar_fala_transcricao(estado_s, f"Testemunha {t_info['nome']} (Autor - IA)", fala_test_autor)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_TESTEMUNHAS_AUTOR_CONTRADITA_REU, f"Contradite ou faça perguntas à testemunha {t_info['nome']} (Autor)."
else: # Caso raro de lógica inconsistente, trata como se não houvesse mais testemunhas
estado_s["fase_aij"] = FASE_TESTEMUNHAS_REU_INICIO # Ou alegações finais, conforme lógica acima
# ... (repetir lógica de transição para Réu ou Alegações)
elif fase_atual == FASE_TESTEMUNHAS_AUTOR_CONTRADITA_REU:
# Usuário (Adv. Réu) terminou de perguntar à testemunha do Autor.
estado_s["testemunha_em_depoimento"] = None
# Verificar se há mais testemunhas do Autor
if estado_s["testemunha_autor_atual_idx"] + 1 < len(estado_s["testemunhas_autor_supostas_defs"]):
estado_s["fase_aij"] = FASE_TESTEMUNHAS_AUTOR_INICIO # Volta para o juiz pedir ao Adv. Autor chamar a próxima
fala_juiz = gerar_resposta_juiz_ia(estado_s, acao_especifica="Advogado do Réu encerrou perguntas à testemunha do Autor. Verificar próxima testemunha do Autor.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
# Adv Autor precisa ser chamado para agir
fala_adv_autor = gerar_resposta_advogado_autor_ia(estado_s) # Adv Autor chama/pergunta
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_adv_autor)
if not ("Não tenho mais testemunhas" in fala_adv_autor or "Não arrolei testemunhas" in fala_adv_autor):
estado_s["testemunha_autor_atual_idx"] += 1
idx_new = estado_s["testemunha_autor_atual_idx"]
if idx_new < len(estado_s["testemunhas_autor_supostas_defs"]):
t_info_new = estado_s["testemunhas_autor_supostas_defs"][idx_new]
estado_s["testemunha_em_depoimento"] = {"nome": t_info_new["nome"], "pontos_chave": t_info_new["pontos_chave"], "parte": "AUTOR"}
fala_test_autor_new = gerar_resposta_testemunha_autor_ia(estado_s, pergunta_feita=fala_adv_autor)
estado_s = adicionar_fala_transcricao(estado_s, f"Testemunha {t_info_new['nome']} (Autor - IA)", fala_test_autor_new)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_TESTEMUNHAS_AUTOR_CONTRADITA_REU, f"Contradite ou faça perguntas à testemunha {t_info_new['nome']} (Autor)."
else: # Adv. Autor não tem mais, mesmo que houvesse na lista (raro)
if estado_s["testemunhas_reu_defs"]: estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_TESTEMUNHAS_REU_INICIO, "Selecione sua testemunha para chamar."
else: estado_s["fase_aij"] = FASE_ALEGACOES_FINAIS_AUTOR
fala_juiz_trans = gerar_resposta_juiz_ia(estado_s) # Juiz comanda nova fase
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz_trans)
if estado_s["fase_aij"] == FASE_ALEGACOES_FINAIS_AUTOR:
fala_aleg_autor = gerar_resposta_advogado_autor_ia(estado_s)
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_aleg_autor)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_ALEGACOES_FINAIS_REU, "Apresente suas Alegações Finais."
else: # Não há mais testemunhas do Autor
if estado_s["testemunhas_reu_defs"]:
estado_s["fase_aij"] = FASE_TESTEMUNHAS_REU_INICIO
fala_juiz = gerar_resposta_juiz_ia(estado_s, acao_especifica="Encerrada oitiva das testemunhas do Autor. Iniciar oitiva das testemunhas do Réu.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
estado_s["instrucao_para_usuario"] = "Selecione sua testemunha para chamar."
else: # Sem testemunhas do Réu, vai para alegações finais
estado_s["fase_aij"] = FASE_ALEGACOES_FINAIS_AUTOR
fala_juiz = gerar_resposta_juiz_ia(estado_s, acao_especifica="Instrução encerrada. Passar para alegações finais do Autor.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
fala_aleg_autor = gerar_resposta_advogado_autor_ia(estado_s) # Adv Autor faz alegações
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_aleg_autor)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_ALEGACOES_FINAIS_REU, "Apresente suas Alegações Finais."
elif fase_atual in [FASE_TESTEMUNHAS_REU_PERGUNTAS_REU, FASE_TESTEMUNHAS_REU_INQUIRICAO_AUTOR]:
# Usuário (Adv. Réu) dispensou sua testemunha atual.
nome_test_dispensada = estado_s.get("testemunha_em_depoimento", {}).get("nome", "a testemunha do Réu")
estado_s["testemunha_em_depoimento"] = None
fala_juiz_dispensa = f"Juiz (IA): Dispensada {nome_test_dispensada}."
if estado_s.get("testemunha_em_depoimento"): # Adiciona só se havia uma testemunha em depoimento
fala_juiz_dispensa = gerar_resposta_juiz_ia(estado_s, acao_especifica=f"Dispensar {nome_test_dispensada}. Perguntar ao Adv. Réu se tem mais testemunhas.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz_dispensa)
if estado_s["testemunha_reu_atual_idx"] + 1 < len(estado_s["testemunhas_reu_defs"]):
estado_s["fase_aij"] = FASE_TESTEMUNHAS_REU_INICIO # Volta para o usuário selecionar a próxima
estado_s["instrucao_para_usuario"] = "Selecione sua próxima testemunha para chamar ou clique 'Juiz Avançar' para encerrar oitiva das suas testemunhas."
else: # Não há mais testemunhas do Réu
estado_s["fase_aij"] = FASE_ALEGACOES_FINAIS_AUTOR
fala_juiz = gerar_resposta_juiz_ia(estado_s, acao_especifica="Encerrada oitiva das testemunhas do Réu. Passar para alegações finais do Autor.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
fala_adv_autor = gerar_resposta_advogado_autor_ia(estado_s) # Adv Autor faz alegações
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Autor (IA)", fala_adv_autor)
estado_s["fase_aij"], estado_s["instrucao_para_usuario"] = FASE_ALEGACOES_FINAIS_REU, "Apresente suas Alegações Finais."
elif fase_atual == FASE_ALEGACOES_FINAIS_AUTOR:
# Adv. Autor terminou alegações, Juiz passa palavra ao Réu
estado_s["fase_aij"] = FASE_ALEGACOES_FINAIS_REU
fala_juiz = gerar_resposta_juiz_ia(estado_s) # Juiz passa a palavra ao Réu
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
estado_s["instrucao_para_usuario"] = "Apresente suas Alegações Finais."
else: # Fallback para fases não explicitamente tratadas acima
fala_juiz = gerar_resposta_juiz_ia(estado_s, acao_especifica="Conduza para a próxima etapa lógica da audiência.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
estado_s["instrucao_para_usuario"] = "Siga as instruções do Juiz ou avance a fase."
estado_s["feedback_para_usuario"] = analisar_atuacao_defesa_ia(estado_s)
gr.Info("Fase avançada. Interações da IA geradas.")
return [estado_s, estado_s["transcricao_chat"], estado_s["feedback_para_usuario"], estado_s["instrucao_para_usuario"]] + mostrar_botoes_corretos(estado_s["fase_aij"])
def chamar_testemunha_reu_selecionada(estado_s, nome_testemunha_selecionada):
# (Função mantida como no Script 1 original)
estado_s = copy.deepcopy(estado_s)
if not nome_testemunha_selecionada:
estado_s["instrucao_para_usuario"] = "Nenhuma testemunha selecionada. Por favor, selecione uma testemunha da lista."
gr.Warning("Selecione uma testemunha da lista.")
return [estado_s, estado_s["transcricao_chat"], estado_s["feedback_para_usuario"], estado_s["instrucao_para_usuario"]] + mostrar_botoes_corretos(estado_s["fase_aij"])
idx_testemunha = next((i for i, t in enumerate(estado_s["testemunhas_reu_defs"]) if t["nome"] == nome_testemunha_selecionada), -1)
if idx_testemunha == -1:
estado_s["instrucao_para_usuario"] = f"Testemunha '{nome_testemunha_selecionada}' não encontrada na configuração."
gr.Error(f"Testemunha '{nome_testemunha_selecionada}' não encontrada.")
return [estado_s, estado_s["transcricao_chat"], estado_s["feedback_para_usuario"], estado_s["instrucao_para_usuario"]] + mostrar_botoes_corretos(estado_s["fase_aij"])
estado_s["testemunha_reu_atual_idx"] = idx_testemunha
testemunha_obj = estado_s["testemunhas_reu_defs"][idx_testemunha]
estado_s["testemunha_em_depoimento"] = {"nome": testemunha_obj["nome"], "pontos_chave": testemunha_obj["pontos_chave"], "parte": "REU"}
gr.Info(f"Chamando testemunha {testemunha_obj['nome']}. Aguarde IA...")
estado_s = adicionar_fala_transcricao(estado_s, "Advogado do Réu (Você)", f"Chamo para depor minha testemunha, Sr(a). {testemunha_obj['nome']}.")
fala_juiz = gerar_resposta_juiz_ia(estado_s, acao_especifica=f"Advogado do Réu chamou a testemunha {testemunha_obj['nome']}. Qualifique-a e passe a palavra ao Advogado do Réu para inquirição inicial.")
estado_s = adicionar_fala_transcricao(estado_s, "Juiz (IA)", fala_juiz)
estado_s["fase_aij"] = FASE_TESTEMUNHAS_REU_PERGUNTAS_REU
estado_s["instrucao_para_usuario"] = f"Faça sua primeira pergunta à sua testemunha, {testemunha_obj['nome']}. Após sua pergunta e a resposta (que você digitará no chat como se fosse a testemunha), o Advogado do Autor (IA) poderá inquirir."
estado_s["feedback_para_usuario"] = analisar_atuacao_defesa_ia(estado_s)
gr.Info("Testemunha chamada. Interações da IA geradas.")
return [estado_s, estado_s["transcricao_chat"], estado_s["feedback_para_usuario"], estado_s["instrucao_para_usuario"]] + mostrar_botoes_corretos(estado_s["fase_aij"])
# --- UI Callbacks para Novas Abas ---
def avaliar_argumentos_defesa_ia_ui(fatos_caso_atual, provas_reu_atual, tipo_argumento_selecionado, argumento_digitado):
if not GEMINI_API_KEY: return "ERRO: API Key não configurada."
if not argumento_digitado or not tipo_argumento_selecionado:
return "Por favor, selecione o tipo de argumento e digite seu texto."
gr.Info(f"Avaliando seu argumento ({tipo_argumento_selecionado})... Aguarde.")
feedback = avaliar_argumentos_defesa_ia(fatos_caso_atual, provas_reu_atual, tipo_argumento_selecionado, argumento_digitado)
gr.Info("Avaliação concluída.")
return feedback
_historico_treino_testemunha_atual = [] # Simples cache para o diálogo de treino
def gerar_dialogo_testemunha_defesa_para_treino_ui(fatos_caso_atual, testemunhas_reu_defs_atual_str, testemunha_selecionada_nome, pergunta_adv_defesa):
global _historico_treino_testemunha_atual
if not GEMINI_API_KEY:
return _historico_treino_testemunha_atual + [ (None, "ERRO: API Key não configurada.") ]
if not testemunha_selecionada_nome:
return _historico_treino_testemunha_atual + [ (None, "Por favor, selecione uma testemunha da sua lista na aba 'Configuração'.") ]
if not pergunta_adv_defesa:
return _historico_treino_testemunha_atual + [ (None, "Por favor, digite sua pergunta para a testemunha.") ]
# Recriar testemunhas_reu_defs a partir da string (se fornecida e mudou) ou usar a padrão
testemunhas_reu_defs_usar = []
if testemunhas_reu_defs_atual_str:
try:
# Re-parse a string de testemunhas do réu da aba de configuração
linhas = testemunhas_reu_defs_atual_str.strip().split('\n')
for linha in linhas:
if linha.strip():
partes = linha.split(':', 1)
if len(partes) == 2:
testemunhas_reu_defs_usar.append({"nome": partes[0].strip(), "pontos_chave": partes[1].strip()})
elif len(partes) == 1: # Nome sem pontos chave
testemunhas_reu_defs_usar.append({"nome": partes[0].strip(), "pontos_chave": "Não especificado."})
except Exception as e:
print(f"Erro ao parsear testemunhas_reu_defs_atual_str: {e}")
testemunhas_reu_defs_usar = TESTEMUNHAS_REU_PREDEFINIDAS # Fallback
else:
testemunhas_reu_defs_usar = TESTEMUNHAS_REU_PREDEFINIDAS
testemunha_obj = next((t for t in testemunhas_reu_defs_usar if t["nome"] == testemunha_selecionada_nome), None)
if not testemunha_obj:
# Se não achou na lista dinâmica, tenta na lista padrão
testemunha_obj = next((t for t in TESTEMUNHAS_REU_PREDEFINIDAS if t["nome"] == testemunha_selecionada_nome), None)
if not testemunha_obj:
return _historico_treino_testemunha_atual + [ (None, f"Testemunha '{testemunha_selecionada_nome}' não encontrada. Verifique a aba 'Configuração'.") ]
# Reinicia o histórico se a testemunha mudou (simplificado)
if not _historico_treino_testemunha_atual or \
(_historico_treino_testemunha_atual and not _historico_treino_testemunha_atual[0][1].startswith(f"**{testemunha_obj['nome']}**:")):
_historico_treino_testemunha_atual = []
_historico_treino_testemunha_atual.append( (None, f"Iniciando inquirição de **{testemunha_obj['nome']}**. Pontos chave: {testemunha_obj['pontos_chave']}") )
gr.Info(f"Gerando resposta da testemunha {testemunha_obj['nome']}... Aguarde.")
resposta_testemunha = gerar_resposta_testemunha_defesa_para_treino_ia(
fatos_caso_atual if fatos_caso_atual else CASO_FATOS_COMPLETO_PREDEFINIDO,
testemunha_obj['nome'],
testemunha_obj['pontos_chave'],
[(q,r) for q,r in _historico_treino_testemunha_atual if q is not None], # Passa apenas Q/A anteriores
pergunta_adv_defesa
)
_historico_treino_testemunha_atual.append( (pergunta_adv_defesa, resposta_testemunha) )
gr.Info("Resposta da testemunha gerada.")
return _historico_treino_testemunha_atual, "" # Retorna o histórico e limpa o campo de pergunta
# --- Interface Gráfica (Gradio UI) ---
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="orange"), title="Simulador AIJ Interativo") as demo:
gr.Markdown("# ⚖️ Simulador Interativo de Audiência de Instrução e Julgamento (AIJ)")
gr.Markdown("Tema: **Direito ao Esquecimento vs. Liberdade de Imprensa**. Você assume o papel de **Advogado(a) do Réu (Jornal)**.")
if not GEMINI_API_KEY:
gr.Warning("API Key do Gemini (GEMINI_API_KEY) não encontrada! O aplicativo pode não funcionar corretamente. Configure-a como Secret neste Space ou localmente como variável de ambiente.")
sim_state = gr.State(value=estado_inicial_simulacao())
with gr.Tabs() as abas_principais:
with gr.TabItem("1. Configuração do Caso", id=0):
gr.Markdown("## Detalhes do Caso para Simulação")
gr.Markdown("Preencha os campos abaixo ou use os botões para gerar/carregar um caso.")
with gr.Row():
btn_gerar_caso_ia = gr.Button("✨ Gerar Novo Caso com IA", icon="🧠", scale=1)
btn_carregar_caso_padrao = gr.Button("📄 Carregar Caso Padrão (Esquecimento)", icon="📜", scale=1)
with gr.Row():
with gr.Column(scale=2):
fatos_input = gr.Textbox(lines=7, label="Resumo dos Fatos, Partes e Título:", placeholder="Descreva o caso ou gere/carregue.")
provas_reu_input = gr.Textbox(lines=4, label="Argumentos e Provas do Réu (Seu Cliente - Jornal):", placeholder="Ex: Arg: Liberdade de imprensa. Prova: Art. 5 CF.")
provas_autor_input = gr.Textbox(lines=4, label="Argumentos e Provas (Supostas) do Autor:", placeholder="Ex: Arg: Dano à imagem. Prova: Laudo X.")
with gr.Column(scale=1):
testemunhas_reu_input = gr.Textbox(lines=5, label="Suas Testemunhas (Réu) - Formato: Nome: Pontos Chave a Depor", placeholder="João Silva: Viu X e Y.\nMaria Costa: Sabe Z.")
testemunhas_autor_supostas_input = gr.Textbox(lines=5, label="Supostas Testemunhas do Autor - Formato: Nome: Pontos Chave", placeholder="Carlos Lima: Sofreu Z.\nAna B.: Testemunhará sobre Q.")
btn_config_iniciar = gr.Button("💾 Salvar Configurações e Iniciar Simulação Interativa", variant="primary")
status_config_output = gr.Label(value="Aguardando configuração do caso...")
outputs_gerar_caso = [fatos_input, provas_reu_input, provas_autor_input, testemunhas_reu_input, testemunhas_autor_supostas_input, status_config_output]
btn_gerar_caso_ia.click(acao_gerar_caso_ficticio_ui, inputs=None, outputs=outputs_gerar_caso)
btn_carregar_caso_padrao.click(acao_carregar_caso_padrao_ui, inputs=None, outputs=outputs_gerar_caso)
with gr.TabItem("2. Audiência Interativa", id=1):
gr.Markdown("## Andamento da Audiência Simulada")
instrucao_usuario_output = gr.Markdown("Instrução: Configure o caso na aba 'Configuração' e clique em 'Salvar e Iniciar' para começar.")
chat_aij_output = gr.Chatbot(label="Transcrição da Audiência", height=500, bubble_full_width=False, show_copy_button=True, avatar_images=(None, "https://img.icons8.com/fluency/96/robot-2.png"))
fala_usuario_input = gr.Textbox(show_label=False, placeholder="Digite sua fala aqui ou use os botões de ação abaixo...", scale=4, lines=3)
btn_enviar_fala_usuario = gr.Button("🎤 Enviar Fala / Ação", variant="stop")
with gr.Accordion("Ações Contextuais do Advogado do Réu (Você)", open=True):
with gr.Row():
btn_responder_conciliacao = gr.Button("Responder à Conciliação", visible=False)
dropdown_testemunhas_reu_select = gr.Dropdown(label="Sua Testemunha a Chamar:", choices=[], visible=False, interactive=True)
btn_chamar_testemunha_reu_action = gr.Button("Chamar Testemunha Selecionada", visible=False)
with gr.Row():
btn_perguntar_testemunha_autor_action = gr.Button("Perguntar à Test. do Autor", visible=False)
btn_adv_reu_pergunta_sua_testemunha_action = gr.Button("Perguntar à Minha Testemunha", visible=False)
btn_adv_reu_responde_pela_sua_testemunha_action = gr.Button("Responder pela Minha Testemunha (à IA)", visible=False)
btn_apresentar_alegacoes_finais_reu_action = gr.Button("Apresentar Alegações Finais", visible=False)
btn_juiz_avancar_fase_action = gr.Button("⚖️ Juiz (IA): Concluir Etapa / Avançar Fase", visible=False, variant="secondary")
lista_botoes_feedback = [btn_responder_conciliacao, btn_chamar_testemunha_reu_action, dropdown_testemunhas_reu_select, btn_perguntar_testemunha_autor_action, btn_adv_reu_pergunta_sua_testemunha_action, btn_adv_reu_responde_pela_sua_testemunha_action, btn_apresentar_alegacoes_finais_reu_action, btn_juiz_avancar_fase_action]
with gr.TabItem("3. Feedback da Atuação (Professor IA)", id=2):
gr.Markdown("## 💡 Análise da Sua Atuação na Audiência Interativa")
gr.Markdown("Este feedback é gerado pela IA com base na sua participação na aba 'Audiência Interativa'.")
feedback_output = gr.Textbox(lines=20, label="Feedback Detalhado:", interactive=False, show_copy_button=True)
with gr.TabItem("4. Treinamento de Argumentação (Defesa)", id=3):
gr.Markdown("## 🗣️ Pratique e Avalie Seus Argumentos (Advogado de Defesa)")
gr.Markdown("Use esta seção para redigir e obter feedback sobre argumentos específicos para o caso configurado.")
with gr.Row():
fatos_caso_treino_arg_display = gr.Textbox(label="Fatos do Caso (da Configuração):", value=CASO_FATOS_COMPLETO_PREDEFINIDO, lines=5, interactive=False) # Mostra fatos do caso padrão ou o configurado
provas_reu_treino_arg_display = gr.Textbox(label="Provas do Réu (da Configuração):", value=PROVAS_REU_TEXTO_PREDEFINIDO, lines=5, interactive=False)
tipo_argumento_treino = gr.Radio(
["Contestação (teses principais)", "Perguntas para Testemunha do Autor", "Perguntas para Testemunha do Réu", "Alegações Finais (memoriais)"],
label="Selecione o Tipo de Argumento/Peça para Treinar:", value="Alegações Finais (memoriais)"
)
argumento_input_treino = gr.Textbox(lines=10, label="Digite seu argumento aqui:", placeholder="Ex: 'Excelência, a matéria jornalística é um retrato fiel dos fatos públicos...'")
btn_avaliar_argumento_treino = gr.Button("🤖 Avaliar Argumento com IA", variant="primary")
avaliacao_output_treino = gr.Markdown(label="Feedback da IA sobre o Argumento:")
# Atualizar displays quando a configuração mudar
fatos_input.change(lambda x: x, inputs=fatos_input, outputs=fatos_caso_treino_arg_display)
provas_reu_input.change(lambda x: x, inputs=provas_reu_input, outputs=provas_reu_treino_arg_display)
btn_avaliar_argumento_treino.click(
avaliar_argumentos_defesa_ia_ui,
inputs=[fatos_caso_treino_arg_display, provas_reu_treino_arg_display, tipo_argumento_treino, argumento_input_treino],
outputs=avaliacao_output_treino
)
with gr.TabItem("5. Preparar Testemunhas (Defesa)", id=4):
gr.Markdown("## 🎙️ Simule a Inquirição das Suas Testemunhas (Defesa)")
gr.Markdown("Pratique como você (Advogado de Defesa) inquiriria suas próprias testemunhas. A IA responderá como a testemunha selecionada.")
fatos_caso_treino_test_display = gr.Textbox(label="Fatos do Caso (da Configuração):", value=CASO_FATOS_COMPLETO_PREDEFINIDO, lines=5, interactive=False)
testemunhas_reu_config_treino_display = gr.Textbox(label="Definição das Testemunhas do Réu (da Configuração):", value=TESTEMUNHAS_REU_TEXTO_PREDEFINIDO, lines=3, interactive=False)
# Atualizar displays quando a configuração mudar
fatos_input.change(lambda x: x, inputs=fatos_input, outputs=fatos_caso_treino_test_display)
testemunhas_reu_input.change(lambda x: x, inputs=testemunhas_reu_input, outputs=testemunhas_reu_config_treino_display)
# Dropdown para selecionar testemunha do réu para treino
dropdown_testemunhas_reu_treino = gr.Dropdown(label="Selecione Sua Testemunha para Inquirir:", choices=[t['nome'] for t in TESTEMUNHAS_REU_PREDEFINIDAS], interactive=True)
# Atualizar choices do dropdown quando testemunhas_reu_input mudar
def update_dropdown_treino_choices(t_reu_str):
nomes = []
if t_reu_str and t_reu_str.strip():
for linha in t_reu_str.strip().split('\n'):
if linha.strip():
partes = linha.split(':', 1)
nomes.append(partes[0].strip())
return gr.Dropdown(choices=nomes if nomes else [t['nome'] for t in TESTEMUNHAS_REU_PREDEFINIDAS], value=nomes[0] if nomes else None)
testemunhas_reu_input.change(update_dropdown_treino_choices, inputs=testemunhas_reu_input, outputs=dropdown_testemunhas_reu_treino)
chat_treino_testemunha = gr.Chatbot(label="Simulação de Depoimento (Treino)", height=300, show_copy_button=True, bubble_full_width=False, avatar_images=(None, "https://img.icons8.com/officel/80/person-male.png"))
pergunta_testemunha_treino_input = gr.Textbox(label="Sua Pergunta para a Testemunha:", placeholder="Ex: 'Senhor Silva, poderia descrever o procedimento editorial?'")
btn_perguntar_testemunha_treino = gr.Button("💬 Perguntar à Testemunha (IA)", variant="primary")
btn_limpar_chat_treino_testemunha = gr.Button("🗑️ Limpar Chat de Treino")
def limpar_chat_treino():
global _historico_treino_testemunha_atual
_historico_treino_testemunha_atual = []
return [], ""
btn_limpar_chat_treino_testemunha.click(limpar_chat_treino, outputs=[chat_treino_testemunha, pergunta_testemunha_treino_input])
btn_perguntar_testemunha_treino.click(
gerar_dialogo_testemunha_defesa_para_treino_ui,
inputs=[fatos_caso_treino_test_display, testemunhas_reu_config_treino_display, dropdown_testemunhas_reu_treino, pergunta_testemunha_treino_input],
outputs=[chat_treino_testemunha, pergunta_testemunha_treino_input] # Limpa input após envio
)
with gr.TabItem("ℹ️ Ajuda / Sobre o Caso Padrão", id=5):
gr.Markdown("## Sobre o Caso Padrão: Direito ao Esquecimento vs. Liberdade de Imprensa")
gr.Markdown(f"**Título:** {CASO_TITULO_PREDEFINIDO}")
gr.Markdown(f"**Partes:**\n{CASO_PARTES_PREDEFINIDO.replace('\n', '\n\n')}")
gr.Markdown(f"**Resumo do Caso:**\n{CASO_DESCRICAO_PREDEFINIDO}")
with gr.Accordion("Argumentos Principais do Autor (Caso Padrão)", open=False):
gr.Markdown("\n".join([f"- {arg}" for arg in ARGUMENTOS_AUTOR_PREDEFINIDOS]))
with gr.Accordion("Argumentos Principais do Réu/Jornal (Caso Padrão)", open=False):
gr.Markdown("\n".join([f"- {arg}" for arg in CONTRA_ARGUMENTOS_REU_PREDEFINIDOS]))
with gr.Accordion("Testemunhas do Réu/Jornal (Caso Padrão)", open=False):
gr.Markdown("\n".join([f"- **{t['nome']}**: {t['pontos_chave']}" for t in TESTEMUNHAS_REU_PREDEFINIDAS]))
gr.Markdown("### Legislação e Precedentes Relevantes (Geral)")
with gr.Row():
with gr.Column():
gr.Markdown("**Potencialmente Favoráveis ao Réu (Jornal):**")
gr.Markdown("\n".join([f"- {lei}" for lei in LEGISLACAO_PRECEDENTES_PREDEFINIDO["favoraveis_ao_reu"]]))
with gr.Column():
gr.Markdown("**Potencialmente Favoráveis ao Autor:**")
gr.Markdown("\n".join([f"- {lei}" for lei in LEGISLACAO_PRECEDENTES_PREDEFINIDO["favoraveis_ao_autor"]]))
gr.Markdown("""
## Como utilizar este simulador:
1. **Configuração (Aba 1):**
* **Gerar Novo Caso com IA:** Cria um caso fictício aleatório sobre o tema.
* **Carregar Caso Padrão:** Preenche os campos com o "Caso da Reportagem Revisitada".
* Ou preencha manualmente os detalhes do seu próprio caso.
* **Salve e Inicie:** Fundamental para começar a simulação interativa.
2. **Audiência Interativa (Aba 2):**
* O núcleo da simulação. Siga as instruções e interaja como Advogado(a) do Réu.
* Use o campo de texto para suas falas ou os botões de ação contextual.
* O "Juiz (IA): Avançar Fase" é usado para progredir quando você conclui sua parte em uma etapa ou quando a IA indica.
3. **Feedback da Atuação (Aba 3):**
* Após interagir na Aba 2, verifique aqui a análise da IA sobre sua performance.
4. **Treinamento de Argumentação (Aba 4):**
* Use para praticar a redação de argumentos específicos (ex: para contestação, alegações finais) e receber feedback da IA. Baseia-se nos fatos e provas configurados na Aba 1.
5. **Preparar Testemunhas (Aba 5):**
* Treine a inquirição das suas testemunhas (do Réu). Você faz as perguntas, e a IA responde como se fosse a testemunha selecionada, baseando-se nos "pontos chave" definidos na Aba 1.
## Dicas para Atuação como Advogado(a) do Réu (Jornal):
* **Liberdade de Imprensa:** Seu principal argumento. Fundamente com a Constituição.
* **Interesse Público:** Demonstre a relevância da matéria.
* **Veracidade dos Fatos:** Crucial. A matéria deve ser factualmente correta.
* **Ausência de Dolo/Culpa:** Argumente que não houve intenção de prejudicar, apenas informar.
* **Menção à Absolvição:** Se o autor foi absolvido e a matéria menciona isso, é um ponto forte para a defesa.
* **Precedentes (STF):** Cite o RE 1.010.606, que ponderou o direito ao esquecimento com a liberdade de informação.
* **Contraditório:** Explore as perguntas às testemunhas do Autor para enfraquecer a tese dele.
* **Suas Testemunhas:** Prepare-as para reforçar a tese da defesa.
""")
# --- Conexões dos Componentes da UI (Event Handlers) ---
outputs_config = [sim_state, chat_aij_output, feedback_output, instrucao_usuario_output, dropdown_testemunhas_reu_select] + lista_botoes_feedback
btn_config_iniciar.click(
configurar_e_iniciar_simulacao,
inputs=[sim_state, fatos_input, provas_reu_input, provas_autor_input, testemunhas_reu_input, testemunhas_autor_supostas_input],
outputs=outputs_config
).then(lambda: gr.Textbox(value=""), outputs=[fala_usuario_input] # Limpa o campo de fala
).then(lambda: gr.Tabs(selected=1), outputs=[abas_principais]) # Muda para aba Audiência
outputs_fala_usuario = [sim_state, chat_aij_output, feedback_output, instrucao_usuario_output, fala_usuario_input] + lista_botoes_feedback
btn_enviar_fala_usuario.click(lidar_com_fala_usuario, inputs=[sim_state, fala_usuario_input], outputs=outputs_fala_usuario)
fala_usuario_input.submit(lidar_com_fala_usuario, inputs=[sim_state, fala_usuario_input], outputs=outputs_fala_usuario)
outputs_acao_juiz = [sim_state, chat_aij_output, feedback_output, instrucao_usuario_output] + lista_botoes_feedback
btn_juiz_avancar_fase_action.click(acao_botao_juiz_avancar, inputs=[sim_state], outputs=outputs_acao_juiz).then(lambda: gr.Textbox(value=""), outputs=[fala_usuario_input])
btn_chamar_testemunha_reu_action.click(chamar_testemunha_reu_selecionada, inputs=[sim_state, dropdown_testemunhas_reu_select], outputs=outputs_acao_juiz).then(lambda: gr.Textbox(value=""), outputs=[fala_usuario_input])
# Links dos botões de ação específicos para lidar_com_fala_usuario (eles apenas enviam o texto do botão como "fala")
# Estes botões agora estão mais para indicar o contexto da fala do usuário no input principal.
# A lógica de o que fazer com a fala do usuário está centralizada em `lidar_com_fala_usuario`.
# Se o botão for para uma ação específica que não envolve fala direta, ele precisa de seu próprio handler.
# Ex: Responder conciliação, apresentar alegações finais - podem usar o `lidar_com_fala_usuario` se o usuário digitar no campo.
# Se forem "ações puras" sem texto, podem precisar de lógica adaptada ou de um `fala_usuario_txt` especial.
# Para simplificar, vamos assumir que o usuário digita a resposta no campo de texto principal após clicar nesses botões (que agora servem mais como lembretes visuais).
# A alternativa seria esses botões passarem um placeholder de texto para `lidar_com_fala_usuario`.
# Por exemplo, btn_responder_conciliacao.click(lambda s: lidar_com_fala_usuario(s, "Réu se manifesta sobre conciliação (detalhes no campo de texto)."), ...)
# Mas a implementação atual já faz o `lidar_com_fala_usuario` receber o texto do `fala_usuario_input`.
# Botões que enviam a fala do input principal
btn_responder_conciliacao.click(lambda: gr.Info("Digite sua resposta à conciliação no campo de fala e envie."), inputs=[], outputs=[]).then(
lidar_com_fala_usuario, inputs=[sim_state, fala_usuario_input], outputs=outputs_fala_usuario
)
btn_perguntar_testemunha_autor_action.click(lambda: gr.Info("Digite sua pergunta à testemunha do Autor no campo de fala e envie."), inputs=[], outputs=[]).then(
lidar_com_fala_usuario, inputs=[sim_state, fala_usuario_input], outputs=outputs_fala_usuario
)
btn_adv_reu_pergunta_sua_testemunha_action.click(lambda: gr.Info("Digite sua pergunta à sua testemunha no campo de fala e envie. Você também digitará a RESPOSTA dela em seguida."), inputs=[], outputs=[]).then(
lidar_com_fala_usuario, inputs=[sim_state, fala_usuario_input], outputs=outputs_fala_usuario
)
btn_adv_reu_responde_pela_sua_testemunha_action.click(lambda: gr.Info("Digite a resposta da sua testemunha (à pergunta do Adv. Autor) no campo de fala e envie."), inputs=[], outputs=[]).then(
lidar_com_fala_usuario, inputs=[sim_state, fala_usuario_input], outputs=outputs_fala_usuario
)
btn_apresentar_alegacoes_finais_reu_action.click(lambda: gr.Info("Digite suas alegações finais no campo de fala e envie."), inputs=[], outputs=[]).then(
lidar_com_fala_usuario, inputs=[sim_state, fala_usuario_input], outputs=outputs_fala_usuario
)
# Estado inicial da UI no carregamento
def setup_initial_ui_state_load(s):
initial_fase = s["fase_aij"]
dropdown_choices = [t["nome"] for t in s.get("testemunhas_reu_defs", [])] if s.get("testemunhas_reu_defs") else []
return [gr.Dropdown(choices=dropdown_choices, value=None, interactive=True)] + mostrar_botoes_corretos(initial_fase)
demo.load(
lambda s: (s, s["transcricao_chat"], s["feedback_para_usuario"], s["instrucao_para_usuario"]) + tuple(setup_initial_ui_state_load(s)),
inputs=[sim_state],
outputs=[sim_state, chat_aij_output, feedback_output, instrucao_usuario_output, dropdown_testemunhas_reu_select] + lista_botoes_feedback
)
if __name__ == "__main__":
if not GEMINI_API_KEY:
print("#####################################################################")
print("ATENÇÃO: GEMINI_API_KEY não configurada como variável de ambiente.")
print("Para rodar localmente, edite o script e insira sua chave ou defina a variável de ambiente.")
print("Para Hugging Face Spaces, configure o Secret 'GEMINI_API_KEY'.")
print("#####################################################################")
demo.queue(max_size=20).launch(debug=False) # Adicionado max_size para melhor gerenciamento de fila.