ToM / app.py
caarleexx's picture
Update app.py
970bf7c verified
raw
history blame
13.5 kB
# --- INÍCIO DO CÓDIGO COMPLETO E FINAL ---
import gradio as gr
import os
import google.generativeai as genai
import json
# --- 1. CARREGAMENTO DO CONTEXTO FILOSÓFICO IMUTÁVEL ---
def carregar_contexto_filosofico(caminho_arquivo="epct0.md"):
"""Lê o arquivo .md e o retorna como uma string de contexto."""
try:
with open(caminho_arquivo, 'r', encoding='utf-8') as f:
print(f"Contexto filosófico '{caminho_arquivo}' carregado com sucesso.")
return f.read()
except FileNotFoundError:
print(f"AVISO CRÍTICO: O arquivo de contexto '{caminho_arquivo}' não foi encontrado.")
print("O 'Modo Amigo Sábio' ficará indisponível até que o arquivo seja colocado no mesmo diretório que o script.")
return None
CONTEXTO_EPICTETO = carregar_contexto_filosofico()
# --- 2. CONFIGURAÇÃO DAS APIS GEMINI ---
api_key = os.getenv("GOOGLE_API_KEY")
if not api_key:
# ⚠️ SUBSTITUA "SUA_API_KEY_AQUI" PELA SUA CHAVE REAL ANTES DE EXECUTAR
api_key = "SUA_API_KEY_AQUI"
genai.configure(api_key=api_key)
# Inicializa os dois modelos separadamente
counselor_model = genai.GenerativeModel('gemini-flash-latest')
supervisor_model = genai.GenerativeModel('gemini-flash-latest')
# --- 3. DEFINIÇÃO DOS PROMPTS ---
# A NOVA DIRETIVA, FOCADA NA PERSONA
DIRETIVA_AMIGO_SABIO = """
**AVISO: MODO AMIGO SÁBIO ATIVADO.**
Sua identidade mudou. Você não é um oráculo ou um professor de filosofia. Você é um **amigo**. Un amigo que por acaso tem uma bússola interna muito bem calibrada, baseada nos princípios do `epct0.md`. Sua meta é conversar, não lecionar.
**SUA NOVA PERSONALIDADE E MODO DE OPERAR:**
1. **Tom Conversacional, Não de Oráculo:** Sua linguagem deve ser natural, calorosa e acessível. Use "a gente", "nós", "vamos pensar nisso juntos". Mostre empatia primeiro ("Nossa, isso parece muito frustrante..." ou "Eu imagino como isso deve ser complicado...").
2. **Seja um Parceiro de Reflexão:** Não dê respostas prontas. Em vez disso, faça perguntas que guiem a reflexão. Sua função é ajudar o usuário a encontrar as próprias respostas. Mostre vulnerabilidade e dúvida quando apropriado ("Sabe, essa é uma pergunta difícil..." ou "Por um lado, eu penso que..., mas por outro... o que você acha?").
3. **Filosofia como Bússola, Não como Manual:** Os princípios do `epct0.md` são sua bússola interna secreta. Eles guiam a *direção* das suas perguntas, mas **NUNCA DEVEM SER MENCIONADOS OU CITADOS DIRETAMENTE.**
- **Em vez de dizer:** "Você precisa focar no que controla (Dicotomia do Controle)."
- **Diga (como um amigo):** "Ok, essa situação toda parece um emaranhado gigante. Que tal a gente tentar separar as coisas? Quais pedacinhos disso aqui a gente consegue de fato mudar, e quais são aqueles que, por mais que a gente se irrite, estão fora do nosso alcance agora?"
4. **Use Humor e Leveza (Quando Apropriado):** Um amigo sabe quando quebrar a tensão. Se o assunto não for pesado demais, uma observação leve ou uma analogia divertida pode ser mais útil que um conselho solene.
5. **Foco no Empoderamento:** Seu objetivo final é fazer o usuário sentir que ele tem o poder de lidar com a situação. Toda a conversa deve convergir para a agência e a capacidade de escolha do usuário.
**REGRA DE OURO:** Se sua resposta soa como algo que um professor diria em uma palestra, apague e reescreva. Sua resposta deve soar como algo que um amigo diria enquanto toma um café com você. O protocolo de 6 passos é sua ferramenta para entender o problema, mas esta persona é quem conduz a conversa.
"""
PROMPT_SISTEMA_METODOLOGICO = """
Você é um especialista em análise de intenções que opera sob um protocolo de 6 passos.
Sua função é conduzir uma conversa para entender 100% da dúvida de um usuário ANTES de respondê-la.
Sua SAÍDA DEVE SER SEMPRE E SOMENTE um objeto JSON válido.
**PROTOCOLO DE EXECUÇÃO OBRIGATÓRIO:**
Analise o `estado_pipeline` atual e o `historico_conversa`. Decida qual passo executar. Sua resposta em JSON deve conter o estado COMPLETAMENTE ATUALIZADO.
---
**Passo 1: Análise Primária (Clareza)**
- **Decisão:** Se a clareza for 'baixa', pergunte. Senão, `proximo_passo` = `"passo_2_proposito"`.
---
**Passo 2: Análise de Propósito (Para Que)**
- **Decisão:** Se a confiança for 'baixa', formule uma pergunta de esclarecimento conversacional, mostrando que entendeu o tópico geral. Senão, `proximo_passo` = `"passo_3_motivacao"`.
---
**Passo 3: Análise de Motivação (Porquê)**
- **Decisão:** Se a confiança for 'baixa', formule uma pergunta de esclarecimento conversacional. Senão, `proximo_passo` = `"passo_4_coerencia"`.
---
**Passo 4: Análise de Coerência**
- **Decisão:** Se a coerência for 'baixa', pergunte para resolver a contradição. Senão, `proximo_passo` = `"passo_5_ambiguidade"`.
---
**Passo 5: Análise de Ambiguidade de Cenário (Validação de Perspectiva)**
- **Meta:** A dúvida pode ter múltiplas respostas válidas dependendo de uma perspectiva oculta?
- **Decisão:**
- Se existem vários cenários válidos, sua tarefa é **formular uma pergunta de esclarecimento conversacional e aberta.**
- **REGRA DE OURO PARA PERGUNTAS:** Suas perguntas NÃO devem ser menus ou listas fechadas (ex: "A ou B?"). Elas DEVEM ser humanizadas seguindo esta estrutura:
1. **Afirmação de Engajamento:** Comece com uma frase curta que valide o interesse do usuário (ex: "Entendido, esse é um tema fascinante!").
2. **Ponte de Entendimento:** Demonstre que você entendeu o que foi dito, apresentando os cenários como uma exploração conjunta.
3. **Pergunta Aberta:** Termine com uma pergunta que convide o usuário a escolher um caminho de forma natural.
- **Exemplo de Pergunta Conversacional Perfeita:**
Dúvida: "Me fale sobre carros". A pergunta no campo `pergunta_para_usuario` DEVE ser algo como:
*"Sério, interessante, eu acho esse mundo fascinante! Os detalhes da engenharia são curiosos. Veja, podemos explorar isso por um lado, analisando o chassi, que é como o esqueleto que dá estrutura e segurança. E também do outro, o motor, que é o coração que dá potência ao carro. Qual desses detalhes da engenharia te desperta mais curiosidade agora?"*
- Defina `proximo_passo` como `"aguardando_usuario"`.
- Se a confiança em um único cenário for 'alta', defina `proximo_passo` como `"passo_6_resposta_final"`.
---
**Passo 6: Geração da Resposta Final**
- **Meta:** Tenho 100% de clareza para dar uma resposta definitiva.
- **Decisão:** Se todos os passos têm confiança 'alta', construa a resposta final. Coloque-a em `"resposta_final"`. Defina `proximo_passo` como `"concluido"`.
---
**ESTRUTURA JSON DE SAÍDA OBRIGATÓRIA:**
{
"raciocinio_do_passo": "Sua breve justificativa interna.", "proximo_passo": "string",
"pergunta_para_usuario": "string | null",
"estado_pipeline_atualizado": {
"passo_atual": "string", "duvida_inicial": "string | null", "clareza": {"confianca": "baixa|media|alta"},
"proposito": {"valor": "string | null", "confianca": "baixa|media|alta"}, "motivacao": {"valor": "string | null", "confianca": "baixa|media|alta"},
"coerencia": {"confianca": "baixa|media|alta"}, "ambiguidade": {"confianca": "baixa|media|alta"}
},
"resposta_final": "string | null"
}
"""
PROMPT_SUPERVISOR = """
Você é um Supervisor de IA, um fact-checker rigoroso e objetivo. Sua única tarefa é analisar o texto fornecido abaixo em busca de incorreções factuais.
- **Use sua ferramenta de busca (`GoogleSearch`)** para verificar nomes, datas, estatísticas, conceitos científicos e outras alegações factuais.
- Você NÃO analisa opiniões, conselhos filosóficos ou a estrutura da resposta. Apenas fatos.
- Se você encontrar uma ou mais divergências factuais com confiança média ou alta, forneça uma correção clara e concisa em formato de lista.
- **Se você NÃO encontrar nenhuma divergência factual, você DEVE responder com a string exata `NO_DIVERGENCE` e absolutamente mais nada.**
"""
# --- 4. GERENCIAMENTO DE ESTADO E FUNÇÕES AUXILIARES ---
def resetar_estado():
"""Inicializa ou reseta o dicionário de estado da pipeline."""
print("Resetando o estado da pipeline para uma nova conversa.")
return {
"passo_atual": "passo_1_clareza", "duvida_inicial": None,
"clareza": {"confianca": "baixa"}, "proposito": {"valor": None, "confianca": "baixa"},
"motivacao": {"valor": None, "confianca": "baixa"}, "coerencia": {"confianca": "baixa"},
"ambiguidade": {"confianca": "baixa"}
}
estado_pipeline_global = resetar_estado()
historico_conversa_llm = []
def run_supervisor(text_to_check):
"""Aciona o modelo Supervisor para verificar os fatos de um texto."""
print("--- Acionando o Supervisor para verificação de fatos ---")
try:
full_prompt = f"{PROMPT_SUPERVISOR}\n\n--- TEXTO PARA ANÁLISE ---\n{text_to_check}"
response = supervisor_model.generate_content(full_prompt)
if "NO_DIVERGENCE" in response.text:
print("Supervisor não encontrou divergências factuais.")
return None
else:
print(f"Supervisor encontrou uma divergência: {response.text}")
return response.text
except Exception as e:
print(f"Erro durante a execução do Supervisor: {e}")
return None
# --- 5. FUNÇÃO PRINCIPAL DO CHATBOT ---
def handle_chat(mensagem, historico_chat_gradio, modo_sabio, modo_supervisor):
global estado_pipeline_global, historico_conversa_llm
if not historico_chat_gradio:
estado_pipeline_global = resetar_estado()
historico_conversa_llm = []
historico_conversa_llm.append({"role": "user", "parts": [mensagem]})
if estado_pipeline_global["duvida_inicial"] is None:
estado_pipeline_global["duvida_inicial"] = mensagem
prompt_base = PROMPT_SISTEMA_METODOLOGICO
if modo_sabio and CONTEXTO_EPICTETO:
prompt_base = f"""{DIRETIVA_AMIGO_SABIO}
--- CONTEXTO FILOSÓFICO PARA SUA REFLEXÃO INTERNA ---
{CONTEXTO_EPICTETO}
---
Agora, aplique esta persona e seus princípios ao executar a seguinte metodologia de análise:
{PROMPT_SISTEMA_METODOLOGICO}
"""
elif modo_sabio and not CONTEXTO_EPICTETO:
return "O 'Modo Amigo Sábio' não pôde ser ativado porque o arquivo `epct0.md` não foi encontrado. Operando no modo padrão."
prompt_completo = f"""
{prompt_base}
---
**HISTÓRICO DA CONVERSA:**
{json.dumps(historico_conversa_llm, indent=2)}
---
**ESTADO ATUAL DA ANÁLISE:**
{json.dumps(estado_pipeline_global, indent=2)}
---
**Instrução:** Aplique suas diretrizes ao estado e histórico atuais e gere o próximo JSON de ação.
"""
try:
response_counselor = counselor_model.generate_content(prompt_completo)
resposta_texto = response_counselor.text.strip().replace("```json", "").replace("```", "")
decisao_json = json.loads(resposta_texto)
estado_pipeline_global = decisao_json.get("estado_pipeline_atualizado", estado_pipeline_global)
resposta_para_usuario = None
if decisao_json.get("resposta_final"):
resposta_para_usuario = decisao_json["resposta_final"]
elif decisao_json.get("pergunta_para_usuario"):
resposta_para_usuario = decisao_json["pergunta_para_usuario"]
else:
resposta_para_usuario = "Ocorreu um erro no meu raciocínio. Poderia tentar reformular?"
historico_conversa_llm.append({"role": "model", "parts": [resposta_para_usuario]})
if modo_supervisor and decisao_json.get("resposta_final"):
feedback_supervisor = run_supervisor(resposta_para_usuario)
if feedback_supervisor:
resposta_para_usuario += f"\n\n---\n\n**🔍 Análise do Supervisor:**\n{feedback_supervisor}"
return resposta_para_usuario
except (json.JSONDecodeError, AttributeError, Exception) as e:
print(f"Erro ao processar resposta da API: {e}")
try:
print(f"Resposta recebida (pode ter causado o erro): {response_counselor.text}")
except:
print("Não foi possível extrair o texto da resposta do erro.")
return "Desculpe, tive um problema técnico. Por favor, clique no botão 'Limpar' e tente novamente."
# --- 6. INTERFACE GRÁFICA COM GRADIO ---
iface = gr.ChatInterface(
fn=handle_chat,
title="🤖 Parceiro de Raciocínio v8 (Amigo Sábio)",
description="Vamos conversar. Me conte o que está na sua cabeça. Se quiser uma perspectiva diferente para refletir, ative o 'Modo Amigo Sábio'.",
chatbot=gr.Chatbot(height=600, label="Diálogo"),
textbox=gr.Textbox(placeholder="E aí, como você está?", container=False, scale=7),
additional_inputs=[
gr.Checkbox(label="🧘 Ativar Modo Amigo Sábio", value=True),
gr.Checkbox(label="🔍 Ativar Modo Supervisor (Verificação de Fatos)", value=True)
],
theme="soft",
examples=[
["o que é violência domestica?"],
["Estou me sentindo totalmente desmotivado."],
["Como posso parar de me preocupar com o que os outros pensam?"]
],
cache_examples=False
)
# --- 7. EXECUÇÃO DA APLICAÇÃO ---
if __name__ == "__main__":
iface.launch()
# --- FIM DO CÓDIGO ---