Files
2026-02-07 10:10:01 +08:00

256 lines
8.1 KiB
JavaScript

import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
class EventManager {
constructor() {
this.listeners = new Map();
}
addEventListener(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event).push(callback);
}
removeEventListener(event, callback) {
if (this.listeners.has(event)) {
const callbacks = this.listeners.get(event);
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
}
}
dispatchEvent(event, detail = {}) {
if (this.listeners.has(event)) {
const callbacks = this.listeners.get(event);
callbacks.forEach(callback => {
try {
callback({ detail });
} catch (error) {
console.error(`Error in event listener for ${event}:`, error);
}
});
}
}
}
class QueueManager {
constructor() {
this.eventManager = new EventManager();
this.queueNodeIds = null;
this.processingQueue = false;
this.lastAdjustedMouseEvent = null;
this.initializeHooks();
}
initializeHooks() {
const originalQueuePrompt = app.queuePrompt;
const originalGraphToPrompt = app.graphToPrompt;
const originalApiQueuePrompt = api.queuePrompt;
app.queuePrompt = async function() {
queueManager.processingQueue = true;
queueManager.eventManager.dispatchEvent("queue");
try {
await originalQueuePrompt.apply(app, [...arguments]);
} finally {
queueManager.processingQueue = false;
queueManager.eventManager.dispatchEvent("queue-end");
}
};
app.graphToPrompt = async function() {
queueManager.eventManager.dispatchEvent("graph-to-prompt");
let promise = originalGraphToPrompt.apply(app, [...arguments]);
await promise;
queueManager.eventManager.dispatchEvent("graph-to-prompt-end");
return promise;
};
api.queuePrompt = async function(index, prompt) {
// 创建局部副本,避免异步执行时queueNodeIds被重置导致数据丢失
const localQueueNodeIds = [...(queueManager.queueNodeIds || [])];
// 修复:检测到有 CCXGroupExecutorSender 输出节点时,只保留它
if (prompt.output && prompt.nodes) {
let hasSenderNode = false;
let senderNodeId = null;
for (const outputNodeId in prompt.output) {
const nodeData = prompt.nodes[outputNodeId];
if (nodeData && nodeData.class_type === "CCXGroupExecutorSender") {
hasSenderNode = true;
senderNodeId = outputNodeId;
break;
}
}
// 只在没有明确指定输出节点ID时才进行此修改
// 避免与CCXGroupExecutor的自定义执行逻辑冲突
if (hasSenderNode && senderNodeId && !localQueueNodeIds.length) {
console.log(`[QueueManager] 检测到 CCXGroupExecutorSender 节点,只保留它作为输出节点`);
// 只保留 sender 节点
const oldOutput = prompt.output;
prompt.output = {};
prompt.output[senderNodeId] = oldOutput[senderNodeId];
}
}
if (localQueueNodeIds.length && prompt.output) {
const oldOutput = prompt.output;
let newOutput = {};
for (const queueNodeId of localQueueNodeIds) {
queueManager.recursiveAddNodes(String(queueNodeId), oldOutput, newOutput);
}
prompt.output = newOutput;
}
queueManager.eventManager.dispatchEvent("comfy-api-queue-prompt-before", {
workflow: prompt.workflow,
output: prompt.output,
});
const response = originalApiQueuePrompt.apply(api, [index, prompt]);
queueManager.eventManager.dispatchEvent("comfy-api-queue-prompt-end");
return response;
};
const originalProcessMouseDown = LGraphCanvas.prototype.processMouseDown;
const originalAdjustMouseEvent = LGraphCanvas.prototype.adjustMouseEvent;
const originalProcessMouseMove = LGraphCanvas.prototype.processMouseMove;
LGraphCanvas.prototype.processMouseDown = function(e) {
const result = originalProcessMouseDown.apply(this, [...arguments]);
queueManager.lastAdjustedMouseEvent = e;
return result;
};
LGraphCanvas.prototype.adjustMouseEvent = function(e) {
originalAdjustMouseEvent.apply(this, [...arguments]);
queueManager.lastAdjustedMouseEvent = e;
};
LGraphCanvas.prototype.processMouseMove = function(e) {
const result = originalProcessMouseMove.apply(this, [...arguments]);
if (e && !e.canvasX && !e.canvasY) {
const canvas = app.canvas;
const offset = canvas.convertEventToCanvasOffset(e);
e.canvasX = offset[0];
e.canvasY = offset[1];
}
queueManager.lastAdjustedMouseEvent = e;
return result;
};
}
recursiveAddNodes(nodeId, oldOutput, newOutput) {
let currentId = nodeId;
let currentNode = oldOutput[currentId];
if (!currentNode) {
console.warn(`[QueueManager] 节点 ${currentId} 在输出中不存在`);
return newOutput;
}
if (newOutput[currentId] == null) {
newOutput[currentId] = currentNode;
for (const inputValue of Object.values(currentNode.inputs || [])) {
if (Array.isArray(inputValue)) {
this.recursiveAddNodes(inputValue[0], oldOutput, newOutput);
}
}
}
return newOutput;
}
async queueOutputNodes(nodeIds) {
// 如果队列正在处理中,等待它完成后再继续
while (this.processingQueue) {
await new Promise(resolve => setTimeout(resolve, 100));
}
try {
this.queueNodeIds = nodeIds;
this.processingQueue = true;
this.eventManager.dispatchEvent("queue");
await app.queuePrompt();
} catch (e) {
console.error("队列节点时出错:", e);
} finally {
this.queueNodeIds = null;
this.processingQueue = false;
this.eventManager.dispatchEvent("queue-end");
}
}
getLastMouseEvent() {
return this.lastAdjustedMouseEvent;
}
addEventListener(event, callback) {
this.eventManager.addEventListener(event, callback);
}
removeEventListener(event, callback) {
this.eventManager.removeEventListener(event, callback);
}
}
function getOutputNodes(nodes) {
return (nodes?.filter((n) => {
return (n.mode != LiteGraph.NEVER &&
n.constructor.nodeData?.output_node);
}) || []);
}
const queueManager = new QueueManager();
function queueSelectedOutputNodes() {
const selectedNodes = app.canvas.selected_nodes;
if (!selectedNodes || Object.keys(selectedNodes).length === 0) {
console.log("[LG]队列: 没有选中的节点");
return;
}
const outputNodes = getOutputNodes(Object.values(selectedNodes));
if (!outputNodes || outputNodes.length === 0) {
console.log("[LG]队列: 选中的节点中没有输出节点");
return;
}
console.log(`[LG]队列: 执行 ${outputNodes.length} 个输出节点`);
queueManager.queueOutputNodes(outputNodes.map((n) => n.id));
}
function queueGroupOutputNodes() {
const lastMouseEvent = queueManager.getLastMouseEvent();
if (!lastMouseEvent) {
return;
}
let canvasX = lastMouseEvent.canvasX;
let canvasY = lastMouseEvent.canvasY;
if (!canvasX || !canvasY) {
const canvas = app.canvas;
const mousePos = canvas.getMousePos();
canvasX = mousePos[0];
canvasY = mousePos[1];
}
const group = app.graph.getGroupOnPos(canvasX, canvasY);
if (!group) {
return;
}
group.recomputeInsideNodes();
if (!group._nodes || group._nodes.length === 0) {
return;
}
const outputNodes = getOutputNodes(group._nodes);
if (!outputNodes || outputNodes.length === 0) {
return;
}
queueManager.queueOutputNodes(outputNodes.map((n) => n.id));
}
export { queueManager, getOutputNodes, queueSelectedOutputNodes, queueGroupOutputNodes };