[Log] Info: FunPack Diffusion Model Loader | flux.safetensors loaded, attention sage
[Log] Alert: MiniMaxH3ImageToVideo node | no "first_image" input is connected
[Log] Warning: FunPack LoRA Loader | style.safetensors is empty and will not load
[Log] Critical: torch | cannot allocate 14 GB (3 GB free); the run will not start
The difference between the middle two is the one that matters. Alert is a
choice you may not have made on purpose. Warning is something that will NOT
do what its name says -- the level v4 needed and did not have, which is how
560 handlers came to swallow a failure and carry on, so a feature could be
switched on, do nothing, and never say so.
Info is not decoration either: "loaded on GPU using sage attention" is how
an attention setting that did nothing gets noticed months before the
pictures look wrong enough to investigate.
Every call site moved -- there is no note() left to be vague through -- and
the loaders now say what they actually loaded rather than only what they
were asked for. Records are kept in a bounded ring as well as printed, so a
long rental session cannot turn the log into a memory leak, and served at
/funpack/api/log so a person can read it somewhere other than a terminal
full of ComfyUI's own output. There is a page for it.
Also dropped the preflight this was traded for: min and max are already
declared and already enforced at both doors, and a second protection layer
around a check that exists is ceremony.
Two mistakes worth keeping: a log line reached into the model's shape to
describe it and could have failed the load it was only narrating; and both
new pages passed `children` to an element that takes `rows`, which the kit
accepted and silently dropped. It throws on an unknown element and not on an
unknown prop.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
71 lines
2.2 KiB
JavaScript
71 lines
2.2 KiB
JavaScript
// The log, where a person can read it.
|
|
//
|
|
// The terminal is where this ends up by default, buried among ComfyUI's own
|
|
// output. The whole reason for a severity and a source is that a line can be
|
|
// found later, so there has to be somewhere to look.
|
|
|
|
import { composer } from "../composer/composer.js";
|
|
|
|
const root = document.querySelector("#app");
|
|
|
|
// Severity -> the chip tone that already exists in the kit. Info is deliberately
|
|
// quiet: most lines are Info, and a wall of coloured chips says nothing.
|
|
const TONE = { Info: "neutral", Alert: "info", Warning: "warn", Critical: "danger" };
|
|
|
|
let filter = null;
|
|
|
|
async function load() {
|
|
const url = "/funpack/api/log" + (filter ? `?level=${encodeURIComponent(filter)}` : "");
|
|
const response = await fetch(url);
|
|
if (!response.ok) throw new Error(`${url} answered ${response.status}`);
|
|
return response.json();
|
|
}
|
|
|
|
function render(data) {
|
|
const counts = {};
|
|
for (const level of data.levels) counts[level] = 0;
|
|
for (const record of data.records) counts[record.level] = (counts[record.level] || 0) + 1;
|
|
|
|
const filters = composer.segmented.md({
|
|
label: "Show",
|
|
value: filter || "all",
|
|
options: [{ value: "all", label: "Everything" },
|
|
...data.levels.map((l) => ({ value: l, label: `${l} (${counts[l] || 0})` }))],
|
|
onChange: (value) => { filter = value === "all" ? null : value; start(); },
|
|
});
|
|
|
|
// Newest last, like a terminal: the eye expects the end to be the present.
|
|
const items = data.records.map((record, i) => ({
|
|
id: `r${i}`,
|
|
label: record.message,
|
|
hint: `${record.level} · ${record.source || "FunPack"}`,
|
|
}));
|
|
|
|
root.replaceChildren(composer.panel.default({
|
|
title: "Log",
|
|
body: composer.group.default({
|
|
rows: [
|
|
filters,
|
|
items.length
|
|
? composer.list.rows({ items, reorder: false })
|
|
: composer.emptyState.default({
|
|
icon: "○", title: "Nothing logged yet",
|
|
hint: filter ? `No ${filter} messages.` : "Run a generation and come back.",
|
|
}),
|
|
],
|
|
}),
|
|
}).node);
|
|
}
|
|
|
|
async function start() {
|
|
try {
|
|
render(await load());
|
|
} catch (err) {
|
|
root.replaceChildren(composer.emptyState.default({
|
|
icon: "▲", title: "Could not read the log", hint: err.message,
|
|
}).node);
|
|
}
|
|
}
|
|
|
|
start();
|