Old project/workflow names and browser settings migrate on load; /funpack redirects to /fun. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016acRss69eH1235eRdFTZHY
44 lines
3.3 KiB
JavaScript
44 lines
3.3 KiB
JavaScript
// About FunUI: which build this is, and the machine ComfyUI runs on (which on a rental is not this browser's).
|
|
import { composer as c } from "../../composer/composer.js";
|
|
|
|
const facts = (rows) => rows.filter(([, v]) => v).map(([k, v]) => c.settingsRow.default({ label: k, control: c.text.sm({ text: String(v) }) }));
|
|
|
|
|
|
export const about = (api) => function mount() {
|
|
const body = c.region.stack({ gap: "sm", label: "About" });
|
|
body.set([c.hint.default({ text: "Looking…" })]);
|
|
Promise.all([api.gitStatus().catch(() => ({})), api.system().catch(() => null)]).then(([git, sys]) => {
|
|
const major = String(git.version || "").split(".")[0];
|
|
const mem = (sys && sys.memory) || {}, cpu = (sys && sys.cpu) || {}, disk = (sys && sys.disk) || {}, torch = (sys && sys.torch) || {}, gpu = ((sys && sys.gpus) || [])[0];
|
|
body.set([
|
|
c.hero.default({ title: `FunUI${major ? ` ${major}` : ""}`, hint: [git.codename && `“${git.codename}”`, "Cutting Room"].filter(Boolean).join(" · ") }),
|
|
...facts([["Version", git.version], ["Commit", git.commit && String(git.commit).slice(0, 7)], ["Branch", git.branch]]),
|
|
...(sys ? [c.label.section({ text: "Hardware" }),
|
|
...facts([["Chip", cpu.name], ["Memory", mem.total_gb != null && `${mem.available_gb} GB free of ${mem.total_gb} GB`],
|
|
["Graphics", gpu ? [gpu.name, gpu.vram_gb && `${gpu.vram_gb} GB`].filter(Boolean).join(" · ") : sys.mps ? "Apple GPU (MPS)" : "CPU only"],
|
|
["Storage", disk.total_gb != null && `${disk.free_gb} GB available of ${disk.total_gb} GB`]]),
|
|
c.label.section({ text: "Software" }),
|
|
...facts([["System", sys.os], ["ComfyUI", sys.comfyui], ["Python", sys.python], ["Torch", [torch.version, torch.cuda && `CUDA ${torch.cuda}`].filter(Boolean).join(" · ")], ["Host", sys.host]]),
|
|
c.hint.default({ text: "The machine ComfyUI runs on — not this browser." })] : [c.hint.default({ text: "Machine details are not available from this server." })]),
|
|
]);
|
|
});
|
|
return body;
|
|
};
|
|
|
|
/** "Is this machine ready to generate?": the rows core/readiness.py reports, worst first. */
|
|
export const readiness = (api) => function mount() {
|
|
const body = c.region.stack({ gap: "sm", label: "Ready to generate" });
|
|
const MARK = { ok: "✓", warn: "!", fail: "✗" }, TONE = { ok: "good", warn: "warn", fail: "danger" }, ORDER = { fail: 0, warn: 1, ok: 2 };
|
|
const run = async () => {
|
|
body.set([c.hint.default({ text: "Checking…" })]);
|
|
let rows;
|
|
try { rows = (await api.readiness()).rows; } catch (err) { return body.set([c.banner.warn({ text: `Could not check: ${err.message}` }), check]); }
|
|
const bad = rows.filter((r) => r.level !== "ok").length;
|
|
body.set([check, bad ? c.banner.warn({ text: `${bad} thing${bad > 1 ? "s" : ""} to look at.` }) : c.banner.info({ text: "Nothing in the way." }),
|
|
...[...rows].sort((a, b) => ORDER[a.level] - ORDER[b.level]).map((r) => c.settingsRow.default({ label: r.text, control: c.chip[TONE[r.level]]({ label: MARK[r.level] }) }))]);
|
|
};
|
|
const check = c.button.sm({ label: "Check this machine", tone: "ghost", title: "Look for what a first run on a new GPU box trips over", onClick: run });
|
|
body.set([c.hint.default({ text: "Run this on a new rental before the first generation: it checks ffmpeg, the GPU, model files, installed nodes and loaded modules." }), check]);
|
|
return body;
|
|
};
|