bizydraft 0.2.73.dev20251015100429__py3-none-any.whl → 0.2.75.dev20251022064022__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/hijack_nodes.py +29 -12
- bizydraft/hijack_routes.py +4 -1
- bizydraft/patch_handlers.py +83 -1
- bizydraft/static/js/hookLoadImage.js +145 -23
- bizydraft/static/js/hookLoadModel.js +9 -294
- {bizydraft-0.2.73.dev20251015100429.dist-info → bizydraft-0.2.75.dev20251022064022.dist-info}/METADATA +1 -1
- {bizydraft-0.2.73.dev20251015100429.dist-info → bizydraft-0.2.75.dev20251022064022.dist-info}/RECORD +9 -9
- {bizydraft-0.2.73.dev20251015100429.dist-info → bizydraft-0.2.75.dev20251022064022.dist-info}/WHEEL +0 -0
- {bizydraft-0.2.73.dev20251015100429.dist-info → bizydraft-0.2.75.dev20251022064022.dist-info}/top_level.txt +0 -0
bizydraft/hijack_nodes.py
CHANGED
|
@@ -20,34 +20,42 @@ class BizyDraftLoadVideo(LoadVideo):
|
|
|
20
20
|
super().__init__(*args, **kwargs)
|
|
21
21
|
|
|
22
22
|
@classmethod
|
|
23
|
-
def INPUT_TYPES(cls):
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
23
|
+
def INPUT_TYPES(cls, **kwargs):
|
|
24
|
+
# 调用父类方法,保持兼容性
|
|
25
|
+
return super().INPUT_TYPES(**kwargs)
|
|
27
26
|
|
|
28
27
|
@classmethod
|
|
29
28
|
def VALIDATE_INPUTS(s, *args, **kwargs):
|
|
30
29
|
return True
|
|
31
30
|
|
|
31
|
+
@classmethod
|
|
32
|
+
def validate_inputs(s, *args, **kwargs):
|
|
33
|
+
# V3 API 使用小写的 validate_inputs
|
|
34
|
+
return True
|
|
35
|
+
|
|
32
36
|
|
|
33
37
|
class BizyDraftLoadImage(LoadImage):
|
|
34
38
|
def __init__(self, *args, **kwargs):
|
|
35
39
|
super().__init__(*args, **kwargs)
|
|
36
40
|
|
|
37
41
|
@classmethod
|
|
38
|
-
def INPUT_TYPES(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
+
def INPUT_TYPES(cls, **kwargs):
|
|
43
|
+
# 调用父类方法,保持兼容性
|
|
44
|
+
return super().INPUT_TYPES(**kwargs)
|
|
42
45
|
|
|
43
46
|
@classmethod
|
|
44
47
|
def VALIDATE_INPUTS(s, *args, **kwargs):
|
|
45
48
|
return True
|
|
46
49
|
|
|
50
|
+
@classmethod
|
|
51
|
+
def validate_inputs(s, *args, **kwargs):
|
|
52
|
+
# V3 API 使用小写的 validate_inputs
|
|
53
|
+
return True
|
|
54
|
+
|
|
47
55
|
|
|
48
56
|
CLASS_PATCHES = {
|
|
49
|
-
#
|
|
50
|
-
#
|
|
57
|
+
# "LoadImage": BizyDraftLoadImage,
|
|
58
|
+
# "LoadVideo": BizyDraftLoadVideo,
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
|
|
@@ -62,7 +70,12 @@ def get_data_load_classes_from_url(config_url):
|
|
|
62
70
|
response = requests.get(config_url)
|
|
63
71
|
response.raise_for_status()
|
|
64
72
|
data = response.json()
|
|
65
|
-
keys_list =
|
|
73
|
+
keys_list = []
|
|
74
|
+
if "weight_load_nodes" in data:
|
|
75
|
+
keys_list.extend(list(data["weight_load_nodes"].keys()))
|
|
76
|
+
if "media_load_nodes" in data:
|
|
77
|
+
keys_list.extend(list(data["media_load_nodes"].keys()))
|
|
78
|
+
|
|
66
79
|
return keys_list
|
|
67
80
|
except Exception as e:
|
|
68
81
|
logger.error(
|
|
@@ -104,6 +117,7 @@ def hijack_nodes():
|
|
|
104
117
|
|
|
105
118
|
# 通用情况,正则匹配后,打通用patch、替换
|
|
106
119
|
for node_name, base_class in NODE_CLASS_MAPPINGS.items():
|
|
120
|
+
|
|
107
121
|
regex = r"^(?!BizyAir_)\w+.*Loader.*"
|
|
108
122
|
match = re.match(regex, node_name, re.IGNORECASE)
|
|
109
123
|
if (match and (node_name not in CLASS_PATCHES)) or (
|
|
@@ -116,7 +130,10 @@ def hijack_nodes():
|
|
|
116
130
|
|
|
117
131
|
def create_patched_class(base_class, validate_inputs_func=None):
|
|
118
132
|
class PatchedClass(base_class):
|
|
119
|
-
|
|
133
|
+
@classmethod
|
|
134
|
+
def validate_inputs(cls, *args, **kwargs):
|
|
135
|
+
# V3 API
|
|
136
|
+
return True
|
|
120
137
|
|
|
121
138
|
if validate_inputs_func:
|
|
122
139
|
PatchedClass.VALIDATE_INPUTS = classmethod(validate_inputs_func)
|
bizydraft/hijack_routes.py
CHANGED
|
@@ -2,7 +2,7 @@ from aiohttp import web
|
|
|
2
2
|
from loguru import logger
|
|
3
3
|
|
|
4
4
|
from bizydraft.oss_utils import upload_image, upload_mask
|
|
5
|
-
from bizydraft.patch_handlers import post_prompt, view_image
|
|
5
|
+
from bizydraft.patch_handlers import post_prompt, view_image, view_video
|
|
6
6
|
|
|
7
7
|
try:
|
|
8
8
|
from server import PromptServer
|
|
@@ -29,6 +29,8 @@ def hijack_routes_pre_add_routes():
|
|
|
29
29
|
("/api/prompt", "POST"): post_prompt,
|
|
30
30
|
("/api/upload/image", "POST"): upload_image,
|
|
31
31
|
("/api/upload/mask", "POST"): upload_mask,
|
|
32
|
+
# VHS plugin support
|
|
33
|
+
("/api/vhs/viewvideo", "GET"): view_video,
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
async def middleware_handler(request):
|
|
@@ -55,6 +57,7 @@ def hijack_routes_pre_add_routes():
|
|
|
55
57
|
"/view",
|
|
56
58
|
"/upload/image",
|
|
57
59
|
"/upload/mask",
|
|
60
|
+
"/vhs/viewvideo",
|
|
58
61
|
"/",
|
|
59
62
|
"/ws",
|
|
60
63
|
"/extensions",
|
bizydraft/patch_handlers.py
CHANGED
|
@@ -51,7 +51,11 @@ async def view_image(request):
|
|
|
51
51
|
try:
|
|
52
52
|
if "http" in subfolder:
|
|
53
53
|
subfolder = subfolder[subfolder.find("http") :]
|
|
54
|
-
subfolder = unquote(subfolder)
|
|
54
|
+
subfolder = unquote(subfolder)
|
|
55
|
+
if "https:/" in subfolder and not subfolder.startswith("https://"):
|
|
56
|
+
subfolder = subfolder.replace("https:/", "https://", 1)
|
|
57
|
+
if "http:/" in subfolder and not subfolder.startswith("http://"):
|
|
58
|
+
subfolder = subfolder.replace("http:/", "http://", 1)
|
|
55
59
|
filename = (
|
|
56
60
|
f"{subfolder}/{filename}"
|
|
57
61
|
if not filename.startswith(http_prefix_options)
|
|
@@ -124,6 +128,84 @@ def human_readable_size(size_bytes):
|
|
|
124
128
|
return f"{s} {size_name[i]}"
|
|
125
129
|
|
|
126
130
|
|
|
131
|
+
async def view_video(request):
|
|
132
|
+
"""处理VHS插件的viewvideo接口,支持从OSS URL加载视频"""
|
|
133
|
+
logger.debug(
|
|
134
|
+
f"Received request for /vhs/viewvideo with query: {request.rel_url.query}"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
if "filename" not in request.rel_url.query:
|
|
138
|
+
logger.warning("'filename' not provided in query string, returning 404")
|
|
139
|
+
return web.Response(status=404, text="'filename' not provided in query string")
|
|
140
|
+
|
|
141
|
+
# VHS插件的filename参数本身就是完整的URL(可能是URL编码的)
|
|
142
|
+
filename = unquote(request.rel_url.query["filename"])
|
|
143
|
+
|
|
144
|
+
http_prefix_options = ("http:", "https:")
|
|
145
|
+
|
|
146
|
+
if not filename.startswith(http_prefix_options):
|
|
147
|
+
logger.warning(f"Invalid filename format: {filename=}, only URLs are supported")
|
|
148
|
+
return web.Response(
|
|
149
|
+
status=400, text="Invalid filename format(only url supported)"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
content_type, _ = mimetypes.guess_type(filename)
|
|
154
|
+
|
|
155
|
+
timeout = ClientTimeout(total=BIZYDRAFT_REQUEST_TIMEOUT)
|
|
156
|
+
async with ClientSession(timeout=timeout) as session:
|
|
157
|
+
async with session.get(filename) as resp:
|
|
158
|
+
resp.raise_for_status()
|
|
159
|
+
|
|
160
|
+
# 优先使用服务器返回的Content-Type
|
|
161
|
+
final_content_type = (
|
|
162
|
+
resp.headers.get("Content-Type")
|
|
163
|
+
or content_type
|
|
164
|
+
or "application/octet-stream"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
content_length = int(resp.headers.get("Content-Length", 0))
|
|
168
|
+
if content_length > BIZYDRAFT_MAX_FILE_SIZE:
|
|
169
|
+
logger.warning(
|
|
170
|
+
f"File size {human_readable_size(content_length)} exceeds limit {human_readable_size(BIZYDRAFT_MAX_FILE_SIZE)}"
|
|
171
|
+
)
|
|
172
|
+
return web.Response(
|
|
173
|
+
status=413,
|
|
174
|
+
text=f"File size exceeds limit ({human_readable_size(BIZYDRAFT_MAX_FILE_SIZE)})",
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
headers = {
|
|
178
|
+
"Content-Disposition": f'attachment; filename="{uuid.uuid4()}"',
|
|
179
|
+
"Content-Type": final_content_type,
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
proxy_response = web.StreamResponse(headers=headers)
|
|
183
|
+
await proxy_response.prepare(request)
|
|
184
|
+
|
|
185
|
+
total_bytes = 0
|
|
186
|
+
async for chunk in resp.content.iter_chunked(BIZYDRAFT_CHUNK_SIZE):
|
|
187
|
+
total_bytes += len(chunk)
|
|
188
|
+
if total_bytes > BIZYDRAFT_MAX_FILE_SIZE:
|
|
189
|
+
await proxy_response.write(b"")
|
|
190
|
+
return web.Response(
|
|
191
|
+
status=413,
|
|
192
|
+
text=f"File size exceeds limit during streaming ({human_readable_size(BIZYDRAFT_MAX_FILE_SIZE)})",
|
|
193
|
+
)
|
|
194
|
+
await proxy_response.write(chunk)
|
|
195
|
+
|
|
196
|
+
return proxy_response
|
|
197
|
+
|
|
198
|
+
except asyncio.TimeoutError:
|
|
199
|
+
return web.Response(
|
|
200
|
+
status=504,
|
|
201
|
+
text=f"Request timed out (max {BIZYDRAFT_REQUEST_TIMEOUT//60} minutes)",
|
|
202
|
+
)
|
|
203
|
+
except Exception as e:
|
|
204
|
+
return web.Response(
|
|
205
|
+
status=502, text=f"Failed to fetch remote resource: {str(e)}"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
127
209
|
async def post_prompt(request):
|
|
128
210
|
json_data = await request.json()
|
|
129
211
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { app } from "../../scripts/app.js";
|
|
2
2
|
import { getCookie, computeIsLoadNode, computeExt, hideWidget } from './tool.js';
|
|
3
|
+
import { getMediaNodeConfig, getMediaInputKeys, possibleMediaWidgetNames } from './hookLoad/media.js';
|
|
3
4
|
|
|
4
5
|
|
|
6
|
+
console.log('hookLoadImage.js 已加载');
|
|
5
7
|
app.registerExtension({
|
|
6
8
|
name: "bizyair.image.to.oss",
|
|
7
9
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
|
10
|
+
console.log('beforeRegisterNodeDef 被调用,节点:', nodeData.name);
|
|
8
11
|
let workflowParams = null
|
|
9
12
|
document.addEventListener('workflowLoaded', (event) => {
|
|
10
13
|
workflowParams = event.detail;
|
|
@@ -30,15 +33,51 @@ app.registerExtension({
|
|
|
30
33
|
}
|
|
31
34
|
});
|
|
32
35
|
})
|
|
36
|
+
console.log('检查节点:', nodeData.name, '是否在loadNodeList中:', computeIsLoadNode(nodeData.name));
|
|
33
37
|
if (computeIsLoadNode(nodeData.name)) {
|
|
38
|
+
console.log('节点', nodeData.name, '被处理');
|
|
34
39
|
nodeType.prototype.onNodeCreated = async function() {
|
|
35
40
|
const apiHost = 'https://bizyair.cn/api'
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
// 优先使用 API 的媒体输入键匹配到具体的 widget;若未命中则回退到原有字段集合
|
|
42
|
+
let media_widget = null;
|
|
43
|
+
const mediaNodeConfig = await getMediaNodeConfig(nodeData.name);
|
|
44
|
+
const apiInputKeys = getMediaInputKeys(mediaNodeConfig);
|
|
45
|
+
if (apiInputKeys && apiInputKeys.length > 0) {
|
|
46
|
+
for (const key of apiInputKeys) {
|
|
47
|
+
const w = this.widgets.find(x => x.name === key);
|
|
48
|
+
if (w) { media_widget = w; break; }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!media_widget) {
|
|
52
|
+
media_widget = this.widgets.find(w => {
|
|
53
|
+
return possibleMediaWidgetNames.includes(w.name);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
// 查找所有name等于接口配置中inputs下的字段的widget(如video、audio等)
|
|
57
|
+
let va_widgets = [];
|
|
58
|
+
if (apiInputKeys && apiInputKeys.length > 0) {
|
|
59
|
+
for (const key of apiInputKeys) {
|
|
60
|
+
const w = this.widgets.find(x => x.name === key);
|
|
61
|
+
if (w) {
|
|
62
|
+
va_widgets.push(w);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 如果API配置没有找到,使用回退逻辑查找常见的媒体widget
|
|
68
|
+
if (va_widgets.length === 0) {
|
|
69
|
+
for (const widgetName of possibleMediaWidgetNames) {
|
|
70
|
+
const w = this.widgets.find(x => x.name === widgetName);
|
|
71
|
+
if (w) {
|
|
72
|
+
va_widgets.push(w);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log('节点名称:', nodeData.name);
|
|
78
|
+
console.log('apiInputKeys:', apiInputKeys);
|
|
79
|
+
console.log('找到的va_widgets:', va_widgets.map(w => w.name));
|
|
80
|
+
console.log('所有widgets:', this.widgets.map(w => w.name));
|
|
42
81
|
let image_name_widget = this.widgets.find(w => w.name === 'image_name');
|
|
43
82
|
let image_list = []
|
|
44
83
|
const getData = async () => {
|
|
@@ -65,21 +104,104 @@ app.registerExtension({
|
|
|
65
104
|
name: item.name
|
|
66
105
|
}
|
|
67
106
|
})
|
|
68
|
-
|
|
107
|
+
// 如果找到va_widgets,处理它们
|
|
108
|
+
if (va_widgets.length > 0) {
|
|
109
|
+
// 隐藏所有va_widgets
|
|
110
|
+
va_widgets.forEach(va_widget => {
|
|
111
|
+
hideWidget(this, va_widget.name);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// 创建image_name_widget来替代显示
|
|
115
|
+
if (!image_name_widget) {
|
|
116
|
+
image_name_widget = this.addWidget("combo", "image_name", "", function(e){
|
|
117
|
+
const item = image_list.find(item => item.name === e)
|
|
118
|
+
if (item) {
|
|
119
|
+
const image_url = decodeURIComponent(item.url);
|
|
120
|
+
// 更新所有va_widgets的值
|
|
121
|
+
va_widgets.forEach(va_widget => {
|
|
122
|
+
va_widget.value = image_url;
|
|
123
|
+
if (va_widget.callback) {
|
|
124
|
+
va_widget.callback(e);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}, {
|
|
129
|
+
serialize: true,
|
|
130
|
+
values: image_list.map(item => item.name)
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 为每个va_widget重写callback
|
|
135
|
+
va_widgets.forEach(va_widget => {
|
|
136
|
+
console.log('处理va_widget:', va_widget.name, '原始callback:', va_widget.callback);
|
|
137
|
+
|
|
138
|
+
// 保存va_widget的原始callback
|
|
139
|
+
const originalVaCallback = va_widget.callback;
|
|
140
|
+
|
|
141
|
+
// 重写va_widget的callback,当被触发时给image_name_widget赋值
|
|
142
|
+
va_widget.callback = function(e) {
|
|
143
|
+
console.log('va_widget callback被触发:', va_widget.name, '参数:', e);
|
|
144
|
+
|
|
145
|
+
// 调用原始callback
|
|
146
|
+
if (originalVaCallback) {
|
|
147
|
+
originalVaCallback(e);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 给image_name_widget赋值
|
|
151
|
+
if (image_name_widget) {
|
|
152
|
+
if (typeof e === 'string') {
|
|
153
|
+
const item = image_list.find(item => item.url === e);
|
|
154
|
+
if (item) {
|
|
155
|
+
image_name_widget.value = item.name;
|
|
156
|
+
} else {
|
|
157
|
+
// 如果没找到对应的item,尝试从URL中提取文件名
|
|
158
|
+
const fileName = e.split('/').pop();
|
|
159
|
+
image_name_widget.value = fileName;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// 监听widget的value变化
|
|
166
|
+
const originalSetValue = va_widget.setValue;
|
|
167
|
+
if (originalSetValue) {
|
|
168
|
+
va_widget.setValue = function(value) {
|
|
169
|
+
console.log('va_widget setValue被调用:', va_widget.name, '新值:', value);
|
|
170
|
+
originalSetValue.call(this, value);
|
|
171
|
+
|
|
172
|
+
// 当value变化时,更新image_name_widget
|
|
173
|
+
if (image_name_widget && value) {
|
|
174
|
+
if (typeof value === 'string') {
|
|
175
|
+
const item = image_list.find(item => item.url === value);
|
|
176
|
+
if (item) {
|
|
177
|
+
image_name_widget.value = item.name;
|
|
178
|
+
} else {
|
|
179
|
+
const fileName = value.split('/').pop();
|
|
180
|
+
image_name_widget.value = fileName;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 如果va_widgets没有创建image_name_widget,使用原有逻辑创建
|
|
190
|
+
if (!image_name_widget && media_widget) {
|
|
69
191
|
image_name_widget = this.addWidget("combo", "image_name", "", function(e){
|
|
70
192
|
const item = image_list.find(item => item.name === e)
|
|
71
193
|
const image_url = decodeURIComponent(item.url);
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
|
|
194
|
+
media_widget.value = image_url;
|
|
195
|
+
if (media_widget.callback) {
|
|
196
|
+
media_widget.callback(e);
|
|
75
197
|
}
|
|
76
198
|
}, {
|
|
77
199
|
serialize: true,
|
|
78
200
|
values: image_list.map(item => item.name)
|
|
79
201
|
});
|
|
80
202
|
}
|
|
81
|
-
const val = image_list.find(item => item.url ===
|
|
82
|
-
image_name_widget.label =
|
|
203
|
+
const val = image_list.find(item => item.url === media_widget.value)?.name || media_widget.value
|
|
204
|
+
image_name_widget.label = media_widget.label
|
|
83
205
|
image_name_widget.value = val
|
|
84
206
|
|
|
85
207
|
const currentIndex = this.widgets.indexOf(image_name_widget);
|
|
@@ -87,11 +209,11 @@ app.registerExtension({
|
|
|
87
209
|
this.widgets.splice(currentIndex, 1);
|
|
88
210
|
this.widgets.splice(1, 0, image_name_widget);
|
|
89
211
|
}
|
|
90
|
-
hideWidget(this,
|
|
91
|
-
|
|
212
|
+
hideWidget(this, media_widget.name)
|
|
213
|
+
media_widget.options.values = image_list.map(item => item.name);
|
|
92
214
|
|
|
93
|
-
const callback =
|
|
94
|
-
|
|
215
|
+
const callback = media_widget.callback
|
|
216
|
+
media_widget.callback = async function(e) {
|
|
95
217
|
if (typeof e == 'string') {
|
|
96
218
|
const item = e.includes('http') ?
|
|
97
219
|
image_list.find(item => item.url === e) :
|
|
@@ -100,7 +222,7 @@ app.registerExtension({
|
|
|
100
222
|
const image_url = item ? decodeURIComponent(item.url) : e;
|
|
101
223
|
|
|
102
224
|
image_name_widget.value = item ? item.name : e;
|
|
103
|
-
|
|
225
|
+
media_widget.value = image_url;
|
|
104
226
|
callback([image_url])
|
|
105
227
|
} else {
|
|
106
228
|
const item = e[0].split('/')
|
|
@@ -119,7 +241,7 @@ app.registerExtension({
|
|
|
119
241
|
await getData()
|
|
120
242
|
|
|
121
243
|
|
|
122
|
-
function applyWorkflowImageSettings(workflowParams, image_list,
|
|
244
|
+
function applyWorkflowImageSettings(workflowParams, image_list, media_widget, image_name_widget, currentNodeId) {
|
|
123
245
|
if (workflowParams && workflowParams.nodes) {
|
|
124
246
|
// 根据当前节点ID查找对应的节点数据,而不是总是选择第一个
|
|
125
247
|
const imageNode = workflowParams.nodes.find(item =>
|
|
@@ -131,23 +253,23 @@ app.registerExtension({
|
|
|
131
253
|
name: item[item.length - 1],
|
|
132
254
|
url: imageNode.widgets_values[0]
|
|
133
255
|
})
|
|
134
|
-
|
|
256
|
+
media_widget.value = imageNode.widgets_values[0]
|
|
135
257
|
|
|
136
|
-
|
|
258
|
+
media_widget.options.values = image_list.map(item => item.url)
|
|
137
259
|
image_name_widget.options.values = image_list.map(item => item.name)
|
|
138
|
-
|
|
260
|
+
media_widget.callback(imageNode.widgets_values[0])
|
|
139
261
|
}
|
|
140
262
|
}
|
|
141
263
|
}
|
|
142
264
|
|
|
143
265
|
// 如果有存储的工作流数据,应用图像设置
|
|
144
266
|
if (window.currentWorkflowData) {
|
|
145
|
-
applyWorkflowImageSettings(window.currentWorkflowData, image_list,
|
|
267
|
+
applyWorkflowImageSettings(window.currentWorkflowData, image_list, media_widget, image_name_widget, this.id);
|
|
146
268
|
// 清除存储的数据,避免重复处理
|
|
147
269
|
delete window.currentWorkflowData;
|
|
148
270
|
} else {
|
|
149
271
|
// 原有的调用
|
|
150
|
-
applyWorkflowImageSettings(workflowParams, image_list,
|
|
272
|
+
applyWorkflowImageSettings(workflowParams, image_list, media_widget, image_name_widget, this.id);
|
|
151
273
|
}
|
|
152
274
|
//在这里发个postmessage
|
|
153
275
|
window.parent.postMessage({
|
|
@@ -1,300 +1,15 @@
|
|
|
1
1
|
import { app } from "../../scripts/app.js";
|
|
2
2
|
import '../BizyAir/bizyair_frontend.js'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import {
|
|
4
|
+
getNodeConfig,
|
|
5
|
+
createSetWidgetCallback,
|
|
6
|
+
setupNodeMouseBehavior,
|
|
7
|
+
addBadge,
|
|
8
|
+
possibleWidgetNames
|
|
9
|
+
} from './hookLoad/model.js'
|
|
10
|
+
|
|
11
|
+
// 存储清理标志
|
|
8
12
|
let storageClearedOnce = false;
|
|
9
|
-
|
|
10
|
-
// API配置
|
|
11
|
-
const CONFIG_API_URL = 'https://bizyair.cn/api/special/comfyagent_node_config?t=' + Math.floor(Date.now() / 60000);
|
|
12
|
-
|
|
13
|
-
// 获取节点配置的API函数
|
|
14
|
-
async function fetchNodeConfig() {
|
|
15
|
-
if (nodeConfigCache) {
|
|
16
|
-
return nodeConfigCache;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (configLoadPromise) {
|
|
20
|
-
return configLoadPromise;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
configLoadPromise = (async () => {
|
|
24
|
-
try {
|
|
25
|
-
console.log('正在从API获取节点配置...');
|
|
26
|
-
const response = await fetch(CONFIG_API_URL, { credentials: 'include' });
|
|
27
|
-
|
|
28
|
-
if (!response.ok) {
|
|
29
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const result = await response.json();
|
|
33
|
-
|
|
34
|
-
if (result.code === 20000 && result.data && result.data.weight_load_nodes) {
|
|
35
|
-
nodeConfigCache = result.data.weight_load_nodes;
|
|
36
|
-
console.log('节点配置加载成功:', Object.keys(nodeConfigCache).length, '个节点');
|
|
37
|
-
return nodeConfigCache;
|
|
38
|
-
} else {
|
|
39
|
-
throw new Error('API返回数据格式不正确');
|
|
40
|
-
}
|
|
41
|
-
} catch (error) {
|
|
42
|
-
console.error('获取节点配置失败:', error);
|
|
43
|
-
nodeConfigCache = null;
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
})();
|
|
47
|
-
|
|
48
|
-
return configLoadPromise;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 启动时后台预取(不阻塞后续逻辑)
|
|
52
|
-
try { void fetchNodeConfig(); } catch (e) { /* noop */ }
|
|
53
|
-
|
|
54
|
-
const HAZY_WHITELIST_NODES = {
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const possibleWidgetNames=[
|
|
59
|
-
"clip_name",
|
|
60
|
-
"clip_name1",
|
|
61
|
-
"clip_name2",
|
|
62
|
-
"clip_name3",
|
|
63
|
-
"clip_name4",
|
|
64
|
-
"ckpt_name",
|
|
65
|
-
"lora_name",
|
|
66
|
-
"name",
|
|
67
|
-
"lora",
|
|
68
|
-
"lora_01",
|
|
69
|
-
"lora_02",
|
|
70
|
-
"lora_03",
|
|
71
|
-
"lora_04",
|
|
72
|
-
"lora_1_name",
|
|
73
|
-
"lora_2_name",
|
|
74
|
-
"lora_3_name",
|
|
75
|
-
"lora_4_name",
|
|
76
|
-
"lora_5_name",
|
|
77
|
-
"lora_6_name",
|
|
78
|
-
"lora_7_name",
|
|
79
|
-
"lora_8_name",
|
|
80
|
-
"lora_9_name",
|
|
81
|
-
"lora_10_name",
|
|
82
|
-
"lora_11_name",
|
|
83
|
-
"lora_12_name",
|
|
84
|
-
"model_name",
|
|
85
|
-
"control_net_name",
|
|
86
|
-
"ipadapter_file",
|
|
87
|
-
"unet_name",
|
|
88
|
-
"vae_name",
|
|
89
|
-
"model",
|
|
90
|
-
"model_name",
|
|
91
|
-
"instantid_file",
|
|
92
|
-
"pulid_file",
|
|
93
|
-
"style_model_name",
|
|
94
|
-
"yolo_model",
|
|
95
|
-
"face_model",
|
|
96
|
-
"bbox_model_name",
|
|
97
|
-
"sam_model_name",
|
|
98
|
-
"model_path",
|
|
99
|
-
"upscale_model",
|
|
100
|
-
"supir_model",
|
|
101
|
-
"sdxl_model",
|
|
102
|
-
"upscale_model_1",
|
|
103
|
-
"upscale_model_2",
|
|
104
|
-
"upscale_model_3",
|
|
105
|
-
"sam_model",
|
|
106
|
-
"sam2_model",
|
|
107
|
-
"grounding_dino_model"
|
|
108
|
-
]
|
|
109
|
-
|
|
110
|
-
// 读取 mode_type(不再兼容旧的 modelType)
|
|
111
|
-
function getModelTypeFromInput(inputConfig) {
|
|
112
|
-
console.log('inputConfig', inputConfig);
|
|
113
|
-
if (!inputConfig) return undefined;
|
|
114
|
-
console.log('inputConfig', inputConfig);
|
|
115
|
-
return inputConfig.mode_type;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// 根据节点名称获取节点配置信息(名单优先,正则补充;不阻塞返回)
|
|
119
|
-
async function getNodeConfig(nodeName) {
|
|
120
|
-
if (/bizyair/i.test(nodeName)) {
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// 1) 名单(API)优先(仅用缓存,不等待网络)
|
|
125
|
-
if (nodeConfigCache && nodeConfigCache[nodeName]) {
|
|
126
|
-
return { nodeName, config: nodeConfigCache[nodeName] };
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// 若尚未发起请求,后台发起一次
|
|
130
|
-
if (!configLoadPromise) { try { void fetchNodeConfig(); } catch (e) {} }
|
|
131
|
-
|
|
132
|
-
// 2) 正则补充:如 XxxLoader => Xxx(立即返回,不等待API)
|
|
133
|
-
const regex = /^(\w+).*Loader.*/i;
|
|
134
|
-
const match = nodeName.match(regex);
|
|
135
|
-
if (match) {
|
|
136
|
-
const inferredType = match[1];
|
|
137
|
-
return { nodeName, config: { inputs: { [nodeName]: { mode_type: inferredType, required: true } } } };
|
|
138
|
-
}
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function createSetWidgetCallback(nodeConfig, selectedBaseModels = []) {
|
|
143
|
-
return function setWidgetCallback() {
|
|
144
|
-
if (!nodeConfig || !nodeConfig.config || !nodeConfig.config.inputs) {
|
|
145
|
-
console.warn('节点配置无效:', nodeConfig);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const inputs = nodeConfig.config.inputs;
|
|
150
|
-
const inputKeys = Object.keys(inputs);
|
|
151
|
-
|
|
152
|
-
// 根据API配置找到对应的widget
|
|
153
|
-
const targetWidgets = [];
|
|
154
|
-
inputKeys.forEach(inputKey => {
|
|
155
|
-
const widget = this.widgets.find(w => w.name === inputKey);
|
|
156
|
-
if (widget) {
|
|
157
|
-
targetWidgets.push({
|
|
158
|
-
widget: widget,
|
|
159
|
-
inputKey: inputKey,
|
|
160
|
-
inputConfig: inputs[inputKey]
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
// 如果没有找到匹配的widget,使用原来的逻辑作为备选
|
|
166
|
-
if (targetWidgets.length === 0) {
|
|
167
|
-
const fallbackWidgets = this.widgets.filter(widget => possibleWidgetNames.includes(widget.name));
|
|
168
|
-
fallbackWidgets.forEach((wdt, index) => {
|
|
169
|
-
const firstInput = Object.values(inputs)[0];
|
|
170
|
-
if (firstInput) {
|
|
171
|
-
targetWidgets.push({
|
|
172
|
-
widget: wdt,
|
|
173
|
-
inputKey: wdt.name,
|
|
174
|
-
inputConfig: firstInput,
|
|
175
|
-
index: index
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
targetWidgets.forEach(({ widget, inputKey, inputConfig, index }) => {
|
|
182
|
-
// 检查是否禁用comfyagent
|
|
183
|
-
if (inputConfig.disable_comfyagent) {
|
|
184
|
-
console.log(`跳过禁用的widget: ${inputKey}`);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
widget.value = widget.value || "to choose";
|
|
189
|
-
widget.mouse = function(e, pos, canvas) {
|
|
190
|
-
try {
|
|
191
|
-
if (e.type === "pointerdown" || e.type === "mousedown" || e.type === "click" || e.type === "pointerup") {
|
|
192
|
-
e.preventDefault();
|
|
193
|
-
e.stopPropagation();
|
|
194
|
-
e.widgetClick = true;
|
|
195
|
-
window.parent.postMessage({
|
|
196
|
-
type: 'collapsePublishWorkflowDialog',
|
|
197
|
-
method: 'collapsePublishWorkflowDialog',
|
|
198
|
-
result: true
|
|
199
|
-
}, '*');
|
|
200
|
-
const currentNode = this.node;
|
|
201
|
-
|
|
202
|
-
if (!currentNode || !currentNode.widgets) {
|
|
203
|
-
console.warn("Node or widgets not available");
|
|
204
|
-
return false;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (typeof bizyAirLib !== 'undefined' && typeof bizyAirLib.showModelSelect === 'function') {
|
|
208
|
-
bizyAirLib.showModelSelect({
|
|
209
|
-
modelType: [getModelTypeFromInput(inputConfig)],
|
|
210
|
-
selectedBaseModels,
|
|
211
|
-
onApply: (version, model) => {
|
|
212
|
-
if (!currentNode || !currentNode.widgets) return;
|
|
213
|
-
|
|
214
|
-
// 更新widget值
|
|
215
|
-
widget.value = version.file_name;
|
|
216
|
-
|
|
217
|
-
// 找到对应的隐藏字段(固定命名:model_version_id, model_version_id2...)
|
|
218
|
-
let modelVersionField;
|
|
219
|
-
// 真实绑定顺序应与targetWidgets相同,因此通过当前widget在targetWidgets的索引定位
|
|
220
|
-
const twIndex = targetWidgets.findIndex(tw => tw.widget === widget);
|
|
221
|
-
const fieldName = twIndex === 0 ? "model_version_id" : `model_version_id${twIndex + 1}`;
|
|
222
|
-
modelVersionField = currentNode.widgets.find(w => w.name === fieldName);
|
|
223
|
-
|
|
224
|
-
if (model && modelVersionField && version) {
|
|
225
|
-
modelVersionField.value = version.id;
|
|
226
|
-
currentNode.setDirtyCanvas(true);
|
|
227
|
-
|
|
228
|
-
// 删除节点上的感叹号徽章
|
|
229
|
-
if (currentNode && currentNode.badges && Array.isArray(currentNode.badges)) {
|
|
230
|
-
// 移除 text 为 '!' 的徽章
|
|
231
|
-
currentNode.badges = currentNode.badges.filter(badgeFn => {
|
|
232
|
-
try {
|
|
233
|
-
const badge = typeof badgeFn === 'function' ? badgeFn() : badgeFn;
|
|
234
|
-
return badge.text !== '!';
|
|
235
|
-
} catch (e) {
|
|
236
|
-
return true;
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
// 同时移除 hasTips 标记
|
|
240
|
-
if (currentNode.hasTips) {
|
|
241
|
-
delete currentNode.hasTips;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
} else {
|
|
248
|
-
console.error("bizyAirLib not available");
|
|
249
|
-
}
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
} catch (error) {
|
|
253
|
-
console.error("Error handling mouse event:", error);
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
widget.options = widget.options || {};
|
|
258
|
-
widget.options.values = () => [];
|
|
259
|
-
widget.options.editable = false;
|
|
260
|
-
widget.clickable = true;
|
|
261
|
-
widget.processMouse = true;
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function setupNodeMouseBehavior(node, nodeConfig) {
|
|
267
|
-
// 固定隐藏主版本ID字段(其余编号字段为hidden类型本身不可见)
|
|
268
|
-
hideWidget(node, "model_version_id");
|
|
269
|
-
|
|
270
|
-
// 只设置必要的状态信息,不修改onMouseDown(已在上面的扩展中处理)
|
|
271
|
-
if (!node._bizyairState) {
|
|
272
|
-
node._bizyairState = {
|
|
273
|
-
lastClickTime: 0,
|
|
274
|
-
DEBOUNCE_DELAY: 300,
|
|
275
|
-
nodeConfig: nodeConfig
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
function addBadge(node) {
|
|
280
|
-
const customBadge = new LGraphBadge({
|
|
281
|
-
text: '!',
|
|
282
|
-
fgColor: 'white',
|
|
283
|
-
bgColor: '#FF6B6B',
|
|
284
|
-
fontSize: 12,
|
|
285
|
-
padding: 8,
|
|
286
|
-
height: 20,
|
|
287
|
-
cornerRadius: 10
|
|
288
|
-
})
|
|
289
|
-
if (!Array.isArray(node.badges)) {
|
|
290
|
-
node.badges = []
|
|
291
|
-
}
|
|
292
|
-
if (node.hasTips) {
|
|
293
|
-
return
|
|
294
|
-
}
|
|
295
|
-
node.badges.push(() => customBadge);
|
|
296
|
-
node.hasTips = true;
|
|
297
|
-
}
|
|
298
13
|
app.registerExtension({
|
|
299
14
|
name: "bizyair.hook.load.model",
|
|
300
15
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
{bizydraft-0.2.73.dev20251015100429.dist-info → bizydraft-0.2.75.dev20251022064022.dist-info}/RECORD
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
bizydraft/__init__.py,sha256=OM-sKCQrPh25nHVJIX-DgF1raMYyoWLSuyduIAHt0Gs,78
|
|
2
2
|
bizydraft/block_nodes.py,sha256=Lqn3oSCaGDHR2OICc8a2iRoRCVVK9v1-9MM3r-qIZgA,1092
|
|
3
3
|
bizydraft/env.py,sha256=VFmGopVL2TGWA6hwxyFhIglCEcQxy6iVvL_raMNd6u4,407
|
|
4
|
-
bizydraft/hijack_nodes.py,sha256=
|
|
5
|
-
bizydraft/hijack_routes.py,sha256=
|
|
4
|
+
bizydraft/hijack_nodes.py,sha256=riHsp4DhU60E60bfXUl8kVqjs1QvQWmx_FsgQAdWTa4,4197
|
|
5
|
+
bizydraft/hijack_routes.py,sha256=TVK7zdSIe4wN5dusjnAr1we43K6B_Zup5-dWcBj5rxo,3545
|
|
6
6
|
bizydraft/oss_utils.py,sha256=JHpMA61NxFzA053y8IzBc01xxMJCF6G2PTHk-rXqIFo,15590
|
|
7
|
-
bizydraft/patch_handlers.py,sha256=
|
|
7
|
+
bizydraft/patch_handlers.py,sha256=JWIEK4yKOPpzs3KLAiBCEYfBohyoVUOdlsVOTt3ULeY,9657
|
|
8
8
|
bizydraft/postload.py,sha256=XFElKcmCajT_oO7SVJJBaN04XcWro54N5HB5cSCxfvI,1308
|
|
9
9
|
bizydraft/prestartup_patch.py,sha256=4FGjmRcDHELjtlQOrfTfk2Un5OS89QIqfq-gEcB9WDs,998
|
|
10
10
|
bizydraft/resp.py,sha256=8INvKOe5Dgai3peKfqKjrhUoYeuXWXn358w30-_cY-A,369
|
|
@@ -15,8 +15,8 @@ bizydraft/static/js/clipspaceToOss.js,sha256=brfEPs71Tky5Dnc47UXNEFeFlESDE3kQvUH
|
|
|
15
15
|
bizydraft/static/js/disableComfyWebSocket.js,sha256=nL6DjLUdC2FlAqfYPaFW-dAtkamv01c461W0DUupIKk,1124
|
|
16
16
|
bizydraft/static/js/freezeModeHandler.js,sha256=SjpHD2nYymR-E13B0YcqkA6e4WycZOVI3c48Ts9qvWE,18027
|
|
17
17
|
bizydraft/static/js/handleStyle.js,sha256=liIzTu-wnV172g58gHWGLYTfd86xpJxL4A-HuHpFnq4,3616
|
|
18
|
-
bizydraft/static/js/hookLoadImage.js,sha256=
|
|
19
|
-
bizydraft/static/js/hookLoadModel.js,sha256=
|
|
18
|
+
bizydraft/static/js/hookLoadImage.js,sha256=SOxkmSO8gRiiTw9QZ_LzIGtnFFDkBTieG1f7ZfVF2b0,14980
|
|
19
|
+
bizydraft/static/js/hookLoadModel.js,sha256=TWVmfKp45ta-nE6U5rY3Bv9wiaEBp0QMNt2xaQ3fs9g,6720
|
|
20
20
|
bizydraft/static/js/main.js,sha256=PRe4LdsquEQWrZDnVd4ubpVQuD1eDIedAXFFazKdoKQ,188
|
|
21
21
|
bizydraft/static/js/nodeFocusHandler.js,sha256=24xXbS4Q-GjJdRqf11i-1pBo8MkOJ24F7MHFV44EG6Q,4683
|
|
22
22
|
bizydraft/static/js/nodeParamsFilter.js,sha256=H7lBB0G8HNqoGhOCH1hNXqPU-rPlrFyTxg_f_JgLEMk,4168
|
|
@@ -25,7 +25,7 @@ bizydraft/static/js/socket.js,sha256=VE3fTAgEfM0FZhL526Skt7OCRokOa3mzTCAjAomI_tE
|
|
|
25
25
|
bizydraft/static/js/tool.js,sha256=VupamUuh7tYiDnBTrL5Z_yLmhJinskhzRXwE3zfsKZM,2901
|
|
26
26
|
bizydraft/static/js/uploadFile.js,sha256=WvglKzHMeOzDhOH3P-fLcPHxCLbKOJpo4DntoRxeJtI,4908
|
|
27
27
|
bizydraft/static/js/workflow_io.js,sha256=FWAjncvWhvy-3nN_legD2fpRwgnIncpRLHU5X016a-U,5236
|
|
28
|
-
bizydraft-0.2.
|
|
29
|
-
bizydraft-0.2.
|
|
30
|
-
bizydraft-0.2.
|
|
31
|
-
bizydraft-0.2.
|
|
28
|
+
bizydraft-0.2.75.dev20251022064022.dist-info/METADATA,sha256=9iXlOl3FTtd_dIQof9KKldqObaSMZZWaEPbzV9wKaxA,180
|
|
29
|
+
bizydraft-0.2.75.dev20251022064022.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
30
|
+
bizydraft-0.2.75.dev20251022064022.dist-info/top_level.txt,sha256=XtoBq6hjZhXIM7aas4GtPDtAiKo8FdLzMABXW8qqQ8M,10
|
|
31
|
+
bizydraft-0.2.75.dev20251022064022.dist-info/RECORD,,
|
{bizydraft-0.2.73.dev20251015100429.dist-info → bizydraft-0.2.75.dev20251022064022.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|