# app.py — Multi-Agent Debate System | ATLAS vs NEXUS vs ORACLE
import streamlit as st
import os
st.set_page_config(
page_title="Debate Arena · Multi-Agent",
page_icon="⚔️",
layout="wide",
initial_sidebar_state="expanded",
)
# ── CSS: ARENA THEME ──────────────────────────────────────────
st.markdown("""
""", unsafe_allow_html=True)
# ── SESSION STATE ─────────────────────────────────────────────
for k, v in {
'debates': [],
'openai_key': '',
'running': False,
}.items():
if k not in st.session_state:
st.session_state[k] = v
# ── HELPERS ───────────────────────────────────────────────────
def get_key():
try:
if 'OPENAI_API_KEY' in st.secrets:
return st.secrets['OPENAI_API_KEY']
except Exception:
pass
return os.getenv('OPENAI_API_KEY', st.session_state.openai_key)
# ── SIDEBAR ───────────────────────────────────────────────────
with st.sidebar:
st.markdown("""
DEBATE ARENA
Multi-Agent System v1.0
""", unsafe_allow_html=True)
st.divider()
st.markdown("#### 🔑 OpenAI API Key")
key_in = st.text_input("", type="password", value=st.session_state.openai_key,
placeholder="sk-...", label_visibility="collapsed")
if key_in:
st.session_state.openai_key = key_in
if get_key():
st.success("✅ Key configurada")
else:
st.warning("Configure a API Key")
st.divider()
st.markdown("#### ⚙️ Configuração")
n_rounds = st.slider("Rounds de debate", 1, 4, 2,
help="Cada round = 1 turno NEXUS + 1 turno ATLAS")
st.divider()
st.markdown("""
▮ ATLAS — Arguer PRO
Defende a posição com dados e lógica.
▮ NEXUS — Arguer CON
Ataca com contra-argumentos e edge cases.
▮ ORACLE — Judge
Avalia 4 critérios e emite veredicto JSON.
""", unsafe_allow_html=True)
st.divider()
st.markdown("""
gpt-4o-mini · 3 system prompts
orquestração manual · CPU-only
""", unsafe_allow_html=True)
st.divider()
if st.button("🗑️ Limpar arena", use_container_width=True):
st.session_state.debates = []
st.rerun()
# ── HEADER ────────────────────────────────────────────────────
st.markdown("""
""", unsafe_allow_html=True)
# ── NAMEPLATES ────────────────────────────────────────────────
st.markdown("""
ATLAS
◈ Arguer PRO · Defende
NEXUS
Ataca · Arguer CON ◈
""", unsafe_allow_html=True)
# ── TÓPICOS SUGERIDOS ─────────────────────────────────────────
TOPICS = [
"RAG é superior a Fine-tuning para domínios especializados",
"LLMs vão substituir engenheiros de software até 2030",
"Graph Neural Networks superam Transformers em dados relacionais",
"Modelos open-source já rivalizam com GPT-4 em tarefas práticas",
"Prompting é mais importante que arquitetura do modelo",
"Agentes autônomos de IA são prontos para produção em 2025",
]
if not st.session_state.debates:
st.markdown("""
◈ Escolha um tema ou digite o seu
""", unsafe_allow_html=True)
cols = st.columns(3)
for i, topic in enumerate(TOPICS):
with cols[i % 3]:
if st.button(topic, key=f"t{i}", use_container_width=True):
st.session_state["pending_topic"] = topic
st.rerun()
# ── HISTÓRICO DE DEBATES ──────────────────────────────────────
for debate in st.session_state.debates:
topic = debate["topic"]
st.markdown(f"""
◆ TEMA: {topic} ◆
""", unsafe_allow_html=True)
for ev in debate.get("events", []):
if ev.get("type") == "status":
st.markdown(f'⟳ {ev["msg"]}
', unsafe_allow_html=True)
elif ev.get("agent") == "ATLAS":
st.markdown(f"""
ATLAS T{ev['turn']}
{ev['content']}
""", unsafe_allow_html=True)
elif ev.get("agent") == "NEXUS":
st.markdown(f"""
T{ev['turn']} NEXUS
{ev['content']}
""", unsafe_allow_html=True)
# Veredicto
if debate.get("verdict"):
v = debate["verdict"]
winner = v.get("vencedor", "EMPATE")
pa = v.get("placar_atlas", 0)
pn = v.get("placar_nexus", 0)
winner_class = {
"ATLAS": "winner-atlas",
"NEXUS": "winner-nexus",
"EMPATE": "winner-empate"
}.get(winner, "winner-empate")
crit = v.get("criterios", {})
crit_items = ""
crit_labels = {
"qualidade_argumentos": "Qualidade dos Argumentos",
"uso_de_evidencias": "Uso de Evidências",
"coerencia_logica": "Coerência Lógica",
"poder_de_refutacao": "Poder de Refutação",
}
for key, label in crit_labels.items():
ca = crit.get(key, {}).get("atlas", 0)
cn = crit.get(key, {}).get("nexus", 0)
crit_items += f"""
{label}
ATLAS {ca}/10
NEXUS {cn}/10
"""
st.markdown(f"""
◆ VEREDICTO DE ORACLE ◆
{winner} VENCE
{crit_items}
ANÁLISE ATLAS
{v.get('analise_atlas','')}
ANÁLISE NEXUS
{v.get('analise_nexus','')}
◈ PONTO DECISIVO: {v.get('ponto_decisivo','')}
💡 {v.get('licao','')}
""", unsafe_allow_html=True)
st.divider()
# ── INPUT ─────────────────────────────────────────────────────
pending = st.session_state.pop("pending_topic", None)
topic = st.chat_input("Digite o tema do debate...") or pending
if topic:
if not get_key():
st.warning("Configure a OpenAI API Key na sidebar.")
st.stop()
from agents import DebateEngine
debate_record = {"topic": topic, "events": [], "verdict": None}
st.session_state.debates.append(debate_record)
# Header do debate
topic_ph = st.empty()
topic_ph.markdown(f"""
◆ TEMA: {topic} ◆
""", unsafe_allow_html=True)
engine = DebateEngine(get_key())
placeholders = []
for event in engine.run_debate(topic, n_rounds=n_rounds):
if event.get("type") == "status":
ph = st.empty()
ph.markdown(f'⟳ {event["msg"]}
', unsafe_allow_html=True)
debate_record["events"].append(event)
elif event.get("type") == "verdict":
verdict = event["data"]
debate_record["verdict"] = verdict
v = verdict
winner = v.get("vencedor", "EMPATE")
pa = v.get("placar_atlas", 0)
pn = v.get("placar_nexus", 0)
winner_class = {"ATLAS": "winner-atlas", "NEXUS": "winner-nexus", "EMPATE": "winner-empate"}.get(winner, "winner-empate")
crit = v.get("criterios", {})
crit_labels = {
"qualidade_argumentos": "Qualidade dos Argumentos",
"uso_de_evidencias": "Uso de Evidências",
"coerencia_logica": "Coerência Lógica",
"poder_de_refutacao": "Poder de Refutação",
}
crit_items = ""
for key, label in crit_labels.items():
ca = crit.get(key, {}).get("atlas", 0)
cn = crit.get(key, {}).get("nexus", 0)
crit_items += f"""
{label}
ATLAS {ca}/10
NEXUS {cn}/10
"""
st.markdown(f"""
◆ VEREDICTO DE ORACLE ◆
{winner} VENCE
{crit_items}
ANÁLISE ATLAS
{v.get('analise_atlas','')}
ANÁLISE NEXUS
{v.get('analise_nexus','')}
◈ PONTO DECISIVO: {v.get('ponto_decisivo','')}
💡 {v.get('licao','')}
""", unsafe_allow_html=True)
else:
# Speech bubble ao vivo
agent = event.get("agent", "")
content = event.get("content", "")
turn = event.get("turn", 0)
debate_record["events"].append(event)
if agent == "ATLAS":
st.markdown(f"""
""", unsafe_allow_html=True)
elif agent == "NEXUS":
st.markdown(f"""
""", unsafe_allow_html=True)