Files
xiaodoudou-ComfyUI-RigShare/web/rigshare/server-widget.js
T
Edouard Durand 4fdbc035f4 Performance: run in progress vs ETA and last runs, in the Server tab and as a floating card
Floating cards share one base (float.js) with magnet docking; docked cards
stack in the corner. Durations come from ComfyUI's history timestamps, the
start of the current run from the execution_start event.
2026-09-27 03:22:51 +00:00

86 lines
4.0 KiB
JavaScript

// Floating cards over the canvas: the server monitor and performance. Docking,
// dragging and the magnet come from FloatCard (float.js).
import { h } from "./ui.js";
import { FloatCard } from "./float.js";
import { perfView } from "./perf.js";
function mini(label, pct, text) {
const p = Math.max(0, Math.min(100, pct || 0));
const level = p > 90 ? "hot" : p > 70 ? "warm" : "";
return h("div", { class: "rs-mini", title: `${label}: ${text}` },
h("span", { class: "rs-mini-label" }, label),
h("span", { class: "rs-mini-track" }, h("span", { class: `rs-meter-fill ${level}`, style: `width:${p}%` })),
h("span", { class: "rs-mini-text" }, text));
}
/** Server monitor; admins also get ComfyUI's memory actions. */
export class ServerWidget extends FloatCard {
constructor(client, onChange, { inAppMode } = {}) {
super({ key: "rigshare.serverFloat", title: "Server", icon: "pi-server", inAppMode, onChange });
this.client = client;
client.on("stats", () => this.render());
client.on("self", () => this.render());
this.start();
}
async free(options, done) {
try {
await this.client.request("POST", "/api/free", options);
this.client.emit("toast", { severity: "success", summary: "RigShare", detail: done });
} catch (e) {
this.client.emit("toast", { severity: "error", summary: "RigShare", detail: e.message || String(e) });
}
}
render() {
if (!this.el) return;
const st = this.client.stats;
const admin = !!this.client.perms?.admin;
this.actions.style.display = admin ? "" : "none";
if (admin && !this.actions.childElementCount) {
this.actions.append(
h("button", {
class: "rs-btn rs-btn-sm", title: "Unload the models ComfyUI is holding in memory",
onclick: () => this.free({ unload_models: true }, "Models unloaded"),
}, "Unload models"),
h("button", {
class: "rs-btn rs-btn-sm", title: "Unload the models and clear the node cache (the next run starts from scratch)",
onclick: () => this.free({ unload_models: true, free_memory: true }, "Models and cache freed"),
}, "Free models & cache"));
}
if (!st) {
this.body.replaceChildren(h("div", { class: "rs-muted rs-small" }, "Waiting for data…"));
return;
}
const rows = [];
if (st.cpu != null) rows.push(mini("CPU", st.cpu, `${Math.round(st.cpu)}%`));
if (st.ram_total) rows.push(mini("RAM", (st.ram_used / st.ram_total) * 100, `${Math.round(st.ram_used)}G`));
for (const g of st.gpus || []) {
rows.push(mini(`GPU${g.index}`, g.util, `${g.util}%${g.temp != null ? ` ${g.temp}°` : ""}`));
rows.push(mini(`VRAM${g.index}`, (g.vram_used / g.vram_total) * 100, `${g.vram_used.toFixed(1)}G`));
}
const q = st.queue;
if (q) rows.push(h("div", { class: "rs-mini-queue" }, q.running || q.pending ? `${q.running} running · ${q.pending} queued` : "queue idle"));
this.body.replaceChildren(...rows);
}
}
/** Performance: the run in progress against its ETA, and the last runs. */
export class PerfWidget extends FloatCard {
constructor(client, onChange, { inAppMode } = {}) {
super({ key: "rigshare.perfFloat", title: "Performance", icon: "pi-stopwatch", inAppMode, onChange });
this.client = client;
this.receivedAt = Date.now();
client.on("stats", () => { this.receivedAt = Date.now(); this.render(); });
// The clock keeps ticking between server updates.
setInterval(() => { if (this.el && this.client.stats?.performance?.running?.length) this.render(); }, 250);
this.start();
}
render() {
if (!this.el) return;
this.body.replaceChildren(...perfView(this.client.stats?.performance, this.receivedAt, { compact: true }));
}
}