fix: make model placement controls observable
This commit is contained in:
@@ -295,7 +295,7 @@
|
|||||||
<section data-tab="billing" data-admin-only><h2>Node pending payouts</h2><div id="pending" class="empty">admin login required</div></section>
|
<section data-tab="billing" data-admin-only><h2>Node pending payouts</h2><div id="pending" class="empty">admin login required</div></section>
|
||||||
<section data-tab="billing" data-admin-only><h2>Settlement history</h2><div id="settlements" class="empty">admin login required</div></section>
|
<section data-tab="billing" data-admin-only><h2>Settlement history</h2><div id="settlements" class="empty">admin login required</div></section>
|
||||||
<section data-tab="admin"><h2>Tracker hive</h2><div id="hive" class="empty">loading…</div></section>
|
<section data-tab="admin"><h2>Tracker hive</h2><div id="hive" class="empty">loading…</div></section>
|
||||||
<section data-tab="admin" class="wide"><h2>Model placement</h2><div id="admin-model-placement" class="empty">admin login required</div></section>
|
<section data-tab="admin" class="wide"><h2>Model placement</h2><div id="admin-model-placement-status" class="dim">Choose a model to load or release.</div><div id="admin-model-placement" class="empty">admin login required</div></section>
|
||||||
<section data-tab="admin" id="admin-section"><h2>All accounts (admin)</h2><div id="admin" class="empty"></div></section>
|
<section data-tab="admin" id="admin-section"><h2>All accounts (admin)</h2><div id="admin" class="empty"></div></section>
|
||||||
<section data-tab="admin" data-admin-only><h2>Strikes / bans / forfeitures</h2><div id="fraud" class="empty">admin login required</div></section>
|
<section data-tab="admin" data-admin-only><h2>Strikes / bans / forfeitures</h2><div id="fraud" class="empty">admin login required</div></section>
|
||||||
<section data-tab="admin"><h2>Client balances</h2><div id="clients" class="empty">admin login required</div></section>
|
<section data-tab="admin"><h2>Client balances</h2><div id="clients" class="empty">admin login required</div></section>
|
||||||
@@ -1801,25 +1801,34 @@ async function requestSelectedModelLoad() {
|
|||||||
|
|
||||||
async function requestAdminModelLoad(model) {
|
async function requestAdminModelLoad(model) {
|
||||||
const result = await apiCall("/v1/models/load", "POST", { model, force: true });
|
const result = await apiCall("/v1/models/load", "POST", { model, force: true });
|
||||||
if (!result.ok) return alert(result.data.error || "model load request failed");
|
if (!result.ok) return showAdminModelPlacementStatus(result.data.error || "model load request failed", true);
|
||||||
|
const assignment = result.data.assignment || {};
|
||||||
|
showAdminModelPlacementStatus(`Load queued on ${short(assignment.node_id || "node")} for ${model}.`);
|
||||||
await refreshActiveTab(true);
|
await refreshActiveTab(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function releaseAdminModel(model) {
|
async function releaseAdminModel(model) {
|
||||||
if (!confirm(`Release ${model} from every serving node?`)) return;
|
|
||||||
const result = await apiCall("/v1/models/release", "POST", { model });
|
const result = await apiCall("/v1/models/release", "POST", { model });
|
||||||
if (!result.ok) return alert(result.data.error || "model release request failed");
|
if (!result.ok) return showAdminModelPlacementStatus(result.data.error || "model release request failed", true);
|
||||||
|
showAdminModelPlacementStatus(`Release queued for ${result.data.released || 0} node(s) serving ${model}.`);
|
||||||
await refreshActiveTab(true);
|
await refreshActiveTab(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showAdminModelPlacementStatus(message, isError) {
|
||||||
|
const status = $("admin-model-placement-status");
|
||||||
|
status.textContent = message;
|
||||||
|
status.className = isError ? "bad" : "ok";
|
||||||
|
}
|
||||||
|
|
||||||
function renderAdminModelPlacement(models, map) {
|
function renderAdminModelPlacement(models, map) {
|
||||||
const nodes = (map && map.nodes) || [];
|
const nodes = (map && map.nodes) || [];
|
||||||
const rows = ((models && models.data) || []).map(model => {
|
const rows = ((models && models.data) || []).map(model => {
|
||||||
const aliases = new Set([model.id, model.hf_repo, ...(model.aliases || [])].filter(Boolean));
|
const aliases = new Set([model.id, model.hf_repo, ...(model.aliases || [])].filter(Boolean));
|
||||||
const serving = nodes.filter(node => aliases.has(node.model) || aliases.has(node.hf_repo)).length;
|
const serving = nodes.filter(node => aliases.has(node.model) || aliases.has(node.hf_repo)).length;
|
||||||
const downloaded = nodes.filter(node => (node.downloaded_models || []).some(item => aliases.has(item.model) || aliases.has(item.hf_repo))).length;
|
const downloaded = nodes.filter(node => aliases.has(node.model) || aliases.has(node.hf_repo) ||
|
||||||
const actions = `<button class="small" onclick="requestAdminModelLoad(${JSON.stringify(model.id)})">load</button> ` +
|
(node.downloaded_models || []).some(item => aliases.has(item.model) || aliases.has(item.hf_repo))).length;
|
||||||
`<button class="small" onclick="releaseAdminModel(${JSON.stringify(model.id)})"${serving ? "" : " disabled"}>release</button>`;
|
const actions = `<button class="small" data-admin-model-load="${esc(model.id)}">load</button> ` +
|
||||||
|
`<button class="small" data-admin-model-release="${esc(model.id)}"${serving ? "" : " disabled"}>release</button>`;
|
||||||
return [esc(model.name || model.id), String(serving), String(downloaded), actions];
|
return [esc(model.name || model.id), String(serving), String(downloaded), actions];
|
||||||
});
|
});
|
||||||
$("admin-model-placement").innerHTML = rows.length
|
$("admin-model-placement").innerHTML = rows.length
|
||||||
@@ -1827,6 +1836,13 @@ function renderAdminModelPlacement(models, map) {
|
|||||||
: '<div class="empty">no model presets configured</div>';
|
: '<div class="empty">no model presets configured</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$("admin-model-placement").addEventListener("click", event => {
|
||||||
|
const load = event.target.closest("[data-admin-model-load]");
|
||||||
|
const release = event.target.closest("[data-admin-model-release]");
|
||||||
|
if (load) void requestAdminModelLoad(load.dataset.adminModelLoad);
|
||||||
|
if (release) void releaseAdminModel(release.dataset.adminModelRelease);
|
||||||
|
});
|
||||||
|
|
||||||
function chatAuthToken() {
|
function chatAuthToken() {
|
||||||
if (accountApiKeys.length) return accountApiKeys[0];
|
if (accountApiKeys.length) return accountApiKeys[0];
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ def test_dashboard_exposes_admin_model_inventory_and_release_controls():
|
|||||||
assert '"/v1/models/release"' in html
|
assert '"/v1/models/release"' in html
|
||||||
assert "requestAdminModelLoad" in html
|
assert "requestAdminModelLoad" in html
|
||||||
assert "releaseAdminModel" in html
|
assert "releaseAdminModel" in html
|
||||||
|
assert 'data-admin-model-load=' in html
|
||||||
|
assert 'data-admin-model-release=' in html
|
||||||
|
assert "admin-model-placement-status" in html
|
||||||
|
|
||||||
|
|
||||||
def test_network_map_includes_node_friendly_name():
|
def test_network_map_includes_node_friendly_name():
|
||||||
|
|||||||
Reference in New Issue
Block a user