fivetech commited on
Commit
03fe476
·
verified ·
1 Parent(s): c9cfc5c

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +44 -11
app.js CHANGED
@@ -352,12 +352,22 @@ async function generate(system, user, maxTokens, onDelta) {
352
  return out.replace(/^\s*(?:\*\*)?[A-Za-zÀ-ɏ0-9_ ]{1,30}:\s*/, '').trim();
353
  }
354
  function extractJSON(text) {
355
- const start = text.indexOf('{');
356
- if (start < 0) return null;
357
- let depth = 0;
358
- for (let i = start; i < text.length; i++) {
359
- if (text[i] === '{') depth++;
360
- else if (text[i] === '}') { depth--; if (depth === 0) { try { return JSON.parse(text.slice(start, i + 1)); } catch { return null; } } }
 
 
 
 
 
 
 
 
 
 
361
  }
362
  return null;
363
  }
@@ -525,6 +535,11 @@ async function runJudging() {
525
  try {
526
  const out = await generate(system, user, CONFIG.judgeTokens);
527
  parsed = extractJSON(out);
 
 
 
 
 
528
  } catch (e) { console.warn(j.name, e); }
529
  // fallback heurístico si el JSON no es parseable
530
  ps.forEach(a => {
@@ -554,6 +569,10 @@ async function runJudging() {
554
  `Responde SOLO con JSON válido: {"winner":"<nombre exacto del ganador o Empate>","justification":"2-4 frases","decisive":["argumento decisivo 1","2"],"mistakes":["error detectado 1","2"],"best":["mejor intervención 1"]}`;
555
  const out = await generate(system, user, CONFIG.judgeTokens + 50);
556
  verdict = extractJSON(out);
 
 
 
 
557
  } catch (e) { console.warn('head judge', e); }
558
  finalizeBattle(verdict);
559
  }
@@ -602,12 +621,26 @@ function renderResults(totals, winner, verdict) {
602
  <div class="crown">${heur ? '⚠️' : '👑'}</div>
603
  <h1 style="font-size:1.8rem;font-weight:900">${heur ? '⚠️ Evaluación no fiable' : (winner ? `<span style="color:${winner.color}">${winner.emoji} ${esc(winner.name)}</span> gana la batalla` : '🤝 EMPATE')}</h1>
604
  <p style="color:var(--muted);margin-top:8px;font-size:.9rem">${esc(battle.topic)}</p>
605
- ${heur ? `<p style="max-width:660px;margin:12px auto 0;font-size:.88rem;line-height:1.6;color:#f59e0b">El modelo no produjo evaluaciones estructuradas. Las puntuaciones mostradas son una estimación heurística (número y longitud de intervenciones), NO una valoración real del debate. Esta batalla no cuenta para el Hall of Fame ni otorga premios.</p>` : ''}
606
  ${!heur && verdict?.justification ? `<p style="max-width:640px;margin:12px auto 0;font-size:.9rem;line-height:1.6">${esc(verdict.justification)}</p>` : ''}`;
607
- $('#score-table').innerHTML = `
608
- <tr><th>Criterio (peso)</th>${totals.map(t => `<th style="color:${t.a.color}">${t.a.emoji} ${esc(t.a.name)}</th>`).join('')}</tr>
609
- ${WEIGHTS.map(([k, label, w]) => `<tr><td>${label} <span style="color:var(--muted)">(${w}%)</span></td>${totals.map(t => `<td>${battle.scores[t.a.id][k] ?? '—'}</td>`).join('')}</tr>`).join('')}
610
- <tr style="font-weight:800"><td>TOTAL</td>${totals.map(t => `<td style="color:${t.a.color}">${t.total}</td>`).join('')}</tr>`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
611
  $('#judge-cards').innerHTML = battle.judgeReports.map(r => `
612
  <div class="judge-card"><h4>${r.emoji} ${r.judge}</h4><p>${r.parsed ? esc(JSON.stringify(r.parsed)) : 'Evaluación heurística (respuesta no estructurada).'}</p></div>`).join('') +
613
  `<div class="judge-card"><h4>👑 Head Judge</h4><p>${verdict?.justification ? esc(verdict.justification) : 'Veredicto por puntuación ponderada.'}</p>
 
352
  return out.replace(/^\s*(?:\*\*)?[A-Za-zÀ-ɏ0-9_ ]{1,30}:\s*/, '').trim();
353
  }
354
  function extractJSON(text) {
355
+ if (!text) return null;
356
+ const cleaned = String(text).replace(/```(?:json)?/gi, ' ');
357
+ const tryParse = s => {
358
+ try { return JSON.parse(s); } catch { /* sigue */ }
359
+ try { return JSON.parse(s.replace(/,\s*([}\]])/g, '$1')); } catch { /* comas colgantes */ }
360
+ return null;
361
+ };
362
+ for (let start = cleaned.indexOf('{'); start >= 0; start = cleaned.indexOf('{', start + 1)) {
363
+ let depth = 0;
364
+ for (let i = start; i < cleaned.length; i++) {
365
+ if (cleaned[i] === '{') depth++;
366
+ else if (cleaned[i] === '}') {
367
+ depth--;
368
+ if (depth === 0) { const r = tryParse(cleaned.slice(start, i + 1)); if (r) return r; break; }
369
+ }
370
+ }
371
  }
372
  return null;
373
  }
 
535
  try {
536
  const out = await generate(system, user, CONFIG.judgeTokens);
537
  parsed = extractJSON(out);
538
+ if (!parsed) {
539
+ // un reintento con instrucción más estricta; si sigue fallando, queda como "no evaluable"
540
+ const out2 = await generate(system, user + '\n\nIMPORTANTE: responde ÚNICAMENTE con el JSON válido pedido, sin explicaciones, sin markdown y sin texto adicional.', CONFIG.judgeTokens);
541
+ parsed = extractJSON(out2);
542
+ }
543
  } catch (e) { console.warn(j.name, e); }
544
  // fallback heurístico si el JSON no es parseable
545
  ps.forEach(a => {
 
569
  `Responde SOLO con JSON válido: {"winner":"<nombre exacto del ganador o Empate>","justification":"2-4 frases","decisive":["argumento decisivo 1","2"],"mistakes":["error detectado 1","2"],"best":["mejor intervención 1"]}`;
570
  const out = await generate(system, user, CONFIG.judgeTokens + 50);
571
  verdict = extractJSON(out);
572
+ if (!verdict) {
573
+ const out2 = await generate(system, user + '\n\nIMPORTANTE: responde ÚNICAMENTE con el JSON válido pedido, sin explicaciones, sin markdown y sin texto adicional.', CONFIG.judgeTokens + 50);
574
+ verdict = extractJSON(out2);
575
+ }
576
  } catch (e) { console.warn('head judge', e); }
577
  finalizeBattle(verdict);
578
  }
 
621
  <div class="crown">${heur ? '⚠️' : '👑'}</div>
622
  <h1 style="font-size:1.8rem;font-weight:900">${heur ? '⚠️ Evaluación no fiable' : (winner ? `<span style="color:${winner.color}">${winner.emoji} ${esc(winner.name)}</span> gana la batalla` : '🤝 EMPATE')}</h1>
623
  <p style="color:var(--muted);margin-top:8px;font-size:.9rem">${esc(battle.topic)}</p>
624
+ ${heur ? `<p style="max-width:660px;margin:12px auto 0;font-size:.88rem;line-height:1.6;color:#f59e0b">El modelo no produjo evaluaciones estructuradas: no hay puntuaciones fiables para esta batalla. Solo se muestran métricas mecánicas (número y longitud de intervenciones), que NO son una valoración del debate. Esta batalla no cuenta para el Hall of Fame ni otorga premios.</p>` : ''}
625
  ${!heur && verdict?.justification ? `<p style="max-width:640px;margin:12px auto 0;font-size:.9rem;line-height:1.6">${esc(verdict.justification)}</p>` : ''}`;
626
+ document.querySelector('#mech-metrics')?.remove();
627
+ if (heur) {
628
+ // sin evaluación real no se presentan notas por criterio: solo "no disponible" + métricas mecánicas separadas
629
+ $('#score-table').innerHTML = `
630
+ <tr><th>Criterio (peso)</th>${totals.map(t => `<th style="color:${t.a.color}">${t.a.emoji} ${esc(t.a.name)}</th>`).join('')}</tr>
631
+ ${WEIGHTS.map(([k, label, w]) => `<tr><td>${label} <span style="color:var(--muted)">(${w}%)</span></td>${totals.map(() => `<td style="color:var(--muted)">no disponible</td>`).join('')}</tr>`).join('')}
632
+ <tr style="font-weight:800"><td>TOTAL</td>${totals.map(() => `<td style="color:var(--muted)">—</td>`).join('')}</tr>`;
633
+ const mech = totals.map(t => {
634
+ const mine = battle.events.filter(e => e.agentId === t.a.id);
635
+ return `${t.a.emoji} ${esc(t.a.name)}: ${mine.length} intervenciones · ${mine.reduce((s, e) => s + e.content.length, 0)} caracteres`;
636
+ }).join(' · ');
637
+ $('#score-table').insertAdjacentHTML('afterend', `<p id="mech-metrics" style="color:var(--muted);font-size:.8rem;margin-top:8px">Métricas mecánicas (NO son una evaluación del debate): ${mech}</p>`);
638
+ } else {
639
+ $('#score-table').innerHTML = `
640
+ <tr><th>Criterio (peso)</th>${totals.map(t => `<th style="color:${t.a.color}">${t.a.emoji} ${esc(t.a.name)}</th>`).join('')}</tr>
641
+ ${WEIGHTS.map(([k, label, w]) => `<tr><td>${label} <span style="color:var(--muted)">(${w}%)</span></td>${totals.map(t => `<td>${battle.scores[t.a.id][k] ?? '—'}</td>`).join('')}</tr>`).join('')}
642
+ <tr style="font-weight:800"><td>TOTAL</td>${totals.map(t => `<td style="color:${t.a.color}">${t.total}</td>`).join('')}</tr>`;
643
+ }
644
  $('#judge-cards').innerHTML = battle.judgeReports.map(r => `
645
  <div class="judge-card"><h4>${r.emoji} ${r.judge}</h4><p>${r.parsed ? esc(JSON.stringify(r.parsed)) : 'Evaluación heurística (respuesta no estructurada).'}</p></div>`).join('') +
646
  `<div class="judge-card"><h4>👑 Head Judge</h4><p>${verdict?.justification ? esc(verdict.justification) : 'Veredicto por puntuación ponderada.'}</p>