| |
| async function fetchJSON(url) { |
| const res = await fetch(url); |
| if (!res.ok) throw new Error(`HTTP ${res.status}`); |
| return res.json(); |
| } |
|
|
| |
| 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'; |
| } |
| } |
|
|
| |
| 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 = '<li>No models available</li>'; |
| return; |
| } |
| listEl.innerHTML = models.map(m => `<li><strong>${m.id}</strong> <span class="status-badge status-ok">active</span></li>`).join(''); |
| } catch (e) { |
| listEl.innerHTML = '<li class="status-badge status-err">Failed to load models</li>'; |
| } |
| } |
|
|
| |
| 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; |
| } |
| } |
|
|
| |
| 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(); |
| }; |
| } |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| document.getElementById('create-btn').addEventListener('click', createAccount); |
| loadHealth(); |
| loadModels(); |
| startLogs(); |
| |
| setInterval(loadHealth, 10000); |
| }); |
|
|