bizydraft 0.2.71__py3-none-any.whl → 0.2.72.dev20251013093548__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.

@@ -29,7 +29,6 @@ BIZYDRAFT_CHUNK_SIZE = int(os.getenv("BIZYDRAFT_CHUNK_SIZE", 1024 * 16)) # 16KB
29
29
 
30
30
 
31
31
  async def view_image(request):
32
- from bizydraft.oss_utils import CLIPSPACE_TO_OSS_MAPPING
33
32
 
34
33
  logger.debug(f"Received request for /view with query: {request.rel_url.query}")
35
34
  if "filename" not in request.rel_url.query:
@@ -39,12 +38,6 @@ async def view_image(request):
39
38
  filename = request.rel_url.query["filename"]
40
39
  subfolder = request.rel_url.query.get("subfolder", "")
41
40
 
42
- if subfolder == "clipspace" and filename in CLIPSPACE_TO_OSS_MAPPING:
43
- oss_url = CLIPSPACE_TO_OSS_MAPPING[filename]
44
- logger.info(f"[OSS_MAPPING] Found clipspace mapping: {filename} -> {oss_url}")
45
- filename = oss_url
46
- subfolder = "" # Clear subfolder since filename is now the full URL
47
-
48
41
  http_prefix_options = ("http:", "https:")
49
42
 
50
43
  if not filename.startswith(http_prefix_options) and "http" not in subfolder:
@@ -3,129 +3,314 @@ import { api } from "../../scripts/api.js";
3
3
 
4
4
  window.CLIPSPACE_TO_OSS_MAP = window.CLIPSPACE_TO_OSS_MAP || {};
5
5
 
6
+ // ═══════════════════════════════════════════════════════════════════════════
7
+ // 工具函数:查找 clipspace 文件名对应的 OSS URL
8
+ // ═══════════════════════════════════════════════════════════════════════════
9
+ function findOssUrl(filename) {
10
+ return window.CLIPSPACE_TO_OSS_MAP[filename]
11
+ || window.CLIPSPACE_TO_OSS_MAP[`${filename} [input]`]
12
+ || window.CLIPSPACE_TO_OSS_MAP[`${filename} [output]`];
13
+ }
14
+
15
+ // 去掉末尾的 " [input]" 或 " [output]" 后缀
16
+ function stripTypeSuffix(value) {
17
+ if (!value || typeof value !== 'string') return value;
18
+ return value.replace(/\s\[(input|output)\]$/i, '');
19
+ }
20
+ // ═══════════════════════════════════════════════════════════════════════════
21
+ // 工具函数:替换 clipspace URL 为 OSS URL
22
+ // ═══════════════════════════════════════════════════════════════════════════
23
+ function replaceClipspaceUrl(urlString) {
24
+ if (!urlString || typeof urlString !== 'string') return urlString;
25
+ if (!urlString.includes('/view?') || !urlString.includes('clipspace')) return urlString;
26
+
27
+ try {
28
+ const url = new URL(urlString, window.location.origin);
29
+ const filename = url.searchParams.get('filename');
30
+ const subfolder = url.searchParams.get('subfolder');
31
+
32
+ if (subfolder === 'clipspace' && filename) {
33
+ const ossUrl = findOssUrl(filename);
34
+ if (ossUrl) {
35
+ url.searchParams.set('filename', ossUrl);
36
+ url.searchParams.set('subfolder', '');
37
+ return url.pathname + url.search;
38
+ }
39
+ }
40
+ } catch (e) {
41
+ console.error('[BizyDraft] Error replacing clipspace URL:', e);
42
+ }
43
+
44
+ return urlString;
45
+ }
6
46
 
