257 lines
9.1 KiB
JavaScript
257 lines
9.1 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
|
import { api } from "../../scripts/api.js";
|
|
|
|
// 用於存儲節點 ID 映射
|
|
const nodeIdMap = new Map();
|
|
|
|
// 註冊自定義事件處理器
|
|
api.addEventListener("textbatch-node-feedback", (event) => {
|
|
console.log("Received node feedback:", event);
|
|
try {
|
|
// 從 CustomEvent 中獲取 data
|
|
const data = event.detail;
|
|
|
|
// 檢查 data 物件的完整性
|
|
if (!data || !data.node_id) {
|
|
console.error("Invalid data received:", data);
|
|
return;
|
|
}
|
|
|
|
const nodeId = data.node_id;
|
|
console.log("Looking for node:", nodeId, "Data received:", data);
|
|
|
|
// 嘗試從 nodeIdMap 中獲取節點
|
|
let node = nodeIdMap.get(nodeId);
|
|
|
|
// 如果在 Map 中找不到,再嘗試其他方法
|
|
if (!node) {
|
|
node = app.graph._nodes_by_id?.[nodeId] ||
|
|
app.graph.getNodeById?.(parseInt(nodeId)) ||
|
|
[...(app.graph?.nodes || [])].find(n => n?.id == nodeId);
|
|
}
|
|
|
|
if (!node) {
|
|
console.warn("Node not found by ID:", nodeId, "Available nodes:",
|
|
Array.from(nodeIdMap.keys()));
|
|
return;
|
|
}
|
|
|
|
console.log("Found node:", node);
|
|
const widget = node.widgets?.find(w => w.name === data.widget_name);
|
|
if (!widget) {
|
|
console.warn("Widget not found:", data.widget_name);
|
|
return;
|
|
}
|
|
|
|
if (data.type === "int") {
|
|
console.log("Updating widget value:", data.value);
|
|
widget.value = parseInt(data.value);
|
|
} else {
|
|
widget.value = data.value;
|
|
}
|
|
|
|
// 觸發小部件的變更事件
|
|
if (widget.callback) {
|
|
widget.callback(widget.value);
|
|
}
|
|
} catch (error) {
|
|
console.error("Error in node feedback handler:", error);
|
|
}
|
|
});
|
|
|
|
// 註冊佇列事件處理器
|
|
api.addEventListener("textbatch-add-queue", (data) => {
|
|
try {
|
|
console.log("Received queue event:", data);
|
|
|
|
// 檢查是否正在處理中
|
|
if (app.isProcessing) {
|
|
console.log("Already processing, queueing next prompt");
|
|
}
|
|
|
|
// 獲取當前工作流程
|
|
const workflow = app.graph?.serialize?.(); // ✅ 安全访问
|
|
console.log("Current workflow:", workflow);
|
|
|
|
// 確保在下一個事件循環中執行
|
|
setTimeout(() => {
|
|
try {
|
|
console.log("Executing queued prompt");
|
|
// 使用 queuePrompt 的完整參數
|
|
app.queuePrompt?.(0, 1); // ✅ 兼容性检查
|
|
console.log("Queue prompt executed");
|
|
} catch (queueError) {
|
|
console.error("Error queueing prompt:", queueError);
|
|
}
|
|
}, 100);
|
|
} catch (error) {
|
|
console.error("Error in textbatch-add-queue handler:", error);
|
|
console.error("Error details:", {
|
|
message: error.message,
|
|
stack: error.stack
|
|
});
|
|
}
|
|
});
|
|
|
|
// 為特定節點添加自定義行為
|
|
app.registerExtension({
|
|
name: "TextBatch.TextBatchNode",
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
//console.log("Registering node type:", nodeData.name);
|
|
|
|
if (nodeData.name === "TextBatch" ||
|
|
nodeData.name === "TextQueueProcessor" ||
|
|
nodeData.name === "ZippedPromptBatch" ||
|
|
nodeData.name === "ZippedPromptBatchAdvanced") {
|
|
|
|
console.log("Adding custom behavior to node:", nodeData.name);
|
|
|
|
// 添加自定義小部件行為
|
|
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function() {
|
|
const r = onNodeCreated?.apply?.(this, arguments); // ✅ 安全访问
|
|
|
|
// 確保節點有有效的 ID
|
|
if (!this?.id || this.id === -1) { // ✅ 可选链检查
|
|
console.warn("Invalid node ID detected, waiting for proper initialization");
|
|
// 等待下一個事件循環再進行初始化
|
|
setTimeout(() => {
|
|
console.log("Retrying node initialization:", nodeData.name, "ID:", this.id);
|
|
// 存儲節點 ID
|
|
if (this?.id && this.id !== -1) { // ✅ 双重检查
|
|
nodeIdMap.set(this.id, this);
|
|
// 為節點添加自定義標題
|
|
this.addWidget?.("text", "status", "", (v) => { // ✅ 兼容性检查
|
|
console.log("Status widget updated:", v);
|
|
this.status = v;
|
|
});
|
|
}
|
|
}, 0);
|
|
} else {
|
|
console.log("Node created:", nodeData.name, "ID:", this.id);
|
|
nodeIdMap.set(this.id, this);
|
|
this.addWidget?.("text", "status", "", (v) => { // ✅ 兼容性检查
|
|
console.log("Status widget updated:", v);
|
|
this.status = v;
|
|
});
|
|
}
|
|
|
|
return r;
|
|
};
|
|
|
|
// 添加節點刪除處理
|
|
const onNodeRemoved = nodeType.prototype.onRemoved;
|
|
nodeType.prototype.onRemoved = function() {
|
|
console.log("Node removed:", this.id);
|
|
if (this?.id) { // ✅ 关键修复:添加存在性检查
|
|
console.log("Node removed:", this.id);
|
|
nodeIdMap.delete(this.id);
|
|
}
|
|
onNodeRemoved?.apply?.(this, arguments); // ✅ 安全调用
|
|
};
|
|
}
|
|
}
|
|
});
|
|
|
|
// api.addEventListener('executed', async ({ detail }) => {
|
|
// console.log('#executed', detail)
|
|
// console.log(output)
|
|
// })
|
|
|
|
// TextQueueProcessor 節點擴展
|
|
class TextQueueProcessorNode {
|
|
constructor() {
|
|
if (!this.properties) {
|
|
this.properties = {};
|
|
}
|
|
this.addCustomWidgets?.(); // ✅ 兼容性检查
|
|
}
|
|
|
|
addCustomWidgets() {
|
|
// 添加重置按鈕
|
|
this.addWidget?.("button", "🔄 Reset", null, () => { // ✅ 安全访问
|
|
this.triggerReset?.(); // ✅ 兼容性检查
|
|
});
|
|
|
|
// 添加跳到開頭按鈕
|
|
this.addWidget("button", "⏮️ To Start", null, () => {
|
|
// 將 start_index 設為 0
|
|
this.widgets.find(w => w.name === "start_index").value = 0;
|
|
});
|
|
|
|
// 添加跳到結尾按鈕
|
|
this.addWidget("button", "⏭️ To End", null, () => {
|
|
// 獲取 total 值(如果有的話)
|
|
const total = this.outputs?.[2]?.value ?? 0;
|
|
if (total > 0) {
|
|
this.widgets.find(w => w.name === "start_index").value = total - 1;
|
|
}
|
|
});
|
|
}
|
|
|
|
triggerReset() {
|
|
// 發送重置事件到後端
|
|
const nodeId = this?.id; // ✅ 安全访问
|
|
app.graphToPrompt?.().then(workflow => { // ✅ 兼容性检查
|
|
if (workflow.output) {
|
|
app.queuePrompt(workflow.output, workflow.workflow);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// ImageQueueProcessor 節點擴展
|
|
class ImageQueueProcessorNode {
|
|
constructor() {
|
|
if (!this.properties) {
|
|
this.properties = {};
|
|
}
|
|
this.addCustomWidgets();
|
|
}
|
|
|
|
addCustomWidgets() {
|
|
// 添加重置按鈕
|
|
this.addWidget("button", "🔄 Reset", null, () => {
|
|
// 觸發重置
|
|
this.triggerReset();
|
|
});
|
|
|
|
// 添加跳到開頭按鈕
|
|
this.addWidget("button", "⏮️ To Start", null, () => {
|
|
// 將 start_index 設為 0
|
|
this.widgets.find(w => w.name === "start_index").value = 0;
|
|
});
|
|
|
|
// 添加跳到結尾按鈕
|
|
this.addWidget("button", "⏭️ To End", null, () => {
|
|
// 獲取 total 值(如果有的話)
|
|
const total = this.outputs?.[3]?.value ?? 0;
|
|
if (total > 0) {
|
|
this.widgets.find(w => w.name === "start_index").value = total - 1;
|
|
}
|
|
});
|
|
}
|
|
|
|
triggerReset() {
|
|
// 發送重置事件到後端
|
|
const nodeId = this.id;
|
|
app.graphToPrompt().then(workflow => {
|
|
if (workflow.output) {
|
|
app.queuePrompt(workflow.output, workflow.workflow);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// 註冊節點擴展
|
|
app.registerExtension({
|
|
name: "rgthree.TextBatch",
|
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
|
if (nodeData.name === "TextQueueProcessor") {
|
|
Object.assign(nodeType.prototype, TextQueueProcessorNode.prototype);
|
|
}
|
|
else if (nodeData.name === "ImageQueueProcessor") {
|
|
Object.assign(nodeType.prototype, ImageQueueProcessorNode.prototype);
|
|
}
|
|
}
|
|
}); |