Shokat's picture
Upload 10 files
fc851c4 verified
Raw
History Blame Contribute Delete
4.8 kB
document.addEventListener('DOMContentLoaded', () => {
const startBtn = document.getElementById('startBtn');
const topicInput = document.getElementById('topicInput');
const arena = document.getElementById('arena');
const globalStatus = document.getElementById('globalStatus');
const modelStatusList = document.getElementById('modelStatusList');
const MODELS = [
'openai/gpt-oss-120b',
'llama-3.3-70b-versatile',
'qwen/qwen3-32b',
'gemini-2.5-flash',
'Gemma 4 (Architect)'
];
function initSidebar() {
modelStatusList.innerHTML = '';
MODELS.forEach(m => {
const li = document.createElement('li');
li.id = `status-${m.replace(/[^a-zA-Z0-9]/g, '')}`;
li.innerHTML = `
<span class="model-name">${m}</span>
<span class="model-status">Awaiting task</span>
`;
modelStatusList.appendChild(li);
});
}
initSidebar();
startBtn.addEventListener('click', async () => {
const topic = topicInput.value.trim();
if (!topic) return;
startBtn.disabled = true;
arena.innerHTML = '';
initSidebar();
try {
const response = await fetch('/api/debate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ topic })
});
const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n\n');
buffer = lines.pop() || "";
for (const chunk of lines) {
if (chunk.trim() === '') continue;
const eventMatch = chunk.match(/event: (.*)\n/);
const dataMatch = chunk.match(/data: (.*)/);
if (eventMatch && dataMatch) {
const event = eventMatch[1];
const data = JSON.parse(dataMatch[1]);
handleEvent(event, data);
}
}
}
} catch (error) {
console.error(error);
globalStatus.innerText = "Error occurred.";
} finally {
startBtn.disabled = false;
}
});
function handleEvent(event, data) {
if (event === 'status') {
globalStatus.innerText = data.message;
}
else if (event === 'model_start') {
const id = `status-${data.model.replace(/[^a-zA-Z0-9]/g, '')}`;
const el = document.getElementById(id);
if (el) {
el.className = 'active';
el.querySelector('.model-status').innerHTML = `<span class="pulse-text">Thinking (Round ${data.round})...</span>`;
}
}
else if (event === 'model_end') {
const id = `status-${data.model.replace(/[^a-zA-Z0-9]/g, '')}`;
const el = document.getElementById(id);
if (el) {
el.className = 'done';
el.querySelector('.model-status').innerText = `Finished Round ${data.round}`;
}
appendMessage(data.model, data.round, data.content);
}
else if (event === 'done') {
globalStatus.innerText = "Debate Concluded. Final Verdict Delivered.";
globalStatus.classList.remove('pulse-text');
MODELS.forEach(m => {
const id = `status-${m.replace(/[^a-zA-Z0-9]/g, '')}`;
const el = document.getElementById(id);
if (el) { el.classList.remove('active'); el.classList.remove('done'); }
});
}
}
function appendMessage(model, round, markdownContent) {
const div = document.createElement('div');
div.className = `message-bubble ${model.includes('Architect') ? 'architect' : ''}`;
div.style.animationDelay = `${0.1 * document.querySelectorAll('.message-bubble').length}s`;
let roundLabel = round === 'Final' ? 'VERDICT' : `Round ${round}`;
div.innerHTML = `
<div class="bubble-header">
<span>${model}</span>
<span class="round">${roundLabel}</span>
</div>
<div class="bubble-content">
${marked.parse(markdownContent)}
</div>
`;
arena.appendChild(div);
arena.scrollTop = arena.scrollHeight;
}
});