// Utility: fetch wrapper async function fetchJSON(url) { const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); } // Fetch health async function loadHealth() { try { const data = await fetchJSON('/health'); document.getElementById('total-accounts').textContent = data.accounts_total ?? '–'; document.getElementById('alive-accounts').textContent = data.accounts_alive ?? '–'; } catch (e) { document.getElementById('total-accounts').textContent = 'error'; document.getElementById('alive-accounts').textContent = 'error'; } } // Fetch models async function loadModels() { const listEl = document.getElementById('model-list'); try { const data = await fetchJSON('/v1/models'); const models = data.data || []; if (models.length === 0) { listEl.innerHTML = '
  • No models available
  • '; return; } listEl.innerHTML = models.map(m => `
  • ${m.id} active
  • `).join(''); } catch (e) { listEl.innerHTML = '
  • Failed to load models
  • '; } } // Create account async function createAccount() { const btn = document.getElementById('create-btn'); const msg = document.getElementById('create-msg'); btn.disabled = true; msg.classList.remove('hidden'); msg.textContent = 'Creating…'; msg.className = ''; try { const res = await fetch('/admin/create-account', { method: 'POST' }); const data = await res.json(); if (res.ok && data.status === 'ok') { msg.textContent = '✓ Account created'; msg.classList.add('status-ok'); setTimeout(() => { msg.classList.add('hidden'); }, 3000); loadHealth(); } else { throw new Error(data.error || 'Unknown error'); } } catch (e) { msg.textContent = '✗ ' + e.message; msg.classList.add('status-err'); } finally { btn.disabled = false; } } // SSE Logs function startLogs() { const container = document.getElementById('log-container'); const evtSource = new EventSource('/admin/logs/stream'); container.innerHTML = ''; evtSource.onmessage = (event) => { const div = document.createElement('div'); div.className = 'log-entry'; div.textContent = event.data; container.appendChild(div); container.scrollTop = container.scrollHeight; }; evtSource.onerror = () => { const div = document.createElement('div'); div.className = 'log-entry status-err'; div.textContent = '[SSE connection lost]'; container.appendChild(div); evtSource.close(); }; } // Init document.addEventListener('DOMContentLoaded', () => { document.getElementById('create-btn').addEventListener('click', createAccount); loadHealth(); loadModels(); startLogs(); // Refresh health every 10s setInterval(loadHealth, 10000); });