47
+ // ═══════════════════════════════════════════════════════════════════════════
48
+ // 拦截图片加载请求,将 clipspace URL 替换为 OSS URL
49
+ // ═══════════════════════════════════════════════════════════════════════════
50
+ (function interceptImageLoading() {
51
+ const originalSrcDescriptor = Object.getOwnPropertyDescriptor(Image.prototype, 'src');
52
+
53
+ Object.defineProperty(Image.prototype, 'src', {
54
+ get() {
55
+ return originalSrcDescriptor.get.call(this);
56
+ },
57
+ set(value) {
58
+ const modifiedValue = replaceClipspaceUrl(value);
59
+ originalSrcDescriptor.set.call(this, modifiedValue);
60
+ },
61
+ configurable: true
62
+ });
63
+
64
+ const originalSetAttribute = HTMLImageElement.prototype.setAttribute;
65
+ HTMLImageElement.prototype.setAttribute = function(name, value) {
66
+ if (name === 'src') {
67
+ const modifiedValue = replaceClipspaceUrl(value);
68
+ return originalSetAttribute.call(this, name, modifiedValue);
69
+ }
70
+ return originalSetAttribute.call(this, name, value);
71
+ };
72
+ })();
73
+
74
+ // ═══════════════════════════════════════════════════════════════════════════
75
+ // 拦截上传响应,保存映射并篡改返回值
76
+ // ═══════════════════════════════════════════════════════════════════════════
7
77
  const originalFetchApi = api.fetchApi;
