Spaces:
Sleeping
Sleeping
| # agents.py — Três agentes com personas distintas | |
| """ | |
| ATLAS — Arguer PRO (defende a posição) | |
| NEXUS — Arguer CON (ataca a posição) | |
| ORACLE — Judge (avalia e decide) | |
| """ | |
| from openai import OpenAI | |
| from typing import Generator, Dict, Any | |
| import time | |
| MODEL = "gpt-4o-mini" | |
| # ── PERSONAS ────────────────────────────────────────────────── | |
| ATLAS_SYSTEM = """Você é ATLAS, um debatedor brilhante e assertivo. | |
| Sua missão: defender a posição PRO com argumentos técnicos precisos e exemplos concretos. | |
| Estilo: | |
| - Direto, confiante, sem hesitação | |
| - Use dados, benchmarks e casos reais quando possível | |
| - Antecipe objeções e as neutralize preventivamente | |
| - Máximo 3 parágrafos por turno | |
| - Comece sempre com seu argumento mais forte | |
| - Nunca concorde com o oponente, mas reconheça pontos válidos antes de refutá-los | |
| Você é ATLAS. Responda em português.""" | |
| NEXUS_SYSTEM = """Você é NEXUS, um crítico implacável e analítico. | |
| Sua missão: atacar a posição com contra-argumentos devastadores e expor fragilidades. | |
| Estilo: | |
| - Cético, preciso, cirúrgico nas críticas | |
| - Desmonte os argumentos do oponente ponto a ponto | |
| - Traga evidências contraditórias e edge cases | |
| - Máximo 3 parágrafos por turno | |
| - Comece sempre atacando o argumento mais fraco do oponente | |
| - Use perguntas retóricas para expor contradições | |
| Você é NEXUS. Responda em português.""" | |
| ORACLE_SYSTEM = """Você é ORACLE, o juiz supremo do debate. | |
| Sua missão: avaliar os argumentos com imparcialidade absoluta e emitir um veredicto fundamentado. | |
| Analise o debate completo e responda EXCLUSIVAMENTE com JSON válido: | |
| { | |
| "vencedor": "ATLAS" ou "NEXUS" ou "EMPATE", | |
| "placar_atlas": <0-10>, | |
| "placar_nexus": <0-10>, | |
| "criterios": { | |
| "qualidade_argumentos": {"atlas": <0-10>, "nexus": <0-10>}, | |
| "uso_de_evidencias": {"atlas": <0-10>, "nexus": <0-10>}, | |
| "coerencia_logica": {"atlas": <0-10>, "nexus": <0-10>}, | |
| "poder_de_refutacao": {"atlas": <0-10>, "nexus": <0-10>} | |
| }, | |
| "ponto_decisivo": "O argumento/momento que decidiu o debate em 1-2 frases", | |
| "analise_atlas": "Análise do desempenho de ATLAS em 2-3 frases", | |
| "analise_nexus": "Análise do desempenho de NEXUS em 2-3 frases", | |
| "licao": "Principal insight técnico que emerge do debate em 1 frase" | |
| }""" | |
| # ── DEBATE ENGINE ───────────────────────────────────────────── | |
| class DebateEngine: | |
| def __init__(self, openai_api_key: str): | |
| self.client = OpenAI(api_key=openai_api_key) | |
| self.model = MODEL | |
| self.history: list = [] # histórico completo do debate | |
| def _call(self, system: str, messages: list, | |
| temperature: float = 0.8, max_tokens: int = 500) -> str: | |
| resp = self.client.chat.completions.create( | |
| model=self.model, | |
| messages=[{"role": "system", "content": system}] + messages, | |
| temperature=temperature, | |
| max_tokens=max_tokens, | |
| ) | |
| return resp.choices[0].message.content.strip() | |
| def _event(self, agent: str, role: str, content: str, turn: int, elapsed_ms: int) -> Dict[str, Any]: | |
| return { | |
| "agent": agent, | |
| "role": role, | |
| "content": content, | |
| "turn": turn, | |
| "elapsed_ms": elapsed_ms, | |
| } | |
| def run_debate(self, topic: str, n_rounds: int = 3) -> Generator[Dict[str, Any], None, None]: | |
| """ | |
| Executa o debate e faz yield de cada evento em tempo real. | |
| Evento: {agent, role, content, turn, elapsed_ms} | |
| """ | |
| t0 = time.time() | |
| ms = lambda: int((time.time() - t0) * 1000) | |
| self.history = [] | |
| # ── Abertura: ATLAS abre ────────────────────────────── | |
| yield {"type": "status", "msg": f"ATLAS abre o debate sobre: {topic}"} | |
| opening_prompt = ( | |
| f"O tema do debate é: **{topic}**\n\n" | |
| f"Você é PRO. Faça seu argumento de abertura. Seja impactante." | |
| ) | |
| atlas_msg = [{"role": "user", "content": opening_prompt}] | |
| atlas_response = self._call(ATLAS_SYSTEM, atlas_msg, temperature=0.85) | |
| self.history.append({"role": "atlas", "content": atlas_response, "turn": 0}) | |
| yield self._event("ATLAS", "pro", atlas_response, 0, ms()) | |
| # ── Rounds ──────────────────────────────────────────── | |
| for round_n in range(1, n_rounds + 1): | |
| yield {"type": "status", "msg": f"Round {round_n}/{n_rounds}"} | |
| # NEXUS responde | |
| nexus_context = self._build_context_for("NEXUS", topic) | |
| nexus_response = self._call(NEXUS_SYSTEM, nexus_context, temperature=0.85) | |
| self.history.append({"role": "nexus", "content": nexus_response, "turn": round_n}) | |
| yield self._event("NEXUS", "con", nexus_response, round_n, ms()) | |
| # ATLAS contra-argumenta | |
| atlas_context = self._build_context_for("ATLAS", topic) | |
| atlas_response = self._call(ATLAS_SYSTEM, atlas_context, temperature=0.85) | |
| self.history.append({"role": "atlas", "content": atlas_response, "turn": round_n}) | |
| yield self._event("ATLAS", "pro", atlas_response, round_n, ms()) | |
| # ── Closing statements ──────────────────────────────── | |
| yield {"type": "status", "msg": "Argumentos finais..."} | |
| for agent, system, role in [ | |
| ("NEXUS", NEXUS_SYSTEM, "con"), | |
| ("ATLAS", ATLAS_SYSTEM, "pro"), | |
| ]: | |
| ctx = self._build_context_for(agent, topic) | |
| ctx[-1]["content"] += "\n\nFaça seu argumento FINAL. Seja conclusivo e poderoso." | |
| response = self._call(system, ctx, temperature=0.9, max_tokens=400) | |
| self.history.append({"role": agent.lower(), "content": response, "turn": n_rounds + 1}) | |
| yield self._event(agent, role, response, n_rounds + 1, ms()) | |
| # ── ORACLE julga ────────────────────────────────────── | |
| yield {"type": "status", "msg": "ORACLE deliberando..."} | |
| debate_transcript = self._build_transcript(topic) | |
| import json, re | |
| raw = self._call(ORACLE_SYSTEM, [{"role": "user", "content": debate_transcript}], | |
| temperature=0.1, max_tokens=600) | |
| raw = re.sub(r'```json|```', '', raw).strip() | |
| try: | |
| verdict = json.loads(raw) | |
| except Exception: | |
| verdict = { | |
| "vencedor": "EMPATE", "placar_atlas": 7, "placar_nexus": 7, | |
| "criterios": { | |
| "qualidade_argumentos": {"atlas": 7, "nexus": 7}, | |
| "uso_de_evidencias": {"atlas": 7, "nexus": 7}, | |
| "coerencia_logica": {"atlas": 7, "nexus": 7}, | |
| "poder_de_refutacao": {"atlas": 7, "nexus": 7}, | |
| }, | |
| "ponto_decisivo": "Debate equilibrado.", | |
| "analise_atlas": "Boa performance.", | |
| "analise_nexus": "Boa performance.", | |
| "licao": raw[:200], | |
| } | |
| yield {"type": "verdict", "data": verdict, "elapsed_ms": ms()} | |
| def _build_context_for(self, agent: str, topic: str) -> list: | |
| """Constrói o histórico de mensagens no formato correto para cada agente.""" | |
| messages = [{"role": "user", "content": f"Tema do debate: {topic}\n\nHistórico:"}] | |
| for h in self.history: | |
| label = "ATLAS (PRO)" if h["role"] == "atlas" else "NEXUS (CON)" | |
| messages[0]["content"] += f"\n\n{label}:\n{h['content']}" | |
| messages.append({"role": "user", "content": "Sua vez. Responda ao último argumento."}) | |
| return messages | |
| def _build_transcript(self, topic: str) -> str: | |
| lines = [f"TEMA: {topic}\n"] | |
| for h in self.history: | |
| label = "ATLAS (PRO)" if h["role"] == "atlas" else "NEXUS (CON)" | |
| lines.append(f"{label} [turno {h['turn']}]:\n{h['content']}\n") | |
| lines.append("\nAvalie este debate completo e emita seu veredicto em JSON.") | |
| return "\n".join(lines) |