Update index.html
Browse files- index.html +184 -67
index.html
CHANGED
|
@@ -6,35 +6,73 @@
|
|
| 6 |
<title>Multi-Agent Debate - MiMo-V2.6-Distill-Qwen-9B</title>
|
| 7 |
<style>
|
| 8 |
:root{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
--bg:#efeae2; --surface:#ffffff; --surface2:#f0f2f5; --border:#d1d7db;
|
| 10 |
-
--text:#111b21; --muted:#667781;
|
| 11 |
-
--header:#008069; --
|
|
|
|
|
|
|
| 12 |
}
|
| 13 |
-
body.light{ --bg:#efeae2; --surface:#ffffff; --surface2:#f0f2f5; --border:#d1d7db; --text:#111b21; --muted:#667781; }
|
| 14 |
*{box-sizing:border-box}
|
| 15 |
html,body{margin:0;padding:0;background:var(--bg);color:var(--text);
|
| 16 |
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;font-size:15px}
|
| 17 |
-
#app{max-width:
|
| 18 |
-
box-shadow:0 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
header .title{font-weight:600;font-size:16px;letter-spacing:.1px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
| 25 |
-
header .subtitle{font-size:12px;color:
|
| 26 |
-
#settings-btn{background:none;border:none;color:
|
| 27 |
width:38px;height:38px;cursor:pointer;font-size:18px;display:flex;align-items:center;justify-content:center;transition:.15s}
|
| 28 |
-
#settings-btn:hover{background:rgba(255,255,255,.
|
| 29 |
|
| 30 |
#chat{flex:1;overflow-y:auto;padding:20px 8%;display:flex;flex-direction:column;gap:8px;
|
| 31 |
background-color:var(--bg);
|
|
|
|
|
|
|
| 32 |
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'%3E%3Cg fill='none' stroke='%23d8d1c6' stroke-width='1.4' opacity='0.5'%3E%3Ccircle cx='20' cy='20' r='6'/%3E%3Cpath d='M50 15h16a6 6 0 0 1 6 6v8a6 6 0 0 1-6 6h-9l-5 5v-5h-2a6 6 0 0 1-6-6v-8a6 6 0 0 1 6-6z'/%3E%3Cpath d='M15 60l4 4 8-8'/%3E%3Ccircle cx='95' cy='70' r='8'/%3E%3Cpath d='M40 95c4-6 12-6 16 0'/%3E%3Cpath d='M85 25l2.5 5 5 2.5-5 2.5-2.5 5-2.5-5-5-2.5 5-2.5z'/%3E%3Crect x='60' y='55' width='12' height='12' rx='3'/%3E%3Cpath d='M20 100q6-8 12 0'/%3E%3C/g%3E%3C/svg%3E")}
|
|
|
|
|
|
|
| 33 |
.msg{display:flex;gap:8px;animation:fadein .2s ease;max-width:100%}
|
| 34 |
-
.msg .avatar{width:
|
| 35 |
-
font-size:
|
| 36 |
.msg .content{flex:1;min-width:0;max-width:75%;background:var(--bubble-in);border-radius:8px;padding:6px 9px 8px;
|
| 37 |
-
box-shadow:0 1px 1px rgba(
|
| 38 |
.msg .who{font-size:13px;font-weight:600;margin-bottom:2px}
|
| 39 |
.msg .who .round{font-weight:400;color:var(--muted);margin-left:6px;font-size:11px}
|
| 40 |
.msg .body{line-height:1.42;word-wrap:break-word;color:var(--text);font-size:14.5px}
|
|
@@ -43,8 +81,8 @@ header .subtitle{font-size:12px;color:rgba(255,255,255,.75);font-weight:400}
|
|
| 43 |
.msg.user .content{flex:none;background:var(--bubble-out);border:none;
|
| 44 |
border-radius:8px;padding:7px 10px}
|
| 45 |
.msg.user .who{display:none}
|
| 46 |
-
.msg.err{align-self:center;max-width:92%;background:var(--sys);color:
|
| 47 |
-
border-radius:8px;padding:6px 12px;text-align:center;box-shadow:0 1px 1px rgba(
|
| 48 |
@keyframes fadein{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
|
| 49 |
@keyframes pulse{0%,100%{opacity:.3}50%{opacity:1}}
|
| 50 |
.msg.streaming .body::after{content:"";display:inline-block;width:7px;height:7px;border-radius:50%;
|
|
@@ -53,22 +91,22 @@ details.think{margin:2px 0 6px;font-size:12.5px;color:var(--muted)}
|
|
| 53 |
details.think summary{cursor:pointer;font-size:12px;font-style:italic}
|
| 54 |
details.think .t{white-space:pre-wrap;border-left:3px solid var(--border);padding-left:10px;margin-top:5px;font-size:12.5px}
|
| 55 |
|
| 56 |
-
#controls{padding:8px 12px;background:var(--
|
| 57 |
-
#topic{flex:1;min-width:0;background:
|
| 58 |
-
border-radius:8px;padding:11px 14px;font-size:15px;outline:none
|
| 59 |
#topic::placeholder{color:var(--muted)}
|
| 60 |
#start-btn{flex:none;background:var(--accent);color:#fff;border:none;border-radius:999px;padding:11px 18px;
|
| 61 |
-
cursor:pointer;font-weight:600;font-size:14px;transition:background .15s;white-space:nowrap;box-shadow:0 1px 2px rgba(
|
| 62 |
#start-btn:hover{background:#02b08a}
|
| 63 |
-
#start-btn:disabled{background:
|
| 64 |
-
#stop-btn{flex:none;background:
|
| 65 |
padding:10px 16px;cursor:pointer;font-weight:600;font-size:14px;display:none}
|
| 66 |
|
| 67 |
#settings{display:none;margin:8px 12px 10px;padding:16px;border:1px solid var(--border);
|
| 68 |
-
border-radius:12px;background:var(--surface);box-shadow:0 2px 6px rgba(
|
| 69 |
#settings.open{display:block}
|
| 70 |
#settings label{display:block;font-size:12px;color:var(--muted);margin:10px 0 4px}
|
| 71 |
-
#settings input,#settings textarea{width:100%;background:var(--
|
| 72 |
border:1px solid var(--border);border-radius:8px;padding:9px 12px;font-size:14px;font-family:inherit;outline:none}
|
| 73 |
#settings input:focus,#settings textarea:focus{border-color:var(--accent)}
|
| 74 |
#settings textarea{min-height:150px;font-family:ui-monospace,"SF Mono",Menlo,monospace;font-size:12px}
|
|
@@ -78,18 +116,27 @@ details.think .t{white-space:pre-wrap;border-left:3px solid var(--border);paddin
|
|
| 78 |
padding:10px 18px;cursor:pointer;font-weight:600}
|
| 79 |
|
| 80 |
#status{padding:6px 16px;font-size:12px;color:var(--muted);background:var(--bg)}
|
| 81 |
-
#progress{height:3px;background:
|
| 82 |
#progress>div{height:100%;width:0;background:var(--accent);transition:width .25s}
|
| 83 |
-
footer{padding:10px 16px;font-size:11px;color:var(--muted);border-top:1px solid var(--border);background:var(--
|
| 84 |
display:flex;gap:8px 16px;flex-wrap:wrap;justify-content:center;text-align:center}
|
| 85 |
footer a{color:var(--accent);text-decoration:none}
|
| 86 |
|
| 87 |
-
@media (max-width:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
#chat{padding:12px 4%;gap:7px}
|
| 89 |
#controls{padding:8px 8px}
|
| 90 |
header{padding:8px 10px}
|
| 91 |
header .subtitle{display:none}
|
| 92 |
-
.msg .avatar{width:
|
| 93 |
.msg .content{max-width:85%}
|
| 94 |
#settings{margin:0 8px 8px}
|
| 95 |
}
|
|
@@ -97,42 +144,51 @@ footer a{color:var(--accent);text-decoration:none}
|
|
| 97 |
</head>
|
| 98 |
<body>
|
| 99 |
<div id="app">
|
| 100 |
-
<
|
| 101 |
-
<
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
</header>
|
| 105 |
-
|
| 106 |
-
<div id="settings">
|
| 107 |
-
<div class="row">
|
| 108 |
-
<div><label>Repositorio Hugging Face</label><input id="set-repo"></div>
|
| 109 |
-
<div><label>Archivo GGUF</label><input id="set-file"></div>
|
| 110 |
</div>
|
| 111 |
-
<div
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
</div>
|
| 117 |
-
<label>Agentes (JSON: name, emoji, color, system)</label>
|
| 118 |
-
<textarea id="set-agents" spellcheck="false"></textarea>
|
| 119 |
-
<button id="apply-settings">Aplicar</button>
|
| 120 |
-
</div>
|
| 121 |
|
| 122 |
-
|
| 123 |
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
|
|
|
| 136 |
</div>
|
| 137 |
|
| 138 |
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
@@ -142,11 +198,11 @@ import { Wllama } from 'https://cdn.jsdelivr.net/npm/@wllama/wllama@3.5.1/esm/in
|
|
| 142 |
const params = new URLSearchParams(location.search);
|
| 143 |
|
| 144 |
const DEFAULT_AGENTS = [
|
| 145 |
-
{ name: 'Ada', emoji: '\
|
| 146 |
system: 'Eres Ada, la analista entusiasta del grupo. Defiendes las ideas con argumentos concretos, propones caminos a seguir y reconoces los puntos fuertes de los dem\u00e1s.' },
|
| 147 |
-
{ name: 'Bruno', emoji: '\
|
| 148 |
system: 'Eres Bruno, el esc\u00e9ptico del grupo. Cuestionas supuestos, se\u00f1alas riesgos y fallos l\u00f3gicos, y pides evidencia. Eres duro con las ideas y respetuoso con las personas.' },
|
| 149 |
-
{ name: 'Carla', emoji: '\
|
| 150 |
system: 'Eres Carla, la moderadora. Resume lo dicho, integra los desacuerdos y propone s\u00edntesis o el siguiente paso. Cierra cada ronda con una conclusi\u00f3n breve.' },
|
| 151 |
];
|
| 152 |
|
|
@@ -172,6 +228,8 @@ const progressEl = document.getElementById('progress').firstElementChild;
|
|
| 172 |
const topicEl = document.getElementById('topic');
|
| 173 |
const startBtn = document.getElementById('start-btn');
|
| 174 |
const stopBtn = document.getElementById('stop-btn');
|
|
|
|
|
|
|
| 175 |
|
| 176 |
let wllama = null;
|
| 177 |
let running = false;
|
|
@@ -184,6 +242,60 @@ function setProgress(p) { progressEl.style.width = Math.max(0, Math.min(100, p))
|
|
| 184 |
|
| 185 |
function esc(s){ const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
|
| 186 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
function addMsg(agent, isUser = false) {
|
| 188 |
const d = document.createElement('div');
|
| 189 |
d.className = 'msg' + (isUser ? ' user' : '');
|
|
@@ -197,7 +309,8 @@ function addMsg(agent, isUser = false) {
|
|
| 197 |
else {
|
| 198 |
const av = document.createElement('div');
|
| 199 |
av.className = 'avatar';
|
| 200 |
-
av.style.background = agent.color;
|
|
|
|
| 201 |
av.textContent = agent.emoji;
|
| 202 |
d.appendChild(av);
|
| 203 |
who.textContent = agent.name;
|
|
@@ -296,6 +409,7 @@ async function agentTurn(agent) {
|
|
| 296 |
];
|
| 297 |
const { el, body } = addMsg(agent);
|
| 298 |
el.classList.add('streaming');
|
|
|
|
| 299 |
let think = null;
|
| 300 |
let answer = '', reasoning = '', count = 0;
|
| 301 |
setStatus(`${agent.name} est\u00e1 escribiendo\u2026`);
|
|
@@ -330,14 +444,16 @@ async function agentTurn(agent) {
|
|
| 330 |
el.classList.add('err');
|
| 331 |
body.textContent = 'Error: ' + (e?.message || e);
|
| 332 |
el.classList.remove('streaming');
|
|
|
|
| 333 |
return;
|
| 334 |
}
|
| 335 |
el.classList.remove('streaming');
|
| 336 |
-
if (stopRequested) { el.remove(); setStatus('Detenido'); return; }
|
| 337 |
answer = answer.replace(/^\s*(?:\*\*)?[A-Za-z\u00c0-\u024f]+:\s*/, '').trim();
|
| 338 |
-
if (!answer) { el.remove(); setStatus('Listo'); return; }
|
| 339 |
body.innerHTML = (typeof marked !== 'undefined') ? marked.parse(answer) : esc(answer).replace(/\n/g, '<br>');
|
| 340 |
transcript.push({ name: agent.name, text: answer });
|
|
|
|
| 341 |
setStatus('Listo');
|
| 342 |
}
|
| 343 |
|
|
@@ -407,6 +523,7 @@ document.getElementById('apply-settings').addEventListener('click', async () =>
|
|
| 407 |
try { agents = JSON.parse(document.getElementById('set-agents').value); }
|
| 408 |
catch (e) { alert('JSON de agentes inv\u00e1lido: ' + e.message); return; }
|
| 409 |
if (!Array.isArray(agents) || agents.length < 2) { alert('Se necesitan al menos 2 agentes.'); return; }
|
|
|
|
| 410 |
CONFIG.maxTokens = parseInt(document.getElementById('set-maxtokens').value) || CONFIG.maxTokens;
|
| 411 |
CONFIG.temperature = parseFloat(document.getElementById('set-temp').value) || CONFIG.temperature;
|
| 412 |
CONFIG.rounds = parseInt(document.getElementById('set-rounds').value) || CONFIG.rounds;
|
|
@@ -424,4 +541,4 @@ if (CONFIG.autoload) loadModel(CONFIG.repo, CONFIG.file);
|
|
| 424 |
else setStatus('Modo manual: carga el modelo desde Ajustes.');
|
| 425 |
</script>
|
| 426 |
</body>
|
| 427 |
-
</html>
|
|
|
|
| 6 |
<title>Multi-Agent Debate - MiMo-V2.6-Distill-Qwen-9B</title>
|
| 7 |
<style>
|
| 8 |
:root{
|
| 9 |
+
--bg:#0b141a; --surface:#111b21; --surface2:#202c33; --border:#2a3942;
|
| 10 |
+
--text:#e9edef; --muted:#8696a0; --accent:#00a884;
|
| 11 |
+
--header:#202c33; --header-text:#e9edef; --header-sub:#8696a0;
|
| 12 |
+
--bubble-in:#202c33; --bubble-out:#005c4b; --sys:#2a3942; --sys-text:#ffd279;
|
| 13 |
+
--input:#2a3942; --track:rgba(255,255,255,.12); --disabled:#374248;
|
| 14 |
+
}
|
| 15 |
+
body.light{
|
| 16 |
--bg:#efeae2; --surface:#ffffff; --surface2:#f0f2f5; --border:#d1d7db;
|
| 17 |
+
--text:#111b21; --muted:#667781;
|
| 18 |
+
--header:#008069; --header-text:#ffffff; --header-sub:rgba(255,255,255,.75);
|
| 19 |
+
--bubble-in:#ffffff; --bubble-out:#d9fdd3; --sys:#fdf3c6; --sys-text:#54656f;
|
| 20 |
+
--input:#ffffff; --track:rgba(11,20,26,.08); --disabled:#aebac1;
|
| 21 |
}
|
|
|
|
| 22 |
*{box-sizing:border-box}
|
| 23 |
html,body{margin:0;padding:0;background:var(--bg);color:var(--text);
|
| 24 |
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;font-size:15px}
|
| 25 |
+
#app{max-width:1200px;margin:0 auto;display:flex;height:100vh;height:100dvh;
|
| 26 |
+
box-shadow:0 0 14px rgba(0,0,0,.4);background:var(--bg)}
|
| 27 |
+
|
| 28 |
+
/* --- Lista de contactos (agentes) --- */
|
| 29 |
+
#sidebar{width:300px;flex:none;display:flex;flex-direction:column;min-height:0;
|
| 30 |
+
background:var(--surface);border-right:1px solid var(--border)}
|
| 31 |
+
.side-header{display:flex;align-items:center;gap:10px;padding:10px 16px;
|
| 32 |
+
background:var(--header);color:var(--header-text)}
|
| 33 |
+
.side-logo{width:38px;height:38px;border-radius:50%;flex:none;font-size:19px;
|
| 34 |
+
background:linear-gradient(135deg,#00c49a,#025c4b);display:flex;align-items:center;justify-content:center;
|
| 35 |
+
box-shadow:0 0 10px rgba(0,168,132,.45)}
|
| 36 |
+
.side-title{font-weight:600;font-size:16px;letter-spacing:.1px}
|
| 37 |
+
.side-count{font-weight:400;color:var(--muted);font-size:12.5px;margin-left:4px}
|
| 38 |
+
#contacts{flex:1;overflow-y:auto;padding:6px 0}
|
| 39 |
+
.contact{display:flex;align-items:center;gap:12px;padding:9px 14px;transition:background .15s}
|
| 40 |
+
.contact:hover{background:var(--surface2)}
|
| 41 |
+
.contact.active{background:var(--surface2)}
|
| 42 |
+
.c-avatar{width:46px;height:46px;border-radius:50%;display:flex;align-items:center;justify-content:center;
|
| 43 |
+
font-size:22px;color:#fff;flex:none}
|
| 44 |
+
.c-info{flex:1;min-width:0;display:flex;flex-direction:column}
|
| 45 |
+
.c-name{font-size:15px;font-weight:600;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
| 46 |
+
.c-role{font-size:12.5px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
| 47 |
+
.contact.active .c-role{color:var(--accent);font-style:italic}
|
| 48 |
+
.c-dot{width:9px;height:9px;border-radius:50%;background:var(--accent);flex:none;box-shadow:0 0 6px var(--accent)}
|
| 49 |
|
| 50 |
+
/* --- Columna principal --- */
|
| 51 |
+
#main{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column}
|
| 52 |
+
|
| 53 |
+
header{display:flex;align-items:center;gap:10px;padding:8px 16px;background:var(--header);color:var(--header-text);
|
| 54 |
+
border-bottom:none;box-shadow:0 1px 3px rgba(0,0,0,.3);z-index:2}
|
| 55 |
+
header .logo{width:40px;height:40px;border-radius:50%;background:linear-gradient(135deg,#00c49a,#025c4b);
|
| 56 |
+
display:flex;align-items:center;justify-content:center;font-size:19px;color:#fff;flex:none;
|
| 57 |
+
box-shadow:0 0 10px rgba(0,168,132,.45)}
|
| 58 |
header .title{font-weight:600;font-size:16px;letter-spacing:.1px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
| 59 |
+
header .subtitle{font-size:12px;color:var(--header-sub);font-weight:400}
|
| 60 |
+
#settings-btn{background:none;border:none;color:var(--header-text);border-radius:50%;
|
| 61 |
width:38px;height:38px;cursor:pointer;font-size:18px;display:flex;align-items:center;justify-content:center;transition:.15s}
|
| 62 |
+
#settings-btn:hover{background:rgba(255,255,255,.12)}
|
| 63 |
|
| 64 |
#chat{flex:1;overflow-y:auto;padding:20px 8%;display:flex;flex-direction:column;gap:8px;
|
| 65 |
background-color:var(--bg);
|
| 66 |
+
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'%3E%3Cg fill='none' stroke='%232a3942' stroke-width='1.4' opacity='0.55'%3E%3Ccircle cx='20' cy='20' r='6'/%3E%3Cpath d='M50 15h16a6 6 0 0 1 6 6v8a6 6 0 0 1-6 6h-9l-5 5v-5h-2a6 6 0 0 1-6-6v-8a6 6 0 0 1 6-6z'/%3E%3Cpath d='M15 60l4 4 8-8'/%3E%3Ccircle cx='95' cy='70' r='8'/%3E%3Cpath d='M40 95c4-6 12-6 16 0'/%3E%3Cpath d='M85 25l2.5 5 5 2.5-5 2.5-2.5 5-2.5-5-5-2.5 5-2.5z'/%3E%3Crect x='60' y='55' width='12' height='12' rx='3'/%3E%3Cpath d='M20 100q6-8 12 0'/%3E%3C/g%3E%3C/svg%3E")}
|
| 67 |
+
body.light #chat{
|
| 68 |
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'%3E%3Cg fill='none' stroke='%23d8d1c6' stroke-width='1.4' opacity='0.5'%3E%3Ccircle cx='20' cy='20' r='6'/%3E%3Cpath d='M50 15h16a6 6 0 0 1 6 6v8a6 6 0 0 1-6 6h-9l-5 5v-5h-2a6 6 0 0 1-6-6v-8a6 6 0 0 1 6-6z'/%3E%3Cpath d='M15 60l4 4 8-8'/%3E%3Ccircle cx='95' cy='70' r='8'/%3E%3Cpath d='M40 95c4-6 12-6 16 0'/%3E%3Cpath d='M85 25l2.5 5 5 2.5-5 2.5-2.5 5-2.5-5-5-2.5 5-2.5z'/%3E%3Crect x='60' y='55' width='12' height='12' rx='3'/%3E%3Cpath d='M20 100q6-8 12 0'/%3E%3C/g%3E%3C/svg%3E")}
|
| 69 |
+
#chat::-webkit-scrollbar,#contacts::-webkit-scrollbar{width:6px;height:6px}
|
| 70 |
+
#chat::-webkit-scrollbar-thumb,#contacts::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}
|
| 71 |
.msg{display:flex;gap:8px;animation:fadein .2s ease;max-width:100%}
|
| 72 |
+
.msg .avatar{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;
|
| 73 |
+
font-size:17px;color:#fff;flex:none;margin-top:0}
|
| 74 |
.msg .content{flex:1;min-width:0;max-width:75%;background:var(--bubble-in);border-radius:8px;padding:6px 9px 8px;
|
| 75 |
+
box-shadow:0 1px 1px rgba(0,0,0,.3)}
|
| 76 |
.msg .who{font-size:13px;font-weight:600;margin-bottom:2px}
|
| 77 |
.msg .who .round{font-weight:400;color:var(--muted);margin-left:6px;font-size:11px}
|
| 78 |
.msg .body{line-height:1.42;word-wrap:break-word;color:var(--text);font-size:14.5px}
|
|
|
|
| 81 |
.msg.user .content{flex:none;background:var(--bubble-out);border:none;
|
| 82 |
border-radius:8px;padding:7px 10px}
|
| 83 |
.msg.user .who{display:none}
|
| 84 |
+
.msg.err{align-self:center;max-width:92%;background:var(--sys);color:var(--sys-text);font-size:12.5px;
|
| 85 |
+
border-radius:8px;padding:6px 12px;text-align:center;box-shadow:0 1px 1px rgba(0,0,0,.3)}
|
| 86 |
@keyframes fadein{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
|
| 87 |
@keyframes pulse{0%,100%{opacity:.3}50%{opacity:1}}
|
| 88 |
.msg.streaming .body::after{content:"";display:inline-block;width:7px;height:7px;border-radius:50%;
|
|
|
|
| 91 |
details.think summary{cursor:pointer;font-size:12px;font-style:italic}
|
| 92 |
details.think .t{white-space:pre-wrap;border-left:3px solid var(--border);padding-left:10px;margin-top:5px;font-size:12.5px}
|
| 93 |
|
| 94 |
+
#controls{padding:8px 12px;background:var(--surface);display:flex;gap:8px;align-items:center;border-top:none}
|
| 95 |
+
#topic{flex:1;min-width:0;background:var(--input);border:none;color:var(--text);
|
| 96 |
+
border-radius:8px;padding:11px 14px;font-size:15px;outline:none}
|
| 97 |
#topic::placeholder{color:var(--muted)}
|
| 98 |
#start-btn{flex:none;background:var(--accent);color:#fff;border:none;border-radius:999px;padding:11px 18px;
|
| 99 |
+
cursor:pointer;font-weight:600;font-size:14px;transition:background .15s;white-space:nowrap;box-shadow:0 1px 2px rgba(0,0,0,.3)}
|
| 100 |
#start-btn:hover{background:#02b08a}
|
| 101 |
+
#start-btn:disabled{background:var(--disabled);color:var(--muted);cursor:default;box-shadow:none}
|
| 102 |
+
#stop-btn{flex:none;background:transparent;border:1px solid #ea0038;color:#ea0038;border-radius:999px;
|
| 103 |
padding:10px 16px;cursor:pointer;font-weight:600;font-size:14px;display:none}
|
| 104 |
|
| 105 |
#settings{display:none;margin:8px 12px 10px;padding:16px;border:1px solid var(--border);
|
| 106 |
+
border-radius:12px;background:var(--surface);box-shadow:0 2px 6px rgba(0,0,0,.3)}
|
| 107 |
#settings.open{display:block}
|
| 108 |
#settings label{display:block;font-size:12px;color:var(--muted);margin:10px 0 4px}
|
| 109 |
+
#settings input,#settings textarea{width:100%;background:var(--input);color:var(--text);
|
| 110 |
border:1px solid var(--border);border-radius:8px;padding:9px 12px;font-size:14px;font-family:inherit;outline:none}
|
| 111 |
#settings input:focus,#settings textarea:focus{border-color:var(--accent)}
|
| 112 |
#settings textarea{min-height:150px;font-family:ui-monospace,"SF Mono",Menlo,monospace;font-size:12px}
|
|
|
|
| 116 |
padding:10px 18px;cursor:pointer;font-weight:600}
|
| 117 |
|
| 118 |
#status{padding:6px 16px;font-size:12px;color:var(--muted);background:var(--bg)}
|
| 119 |
+
#progress{height:3px;background:var(--track)}
|
| 120 |
#progress>div{height:100%;width:0;background:var(--accent);transition:width .25s}
|
| 121 |
+
footer{padding:10px 16px;font-size:11px;color:var(--muted);border-top:1px solid var(--border);background:var(--surface);
|
| 122 |
display:flex;gap:8px 16px;flex-wrap:wrap;justify-content:center;text-align:center}
|
| 123 |
footer a{color:var(--accent);text-decoration:none}
|
| 124 |
|
| 125 |
+
@media (max-width:760px){
|
| 126 |
+
#app{flex-direction:column;max-width:none}
|
| 127 |
+
#sidebar{width:100%;flex:none;border-right:none;border-bottom:1px solid var(--border)}
|
| 128 |
+
.side-header{display:none}
|
| 129 |
+
#contacts{display:flex;overflow-x:auto;padding:8px 10px;gap:6px}
|
| 130 |
+
.contact{flex:none;flex-direction:column;gap:4px;padding:6px 10px;min-width:64px;justify-content:center}
|
| 131 |
+
.contact .c-info{align-items:center;text-align:center}
|
| 132 |
+
.c-role{display:none}
|
| 133 |
+
.c-dot{display:none}
|
| 134 |
+
.c-avatar{width:44px;height:44px;font-size:21px}
|
| 135 |
#chat{padding:12px 4%;gap:7px}
|
| 136 |
#controls{padding:8px 8px}
|
| 137 |
header{padding:8px 10px}
|
| 138 |
header .subtitle{display:none}
|
| 139 |
+
.msg .avatar{width:32px;height:32px;font-size:16px}
|
| 140 |
.msg .content{max-width:85%}
|
| 141 |
#settings{margin:0 8px 8px}
|
| 142 |
}
|
|
|
|
| 144 |
</head>
|
| 145 |
<body>
|
| 146 |
<div id="app">
|
| 147 |
+
<aside id="sidebar">
|
| 148 |
+
<div class="side-header">
|
| 149 |
+
<span class="side-logo">🤖</span>
|
| 150 |
+
<span class="side-title">Agentes<span class="side-count" id="side-count">(3)</span></span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
</div>
|
| 152 |
+
<div id="contacts"></div>
|
| 153 |
+
</aside>
|
| 154 |
+
<div id="main">
|
| 155 |
+
<header>
|
| 156 |
+
<span class="logo">🤖</span>
|
| 157 |
+
<span class="title" id="title">Multi-Agent Debate <span class="subtitle" id="subtitle">Ada, Bruno, Carla, Tú</span></span>
|
| 158 |
+
<button id="settings-btn" title="Ajustes">⚙</button>
|
| 159 |
+
</header>
|
| 160 |
+
|
| 161 |
+
<div id="settings">
|
| 162 |
+
<div class="row">
|
| 163 |
+
<div><label>Repositorio Hugging Face</label><input id="set-repo"></div>
|
| 164 |
+
<div><label>Archivo GGUF</label><input id="set-file"></div>
|
| 165 |
+
</div>
|
| 166 |
+
<div class="row">
|
| 167 |
+
<div><label>Contexto (tokens)</label><input id="set-ctx" type="number" step="512" min="2048"></div>
|
| 168 |
+
<div><label>Máx. tokens por turno</label><input id="set-maxtokens" type="number" step="32" min="64"></div>
|
| 169 |
+
<div><label>Temperatura</label><input id="set-temp" type="number" step="0.05" min="0" max="2"></div>
|
| 170 |
+
<div><label>Rondas</label><input id="set-rounds" type="number" step="1" min="1" max="20"></div>
|
| 171 |
+
</div>
|
| 172 |
+
<label>Agentes (JSON: name, emoji, color, system)</label>
|
| 173 |
+
<textarea id="set-agents" spellcheck="false"></textarea>
|
| 174 |
+
<button id="apply-settings">Aplicar</button>
|
| 175 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
|
| 177 |
+
<div id="chat"></div>
|
| 178 |
|
| 179 |
+
<div id="controls">
|
| 180 |
+
<input id="topic" placeholder="Propón un tema y los agentes debaten…">
|
| 181 |
+
<button id="start-btn" disabled>Cargando modelo…</button>
|
| 182 |
+
<button id="stop-btn">Detener</button>
|
| 183 |
+
</div>
|
| 184 |
|
| 185 |
+
<div id="status">Iniciando…</div>
|
| 186 |
+
<div id="progress"><div></div></div>
|
| 187 |
+
<footer>
|
| 188 |
+
<span>La conversación se procesa en tu navegador (WebGPU si está disponible; si no, CPU/WASM). Solo se conecta a Hugging Face para descargar el modelo (5,8 GB la primera vez) y a jsDelivr para las librerías.</span>
|
| 189 |
+
<span>Motor: <a href="https://github.com/ngxson/wllama" target="_blank" rel="noopener">wllama</a> (MIT) · inspirado en el widget de <a href="https://localellm.com" target="_blank" rel="noopener">localellm.com</a> · modelo <a href="https://huggingface.co/XiaomiMiMo/MiMo-V2.6-Distill-Qwen-9B" target="_blank" rel="noopener">MiMo-V2.6-Distill-Qwen-9B</a> (MIT, Xiaomi)</span>
|
| 190 |
+
</footer>
|
| 191 |
+
</div>
|
| 192 |
</div>
|
| 193 |
|
| 194 |
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
|
|
| 198 |
const params = new URLSearchParams(location.search);
|
| 199 |
|
| 200 |
const DEFAULT_AGENTS = [
|
| 201 |
+
{ name: 'Ada', emoji: '\u{1F4A1}', color: '#58a6ff',
|
| 202 |
system: 'Eres Ada, la analista entusiasta del grupo. Defiendes las ideas con argumentos concretos, propones caminos a seguir y reconoces los puntos fuertes de los dem\u00e1s.' },
|
| 203 |
+
{ name: 'Bruno', emoji: '\u{1F9D0}', color: '#f0883e',
|
| 204 |
system: 'Eres Bruno, el esc\u00e9ptico del grupo. Cuestionas supuestos, se\u00f1alas riesgos y fallos l\u00f3gicos, y pides evidencia. Eres duro con las ideas y respetuoso con las personas.' },
|
| 205 |
+
{ name: 'Carla', emoji: '\u{1F3AF}', color: '#3fb950',
|
| 206 |
system: 'Eres Carla, la moderadora. Resume lo dicho, integra los desacuerdos y propone s\u00edntesis o el siguiente paso. Cierra cada ronda con una conclusi\u00f3n breve.' },
|
| 207 |
];
|
| 208 |
|
|
|
|
| 228 |
const topicEl = document.getElementById('topic');
|
| 229 |
const startBtn = document.getElementById('start-btn');
|
| 230 |
const stopBtn = document.getElementById('stop-btn');
|
| 231 |
+
const contactsEl = document.getElementById('contacts');
|
| 232 |
+
const subtitleEl = document.getElementById('subtitle');
|
| 233 |
|
| 234 |
let wllama = null;
|
| 235 |
let running = false;
|
|
|
|
| 242 |
|
| 243 |
function esc(s){ const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
|
| 244 |
|
| 245 |
+
// --- Avatares y lista de contactos ---
|
| 246 |
+
function shade(hex, amt) {
|
| 247 |
+
const n = parseInt(String(hex).replace('#','').slice(0,6), 16);
|
| 248 |
+
if (isNaN(n)) return hex;
|
| 249 |
+
const f = v => Math.max(0, Math.min(255, v + amt));
|
| 250 |
+
const r = f(n >> 16), g = f((n >> 8) & 255), b = f(n & 255);
|
| 251 |
+
return '#' + ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0');
|
| 252 |
+
}
|
| 253 |
+
function avatarBg(color) {
|
| 254 |
+
return `linear-gradient(135deg, ${shade(color, 34)} 0%, ${color} 55%, ${shade(color, -38)} 100%)`;
|
| 255 |
+
}
|
| 256 |
+
function roleOf(agent) {
|
| 257 |
+
const m = /Eres\s+[^,]+,\s*([^\.]+)\./i.exec(agent.system || '');
|
| 258 |
+
let r = m ? m[1].trim() : 'Agente del debate';
|
| 259 |
+
r = r.replace(/\s+del grupo\s*$/i, '').replace(/^(el|la|los|las)\s+/i, '');
|
| 260 |
+
return r ? r.charAt(0).toUpperCase() + r.slice(1) : 'Agente del debate';
|
| 261 |
+
}
|
| 262 |
+
function renderContacts() {
|
| 263 |
+
contactsEl.innerHTML = '';
|
| 264 |
+
agents.forEach(a => {
|
| 265 |
+
const c = document.createElement('div');
|
| 266 |
+
c.className = 'contact';
|
| 267 |
+
c.dataset.name = a.name;
|
| 268 |
+
const av = document.createElement('div');
|
| 269 |
+
av.className = 'c-avatar';
|
| 270 |
+
av.style.background = avatarBg(a.color);
|
| 271 |
+
av.style.boxShadow = `0 0 12px ${a.color}66`;
|
| 272 |
+
av.textContent = a.emoji;
|
| 273 |
+
const info = document.createElement('div');
|
| 274 |
+
info.className = 'c-info';
|
| 275 |
+
const nm = document.createElement('div');
|
| 276 |
+
nm.className = 'c-name'; nm.textContent = a.name;
|
| 277 |
+
const rl = document.createElement('div');
|
| 278 |
+
rl.className = 'c-role'; rl.textContent = roleOf(a);
|
| 279 |
+
info.appendChild(nm); info.appendChild(rl);
|
| 280 |
+
const dot = document.createElement('div');
|
| 281 |
+
dot.className = 'c-dot';
|
| 282 |
+
c.appendChild(av); c.appendChild(info); c.appendChild(dot);
|
| 283 |
+
contactsEl.appendChild(c);
|
| 284 |
+
});
|
| 285 |
+
document.getElementById('side-count').textContent = `(${agents.length})`;
|
| 286 |
+
subtitleEl.textContent = agents.map(a => a.name).join(', ') + ', T\u00fa';
|
| 287 |
+
}
|
| 288 |
+
function markActive(name) {
|
| 289 |
+
contactsEl.querySelectorAll('.contact').forEach(c => {
|
| 290 |
+
const on = c.dataset.name === name;
|
| 291 |
+
c.classList.toggle('active', on);
|
| 292 |
+
const rl = c.querySelector('.c-role');
|
| 293 |
+
if (on) { if (!rl.dataset.orig) rl.dataset.orig = rl.textContent; rl.textContent = 'escribiendo\u2026'; }
|
| 294 |
+
else if (rl.dataset.orig) { rl.textContent = rl.dataset.orig; delete rl.dataset.orig; }
|
| 295 |
+
});
|
| 296 |
+
}
|
| 297 |
+
renderContacts();
|
| 298 |
+
|
| 299 |
function addMsg(agent, isUser = false) {
|
| 300 |
const d = document.createElement('div');
|
| 301 |
d.className = 'msg' + (isUser ? ' user' : '');
|
|
|
|
| 309 |
else {
|
| 310 |
const av = document.createElement('div');
|
| 311 |
av.className = 'avatar';
|
| 312 |
+
av.style.background = avatarBg(agent.color);
|
| 313 |
+
av.style.boxShadow = '0 0 8px ' + agent.color + '55';
|
| 314 |
av.textContent = agent.emoji;
|
| 315 |
d.appendChild(av);
|
| 316 |
who.textContent = agent.name;
|
|
|
|
| 409 |
];
|
| 410 |
const { el, body } = addMsg(agent);
|
| 411 |
el.classList.add('streaming');
|
| 412 |
+
markActive(agent.name);
|
| 413 |
let think = null;
|
| 414 |
let answer = '', reasoning = '', count = 0;
|
| 415 |
setStatus(`${agent.name} est\u00e1 escribiendo\u2026`);
|
|
|
|
| 444 |
el.classList.add('err');
|
| 445 |
body.textContent = 'Error: ' + (e?.message || e);
|
| 446 |
el.classList.remove('streaming');
|
| 447 |
+
markActive(null);
|
| 448 |
return;
|
| 449 |
}
|
| 450 |
el.classList.remove('streaming');
|
| 451 |
+
if (stopRequested) { el.remove(); markActive(null); setStatus('Detenido'); return; }
|
| 452 |
answer = answer.replace(/^\s*(?:\*\*)?[A-Za-z\u00c0-\u024f]+:\s*/, '').trim();
|
| 453 |
+
if (!answer) { el.remove(); markActive(null); setStatus('Listo'); return; }
|
| 454 |
body.innerHTML = (typeof marked !== 'undefined') ? marked.parse(answer) : esc(answer).replace(/\n/g, '<br>');
|
| 455 |
transcript.push({ name: agent.name, text: answer });
|
| 456 |
+
markActive(null);
|
| 457 |
setStatus('Listo');
|
| 458 |
}
|
| 459 |
|
|
|
|
| 523 |
try { agents = JSON.parse(document.getElementById('set-agents').value); }
|
| 524 |
catch (e) { alert('JSON de agentes inv\u00e1lido: ' + e.message); return; }
|
| 525 |
if (!Array.isArray(agents) || agents.length < 2) { alert('Se necesitan al menos 2 agentes.'); return; }
|
| 526 |
+
renderContacts();
|
| 527 |
CONFIG.maxTokens = parseInt(document.getElementById('set-maxtokens').value) || CONFIG.maxTokens;
|
| 528 |
CONFIG.temperature = parseFloat(document.getElementById('set-temp').value) || CONFIG.temperature;
|
| 529 |
CONFIG.rounds = parseInt(document.getElementById('set-rounds').value) || CONFIG.rounds;
|
|
|
|
| 541 |
else setStatus('Modo manual: carga el modelo desde Ajustes.');
|
| 542 |
</script>
|
| 543 |
</body>
|
| 544 |
+
</html>
|