8
78
  api.fetchApi = async function(url, options) {
9
79
  const response = await originalFetchApi.call(this, url, options);
10
- console.log(url,'url--------------------');
11
- if ((url==='/upload/image' || url==='/upload/mask') && response.ok) {
12
- try {
13
- const clonedResponse = response.clone();
14
- const data = await clonedResponse.json();
15
-
16
- if (data && data.name && data.subfolder) {
17
- if (options && options.body && options.body instanceof FormData) {
18
- const imageFile = options.body.get('image');
19
- if (imageFile && imageFile.name) {
20
- const originalFilename = imageFile.name;
21
-
22
- let ossUrl;
23
- if (data.name.startsWith('http://') || data.name.startsWith('https://')) {
24
- ossUrl = data.name;
25
- } else if (data.subfolder && (data.subfolder.includes('http://') || data.subfolder.includes('https://'))) {
26
- ossUrl = `${data.subfolder}/${data.name}`;
27
- } else {
28
- return response;
29
- }
30
80
 
31
- window.CLIPSPACE_TO_OSS_MAP[originalFilename] = ossUrl;
81
+ const isUploadApi = url === '/upload/image' || url === '/upload/mask'
82
+ || url === '/api/upload/image' || url === '/api/upload/mask';
32
83
 
33
- const filenameWithoutSuffix = originalFilename.replace(/ \[(input|output)\]$/, '');
34
- if (filenameWithoutSuffix !== originalFilename) {
35
- window.CLIPSPACE_TO_OSS_MAP[filenameWithoutSuffix] = ossUrl;
36
- }
84
+ if (!isUploadApi || !response.ok) {
85
+ return response;
86
+ }
87
+ try {
88
+ const data = await response.clone().json();
89
+
90
+ // 检查是否是 OSS 上传响应
91
+ const isOssUpload = data.subfolder?.includes('http://') || data.subfolder?.includes('https://')
92
+ || data.name?.startsWith('http://') || data.name?.startsWith('https://');
93
+
94
+ if (!isOssUpload) return response;
95
+
96
+ // 构造完整的 OSS URL
97
+ const ossUrl = data.subfolder?.includes('http')
98
+ ? `${data.subfolder}/${data.name}`
99
+ : data.name;
100
+
101
+ // 处理映射逻辑
102
+ let finalUrl = ossUrl;
103
+
104
+ if (options?.body instanceof FormData) {
105
+ const imageFile = options.body.get('image');
106
+ if (imageFile?.name) {
107
+ const filename = imageFile.name;
108
+ const idMatch = filename.match(/(\d+)/);
109
+ const baseId = idMatch?.[1];
110
+
111
+ // 第一次 /upload/mask 的结果是涂改后的完整图片
112
+ if (baseId && url.includes('/upload/mask')) {
113
+ const firstMaskKey = `__FIRST_MASK_${baseId}__`;
114
+
115
+ if (!window.CLIPSPACE_TO_OSS_MAP[firstMaskKey]) {
116
+ // 首次 mask 上传,保存到所有变体
117
+ window.CLIPSPACE_TO_OSS_MAP[firstMaskKey] = ossUrl;
118
+ finalUrl = ossUrl;
119
+
120
+ [`clipspace-mask-${baseId}.png`, `clipspace-paint-${baseId}.png`,
121
+ `clipspace-painted-${baseId}.png`, `clipspace-painted-masked-${baseId}.png`
122
+ ].forEach(v => window.CLIPSPACE_TO_OSS_MAP[v] = ossUrl);
123
+
124
+ } else {
125
+ // 后续 mask 上传,使用首次的 URL
126
+ finalUrl = window.CLIPSPACE_TO_OSS_MAP[firstMaskKey];
127
+ }
128
+ } else if (baseId) {
129
+ // /upload/image 的上传,如果已有 mask 则使用 mask 的 URL
130
+ const firstMaskUrl = window.CLIPSPACE_TO_OSS_MAP[`__FIRST_MASK_${baseId}__`];
131
+ if (firstMaskUrl) {
132
+ finalUrl = firstMaskUrl;
37
133
  }
38
134
  }
135
+
136
+ // 保存映射
137
+ [filename, `${filename} [input]`, `${filename} [output]`].forEach(key => {
138
+ window.CLIPSPACE_TO_OSS_MAP[key] = finalUrl;
139
+ });
140
+
141
+ const filenameWithoutSuffix = filename.replace(/ \[(input|output)\]$/, '');
142
+ if (filenameWithoutSuffix !== filename) {
143
+ window.CLIPSPACE_TO_OSS_MAP[filenameWithoutSuffix] = finalUrl;
144
+ }
145
+
39
146
  }
40
- } catch (e) {
41
- console.warn('[BizyDraft ClipspaceToOss] Failed to parse upload response:', e);
42
147
  }
43
- }
44
148
 
45
- return response;
149
+ // 同时保存后端返回的文件名映射
150
+ window.CLIPSPACE_TO_OSS_MAP[data.name] = finalUrl;
151
+
152
+ // 🔧 修改 ComfyApp.clipspace,让它使用 OSS URL 而不是 clipspace 路径
153
+ if (window.app?.constructor?.clipspace) {
154
+ const clipspace = window.app.constructor.clipspace;
155
+
156
+ // 修改 clipspace.images
157
+ if (clipspace.images && clipspace.images.length > 0) {
158
+ const clipImage = clipspace.images[clipspace.selectedIndex || 0];
159
+ if (clipImage && clipImage.subfolder === 'clipspace') {
160
+ clipspace.images[clipspace.selectedIndex || 0] = {
161
+ filename: finalUrl,
162
+ subfolder: ''
163
+ };
164
+ }
165
+ }
166
+
167
+ // 修改 clipspace.widgets
168
+ if (clipspace.widgets) {
169
+ const imageWidgetIndex = clipspace.widgets.findIndex(w => w.name === 'image');
170
+ if (imageWidgetIndex >= 0) {
171
+ const widgetValue = clipspace.widgets[imageWidgetIndex].value;
172
+ if (widgetValue && typeof widgetValue === 'object' && widgetValue.subfolder === 'clipspace') {
173
+ clipspace.widgets[imageWidgetIndex].value = {
174
+ filename: finalUrl,
175
+ subfolder: ''
176
+ };
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ // 篡改响应,让 ComfyUI 使用完整的 OSS URL
183
+ const modifiedData = { ...data, name: finalUrl, subfolder: '' };
184
+ return new Response(JSON.stringify(modifiedData), {
185
+ status: response.status,
186
+ statusText: response.statusText,
187
+ headers: response.headers
188
+ });
189
+
190
+ } catch (e) {
191
+ console.error('[BizyDraft Upload] Error:', e);
192
+ return response;
193
+ }
46
194
  };
47
195
 
48
- /**
49
- * Convert clipspace paths to OSS URLs in a prompt object
50
- * @param {Object} prompt - The prompt object to process
51
- * @returns {Object} The processed prompt object
52
- */
196
+ // 转换 prompt 中的 clipspace 路径为 OSS URL
53
197
  function convertClipspacePathsInPrompt(prompt) {
54
198
  if (!prompt || typeof prompt !== 'object') {
55
199
  return prompt;
56
200
  }
57
201
 
58
- let conversionsCount = 0;
59
-
60
- // Iterate through all nodes in the prompt
61
202
  for (const [nodeId, node] of Object.entries(prompt)) {
62
- if (!node || !node.inputs) {
63
- continue;
64
- }
203
+ if (!node?.inputs) continue;
65
204
 
66
- // Check all input values
67
205
  for (const [inputKey, inputValue] of Object.entries(node.inputs)) {
68
206
  if (typeof inputValue === 'string' && inputValue.includes('clipspace')) {
69
- // Extract the filename from paths like:
70
- // "clipspace/clipspace-mask-12345.png [input]"
71
- // "clipspace/clipspace-painted-masked-12345.png [input]"
72
207
  const match = inputValue.match(/clipspace\/([\w-]+\.(?:png|jpg|jpeg|webp|gif))/i);
73
208
  if (match) {
74
- const filename = match[1]; // e.g., "clipspace-mask-12345.png"
75
-
76
- // Look for this filename in our mapping (with or without [input]/[output] suffix)
77
- const filenameWithInput = `${filename} [input]`;
78
- const filenameWithOutput = `${filename} [output]`;
79
-
80
- let ossUrl = window.CLIPSPACE_TO_OSS_MAP[filename]
81
- || window.CLIPSPACE_TO_OSS_MAP[filenameWithInput]
82
- || window.CLIPSPACE_TO_OSS_MAP[filenameWithOutput];
209
+ const filename = match[1];
210
+ const ossUrl = findOssUrl(filename);
83
211
 
84
212
  if (ossUrl) {
85
- console.log(`[BizyDraft ClipspaceToOss] Converting: ${inputValue} -> ${ossUrl}`);
86
213
  node.inputs[inputKey] = ossUrl;
87
214
 
88
- // Also update image_name if it exists
89
215
  if (inputKey === 'image' && node.inputs['image_name']) {
90
- // Extract just the filename from the OSS URL
91
- const ossFilename = ossUrl.split('/').pop();
92
- node.inputs['image_name'] = ossFilename;
93
- console.log(`[BizyDraft ClipspaceToOss] Also updated image_name to: ${ossFilename}`);
216
+ node.inputs['image_name'] = ossUrl.split('/').pop();
94
217
  }
95
-
96
- conversionsCount++;
97
- } else {
98
- console.warn(`[BizyDraft ClipspaceToOss] No OSS URL found for clipspace file: ${filename}`);
99
- console.warn('[BizyDraft ClipspaceToOss] Available mappings:', Object.keys(window.CLIPSPACE_TO_OSS_MAP));
100
218
  }
101
219
  }
102
220
  }
103
221
  }
104
222
  }
105
223
 
106
- if (conversionsCount > 0) {
107
- console.log(`[BizyDraft ClipspaceToOss] Converted ${conversionsCount} clipspace path(s) to OSS URLs`);
108
- }
109
-
110
224
  return prompt;
111
225
  }
112
226
 
227
+ // ═══════════════════════════════════════════════════════════════════════════
228
+ // 拦截 pasteFromClipspace,确保 widget.value 使用 OSS URL
229
+ // ═══════════════════════════════════════════════════════════════════════════
230
+ function interceptPasteFromClipspace() {
231
+ const ComfyApp = window.app?.constructor;
232
+ if (!ComfyApp || !ComfyApp.pasteFromClipspace) return;
233
+
234
+ const originalPasteFromClipspace = ComfyApp.pasteFromClipspace;
235
+ ComfyApp.pasteFromClipspace = function(node) {
236
+ // 调用原始函数
237
+ originalPasteFromClipspace.call(this, node);
238
+
239
+ // 修正 widget.value
240
+ if (node.widgets) {
241
+ const imageWidget = node.widgets.find(w => w.name === 'image');
242
+ if (imageWidget && typeof imageWidget.value === 'string') {
243
+ const value = imageWidget.value;
244
+
245
+ // 1) 如果是 clipspace 路径格式,替换为 OSS URL
246
+ if (value.includes('clipspace/')) {
247
+ // 提取文件名
248
+ const match = value.match(/clipspace\/([\w-]+\.(?:png|jpg|jpeg|webp|gif))(\s\[(input|output)\])?/i);
249
+ if (match) {
250
+ const filename = match[1];
251
+ const ossUrl = findOssUrl(filename);
252
+
253
+ if (ossUrl) {
254
+ imageWidget.value = ossUrl;
255
+ }
256
+ }
257
+ }
258
+ // 2) 如果是 "https://... [input]" 这样的字符串,移除后缀
259
+ else if (/https?:\/\/.*\.(png|jpg|jpeg|webp|gif)\s\[(input|output)\]$/i.test(value)) {
260
+ const cleaned = stripTypeSuffix(value);
261
+ if (cleaned !== value) {
262
+ imageWidget.value = cleaned;
263
+ }
264
+ }
265
+ }
266
+ }
267
+ };
268
+ }
269
+ // 注册 ComfyUI 扩展
113
270
  app.registerExtension({
114
271
  name: "bizyair.clipspace.to.oss",
115
272
 
116
273
  async setup() {
117
274
  const originalGraphToPrompt = app.graphToPrompt;
118
275
 
276
+ // 在构建 Prompt 之前,先清理所有 widget 的值,去掉多余的后缀
277
+ function sanitizeGraphWidgets(graph) {
278
+ const nodes = graph?._nodes || [];
279
+ for (const node of nodes) {
280
+ if (!node?.widgets) continue;
281
+ for (const widget of node.widgets) {
282
+ if (typeof widget?.value === 'string') {
283
+ widget.value = stripTypeSuffix(widget.value);
284
+ }
285
+ }
286
+ }
287
+ }
288
+
119
289
  app.graphToPrompt = async function(...args) {
120
- console.log('[BizyDraft ClipspaceToOss] graphToPrompt called, intercepting...');
290
+ // 预清理,避免 workflow.widgets_values prompt 输入里包含 [input]/[output]
291
+ try { sanitizeGraphWidgets(app.graph); } catch (e) {}
121
292
 
122
293
  const result = await originalGraphToPrompt.apply(this, args);
123
294
 
124
- if (result && result.output) {
125
- result.output = convertClipspacePathsInPrompt(result.output);
295
+ if (result?.output) {
296
+ // 二次清理并转换 clipspace
297
+ const cleaned = convertClipspacePathsInPrompt(result.output);
298
+ // 额外移除任何字符串输入中的类型后缀
299
+ for (const nodeId of Object.keys(cleaned || {})) {
300
+ const node = cleaned[nodeId];
301
+ if (!node?.inputs) continue;
302
+ for (const key of Object.keys(node.inputs)) {
303
+ const v = node.inputs[key];
304
+ node.inputs[key] = typeof v === 'string' ? stripTypeSuffix(v) : v;
305
+ }
306
+ }
307
+ result.output = cleaned;
126
308
  }
127
309
 
128
310
  return result;
129
311
  };
312
+
313
+ // 拦截 pasteFromClipspace
314
+ interceptPasteFromClipspace();
130
315
  }
131
316
  });
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bizydraft
3
- Version: 0.2.71
3
+ Version: 0.2.72.dev20251013093548
4
4
  Summary: bizydraft
5
5
  Requires-Dist: loguru
6
6
  Requires-Dist: aiohttp
@@ -4,14 +4,14 @@ bizydraft/env.py,sha256=VFmGopVL2TGWA6hwxyFhIglCEcQxy6iVvL_raMNd6u4,407
4
4
  bizydraft/hijack_nodes.py,sha256=GivcoUsYAOfMjoEMxeViEkSQlmYjMA0RORy04fCbG60,3652
5
5
  bizydraft/hijack_routes.py,sha256=wLu_PWUbUzhN2uZeayTAj1ShdLXVuKsp85a_FX1UCYY,3415
6
6
  bizydraft/oss_utils.py,sha256=JHpMA61NxFzA053y8IzBc01xxMJCF6G2PTHk-rXqIFo,15590
7
- bizydraft/patch_handlers.py,sha256=1aKOAAI1cCLBuQoym6le7GbW0rs_9_m_h7pCCg3xIz8,6574
7
+ bizydraft/patch_handlers.py,sha256=UQudnqKtDTYPnlS3Aq_k7txg7Je6ph9rkioou5-FgZI,6194
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
11
11
  bizydraft/server.py,sha256=L2zoJgOisr65IRphOyko74AdsLel59gh55peyMaUrO8,2102
12
12
  bizydraft/workflow_io.py,sha256=MYhJbpgkv8hrA5k_aolijOTrWpTtu62nzRznA4hv8JE,4298
13
13
  bizydraft/static/js/aiAppHandler.js,sha256=OQRhhoqvc8iZeCvHTtdaD2VTYBGzkeAGdCk1UMO2RZs,17525
14
- bizydraft/static/js/clipspaceToOss.js,sha256=l0mUiiTsbSZx1mNgDfT9WJaM9Ee-ebP2UcAwrnAquMQ,5355
14
+ bizydraft/static/js/clipspaceToOss.js,sha256=brfEPs71Tky5Dnc47UXNEFeFlESDE3kQvUH8ducpIew,14265
15
15
  bizydraft/static/js/freezeModeHandler.js,sha256=SjpHD2nYymR-E13B0YcqkA6e4WycZOVI3c48Ts9qvWE,18027
16
16
  bizydraft/static/js/handleStyle.js,sha256=liIzTu-wnV172g58gHWGLYTfd86xpJxL4A-HuHpFnq4,3616
17
17
  bizydraft/static/js/hookLoadImage.js,sha256=aFRWkgJW-Cp-YHjZh-3j-vsVcNaDZpBVoQqcFZ2Po0g,8186
@@ -24,7 +24,7 @@ bizydraft/static/js/socket.js,sha256=VE3fTAgEfM0FZhL526Skt7OCRokOa3mzTCAjAomI_tE
24
24
  bizydraft/static/js/tool.js,sha256=VupamUuh7tYiDnBTrL5Z_yLmhJinskhzRXwE3zfsKZM,2901
25
25
  bizydraft/static/js/uploadFile.js,sha256=WvglKzHMeOzDhOH3P-fLcPHxCLbKOJpo4DntoRxeJtI,4908
26
26
  bizydraft/static/js/workflow_io.js,sha256=FWAjncvWhvy-3nN_legD2fpRwgnIncpRLHU5X016a-U,5236
27
- bizydraft-0.2.71.dist-info/METADATA,sha256=oGd700wcCxrsNZSUgsP7MdtRSHoGusF2A3FUdvuDfcI,162
28
- bizydraft-0.2.71.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
- bizydraft-0.2.71.dist-info/top_level.txt,sha256=XtoBq6hjZhXIM7aas4GtPDtAiKo8FdLzMABXW8qqQ8M,10
30
- bizydraft-0.2.71.dist-info/RECORD,,
27
+ bizydraft-0.2.72.dev20251013093548.dist-info/METADATA,sha256=adyjKN3BUqPvC7yvp1ogpPph11xRzLAk9ovHQv9Nprc,180
28
+ bizydraft-0.2.72.dev20251013093548.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
+ bizydraft-0.2.72.dev20251013093548.dist-info/top_level.txt,sha256=XtoBq6hjZhXIM7aas4GtPDtAiKo8FdLzMABXW8qqQ8M,10
30
+ bizydraft-0.2.72.dev20251013093548.dist-info/RECORD,,