Bump to 0.1.0:1 — portability + endpoint display
- configureSparks.ts: generic placeholders (e.g. 192.168.1.10), no Alice-specific IPs; descriptions explain the role of each node instead of naming his hardware - showPublicKey.ts: reads sparkConfig.yaml; emits a ready-to-paste one-liner (KEY='...' followed by 'ssh user@host "echo $KEY >> authorized_keys"' for each configured Spark). Falls back to generic instructions if Configure Sparks hasn't been run yet. - /api/status now includes vllm.base_url for the OpenAI endpoint - New endpoint panel in UI: base URL + model ID rows with copy buttons + collapsible curl example - Bump version to 0.1.0:1
This commit is contained in:
@@ -83,6 +83,52 @@ function renderCurrent(status) {
|
||||
c.innerHTML = `<strong>${label}</strong>`;
|
||||
}
|
||||
|
||||
function renderEndpoint(status) {
|
||||
const v = status.vllm || {};
|
||||
const panel = el('#endpoint-panel');
|
||||
const ready = v.ok && v.current_model && v.base_url;
|
||||
panel.classList.toggle('hidden', !ready);
|
||||
if (!ready) return;
|
||||
el('#ep-url').textContent = v.base_url;
|
||||
el('#ep-model').textContent = v.current_model;
|
||||
const snippet =
|
||||
`curl -s ${v.base_url}/chat/completions \\
|
||||
-H 'content-type: application/json' \\
|
||||
-d '{
|
||||
"model": "${v.current_model}",
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
}'`;
|
||||
el('#ep-curl-snippet').textContent = snippet;
|
||||
}
|
||||
|
||||
function setupCopyButtons() {
|
||||
document.body.addEventListener('click', async (e) => {
|
||||
const btn = e.target.closest('.copy-btn');
|
||||
if (!btn) return;
|
||||
const targetSel = btn.dataset.copy;
|
||||
if (!targetSel) return;
|
||||
const target = el(targetSel);
|
||||
if (!target) return;
|
||||
const text = target.textContent;
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
const original = btn.textContent;
|
||||
btn.classList.add('copied');
|
||||
btn.textContent = 'Copied';
|
||||
setTimeout(() => {
|
||||
btn.classList.remove('copied');
|
||||
btn.textContent = original;
|
||||
}, 1400);
|
||||
} catch {
|
||||
// Clipboard API may fail over plain HTTP; fall back to selection
|
||||
const range = document.createRange();
|
||||
range.selectNode(target);
|
||||
window.getSelection().removeAllRanges();
|
||||
window.getSelection().addRange(range);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderHealth(status) {
|
||||
function setDot(id, ok, payload) {
|
||||
const item = el(id);
|
||||
@@ -221,6 +267,7 @@ async function pollStatus() {
|
||||
state.configured = status.configured;
|
||||
renderBanner(status);
|
||||
renderCurrent(status);
|
||||
renderEndpoint(status);
|
||||
renderHealth(status);
|
||||
if (status.current_swap_job && status.current_swap_job !== state.swap_job_id) {
|
||||
attachToSwap(status.current_swap_job, /*needsBackfill=*/true);
|
||||
@@ -342,6 +389,7 @@ function appendLog(line) {
|
||||
}
|
||||
|
||||
async function init() {
|
||||
setupCopyButtons();
|
||||
await loadModels();
|
||||
await pollStatus();
|
||||
setInterval(pollStatus, 5000);
|
||||
|
||||
Reference in New Issue
Block a user