bizydraft 0.2.49__py3-none-any.whl → 0.2.87__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bizydraft might be problematic. Click here for more details.
- bizydraft/env.py +3 -0
- bizydraft/hijack_nodes.py +60 -42
- bizydraft/hijack_routes.py +36 -3
- bizydraft/oss_utils.py +231 -2
- bizydraft/patch_handlers.py +197 -8
- bizydraft/static/js/aiAppHandler.js +460 -425
- bizydraft/static/js/clipspaceToOss.js +386 -0
- bizydraft/static/js/disableComfyWebSocket.js +64 -0
- bizydraft/static/js/freezeModeHandler.js +425 -404
- bizydraft/static/js/handleStyle.js +128 -36
- bizydraft/static/js/hookLoad/configLoader.js +74 -0
- bizydraft/static/js/hookLoad/media.js +684 -0
- bizydraft/static/js/hookLoad/model.js +322 -0
- bizydraft/static/js/hookLoadMedia.js +196 -0
- bizydraft/static/js/hookLoadModel.js +207 -256
- bizydraft/static/js/main.js +2 -0
- bizydraft/static/js/nodeFocusHandler.js +118 -106
- bizydraft/static/js/nodeParamsFilter.js +91 -89
- bizydraft/static/js/postEvent.js +1207 -967
- bizydraft/static/js/socket.js +55 -50
- bizydraft/static/js/tool.js +71 -63
- bizydraft/static/js/uploadFile.js +49 -41
- bizydraft/static/js/workflow_io.js +193 -0
- {bizydraft-0.2.49.dist-info → bizydraft-0.2.87.dist-info}/METADATA +1 -1
- bizydraft-0.2.87.dist-info/RECORD +34 -0
- bizydraft/static/js/hookLoadImage.js +0 -177
- bizydraft-0.2.49.dist-info/RECORD +0 -28
- {bizydraft-0.2.49.dist-info → bizydraft-0.2.87.dist-info}/WHEEL +0 -0
- {bizydraft-0.2.49.dist-info → bizydraft-0.2.87.dist-info}/top_level.txt +0 -0
bizydraft/static/js/postEvent.js
CHANGED
|
@@ -1,1016 +1,1256 @@
|
|
|
1
1
|
import { app } from "../../scripts/app.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
enableAIAppMode,
|
|
4
|
+
disableAIAppMode,
|
|
5
|
+
selectInputNode,
|
|
6
|
+
deselectInputNode,
|
|
7
|
+
updateInputNodeWidget,
|
|
8
|
+
getSelectedInputNodes,
|
|
9
|
+
clearSelectedInputNodes,
|
|
10
|
+
toggleExportMode,
|
|
11
|
+
} from "./aiAppHandler.js";
|
|
3
12
|
import { focusNodeOnly } from "./nodeFocusHandler.js";
|
|
4
13
|
|
|
5
14
|
app.registerExtension({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// 立即发送一次ping消息
|
|
34
|
-
this.pongReceived = false;
|
|
35
|
-
this.socket.send('ping');
|
|
15
|
+
name: "comfy.BizyAir.Socket",
|
|
16
|
+
|
|
17
|
+
dispatchCustomEvent(type, detail) {
|
|
18
|
+
app.api.dispatchCustomEvent(type, detail);
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
socket: null,
|
|
22
|
+
isConnecting: false,
|
|
23
|
+
taskRunning: false,
|
|
24
|
+
|
|
25
|
+
// 心跳检测
|
|
26
|
+
pingInterval: 5000, // 5秒发送一次心跳
|
|
27
|
+
pingTimer: null,
|
|
28
|
+
pingTimeout: 3000,
|
|
29
|
+
pongReceived: false,
|
|
30
|
+
pingTimeoutTimer: null, // ping超时计时器
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 为特定socket开始心跳检测(每个socket独立的心跳)
|
|
34
|
+
*/
|
|
35
|
+
startPingForSocket(socket) {
|
|
36
|
+
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
36
39
|
|
|
40
|
+
// 在socket对象上存储心跳状态
|
|
41
|
+
socket.pongReceived = false;
|
|
42
|
+
// 立即发送一次ping消息
|
|
43
|
+
socket.send("ping");
|
|
44
|
+
|
|
45
|
+
// 设置ping超时检测
|
|
46
|
+
socket.pingTimeoutTimer = setTimeout(() => {
|
|
47
|
+
if (!socket.pongReceived && socket.readyState === WebSocket.OPEN) {
|
|
48
|
+
console.log("心跳检测超时,关闭此连接");
|
|
49
|
+
this.stopPingForSocket(socket);
|
|
50
|
+
socket.close();
|
|
51
|
+
}
|
|
52
|
+
}, this.pingTimeout);
|
|
53
|
+
|
|
54
|
+
// 设置定时发送ping
|
|
55
|
+
socket.pingTimer = setInterval(() => {
|
|
56
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
57
|
+
socket.pongReceived = false;
|
|
58
|
+
socket.send("ping");
|
|
37
59
|
// 设置ping超时检测
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
60
|
+
socket.pingTimeoutTimer = setTimeout(() => {
|
|
61
|
+
// 如果没有收到pong响应
|
|
62
|
+
if (!socket.pongReceived) {
|
|
63
|
+
console.log("心跳检测超时,关闭此连接");
|
|
64
|
+
this.stopPingForSocket(socket);
|
|
65
|
+
socket.close();
|
|
66
|
+
}
|
|
43
67
|
}, this.pingTimeout);
|
|
68
|
+
} else {
|
|
69
|
+
this.stopPingForSocket(socket);
|
|
70
|
+
}
|
|
71
|
+
}, this.pingInterval);
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 停止特定socket的心跳检测
|
|
76
|
+
*/
|
|
77
|
+
stopPingForSocket(socket) {
|
|
78
|
+
if (!socket) return;
|
|
79
|
+
|
|
80
|
+
if (socket.pingTimer) {
|
|
81
|
+
clearInterval(socket.pingTimer);
|
|
82
|
+
socket.pingTimer = null;
|
|
83
|
+
}
|
|
44
84
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// 设置ping超时检测
|
|
51
|
-
this.pingTimeoutTimer = setTimeout(() => {
|
|
52
|
-
// 如果没有收到pong响应
|
|
53
|
-
if (!this.pongReceived) {
|
|
54
|
-
console.log('心跳检测超时,重新连接WebSocket');
|
|
55
|
-
this.stopPing();
|
|
56
|
-
this.reconnect();
|
|
57
|
-
}
|
|
58
|
-
}, this.pingTimeout);
|
|
59
|
-
} else {
|
|
60
|
-
this.stopPing();
|
|
61
|
-
}
|
|
62
|
-
}, this.pingInterval);
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 停止心跳检测
|
|
67
|
-
*/
|
|
68
|
-
stopPing() {
|
|
69
|
-
if (this.pingTimer) {
|
|
70
|
-
clearInterval(this.pingTimer);
|
|
71
|
-
this.pingTimer = null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (this.pingTimeoutTimer) {
|
|
75
|
-
clearTimeout(this.pingTimeoutTimer);
|
|
76
|
-
this.pingTimeoutTimer = null;
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* 重新连接
|
|
82
|
-
*/
|
|
83
|
-
reconnect() {
|
|
84
|
-
if (this.isConnecting) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const url = this.socket ? this.socket.url : app.api.socket.url;
|
|
88
|
-
this.closeSocket();
|
|
89
|
-
this.createSocket(url);
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* 创建新的WebSocket连接
|
|
94
|
-
*/
|
|
95
|
-
createSocket(customUrl) {
|
|
96
|
-
// 如果正在连接中,避免重复创建
|
|
97
|
-
if (this.isConnecting) {
|
|
98
|
-
console.log('WebSocket连接已在创建中,避免重复创建');
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
85
|
+
if (socket.pingTimeoutTimer) {
|
|
86
|
+
clearTimeout(socket.pingTimeoutTimer);
|
|
87
|
+
socket.pingTimeoutTimer = null;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
101
90
|
|
|
102
|
-
|
|
103
|
-
|
|
91
|
+
/**
|
|
92
|
+
* 开始心跳检测(保留向后兼容)
|
|
93
|
+
*/
|
|
94
|
+
startPing() {
|
|
95
|
+
this.stopPing();
|
|
104
96
|
|
|
105
|
-
|
|
106
|
-
|
|
97
|
+
if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// 使用新的socket专用心跳方法
|
|
101
|
+
this.startPingForSocket(this.socket);
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 停止心跳检测
|
|
106
|
+
*/
|
|
107
|
+
stopPing() {
|
|
108
|
+
if (this.pingTimer) {
|
|
109
|
+
clearInterval(this.pingTimer);
|
|
110
|
+
this.pingTimer = null;
|
|
111
|
+
}
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
if (this.pingTimeoutTimer) {
|
|
114
|
+
clearTimeout(this.pingTimeoutTimer);
|
|
115
|
+
this.pingTimeoutTimer = null;
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 重新连接
|
|
121
|
+
*/
|
|
122
|
+
reconnect() {
|
|
123
|
+
if (this.isConnecting) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const url = this.socket ? this.socket.url : app.api.socket.url;
|
|
127
|
+
this.closeSocket();
|
|
128
|
+
this.createSocket(url);
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 创建新的WebSocket连接
|
|
133
|
+
*/
|
|
134
|
+
createSocket(customUrl) {
|
|
135
|
+
// 如果正在连接中,避免重复创建
|
|
136
|
+
if (this.isConnecting) {
|
|
137
|
+
console.log("WebSocket连接已在创建中,避免重复创建");
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
110
140
|
|
|
141
|
+
// 标记为连接中
|
|
142
|
+
this.isConnecting = true;
|
|
143
|
+
|
|
144
|
+
const url = customUrl || app.api.socket.url;
|
|
145
|
+
console.log("创建WebSocket连接:", url);
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const socket = new WebSocket(url);
|
|
149
|
+
const dispatchCustomEvent = this.dispatchCustomEvent;
|
|
150
|
+
const self = this;
|
|
151
|
+
|
|
152
|
+
socket.onopen = function () {
|
|
153
|
+
console.log("WebSocket连接已打开");
|
|
154
|
+
// 清除连接中标志
|
|
155
|
+
self.isConnecting = false;
|
|
156
|
+
// 存储为单例(最新的连接)
|
|
157
|
+
self.socket = socket;
|
|
158
|
+
// 替换app.api.socket
|
|
159
|
+
app.api.socket = socket;
|
|
160
|
+
// 为这个socket启动独立的心跳检测
|
|
161
|
+
self.startPingForSocket(socket);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
socket.onmessage = function (event) {
|
|
111
165
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
imageMime = 'image/png';
|
|
157
|
-
break;
|
|
158
|
-
case 1:
|
|
159
|
-
default:
|
|
160
|
-
imageMime = 'image/jpeg';
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
const imageBlob = new Blob([imageData], {
|
|
164
|
-
type: imageMime
|
|
165
|
-
});
|
|
166
|
-
dispatchCustomEvent('b_preview', imageBlob);
|
|
167
|
-
break;
|
|
168
|
-
default:
|
|
169
|
-
throw new Error(
|
|
170
|
-
`Unknown binary websocket message of type ${eventType}`
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
} else {
|
|
174
|
-
// 检测[DONE]消息
|
|
175
|
-
if (event.data === '[DONE]') {
|
|
176
|
-
console.log('收到[DONE]消息,任务已完成,停止心跳并关闭连接');
|
|
177
|
-
self.taskRunning = false;
|
|
178
|
-
self.stopPing();
|
|
179
|
-
self.closeSocket(1000);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const msg = JSON.parse(event.data);
|
|
184
|
-
window.parent.postMessage({
|
|
185
|
-
type: 'functionResult',
|
|
186
|
-
method: 'progress_info_change',
|
|
187
|
-
result: msg.progress_info
|
|
188
|
-
}, '*');
|
|
189
|
-
switch (msg.type) {
|
|
190
|
-
case 'load_start':
|
|
191
|
-
case 'load_end':
|
|
192
|
-
case 'prompt_id':
|
|
193
|
-
window.parent.postMessage({
|
|
194
|
-
type: 'functionResult',
|
|
195
|
-
method: 'preparingStatus',
|
|
196
|
-
result: msg
|
|
197
|
-
}, '*')
|
|
198
|
-
case 'status':
|
|
199
|
-
if (msg.data.sid) {
|
|
200
|
-
const clientId = msg.data.sid;
|
|
201
|
-
window.name = clientId;
|
|
202
|
-
sessionStorage.setItem('clientId', clientId);
|
|
203
|
-
socket.clientId = clientId;
|
|
204
|
-
}
|
|
205
|
-
dispatchCustomEvent('status', msg.data.status ?? null);
|
|
206
|
-
break;
|
|
207
|
-
case 'executing':
|
|
208
|
-
dispatchCustomEvent(
|
|
209
|
-
'executing',
|
|
210
|
-
msg.data.display_node || msg.data.node
|
|
211
|
-
);
|
|
212
|
-
break;
|
|
213
|
-
case 'execution_success':
|
|
214
|
-
case 'execution_cached':
|
|
215
|
-
// 检查任务是否完成
|
|
216
|
-
if (msg.data.completed) {
|
|
217
|
-
self.taskRunning = false;
|
|
218
|
-
}
|
|
219
|
-
dispatchCustomEvent(msg.type, msg.data);
|
|
220
|
-
break;
|
|
221
|
-
case 'error':
|
|
222
|
-
self.taskRunning = false;
|
|
223
|
-
dispatchCustomEvent('execution_error', {
|
|
224
|
-
exception_message: msg.data.error_message || 'Unknown error',
|
|
225
|
-
traceback: ['Manual error triggered'],
|
|
226
|
-
executed: [],
|
|
227
|
-
prompt_id: 'manual',
|
|
228
|
-
node_id: '0',
|
|
229
|
-
node_type: 'RunError',
|
|
230
|
-
});
|
|
231
|
-
break;
|
|
232
|
-
case 'execution_error':
|
|
233
|
-
case 'execution_interrupted':
|
|
234
|
-
self.taskRunning = false;
|
|
235
|
-
dispatchCustomEvent(msg.type, msg.data);
|
|
236
|
-
break;
|
|
237
|
-
case 'execution_start':
|
|
238
|
-
self.taskRunning = true;
|
|
239
|
-
dispatchCustomEvent(msg.type, msg.data);
|
|
240
|
-
break;
|
|
241
|
-
case 'progress':
|
|
242
|
-
case 'executed':
|
|
243
|
-
case 'graphChanged':
|
|
244
|
-
case 'promptQueued':
|
|
245
|
-
case 'logs':
|
|
246
|
-
case 'b_preview':
|
|
247
|
-
dispatchCustomEvent(msg.type, msg.data);
|
|
248
|
-
break;
|
|
249
|
-
default:
|
|
250
|
-
const registeredTypes = socket.registeredTypes || new Set();
|
|
251
|
-
const reportedUnknownMessageTypes = socket.reportedUnknownMessageTypes || new Set();
|
|
252
|
-
|
|
253
|
-
if (registeredTypes.has(msg.type)) {
|
|
254
|
-
app.dispatchEvent(
|
|
255
|
-
new CustomEvent(msg.type, { detail: msg.data })
|
|
256
|
-
);
|
|
257
|
-
} else if (!reportedUnknownMessageTypes.has(msg.type)) {
|
|
258
|
-
reportedUnknownMessageTypes.add(msg.type);
|
|
259
|
-
console.warn(`Unknown message type ${msg.type}`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
} catch (error) {
|
|
264
|
-
console.warn('Unhandled message:', event.data, error);
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
socket.onerror = function(error) {
|
|
269
|
-
console.log('WebSocket 错误:', error);
|
|
270
|
-
// 清除连接中标志
|
|
271
|
-
self.isConnecting = false;
|
|
272
|
-
// 停止心跳
|
|
273
|
-
self.stopPing();
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
socket.onclose = function(event) {
|
|
277
|
-
console.log('WebSocket 连接已关闭, 状态码:', event.code, event.reason);
|
|
278
|
-
// 清除连接中标志
|
|
279
|
-
self.isConnecting = false;
|
|
280
|
-
// 清理单例引用
|
|
281
|
-
if (self.socket === socket) {
|
|
282
|
-
self.socket = null;
|
|
166
|
+
// 从 WebSocket URL 中提取 taskId
|
|
167
|
+
let taskIdFromUrl = null;
|
|
168
|
+
try {
|
|
169
|
+
const urlParams = new URLSearchParams(socket.url.split("?")[1]);
|
|
170
|
+
taskIdFromUrl = urlParams.get("taskId");
|
|
171
|
+
if (taskIdFromUrl) {
|
|
172
|
+
taskIdFromUrl = parseInt(taskIdFromUrl, 10);
|
|
173
|
+
}
|
|
174
|
+
console.log("taskIdFromUrl:", taskIdFromUrl);
|
|
175
|
+
} catch (e) {
|
|
176
|
+
console.warn("无法从 WebSocket URL 中提取 taskId:", e);
|
|
177
|
+
}
|
|
178
|
+
// 处理心跳响应
|
|
179
|
+
if (event.data === "pong") {
|
|
180
|
+
// 标记此socket收到pong响应
|
|
181
|
+
socket.pongReceived = true;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (event.data instanceof ArrayBuffer) {
|
|
185
|
+
const view = new DataView(event.data);
|
|
186
|
+
const eventType = view.getUint32(0);
|
|
187
|
+
|
|
188
|
+
let imageMime;
|
|
189
|
+
switch (eventType) {
|
|
190
|
+
case 3:
|
|
191
|
+
const decoder = new TextDecoder();
|
|
192
|
+
const data = event.data.slice(4);
|
|
193
|
+
const nodeIdLength = view.getUint32(4);
|
|
194
|
+
dispatchCustomEvent("progress_text", {
|
|
195
|
+
nodeId: decoder.decode(data.slice(4, 4 + nodeIdLength)),
|
|
196
|
+
text: decoder.decode(data.slice(4 + nodeIdLength)),
|
|
197
|
+
});
|
|
198
|
+
break;
|
|
199
|
+
case 1:
|
|
200
|
+
const imageType = view.getUint32(4);
|
|
201
|
+
const imageData = event.data.slice(8);
|
|
202
|
+
switch (imageType) {
|
|
203
|
+
case 2:
|
|
204
|
+
imageMime = "image/png";
|
|
205
|
+
break;
|
|
206
|
+
case 1:
|
|
207
|
+
default:
|
|
208
|
+
imageMime = "image/jpeg";
|
|
209
|
+
break;
|
|
283
210
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
211
|
+
const imageBlob = new Blob([imageData], {
|
|
212
|
+
type: imageMime,
|
|
213
|
+
});
|
|
214
|
+
dispatchCustomEvent("b_preview", imageBlob);
|
|
215
|
+
break;
|
|
216
|
+
case 4:
|
|
217
|
+
// PREVIEW_IMAGE_WITH_METADATA
|
|
218
|
+
const decoder4 = new TextDecoder();
|
|
219
|
+
const metadataLength = view.getUint32(4);
|
|
220
|
+
const metadataBytes = event.data.slice(8, 8 + metadataLength);
|
|
221
|
+
const metadata = JSON.parse(decoder4.decode(metadataBytes));
|
|
222
|
+
const imageData4 = event.data.slice(8 + metadataLength);
|
|
223
|
+
|
|
224
|
+
let imageMime4 = metadata.image_type;
|
|
225
|
+
|
|
226
|
+
const imageBlob4 = new Blob([imageData4], {
|
|
227
|
+
type: imageMime4,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Dispatch enhanced preview event with metadata
|
|
231
|
+
dispatchCustomEvent("b_preview_with_metadata", {
|
|
232
|
+
blob: imageBlob4,
|
|
233
|
+
nodeId: metadata.node_id,
|
|
234
|
+
displayNodeId: metadata.display_node_id,
|
|
235
|
+
parentNodeId: metadata.parent_node_id,
|
|
236
|
+
realNodeId: metadata.real_node_id,
|
|
237
|
+
promptId: metadata.prompt_id,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Also dispatch legacy b_preview for backward compatibility
|
|
241
|
+
dispatchCustomEvent("b_preview", imageBlob4);
|
|
242
|
+
break;
|
|
243
|
+
default:
|
|
244
|
+
throw new Error(
|
|
245
|
+
`Unknown binary websocket message of type ${eventType}`
|
|
246
|
+
);
|
|
310
247
|
}
|
|
311
|
-
|
|
312
|
-
//
|
|
313
|
-
if (
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
reject(new Error('WebSocket连接创建失败'));
|
|
322
|
-
}
|
|
323
|
-
}, 100); // 每100ms检查一次
|
|
324
|
-
return;
|
|
248
|
+
} else {
|
|
249
|
+
// 检测[DONE]消息
|
|
250
|
+
if (event.data === "[DONE]") {
|
|
251
|
+
console.log("收到[DONE]消息,任务已完成,停止心跳并关闭连接");
|
|
252
|
+
self.taskRunning = false;
|
|
253
|
+
self.stopPingForSocket(socket);
|
|
254
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
255
|
+
socket.close(1000);
|
|
256
|
+
}
|
|
257
|
+
return;
|
|
325
258
|
}
|
|
326
|
-
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
259
|
+
const msg = JSON.parse(event.data);
|
|
260
|
+
// 发送进度信息,添加从 URL 中提取的 taskId
|
|
261
|
+
if (msg.progress_info) {
|
|
262
|
+
const progressData = { ...msg.progress_info };
|
|
263
|
+
if (taskIdFromUrl && !progressData.task_id) {
|
|
264
|
+
progressData.task_id = taskIdFromUrl;
|
|
265
|
+
}
|
|
266
|
+
window.parent.postMessage(
|
|
267
|
+
{
|
|
268
|
+
type: "functionResult",
|
|
269
|
+
method: "progress_info_change",
|
|
270
|
+
result: progressData,
|
|
271
|
+
},
|
|
272
|
+
"*"
|
|
273
|
+
);
|
|
332
274
|
}
|
|
333
275
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
276
|
+
switch (msg.type) {
|
|
277
|
+
case "load_start":
|
|
278
|
+
case "load_end":
|
|
279
|
+
case "prompt_id":
|
|
280
|
+
// 发送准备状态信息,添加从 URL 中提取的 taskId
|
|
281
|
+
const preparingData = { ...msg };
|
|
282
|
+
if (taskIdFromUrl) {
|
|
283
|
+
preparingData.task_id = taskIdFromUrl;
|
|
284
|
+
console.log(
|
|
285
|
+
`🔗 [WebSocket] 添加 task_id=${taskIdFromUrl} 到 ${msg.type} 消息`
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
window.parent.postMessage(
|
|
289
|
+
{
|
|
290
|
+
type: "functionResult",
|
|
291
|
+
method: "preparingStatus",
|
|
292
|
+
result: preparingData,
|
|
293
|
+
},
|
|
294
|
+
"*"
|
|
295
|
+
);
|
|
296
|
+
break;
|
|
297
|
+
case "status":
|
|
298
|
+
if (msg.data.sid) {
|
|
299
|
+
const clientId = msg.data.sid;
|
|
300
|
+
window.name = clientId; // use window name so it isnt reused when duplicating tabs
|
|
301
|
+
sessionStorage.setItem("clientId", clientId); // store in session storage so duplicate tab can load correct workflow
|
|
302
|
+
}
|
|
303
|
+
dispatchCustomEvent("status", msg.data.status ?? null);
|
|
304
|
+
break;
|
|
305
|
+
case "executing":
|
|
306
|
+
dispatchCustomEvent(
|
|
307
|
+
"executing",
|
|
308
|
+
msg.data.display_node || msg.data.node
|
|
309
|
+
);
|
|
310
|
+
break;
|
|
311
|
+
case "execution_start":
|
|
312
|
+
case "execution_error":
|
|
313
|
+
case "execution_interrupted":
|
|
314
|
+
case "execution_cached":
|
|
315
|
+
case "execution_success":
|
|
316
|
+
case "progress":
|
|
317
|
+
case "progress_state":
|
|
318
|
+
case "executed":
|
|
319
|
+
case "graphChanged":
|
|
320
|
+
case "promptQueued":
|
|
321
|
+
case "logs":
|
|
322
|
+
case "b_preview":
|
|
323
|
+
if (msg.data.balance_not_enough) {
|
|
324
|
+
window.parent.postMessage(
|
|
325
|
+
{
|
|
326
|
+
type: "functionResult",
|
|
327
|
+
method: "balanceNotEnough",
|
|
328
|
+
result: true,
|
|
329
|
+
},
|
|
330
|
+
"*"
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
dispatchCustomEvent(msg.type, msg.data);
|
|
334
|
+
break;
|
|
335
|
+
case "feature_flags":
|
|
336
|
+
// Store server feature flags
|
|
337
|
+
this.serverFeatureFlags = msg.data;
|
|
338
|
+
console.log(
|
|
339
|
+
"Server feature flags received:",
|
|
340
|
+
this.serverFeatureFlags
|
|
341
|
+
);
|
|
342
|
+
break;
|
|
343
|
+
default:
|
|
344
|
+
const registeredTypes = socket.registeredTypes || new Set();
|
|
345
|
+
const reportedUnknownMessageTypes =
|
|
346
|
+
socket.reportedUnknownMessageTypes || new Set();
|
|
347
|
+
|
|
348
|
+
if (registeredTypes.has(msg.type)) {
|
|
349
|
+
app.dispatchEvent(
|
|
350
|
+
new CustomEvent(msg.type, { detail: msg.data })
|
|
351
|
+
);
|
|
352
|
+
} else if (!reportedUnknownMessageTypes.has(msg.type)) {
|
|
353
|
+
reportedUnknownMessageTypes.add(msg.type);
|
|
354
|
+
console.warn(`Unknown message type ${msg.type}`);
|
|
355
|
+
}
|
|
402
356
|
}
|
|
403
|
-
|
|
357
|
+
}
|
|
404
358
|
} catch (error) {
|
|
405
|
-
|
|
406
|
-
return false;
|
|
359
|
+
console.warn("Unhandled message:", event.data, error);
|
|
407
360
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
socket.onerror = function (error) {
|
|
364
|
+
console.log("WebSocket 错误:", error);
|
|
365
|
+
// 清除连接中标志
|
|
366
|
+
self.isConnecting = false;
|
|
367
|
+
// 停止此socket的心跳检测
|
|
368
|
+
self.stopPingForSocket(socket);
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
socket.onclose = function (event) {
|
|
372
|
+
console.log("WebSocket 连接已关闭, 状态码:", event.code, event.reason);
|
|
373
|
+
// 清除连接中标志
|
|
374
|
+
self.isConnecting = false;
|
|
375
|
+
// 停止此socket的心跳检测
|
|
376
|
+
self.stopPingForSocket(socket);
|
|
377
|
+
// 清理单例引用(如果这是当前活跃的socket)
|
|
378
|
+
if (self.socket === socket) {
|
|
379
|
+
self.socket = null;
|
|
423
380
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
getCookie(name) {
|
|
427
|
-
const value = `; ${document.cookie}`;
|
|
428
|
-
const parts = value.split(`; ${name}=`);
|
|
429
|
-
if (parts.length === 2) return parts.pop().split(';').shift();
|
|
430
|
-
},
|
|
431
|
-
|
|
432
|
-
async setup() {
|
|
433
|
-
const createSocket = this.createSocket.bind(this);
|
|
434
|
-
const closeSocket = this.closeSocket.bind(this);
|
|
435
|
-
|
|
436
|
-
const customErrorStyles = new Map()
|
|
381
|
+
};
|
|
437
382
|
|
|
383
|
+
socket.registeredTypes = new Set();
|
|
384
|
+
socket.reportedUnknownMessageTypes = new Set();
|
|
438
385
|
|
|
386
|
+
// 返回创建的socket,但不要立即使用,等待onopen
|
|
387
|
+
return socket;
|
|
388
|
+
} catch (error) {
|
|
389
|
+
console.error("创建WebSocket连接失败:", error);
|
|
390
|
+
this.isConnecting = false;
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* 获取可用的socket连接,如果不存在则创建
|
|
397
|
+
* 返回Promise以确保连接已就绪
|
|
398
|
+
*/
|
|
399
|
+
async getSocketAsync(customUrl) {
|
|
400
|
+
return new Promise((resolve, reject) => {
|
|
401
|
+
// 如果已有可用连接,直接返回
|
|
402
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
403
|
+
resolve(this.socket);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// 如果连接正在创建中,等待一段时间后检查
|
|
408
|
+
if (this.isConnecting) {
|
|
409
|
+
console.log("WebSocket连接创建中,等待...");
|
|
410
|
+
const checkInterval = setInterval(() => {
|
|
411
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
412
|
+
clearInterval(checkInterval);
|
|
413
|
+
resolve(this.socket);
|
|
414
|
+
} else if (!this.isConnecting) {
|
|
415
|
+
clearInterval(checkInterval);
|
|
416
|
+
reject(new Error("WebSocket连接创建失败"));
|
|
417
|
+
}
|
|
418
|
+
}, 100); // 每100ms检查一次
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// 创建新连接
|
|
423
|
+
const socket = this.createSocket(customUrl);
|
|
424
|
+
if (!socket) {
|
|
425
|
+
reject(new Error("创建WebSocket连接失败"));
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// 监听连接打开事件
|
|
430
|
+
socket.addEventListener("open", () => {
|
|
431
|
+
resolve(socket);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// 监听错误事件
|
|
435
|
+
socket.addEventListener("error", (error) => {
|
|
436
|
+
reject(error);
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
},
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* 获取可用的socket连接,如果不存在则创建
|
|
443
|
+
* 同步版本,可能返回尚未就绪的连接
|
|
444
|
+
*/
|
|
445
|
+
getSocket(customUrl) {
|
|
446
|
+
// 如果已有可用连接,直接返回
|
|
447
|
+
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
448
|
+
return this.socket;
|
|
449
|
+
}
|
|
439
450
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
clearCanvas: function () {
|
|
463
|
-
app.graph.clear();
|
|
464
|
-
window.parent.postMessage({
|
|
465
|
-
type: 'functionResult',
|
|
466
|
-
method: 'clearCanvas',
|
|
467
|
-
result: true
|
|
468
|
-
}, '*');
|
|
469
|
-
return true;
|
|
470
|
-
},
|
|
471
|
-
loadWorkflow: function (params) {
|
|
472
|
-
app.graph.clear();
|
|
473
|
-
document.dispatchEvent(new CustomEvent('workflowLoaded', {
|
|
474
|
-
detail: params.json
|
|
475
|
-
}));
|
|
476
|
-
if (params.json.version) {
|
|
477
|
-
app.loadGraphData(params.json);
|
|
478
|
-
} else {
|
|
479
|
-
app.loadApiJson(params.json, 'bizyair');
|
|
480
|
-
}
|
|
481
|
-
console.log("-----------loadWorkflow-----------", params.json)
|
|
482
|
-
window.parent.postMessage({
|
|
483
|
-
type: 'functionResult',
|
|
484
|
-
method: 'loadWorkflow',
|
|
485
|
-
result: true
|
|
486
|
-
}, '*');
|
|
487
|
-
return true;
|
|
488
|
-
},
|
|
489
|
-
|
|
490
|
-
saveWorkflow: async function () {
|
|
491
|
-
const graph = await app.graphToPrompt();
|
|
492
|
-
window.parent.postMessage({
|
|
493
|
-
type: 'functionResult',
|
|
494
|
-
method: 'saveWorkflow',
|
|
495
|
-
result: graph.workflow
|
|
496
|
-
}, '*');
|
|
497
|
-
return graph.workflow;
|
|
498
|
-
},
|
|
499
|
-
getWorkflow: async function () {
|
|
500
|
-
const graph = await app.graphToPrompt();
|
|
501
|
-
window.parent.postMessage({
|
|
502
|
-
type: 'functionResult',
|
|
503
|
-
method: 'getWorkflow',
|
|
504
|
-
result: graph.workflow
|
|
505
|
-
}, '*');
|
|
506
|
-
return graph.workflow;
|
|
507
|
-
},
|
|
508
|
-
getWorkflowNotSave: async function () {
|
|
509
|
-
const graph = await app.graphToPrompt();
|
|
510
|
-
// 规范化工作流,移除不影响逻辑的视觉字段,避免颜色等样式变化影响校验
|
|
511
|
-
const normalizeWorkflow = (workflow) => {
|
|
512
|
-
const json = JSON.stringify(workflow, (key, value) => {
|
|
513
|
-
if (key === 'color' || key === 'bgcolor' || key === 'extra') return undefined;
|
|
514
|
-
return value;
|
|
515
|
-
});
|
|
516
|
-
return JSON.parse(json);
|
|
517
|
-
};
|
|
518
|
-
const normalized = normalizeWorkflow(graph.workflow);
|
|
519
|
-
window.parent.postMessage({
|
|
520
|
-
type: 'functionResult',
|
|
521
|
-
method: 'getWorkflowNotSave',
|
|
522
|
-
result: normalized
|
|
523
|
-
}, '*');
|
|
524
|
-
return normalized;
|
|
525
|
-
},
|
|
526
|
-
// 新增:获取 workflow 和 output
|
|
527
|
-
getWorkflowWithOutput: async function () {
|
|
528
|
-
const graph = await app.graphToPrompt();
|
|
529
|
-
// graph.workflow.nodes.forEach(node => {
|
|
530
|
-
// for (const key in graph.output) {
|
|
531
|
-
// if (graph.output[key].class_type === node.type) {
|
|
532
|
-
// if (!graph.output[key]._meta) {
|
|
533
|
-
// graph.output[key]._meta = {};
|
|
534
|
-
// }
|
|
535
|
-
// graph.output[key]._meta.id = node.id;
|
|
536
|
-
// break; // 找到匹配的就跳出循环
|
|
537
|
-
// }
|
|
538
|
-
// }
|
|
539
|
-
// });
|
|
540
|
-
for (const key in graph.output) {
|
|
541
|
-
graph.output[key]._meta.id = Number(key);
|
|
542
|
-
}
|
|
543
|
-
window.parent.postMessage({
|
|
544
|
-
type: 'functionResult',
|
|
545
|
-
method: 'getWorkflowWithOutput',
|
|
546
|
-
result: {
|
|
547
|
-
workflow: graph.workflow,
|
|
548
|
-
output: graph.output
|
|
549
|
-
}
|
|
550
|
-
}, '*');
|
|
551
|
-
return { workflow: graph.workflow, output: graph.output };
|
|
552
|
-
},
|
|
553
|
-
saveApiJson: async function (params) {
|
|
554
|
-
const graph = await app.graphToPrompt();
|
|
555
|
-
window.parent.postMessage({
|
|
556
|
-
type: 'functionResult',
|
|
557
|
-
method: 'saveApiJson',
|
|
558
|
-
result: graph.output
|
|
559
|
-
}, '*');
|
|
560
|
-
return graph.output;
|
|
561
|
-
},
|
|
562
|
-
getClientId: function () {
|
|
563
|
-
const clientId = sessionStorage.getItem("clientId");
|
|
564
|
-
window.parent.postMessage({
|
|
565
|
-
type: 'functionResult',
|
|
566
|
-
method: 'getClientId',
|
|
567
|
-
result: clientId
|
|
568
|
-
}, '*');
|
|
569
|
-
return clientId;
|
|
570
|
-
},
|
|
571
|
-
runWorkflow: async function () {
|
|
572
|
-
try {
|
|
573
|
-
// 确保有连接
|
|
574
|
-
// await getSocketAsync();
|
|
575
|
-
const graph = await app.graphToPrompt();
|
|
576
|
-
const clientId = sessionStorage.getItem("clientId");
|
|
577
|
-
await app.queuePrompt(graph.output);
|
|
578
|
-
const resPrompt = await fetch("api/prompt", {
|
|
579
|
-
method: "POST",
|
|
580
|
-
body: JSON.stringify({
|
|
581
|
-
prompt: graph.output,
|
|
582
|
-
clientId,
|
|
583
|
-
number: graph.output,
|
|
584
|
-
extra_data: {
|
|
585
|
-
extra_pnginfo: {
|
|
586
|
-
workflow: graph.workflow
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
})
|
|
590
|
-
});
|
|
591
|
-
const resPromptJson = await resPrompt.json();
|
|
592
|
-
if (resPromptJson.error) {
|
|
593
|
-
this.openCustomError({
|
|
594
|
-
nodeId: resPromptJson.node_id,
|
|
595
|
-
nodeType: resPromptJson.node_type,
|
|
596
|
-
errorMessage: resPromptJson.details,
|
|
597
|
-
borderColor: '#FF0000'
|
|
598
|
-
})
|
|
599
|
-
return
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
for (const i in resPromptJson.node_errors) {
|
|
603
|
-
|
|
604
|
-
if (resPromptJson.node_errors[i].errors) {
|
|
605
|
-
const err = resPromptJson.node_errors[i].errors[0]
|
|
606
|
-
if (err) {
|
|
607
|
-
this.openCustomError({
|
|
608
|
-
nodeId: i,
|
|
609
|
-
nodeType: err.type,
|
|
610
|
-
errorMessage: err.details,
|
|
611
|
-
borderColor: '#FF0000'
|
|
612
|
-
})
|
|
613
|
-
return
|
|
614
|
-
}
|
|
615
|
-
} else {
|
|
616
|
-
console.log(resPromptJson.node_errors[i])
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
if (Object.keys(resPromptJson.node_errors).length) return
|
|
621
|
-
// graph.workflow.nodes.forEach(node => {
|
|
622
|
-
// for (const key in graph.output) {
|
|
623
|
-
// if (graph.output[key].class_type === node.type) {
|
|
624
|
-
// if (!graph.output[key]._meta) {
|
|
625
|
-
// graph.output[key]._meta = {};
|
|
626
|
-
// }
|
|
627
|
-
// graph.output[key]._meta.id = node.id;
|
|
628
|
-
// console.log(graph.output[key].class_type, node.type, graph.output[key]._meta.id)
|
|
629
|
-
// break; // 找到匹配的就跳出循环
|
|
630
|
-
// }
|
|
631
|
-
// }
|
|
632
|
-
// });
|
|
633
|
-
for (const key in graph.output) {
|
|
634
|
-
graph.output[key]._meta.id = Number(key);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
for (let i in graph.output) {
|
|
638
|
-
if (graph.output[i].class_type == 'LoadImage') {
|
|
639
|
-
graph.output[i].inputs.image = graph.output[i].inputs.image.replace('pasted/http', 'http')
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
console.log(graph.output)
|
|
643
|
-
window.parent.postMessage({
|
|
644
|
-
type: 'functionResult',
|
|
645
|
-
method: 'runWorkflow',
|
|
646
|
-
result: {
|
|
647
|
-
clientId: clientId,
|
|
648
|
-
jsonWorkflow: graph.output,
|
|
649
|
-
workflow: graph.workflow,
|
|
650
|
-
prompt: resPromptJson
|
|
651
|
-
}
|
|
652
|
-
}, '*');
|
|
653
|
-
return true;
|
|
654
|
-
} catch (error) {
|
|
655
|
-
console.error('运行工作流失败:', error);
|
|
656
|
-
window.parent.postMessage({
|
|
657
|
-
type: 'functionResult',
|
|
658
|
-
method: 'runWorkflow',
|
|
659
|
-
error: '运行工作流失败: ' + error.message,
|
|
660
|
-
success: false
|
|
661
|
-
}, '*');
|
|
662
|
-
return false;
|
|
663
|
-
}
|
|
664
|
-
},
|
|
665
|
-
setCookie: function (params) {
|
|
666
|
-
const setCookie = (name, value, days) => {
|
|
667
|
-
let expires = "";
|
|
668
|
-
if (days) {
|
|
669
|
-
const date = new Date();
|
|
670
|
-
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
|
671
|
-
expires = "; expires=" + date.toUTCString();
|
|
672
|
-
}
|
|
673
|
-
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
|
674
|
-
};
|
|
675
|
-
// console.log("-----------setCookie-----------", params)
|
|
676
|
-
// console.log("-----------setCookie-----------", params)
|
|
677
|
-
setCookie(params.name, params.value, params.days);
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
return true;
|
|
681
|
-
},
|
|
682
|
-
fitView: function () {
|
|
683
|
-
app.canvas.fitViewToSelectionAnimated()
|
|
684
|
-
window.parent.postMessage({
|
|
685
|
-
type: 'functionResult',
|
|
686
|
-
method: 'fitView',
|
|
687
|
-
result: true
|
|
688
|
-
}, '*');
|
|
689
|
-
return true;
|
|
690
|
-
},
|
|
691
|
-
clickAssistant: function () {
|
|
692
|
-
const assistantBtn = document.querySelector('.btn-assistant');
|
|
693
|
-
if (assistantBtn) {
|
|
694
|
-
assistantBtn.click();
|
|
695
|
-
window.parent.postMessage({
|
|
696
|
-
type: 'functionResult',
|
|
697
|
-
method: 'clickAssistant',
|
|
698
|
-
result: true
|
|
699
|
-
}, '*');
|
|
700
|
-
return true;
|
|
701
|
-
} else {
|
|
702
|
-
console.warn('Assistant button not found');
|
|
703
|
-
window.parent.postMessage({
|
|
704
|
-
type: 'functionResult',
|
|
705
|
-
method: 'clickAssistant',
|
|
706
|
-
result: false
|
|
707
|
-
}, '*');
|
|
708
|
-
return false;
|
|
709
|
-
}
|
|
710
|
-
},
|
|
711
|
-
clickCommunity: function () {
|
|
712
|
-
const communityBtn = document.querySelector('.btn-community');
|
|
713
|
-
if (communityBtn) {
|
|
714
|
-
communityBtn.click();
|
|
715
|
-
window.parent.postMessage({
|
|
716
|
-
type: 'functionResult',
|
|
717
|
-
method: 'clickCommunity',
|
|
718
|
-
result: true
|
|
719
|
-
}, '*');
|
|
720
|
-
return true;
|
|
721
|
-
} else {
|
|
722
|
-
window.parent.postMessage({
|
|
723
|
-
type: 'functionResult',
|
|
724
|
-
method: 'clickCommunity',
|
|
725
|
-
result: false
|
|
726
|
-
}, '*');
|
|
727
|
-
return false;
|
|
728
|
-
}
|
|
729
|
-
},
|
|
730
|
-
toPublish: async function () {
|
|
731
|
-
const graph = await app.graphToPrompt();
|
|
732
|
-
window.parent.postMessage({
|
|
733
|
-
type: 'functionResult',
|
|
734
|
-
method: 'toPublish',
|
|
735
|
-
result: graph.workflow
|
|
736
|
-
}, '*');
|
|
737
|
-
return graph.workflow;
|
|
738
|
-
},
|
|
739
|
-
|
|
740
|
-
graphToPrompt: async function (params) {
|
|
741
|
-
console.log('postEvent.js - graphToPrompt被调用,参数:', params);
|
|
742
|
-
const graph = await app.graphToPrompt();
|
|
743
|
-
window.parent.postMessage({
|
|
744
|
-
type: 'functionResult',
|
|
745
|
-
method: 'graphToPrompt',
|
|
746
|
-
params: params, // 传递原始参数
|
|
747
|
-
result: {
|
|
748
|
-
workflow: graph.workflow,
|
|
749
|
-
output: graph.output
|
|
750
|
-
}
|
|
751
|
-
}, '*');
|
|
752
|
-
return {
|
|
753
|
-
workflow: graph.workflow,
|
|
754
|
-
output: graph.output
|
|
755
|
-
};
|
|
756
|
-
},
|
|
757
|
-
loadGraphData: function (params) {
|
|
758
|
-
const { json, clear = true, center = false, workflow_name = "" } = params;
|
|
759
|
-
if (clear) {
|
|
760
|
-
app.graph.clear();
|
|
761
|
-
}
|
|
762
|
-
app.loadGraphData(json, clear, center, workflow_name);
|
|
763
|
-
window.parent.postMessage({
|
|
764
|
-
type: 'functionResult',
|
|
765
|
-
method: 'loadGraphData',
|
|
766
|
-
result: true
|
|
767
|
-
}, '*');
|
|
768
|
-
return true;
|
|
769
|
-
},
|
|
451
|
+
// 创建新连接
|
|
452
|
+
return this.createSocket(customUrl);
|
|
453
|
+
},
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* 关闭socket连接
|
|
457
|
+
* @param {number} code - 关闭状态码
|
|
458
|
+
*/
|
|
459
|
+
closeSocket(code) {
|
|
460
|
+
// 先停止心跳
|
|
461
|
+
this.stopPing();
|
|
462
|
+
|
|
463
|
+
if (this.socket) {
|
|
464
|
+
if (
|
|
465
|
+
this.socket.readyState === WebSocket.OPEN ||
|
|
466
|
+
this.socket.readyState === WebSocket.CONNECTING
|
|
467
|
+
) {
|
|
468
|
+
console.log("关闭WebSocket连接");
|
|
469
|
+
this.socket.close(code);
|
|
470
|
+
}
|
|
471
|
+
this.socket = null;
|
|
472
|
+
}
|
|
770
473
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
474
|
+
// 重置任务状态
|
|
475
|
+
this.taskRunning = false;
|
|
476
|
+
|
|
477
|
+
return true;
|
|
478
|
+
},
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* 更改socket URL并创建新连接
|
|
482
|
+
*/
|
|
483
|
+
changeSocketUrl(newUrl) {
|
|
484
|
+
const clientId = sessionStorage.getItem("clientId");
|
|
485
|
+
const fullUrl = newUrl + "?clientId=" + clientId + "&a=1";
|
|
486
|
+
|
|
487
|
+
return this.createSocket(fullUrl);
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* 发送socket消息
|
|
492
|
+
* 确保连接已就绪
|
|
493
|
+
*/
|
|
494
|
+
async sendSocketMessage(message) {
|
|
495
|
+
try {
|
|
496
|
+
const socket = await this.getSocketAsync();
|
|
497
|
+
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
498
|
+
socket.send(
|
|
499
|
+
typeof message === "string" ? message : JSON.stringify(message)
|
|
500
|
+
);
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
503
|
+
return false;
|
|
504
|
+
} catch (error) {
|
|
505
|
+
console.error("发送消息失败:", error);
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* 发送任务提示
|
|
512
|
+
*/
|
|
513
|
+
async sendPrompt(prompt) {
|
|
514
|
+
try {
|
|
515
|
+
// 确保有连接
|
|
516
|
+
await this.getSocketAsync();
|
|
517
|
+
// 发送提示
|
|
518
|
+
app.queuePrompt(prompt);
|
|
519
|
+
return true;
|
|
520
|
+
} catch (error) {
|
|
521
|
+
console.error("发送任务提示失败:", error);
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
|
|
526
|
+
getCookie(name) {
|
|
527
|
+
const value = `; ${document.cookie}`;
|
|
528
|
+
const parts = value.split(`; ${name}=`);
|
|
529
|
+
if (parts.length === 2) return parts.pop().split(";").shift();
|
|
530
|
+
},
|
|
531
|
+
|
|
532
|
+
async setup() {
|
|
533
|
+
const createSocket = this.createSocket.bind(this);
|
|
534
|
+
const closeSocket = this.closeSocket.bind(this);
|
|
535
|
+
|
|
536
|
+
const customErrorStyles = new Map();
|
|
537
|
+
|
|
538
|
+
// 用于节流的时间戳
|
|
539
|
+
let lastRunWorkflowTime = 0;
|
|
540
|
+
const THROTTLE_TIME = 2000; // 2秒
|
|
541
|
+
|
|
542
|
+
// 方法映射
|
|
543
|
+
const methods = {
|
|
544
|
+
customSocket: async function (params) {
|
|
545
|
+
const socket = createSocket(params.url);
|
|
546
|
+
window.parent.postMessage(
|
|
547
|
+
{
|
|
548
|
+
type: "functionResult",
|
|
549
|
+
method: "customSocket",
|
|
550
|
+
result: "自定义socket执行结果",
|
|
551
|
+
},
|
|
552
|
+
"*"
|
|
553
|
+
);
|
|
554
|
+
return socket;
|
|
555
|
+
},
|
|
556
|
+
|
|
557
|
+
closeSocket: function () {
|
|
558
|
+
const result = closeSocket();
|
|
559
|
+
window.parent.postMessage(
|
|
560
|
+
{
|
|
561
|
+
type: "functionResult",
|
|
562
|
+
method: "closeSocket",
|
|
563
|
+
result: result ? "Socket连接已关闭" : "Socket连接关闭失败或已关闭",
|
|
564
|
+
},
|
|
565
|
+
"*"
|
|
566
|
+
);
|
|
567
|
+
return result;
|
|
568
|
+
},
|
|
569
|
+
|
|
570
|
+
clearCanvas: function () {
|
|
571
|
+
app.graph.clear();
|
|
572
|
+
window.parent.postMessage(
|
|
573
|
+
{
|
|
574
|
+
type: "functionResult",
|
|
575
|
+
method: "clearCanvas",
|
|
576
|
+
result: true,
|
|
577
|
+
},
|
|
578
|
+
"*"
|
|
579
|
+
);
|
|
580
|
+
return true;
|
|
581
|
+
},
|
|
582
|
+
loadWorkflow: function (params) {
|
|
583
|
+
app.graph.clear();
|
|
584
|
+
document.dispatchEvent(
|
|
585
|
+
new CustomEvent("workflowLoaded", {
|
|
586
|
+
detail: params.json,
|
|
587
|
+
})
|
|
588
|
+
);
|
|
589
|
+
if (params.json.version) {
|
|
590
|
+
app.loadGraphData(params.json);
|
|
591
|
+
} else {
|
|
592
|
+
app.loadApiJson(params.json, "bizyair");
|
|
593
|
+
}
|
|
594
|
+
console.log("-----------loadWorkflow-----------", params.json);
|
|
595
|
+
window.parent.postMessage(
|
|
596
|
+
{
|
|
597
|
+
type: "functionResult",
|
|
598
|
+
method: "loadWorkflow",
|
|
599
|
+
result: true,
|
|
600
|
+
},
|
|
601
|
+
"*"
|
|
602
|
+
);
|
|
603
|
+
return true;
|
|
604
|
+
},
|
|
605
|
+
|
|
606
|
+
saveWorkflow: async function () {
|
|
607
|
+
const graph = await app.graphToPrompt();
|
|
608
|
+
window.parent.postMessage(
|
|
609
|
+
{
|
|
610
|
+
type: "functionResult",
|
|
611
|
+
method: "saveWorkflow",
|
|
612
|
+
result: graph.workflow,
|
|
613
|
+
},
|
|
614
|
+
"*"
|
|
615
|
+
);
|
|
616
|
+
return graph.workflow;
|
|
617
|
+
},
|
|
618
|
+
getWorkflow: async function () {
|
|
619
|
+
const graph = await app.graphToPrompt();
|
|
620
|
+
window.parent.postMessage(
|
|
621
|
+
{
|
|
622
|
+
type: "functionResult",
|
|
623
|
+
method: "getWorkflow",
|
|
624
|
+
result: graph.workflow,
|
|
625
|
+
},
|
|
626
|
+
"*"
|
|
627
|
+
);
|
|
628
|
+
return graph.workflow;
|
|
629
|
+
},
|
|
630
|
+
getWorkflowNotSave: async function () {
|
|
631
|
+
const graph = await app.graphToPrompt();
|
|
632
|
+
// 规范化工作流,移除不影响逻辑的视觉字段,避免颜色等样式变化影响校验
|
|
633
|
+
const normalizeWorkflow = (workflow) => {
|
|
634
|
+
const json = JSON.stringify(workflow, (key, value) => {
|
|
635
|
+
if (key === "color" || key === "bgcolor" || key === "extra")
|
|
636
|
+
return undefined;
|
|
637
|
+
return value;
|
|
638
|
+
});
|
|
639
|
+
return JSON.parse(json);
|
|
640
|
+
};
|
|
641
|
+
const normalized = normalizeWorkflow(graph.workflow);
|
|
642
|
+
window.parent.postMessage(
|
|
643
|
+
{
|
|
644
|
+
type: "functionResult",
|
|
645
|
+
method: "getWorkflowNotSave",
|
|
646
|
+
result: normalized,
|
|
647
|
+
},
|
|
648
|
+
"*"
|
|
649
|
+
);
|
|
650
|
+
return normalized;
|
|
651
|
+
},
|
|
652
|
+
// 新增:获取 workflow 和 output
|
|
653
|
+
getWorkflowWithOutput: async function () {
|
|
654
|
+
const graph = await app.graphToPrompt();
|
|
655
|
+
for (const key in graph.output) {
|
|
656
|
+
graph.output[key]._meta.id = Number(key);
|
|
657
|
+
graph.output[key]._meta.class_type = graph.output[key].class_type;
|
|
658
|
+
}
|
|
659
|
+
window.parent.postMessage(
|
|
660
|
+
{
|
|
661
|
+
type: "functionResult",
|
|
662
|
+
method: "getWorkflowWithOutput",
|
|
663
|
+
result: {
|
|
664
|
+
workflow: graph.workflow,
|
|
665
|
+
output: graph.output,
|
|
781
666
|
},
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
667
|
+
},
|
|
668
|
+
"*"
|
|
669
|
+
);
|
|
670
|
+
return { workflow: graph.workflow, output: graph.output };
|
|
671
|
+
},
|
|
672
|
+
saveApiJson: async function (params) {
|
|
673
|
+
const graph = await app.graphToPrompt();
|
|
674
|
+
window.parent.postMessage(
|
|
675
|
+
{
|
|
676
|
+
type: "functionResult",
|
|
677
|
+
method: "saveApiJson",
|
|
678
|
+
result: graph.output,
|
|
679
|
+
},
|
|
680
|
+
"*"
|
|
681
|
+
);
|
|
682
|
+
return graph.output;
|
|
683
|
+
},
|
|
684
|
+
getClientId: function () {
|
|
685
|
+
const clientId = sessionStorage.getItem("clientId");
|
|
686
|
+
window.parent.postMessage(
|
|
687
|
+
{
|
|
688
|
+
type: "functionResult",
|
|
689
|
+
method: "getClientId",
|
|
690
|
+
result: clientId,
|
|
691
|
+
},
|
|
692
|
+
"*"
|
|
693
|
+
);
|
|
694
|
+
return clientId;
|
|
695
|
+
},
|
|
696
|
+
runWorkflow: async function () {
|
|
697
|
+
try {
|
|
698
|
+
// 确保有连接
|
|
699
|
+
// await getSocketAsync();
|
|
700
|
+
|
|
701
|
+
const graph = await app.graphToPrompt();
|
|
702
|
+
const clientId = sessionStorage.getItem("clientId");
|
|
703
|
+
await app.queuePrompt(graph.output);
|
|
704
|
+
const resPrompt = await fetch("api/prompt", {
|
|
705
|
+
method: "POST",
|
|
706
|
+
body: JSON.stringify({
|
|
707
|
+
prompt: graph.output,
|
|
708
|
+
clientId,
|
|
709
|
+
number: graph.output,
|
|
710
|
+
extra_data: {
|
|
711
|
+
extra_pnginfo: {
|
|
712
|
+
workflow: graph.workflow,
|
|
713
|
+
},
|
|
714
|
+
},
|
|
715
|
+
}),
|
|
716
|
+
});
|
|
717
|
+
const resPromptJson = await resPrompt.json();
|
|
718
|
+
if (resPromptJson.error && resPromptJson.node_id) {
|
|
719
|
+
this.openCustomError({
|
|
720
|
+
nodeId: resPromptJson.node_id,
|
|
721
|
+
nodeType: resPromptJson.node_type,
|
|
722
|
+
errorMessage: resPromptJson.details,
|
|
723
|
+
borderColor: "#FF0000",
|
|
724
|
+
});
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
for (const i in resPromptJson.node_errors) {
|
|
729
|
+
if (resPromptJson.node_errors[i].errors) {
|
|
730
|
+
const err = resPromptJson.node_errors[i].errors[0];
|
|
731
|
+
if (err) {
|
|
732
|
+
this.openCustomError({
|
|
733
|
+
nodeId: i,
|
|
734
|
+
nodeType: err.type,
|
|
735
|
+
errorMessage: err.details,
|
|
736
|
+
borderColor: "#FF0000",
|
|
737
|
+
});
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
} else {
|
|
741
|
+
console.log(resPromptJson.node_errors[i]);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (Object.keys(resPromptJson.node_errors).length) return;
|
|
746
|
+
for (const key in graph.output) {
|
|
747
|
+
graph.output[key]._meta.id = Number(key);
|
|
748
|
+
graph.output[key]._meta.class_type = graph.output[key].class_type;
|
|
749
|
+
}
|
|
750
|
+
for (let i in graph.output) {
|
|
751
|
+
if (graph.output[i].class_type == "LoadImage") {
|
|
752
|
+
graph.output[i].inputs.image = graph.output[
|
|
753
|
+
i
|
|
754
|
+
].inputs.image.replace("pasted/http", "http");
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
console.log(graph.output);
|
|
758
|
+
window.parent.postMessage(
|
|
759
|
+
{
|
|
760
|
+
type: "functionResult",
|
|
761
|
+
method: "runWorkflow",
|
|
762
|
+
result: {
|
|
763
|
+
clientId: clientId,
|
|
764
|
+
jsonWorkflow: graph.output,
|
|
765
|
+
workflow: graph.workflow,
|
|
766
|
+
prompt: resPromptJson,
|
|
767
|
+
},
|
|
792
768
|
},
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
769
|
+
"*"
|
|
770
|
+
);
|
|
771
|
+
return true;
|
|
772
|
+
} catch (error) {
|
|
773
|
+
console.error("运行工作流失败:", error);
|
|
774
|
+
window.parent.postMessage(
|
|
775
|
+
{
|
|
776
|
+
type: "functionResult",
|
|
777
|
+
method: "runWorkflow",
|
|
778
|
+
error: "运行工作流失败: " + error.message,
|
|
779
|
+
success: false,
|
|
803
780
|
},
|
|
781
|
+
"*"
|
|
782
|
+
);
|
|
783
|
+
return false;
|
|
784
|
+
}
|
|
785
|
+
},
|
|
786
|
+
setCookie: function (params) {
|
|
787
|
+
const setCookie = (name, value, days) => {
|
|
788
|
+
let expires = "";
|
|
789
|
+
if (days) {
|
|
790
|
+
const date = new Date();
|
|
791
|
+
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
|
792
|
+
expires = "; expires=" + date.toUTCString();
|
|
793
|
+
}
|
|
794
|
+
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
|
795
|
+
};
|
|
796
|
+
// console.log("-----------setCookie-----------", params)
|
|
797
|
+
// console.log("-----------setCookie-----------", params)
|
|
798
|
+
setCookie(params.name, params.value, params.days);
|
|
804
799
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
800
|
+
return true;
|
|
801
|
+
},
|
|
802
|
+
removeCookie: function (params) {
|
|
803
|
+
const expires = new Date(0).toUTCString();
|
|
804
|
+
document.cookie = params.name + "=; expires=" + expires + "; path=/";
|
|
805
|
+
return true;
|
|
806
|
+
},
|
|
807
|
+
fitView: function () {
|
|
808
|
+
app.canvas.fitViewToSelectionAnimated();
|
|
809
|
+
window.parent.postMessage(
|
|
810
|
+
{
|
|
811
|
+
type: "functionResult",
|
|
812
|
+
method: "fitView",
|
|
813
|
+
result: true,
|
|
814
|
+
},
|
|
815
|
+
"*"
|
|
816
|
+
);
|
|
817
|
+
return true;
|
|
818
|
+
},
|
|
819
|
+
clickAssistant: function () {
|
|
820
|
+
const assistantBtn = document.querySelector(".btn-assistant");
|
|
821
|
+
if (assistantBtn) {
|
|
822
|
+
assistantBtn.click();
|
|
823
|
+
window.parent.postMessage(
|
|
824
|
+
{
|
|
825
|
+
type: "functionResult",
|
|
826
|
+
method: "clickAssistant",
|
|
827
|
+
result: true,
|
|
814
828
|
},
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
829
|
+
"*"
|
|
830
|
+
);
|
|
831
|
+
return true;
|
|
832
|
+
} else {
|
|
833
|
+
console.warn("Assistant button not found");
|
|
834
|
+
window.parent.postMessage(
|
|
835
|
+
{
|
|
836
|
+
type: "functionResult",
|
|
837
|
+
method: "clickAssistant",
|
|
838
|
+
result: false,
|
|
825
839
|
},
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
840
|
+
"*"
|
|
841
|
+
);
|
|
842
|
+
return false;
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
clickCommunity: function () {
|
|
846
|
+
const communityBtn = document.querySelector(".btn-community");
|
|
847
|
+
if (communityBtn) {
|
|
848
|
+
communityBtn.click();
|
|
849
|
+
window.parent.postMessage(
|
|
850
|
+
{
|
|
851
|
+
type: "functionResult",
|
|
852
|
+
method: "clickCommunity",
|
|
853
|
+
result: true,
|
|
835
854
|
},
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
855
|
+
"*"
|
|
856
|
+
);
|
|
857
|
+
return true;
|
|
858
|
+
} else {
|
|
859
|
+
window.parent.postMessage(
|
|
860
|
+
{
|
|
861
|
+
type: "functionResult",
|
|
862
|
+
method: "clickCommunity",
|
|
863
|
+
result: false,
|
|
845
864
|
},
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
865
|
+
"*"
|
|
866
|
+
);
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
},
|
|
870
|
+
toPublish: async function () {
|
|
871
|
+
const graph = await app.graphToPrompt();
|
|
872
|
+
window.parent.postMessage(
|
|
873
|
+
{
|
|
874
|
+
type: "functionResult",
|
|
875
|
+
method: "toPublish",
|
|
876
|
+
result: graph.workflow,
|
|
877
|
+
},
|
|
878
|
+
"*"
|
|
879
|
+
);
|
|
880
|
+
return graph.workflow;
|
|
881
|
+
},
|
|
882
|
+
|
|
883
|
+
graphToPrompt: async function (params) {
|
|
884
|
+
console.log("postEvent.js - graphToPrompt被调用,参数:", params);
|
|
885
|
+
const graph = await app.graphToPrompt();
|
|
886
|
+
window.parent.postMessage(
|
|
887
|
+
{
|
|
888
|
+
type: "functionResult",
|
|
889
|
+
method: "graphToPrompt",
|
|
890
|
+
params: params, // 传递原始参数
|
|
891
|
+
result: {
|
|
892
|
+
workflow: graph.workflow,
|
|
893
|
+
output: graph.output,
|
|
854
894
|
},
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
895
|
+
},
|
|
896
|
+
"*"
|
|
897
|
+
);
|
|
898
|
+
return {
|
|
899
|
+
workflow: graph.workflow,
|
|
900
|
+
output: graph.output,
|
|
901
|
+
};
|
|
902
|
+
},
|
|
903
|
+
loadGraphData: function (params) {
|
|
904
|
+
const {
|
|
905
|
+
json,
|
|
906
|
+
clear = true,
|
|
907
|
+
center = false,
|
|
908
|
+
workflow_name = "",
|
|
909
|
+
} = params;
|
|
910
|
+
if (clear) {
|
|
911
|
+
app.graph.clear();
|
|
912
|
+
}
|
|
913
|
+
app.loadGraphData(json, clear, center, workflow_name);
|
|
914
|
+
window.parent.postMessage(
|
|
915
|
+
{
|
|
916
|
+
type: "functionResult",
|
|
917
|
+
method: "loadGraphData",
|
|
918
|
+
result: true,
|
|
919
|
+
},
|
|
920
|
+
"*"
|
|
921
|
+
);
|
|
922
|
+
return true;
|
|
923
|
+
},
|
|
924
|
+
|
|
925
|
+
// AI应用相关方法
|
|
926
|
+
toggleAIAppMode: function (params) {
|
|
927
|
+
const enable = params.enable === true;
|
|
928
|
+
const result = enable ? enableAIAppMode() : disableAIAppMode();
|
|
929
|
+
window.parent.postMessage(
|
|
930
|
+
{
|
|
931
|
+
type: "functionResult",
|
|
932
|
+
method: "toggleAIAppMode",
|
|
933
|
+
result: result,
|
|
934
|
+
},
|
|
935
|
+
"*"
|
|
936
|
+
);
|
|
937
|
+
return result;
|
|
938
|
+
},
|
|
939
|
+
|
|
940
|
+
selectInputNode: function (params) {
|
|
941
|
+
if (!params.nodeId) return false;
|
|
942
|
+
const result = selectInputNode(params.nodeId);
|
|
943
|
+
window.parent.postMessage(
|
|
944
|
+
{
|
|
945
|
+
type: "functionResult",
|
|
946
|
+
method: "selectInputNode",
|
|
947
|
+
result: result,
|
|
948
|
+
},
|
|
949
|
+
"*"
|
|
950
|
+
);
|
|
951
|
+
return result;
|
|
952
|
+
},
|
|
953
|
+
|
|
954
|
+
selectExportNode: function (params) {
|
|
955
|
+
if (!params.nodeId) return false;
|
|
956
|
+
const result = selectInputNode(params.nodeId);
|
|
957
|
+
window.parent.postMessage(
|
|
958
|
+
{
|
|
959
|
+
type: "functionResult",
|
|
960
|
+
method: "selectExportNode",
|
|
961
|
+
result: result,
|
|
962
|
+
},
|
|
963
|
+
"*"
|
|
964
|
+
);
|
|
965
|
+
return result;
|
|
966
|
+
},
|
|
967
|
+
|
|
968
|
+
deselectInputNode: function (params) {
|
|
969
|
+
if (!params.nodeId) return false;
|
|
970
|
+
const result = deselectInputNode(params.nodeId);
|
|
971
|
+
window.parent.postMessage(
|
|
972
|
+
{
|
|
973
|
+
type: "functionResult",
|
|
974
|
+
method: "deselectInputNode",
|
|
975
|
+
result: result,
|
|
976
|
+
},
|
|
977
|
+
"*"
|
|
978
|
+
);
|
|
979
|
+
return result;
|
|
980
|
+
},
|
|
981
|
+
|
|
982
|
+
updateInputNodeWidget: function (params) {
|
|
983
|
+
if (!params.nodeId || params.widgetName === undefined) return false;
|
|
984
|
+
const result = updateInputNodeWidget(
|
|
985
|
+
params.nodeId,
|
|
986
|
+
params.widgetName,
|
|
987
|
+
params.value
|
|
988
|
+
);
|
|
989
|
+
window.parent.postMessage(
|
|
990
|
+
{
|
|
991
|
+
type: "functionResult",
|
|
992
|
+
method: "updateInputNodeWidget",
|
|
993
|
+
result: result,
|
|
994
|
+
},
|
|
995
|
+
"*"
|
|
996
|
+
);
|
|
997
|
+
return result;
|
|
998
|
+
},
|
|
999
|
+
|
|
1000
|
+
getInputNodes: function () {
|
|
1001
|
+
const result = getSelectedInputNodes();
|
|
1002
|
+
window.parent.postMessage(
|
|
1003
|
+
{
|
|
1004
|
+
type: "functionResult",
|
|
1005
|
+
method: "getInputNodes",
|
|
1006
|
+
result: result,
|
|
1007
|
+
},
|
|
1008
|
+
"*"
|
|
1009
|
+
);
|
|
1010
|
+
return result;
|
|
1011
|
+
},
|
|
1012
|
+
|
|
1013
|
+
clearInputNodes: function () {
|
|
1014
|
+
const result = clearSelectedInputNodes();
|
|
1015
|
+
window.parent.postMessage(
|
|
1016
|
+
{
|
|
1017
|
+
type: "functionResult",
|
|
1018
|
+
method: "clearInputNodes",
|
|
1019
|
+
result: result,
|
|
1020
|
+
},
|
|
1021
|
+
"*"
|
|
1022
|
+
);
|
|
1023
|
+
return result;
|
|
1024
|
+
},
|
|
1025
|
+
toggleExportMode: function (params) {
|
|
1026
|
+
const result = toggleExportMode(params);
|
|
1027
|
+
window.parent.postMessage(
|
|
1028
|
+
{
|
|
1029
|
+
type: "functionResult",
|
|
1030
|
+
method: "toggleExportMode",
|
|
1031
|
+
result: result,
|
|
1032
|
+
},
|
|
1033
|
+
"*"
|
|
1034
|
+
);
|
|
1035
|
+
return result;
|
|
1036
|
+
},
|
|
1037
|
+
openCustomError: function (params) {
|
|
1038
|
+
const {
|
|
1039
|
+
nodeId,
|
|
1040
|
+
nodeType,
|
|
1041
|
+
errorMessage,
|
|
1042
|
+
borderColor = "#FF0000",
|
|
1043
|
+
} = params;
|
|
1044
|
+
const nodeIds = Array.isArray(nodeId) ? nodeId : [nodeId];
|
|
1045
|
+
function injectErrorDialogStyles() {
|
|
1046
|
+
const styleId = "custom-error-dialog-styles";
|
|
1047
|
+
if (document.getElementById(styleId)) {
|
|
1048
|
+
return; // 样式已经存在
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
const style = document.createElement("style");
|
|
1052
|
+
style.id = styleId;
|
|
1053
|
+
style.textContent = `
|
|
867
1054
|
.comfy-error-report .no-results-placeholder p {
|
|
868
1055
|
text-align: left;
|
|
869
1056
|
}
|
|
870
1057
|
`;
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1058
|
+
document.head.appendChild(style);
|
|
1059
|
+
}
|
|
1060
|
+
injectErrorDialogStyles();
|
|
1061
|
+
function simulateExecutionError(
|
|
1062
|
+
nodeId,
|
|
1063
|
+
nodeType,
|
|
1064
|
+
errorMessage,
|
|
1065
|
+
borderColor
|
|
1066
|
+
) {
|
|
1067
|
+
// const originalNodeErrorStyle = node.strokeStyles?.['nodeError']
|
|
1068
|
+
const node = app.graph.getNodeById(nodeId);
|
|
1069
|
+
if (!node) return;
|
|
1070
|
+
if (!customErrorStyles.has(nodeId)) {
|
|
1071
|
+
customErrorStyles.set(nodeId, {
|
|
1072
|
+
originalStyle: node.strokeStyles?.["nodeError"],
|
|
1073
|
+
customColor: borderColor,
|
|
1074
|
+
nodeId: nodeId,
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
node.strokeStyles = node.strokeStyles || {};
|
|
1078
|
+
node.strokeStyles["nodeError"] = function () {
|
|
1079
|
+
// if (this.id === nodeId) {
|
|
1080
|
+
return { color: borderColor, lineWidth: 2 }; // 自定义颜色和线宽
|
|
1081
|
+
// }
|
|
1082
|
+
};
|
|
1083
|
+
const mockErrorEvent = {
|
|
1084
|
+
detail: {
|
|
1085
|
+
node_id: nodeId,
|
|
1086
|
+
node_type: nodeType,
|
|
1087
|
+
exception_message: errorMessage,
|
|
1088
|
+
exception_type: "ManualError",
|
|
1089
|
+
traceback: ["Manual error triggered"],
|
|
1090
|
+
executed: [],
|
|
1091
|
+
prompt_id: "manual",
|
|
1092
|
+
timestamp: Date.now(),
|
|
1093
|
+
},
|
|
1094
|
+
};
|
|
903
1095
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1096
|
+
// 手动触发事件监听器
|
|
1097
|
+
app.api.dispatchCustomEvent("execution_error", mockErrorEvent.detail);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
nodeIds.forEach((id) => {
|
|
1101
|
+
simulateExecutionError(id, nodeType, errorMessage, borderColor);
|
|
1102
|
+
});
|
|
907
1103
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1104
|
+
app.canvas.draw(true, true);
|
|
1105
|
+
|
|
1106
|
+
// 添加发送消息给前端折叠侧边栏的代码
|
|
1107
|
+
window.parent.postMessage(
|
|
1108
|
+
{
|
|
1109
|
+
type: "collapseParamSelector",
|
|
1110
|
+
method: "collapseParamSelector",
|
|
1111
|
+
result: true,
|
|
1112
|
+
},
|
|
1113
|
+
"*"
|
|
1114
|
+
);
|
|
1115
|
+
|
|
1116
|
+
window.parent.postMessage(
|
|
1117
|
+
{
|
|
1118
|
+
type: "functionResult",
|
|
1119
|
+
method: "openCustomError",
|
|
1120
|
+
result: true,
|
|
1121
|
+
},
|
|
1122
|
+
"*"
|
|
1123
|
+
);
|
|
1124
|
+
},
|
|
1125
|
+
clearAllCustomStyles: function () {
|
|
1126
|
+
customErrorStyles.forEach((styleInfo, nodeId) => {
|
|
1127
|
+
const node = app.graph.getNodeById(nodeId);
|
|
1128
|
+
if (!node) return;
|
|
1129
|
+
console.log(node);
|
|
1130
|
+
// 恢复原始样式
|
|
1131
|
+
if (styleInfo.originalStyle) {
|
|
1132
|
+
node.strokeStyles["nodeError"] = styleInfo.originalStyle;
|
|
1133
|
+
} else {
|
|
1134
|
+
delete node.strokeStyles["nodeError"];
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// 从映射中移除
|
|
1138
|
+
customErrorStyles.delete(nodeId);
|
|
1139
|
+
});
|
|
911
1140
|
|
|
912
|
-
|
|
1141
|
+
// 重绘画布
|
|
1142
|
+
app.canvas.draw(true, true);
|
|
1143
|
+
},
|
|
1144
|
+
focusNodeOnly: function (params) {
|
|
1145
|
+
if (!params.nodeId) return false;
|
|
1146
|
+
const result = focusNodeOnly(params.nodeId);
|
|
1147
|
+
window.parent.postMessage(
|
|
1148
|
+
{
|
|
1149
|
+
type: "functionResult",
|
|
1150
|
+
method: "focusNodeOnly",
|
|
1151
|
+
result: result,
|
|
1152
|
+
},
|
|
1153
|
+
"*"
|
|
1154
|
+
);
|
|
1155
|
+
return result;
|
|
1156
|
+
},
|
|
1157
|
+
};
|
|
1158
|
+
|
|
1159
|
+
methods.deselectExportNode = function (params) {
|
|
1160
|
+
if (params && params.nodeId !== undefined) {
|
|
1161
|
+
if (typeof window.deselectInputNode === "function") {
|
|
1162
|
+
window.deselectInputNode(params.nodeId);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
methods.clearExportNodes = function () {
|
|
1167
|
+
if (typeof window.clearExportNodes === "function") {
|
|
1168
|
+
window.clearExportNodes();
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
// 保存工作流的原始节点颜色信息
|
|
1172
|
+
methods.saveOriginalNodeColors = function (params) {
|
|
1173
|
+
if (typeof window.saveOriginalNodeColors === "function") {
|
|
1174
|
+
window.saveOriginalNodeColors(params.workflowId);
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
// 监听 Ctrl+Enter 快捷键执行工作流
|
|
1179
|
+
document.addEventListener("keydown", (event) => {
|
|
1180
|
+
if (event.ctrlKey && event.key === "Enter") {
|
|
1181
|
+
event.preventDefault();
|
|
1182
|
+
|
|
1183
|
+
// 节流:检查距离上次执行是否已经过了2秒
|
|
1184
|
+
const now = Date.now();
|
|
1185
|
+
if (now - lastRunWorkflowTime < THROTTLE_TIME) {
|
|
1186
|
+
console.log("触发频率过高,请稍后再试");
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
913
1189
|
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
type: 'collapseParamSelector',
|
|
917
|
-
method: 'collapseParamSelector',
|
|
918
|
-
result: true
|
|
919
|
-
}, '*');
|
|
1190
|
+
// 更新上次执行时间
|
|
1191
|
+
lastRunWorkflowTime = now;
|
|
920
1192
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1193
|
+
if (methods.runWorkflow) {
|
|
1194
|
+
window.parent.postMessage(
|
|
1195
|
+
{
|
|
1196
|
+
type: "functionResult",
|
|
1197
|
+
method: "ctrlEnter",
|
|
1198
|
+
result: true,
|
|
926
1199
|
},
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1200
|
+
"*"
|
|
1201
|
+
);
|
|
1202
|
+
methods.runWorkflow();
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
1206
|
+
|
|
1207
|
+
window.addEventListener("message", function (event) {
|
|
1208
|
+
if (event.data && event.data.type === "callMethod") {
|
|
1209
|
+
const methodName = event.data.method;
|
|
1210
|
+
const params = event.data.params || {};
|
|
1211
|
+
|
|
1212
|
+
if (methods[methodName]) {
|
|
1213
|
+
methods[methodName](params);
|
|
1214
|
+
} else {
|
|
1215
|
+
console.error("方法不存在:", methodName);
|
|
1216
|
+
window.parent.postMessage(
|
|
1217
|
+
{
|
|
1218
|
+
type: "functionResult",
|
|
1219
|
+
method: methodName,
|
|
1220
|
+
error: `方法 ${methodName} 不存在`,
|
|
1221
|
+
success: false,
|
|
945
1222
|
},
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
return result;
|
|
1223
|
+
"*"
|
|
1224
|
+
);
|
|
1225
|
+
window.parent.postMessage(
|
|
1226
|
+
{
|
|
1227
|
+
type: "functionResult",
|
|
1228
|
+
method: methodName,
|
|
1229
|
+
error: `方法 ${methodName} 不存在`,
|
|
1230
|
+
success: false,
|
|
955
1231
|
},
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
window.addEventListener('message', function (event) {
|
|
977
|
-
if (event.data && event.data.type === 'callMethod') {
|
|
978
|
-
const methodName = event.data.method;
|
|
979
|
-
const params = event.data.params || {};
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
if (methods[methodName]) {
|
|
984
|
-
methods[methodName](params);
|
|
985
|
-
} else {
|
|
986
|
-
console.error('方法不存在:', methodName);
|
|
987
|
-
window.parent.postMessage({
|
|
988
|
-
type: 'functionResult',
|
|
989
|
-
method: methodName,
|
|
990
|
-
error: `方法 ${methodName} 不存在`,
|
|
991
|
-
success: false
|
|
992
|
-
}, '*');
|
|
993
|
-
window.parent.postMessage({
|
|
994
|
-
type: 'functionResult',
|
|
995
|
-
method: methodName,
|
|
996
|
-
error: `方法 ${methodName} 不存在`,
|
|
997
|
-
success: false
|
|
998
|
-
}, '*');
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
});
|
|
1002
|
-
window.parent.postMessage({ type: 'iframeReady' }, '*');
|
|
1003
|
-
app.api.addEventListener('graphChanged', (e) => {
|
|
1004
|
-
console.log('Graph 发生变化,当前 workflow JSON:', e.detail)
|
|
1005
|
-
window.parent.postMessage({
|
|
1006
|
-
type: 'functionResult',
|
|
1007
|
-
method: 'workflowChanged',
|
|
1008
|
-
result: e.detail
|
|
1009
|
-
}, '*');
|
|
1010
|
-
|
|
1011
|
-
document.dispatchEvent(new CustomEvent('workflowLoaded', {
|
|
1012
|
-
detail: e.detail
|
|
1013
|
-
}));
|
|
1232
|
+
"*"
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
1237
|
+
window.parent.postMessage({ type: "iframeReady" }, "*");
|
|
1238
|
+
app.api.addEventListener("graphChanged", (e) => {
|
|
1239
|
+
console.log("Graph 发生变化,当前 workflow JSON:", e.detail);
|
|
1240
|
+
window.parent.postMessage(
|
|
1241
|
+
{
|
|
1242
|
+
type: "functionResult",
|
|
1243
|
+
method: "workflowChanged",
|
|
1244
|
+
result: e.detail,
|
|
1245
|
+
},
|
|
1246
|
+
"*"
|
|
1247
|
+
);
|
|
1248
|
+
|
|
1249
|
+
document.dispatchEvent(
|
|
1250
|
+
new CustomEvent("workflowLoaded", {
|
|
1251
|
+
detail: e.detail,
|
|
1014
1252
|
})
|
|
1015
|
-
|
|
1253
|
+
);
|
|
1254
|
+
});
|
|
1255
|
+
},
|
|
1016
1256
|
});
|