Files
robertvoy-ComfyUI-Distributed/web/collectorOutputs.js
T
speedyrulzandClaude Fable 5.1 18ff755001 feat: per-GPU preview outputs on the Distributed Collector
Append master and worker_1..worker_8 IMAGE outputs after images/audio so
each participant's own batch can be previewed. worker_N follows the Nth
configured worker so a slot keeps its GPU when others are toggled; slots
with no images return ExecutionBlocker(None) so attached nodes are
skipped silently. The frontend labels worker_N with the worker's name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 16:22:45 -04:00

77 lines
2.6 KiB
JavaScript

import { app } from "/scripts/app.js";
import { ENDPOINTS, NODE_CLASSES } from "./constants.js";
// worker_N previews the Nth configured worker (see nodes/collector.py).
const WORKER_OUTPUT_PREFIX = "worker_";
const WORKERS_CHANGED_EVENT = "distributed:workers-changed";
const trackedNodes = new Set();
let workers = [];
let listenerAttached = false;
async function fetchWorkers() {
try {
const resp = await fetch(ENDPOINTS.CONFIG);
if (!resp.ok) return [];
const config = await resp.json();
return Array.isArray(config.workers) ? config.workers : [];
} catch {
return [];
}
}
// Only the displayed label changes; slot names stay fixed so links survive.
function labelWorkerOutputs(node, configWorkers) {
for (const output of node.outputs || []) {
if (!output?.name?.startsWith(WORKER_OUTPUT_PREFIX)) continue;
const index = parseInt(output.name.slice(WORKER_OUTPUT_PREFIX.length), 10) - 1;
const worker = configWorkers[index];
output.label = worker?.name ? `${output.name} (${worker.name})` : output.name;
}
node.setDirtyCanvas?.(true, true);
}
function relabelAll() {
for (const node of trackedNodes) labelWorkerOutputs(node, workers);
}
function attachListener() {
if (listenerAttached || typeof window === "undefined") return;
window.addEventListener(WORKERS_CHANGED_EVENT, (event) => {
if (Array.isArray(event?.detail?.workers)) {
workers = event.detail.workers;
relabelAll();
}
});
listenerAttached = true;
}
app.registerExtension({
name: "Distributed.CollectorOutputs",
async nodeCreated(node) {
if (node.comfyClass !== NODE_CLASSES.DISTRIBUTED_COLLECTOR) return;
try {
attachListener();
trackedNodes.add(node);
const originalConfigure = node.configure;
node.configure = function (data) {
const result = originalConfigure ? originalConfigure.call(this, data) : undefined;
labelWorkerOutputs(this, workers);
return result;
};
const originalOnRemoved = node.onRemoved;
node.onRemoved = function () {
trackedNodes.delete(this);
return originalOnRemoved ? originalOnRemoved.call(this) : undefined;
};
if (workers.length === 0) workers = await fetchWorkers();
labelWorkerOutputs(node, workers);
} catch (error) {
console.error("Error in DistributedCollector outputs extension:", error);
}
},
});