bizydraft 0.1.0__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/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+
2
+ from .hijack_nodes import hijack_nodes
3
+
4
+ __all__ = [
5
+ "hijack_nodes",
6
+ ]
@@ -0,0 +1,27 @@
1
+ from loguru import logger
2
+
3
+ try:
4
+ from nodes import NODE_CLASS_MAPPINGS, LoadImage
5
+ except ImportError:
6
+ logger.error(
7
+ "failed to import ComfyUI nodes modules, ensure PYTHONPATH is set correctly. (export PYTHONPATH=$PYTHONPATH:/path/to/ComfyUI)"
8
+ )
9
+ exit(1)
10
+
11
+ class BizyDraftLoadImage(LoadImage):
12
+ def __init__(self, *args, **kwargs):
13
+ super().__init__(*args, **kwargs)
14
+
15
+ @classmethod
16
+ def VALIDATE_INPUTS(s, image, *args, **kwargs):
17
+ return True
18
+
19
+
20
+ def hijack_nodes():
21
+ if "LoadImage" in NODE_CLASS_MAPPINGS:
22
+ del NODE_CLASS_MAPPINGS["LoadImage"]
23
+ NODE_CLASS_MAPPINGS["LoadImage"] = BizyDraftLoadImage
24
+
25
+ logger.info(
26
+ "[BizyDraft] Hijacked LoadImage node to BizyDraftLoadImage."
27
+ )
@@ -0,0 +1,165 @@
1
+ import math
2
+ import os
3
+ import asyncio
4
+ import mimetypes
5
+ import uuid
6
+
7
+ from aiohttp import web, ClientSession, ClientTimeout
8
+ from loguru import logger
9
+
10
+ try:
11
+ from server import PromptServer
12
+ import execution
13
+
14
+ comfy_server = PromptServer.instance
15
+ except ImportError:
16
+ logger.error(
17
+ "failed to import ComfyUI modules, ensure PYTHONPATH is set correctly. (export PYTHONPATH=$PYTHONPATH:/path/to/ComfyUI)"
18
+ )
19
+ exit(1)
20
+
21
+
22
+ BIZYDRAFT_MAX_FILE_SIZE = int(
23
+ os.getenv("BIZYDRAFT_MAX_FILE_SIZE", 100 * 1024 * 1024)
24
+ ) # 100MB
25
+ BIZYDRAFT_REQUEST_TIMEOUT = int(
26
+ os.getenv("BIZYDRAFT_REQUEST_TIMEOUT", 20 * 60)
27
+ ) # 20分钟
28
+ BIZYDRAFT_CHUNK_SIZE = int(os.getenv("BIZYDRAFT_CHUNK_SIZE", 1024 * 16)) # 16KB
29
+
30
+
31
+ async def view_image(request, old_handler):
32
+ logger.debug(
33
+ f"Received request for /view with query: {request.rel_url.query}"
34
+ )
35
+ if "filename" not in request.rel_url.query:
36
+ logger.warning("'filename' not provided in query string, returning 404")
37
+ return web.Response(status=404, text="'filename' not provided in query string")
38
+
39
+ filename = request.rel_url.query["filename"]
40
+ subfolder = request.rel_url.query.get("subfolder", "")
41
+
42
+ if not filename.startswith(("http://", "https://")) and not subfolder.startswith(
43
+ ("http://", "https://")
44
+ ):
45
+ logger.warning(f"Invalid filename format: {filename}, only URLs are supported")
46
+ return web.Response(
47
+ status=400, text="Invalid filename format(only url supported)"
48
+ )
49
+
50
+ try:
51
+ filename = (
52
+ f"{subfolder}/{filename}"
53
+ if not filename.startswith(("http://", "https://"))
54
+ else filename
55
+ ) # preview 3d request: https://host:port/api/view?filename=filename.glb&type=output&subfolder=https://bizyair-dev.oss-cn-shanghai.aliyuncs.com/outputs&rand=0.5763957215362988
56
+
57
+ content_type, _ = mimetypes.guess_type(filename)
58
+ if content_type and any(x in content_type for x in ("image", "video")):
59
+ return web.HTTPFound(filename)
60
+
61
+ timeout = ClientTimeout(total=BIZYDRAFT_REQUEST_TIMEOUT)
62
+ async with ClientSession(timeout=timeout) as session:
63
+ async with session.get(filename) as resp:
64
+ resp.raise_for_status()
65
+ content_length = int(resp.headers.get("Content-Length", 0))
66
+ if content_length > BIZYDRAFT_MAX_FILE_SIZE:
67
+ logger.warning(
68
+ f"File size {human_readable_size(content_length)} exceeds limit {human_readable_size(BIZYDRAFT_MAX_FILE_SIZE)}"
69
+ )
70
+ return web.Response(
71
+ status=413,
72
+ text=f"File size exceeds limit ({human_readable_size(BIZYDRAFT_MAX_FILE_SIZE)})",
73
+ )
74
+
75
+ headers = {
76
+ "Content-Disposition": f'attachment; filename="{uuid.uuid4()}"',
77
+ "Content-Type": "application/octet-stream",
78
+ }
79
+
80
+ proxy_response = web.StreamResponse(headers=headers)
81
+ await proxy_response.prepare(request)
82
+
83
+ total_bytes = 0
84
+ async for chunk in resp.content.iter_chunked(BIZYDRAFT_CHUNK_SIZE):
85
+ total_bytes += len(chunk)
86
+ if total_bytes > BIZYDRAFT_MAX_FILE_SIZE:
87
+ await proxy_response.write(b"")
88
+ return web.Response(
89
+ status=413,
90
+ text=f"File size exceeds limit during streaming ({human_readable_size(BIZYDRAFT_MAX_FILE_SIZE)})",
91
+ )
92
+ await proxy_response.write(chunk)
93
+
94
+ return proxy_response
95
+
96
+ except asyncio.TimeoutError:
97
+ return web.Response(
98
+ status=504,
99
+ text=f"Request timed out (max {BIZYDRAFT_REQUEST_TIMEOUT//60} minutes)",
100
+ )
101
+ except Exception as e:
102
+ return web.Response(
103
+ status=502, text=f"Failed to fetch remote resource: {str(e)}"
104
+ )
105
+
106
+
107
+ def human_readable_size(size_bytes):
108
+ if size_bytes == 0:
109
+ return "0B"
110
+ size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
111
+ i = int(math.floor(math.log(size_bytes, 1024)))
112
+ p = math.pow(1024, i)
113
+ s = round(size_bytes / p, 2)
114
+ return f"{s} {size_name[i]}"
115
+
116
+
117
+ async def post_prompt(request):
118
+ json_data = await request.json()
119
+ logger.debug(f"Received POST request to /prompt with data: {json_data}")
120
+ json_data = comfy_server.trigger_on_prompt(json_data)
121
+
122
+ if "prompt" in json_data:
123
+ prompt = json_data["prompt"]
124
+ valid = execution.validate_prompt(prompt)
125
+ if valid[0]:
126
+ response = {
127
+ "prompt_id": None,
128
+ "number": None,
129
+ "node_errors": valid[3],
130
+ }
131
+ return web.json_response(response)
132
+ else:
133
+ return web.json_response(
134
+ {"error": valid[1], "node_errors": valid[3]}, status=400
135
+ )
136
+ else:
137
+ error = {
138
+ "type": "no_prompt",
139
+ "message": "No prompt provided",
140
+ "details": "No prompt provided",
141
+ "extra_info": {},
142
+ }
143
+ return web.json_response({"error": error, "node_errors": {}}, status=400)
144
+
145
+
146
+ def hijack_routes():
147
+ routes = comfy_server.routes
148
+ for idx, route in enumerate(routes._items):
149
+ if route.path == "/view" and route.method == "GET":
150
+ old_handler = route.handler
151
+
152
+ async def new_handler(request):
153
+ return await view_image(request, old_handler)
154
+
155
+ routes._items[idx] = web.get("/view", new_handler)
156
+ routes._items[idx].kwargs.clear()
157
+ logger.info(
158
+ "Hijacked /view route to handle image, video and 3D streaming"
159
+ )
160
+ break
161
+ for idx, route in enumerate(routes._items):
162
+ if route.path == "/prompt" and route.method == "POST":
163
+ routes._items[idx] = web.post("/prompt", post_prompt)
164
+ logger.info("Hijacked /prompt route to handle prompt validation but not execution")
165
+ break
bizydraft/resp.py ADDED
@@ -0,0 +1,17 @@
1
+ from aiohttp import web
2
+
3
+
4
+ def JsonResponse(http_status_code, data):
5
+ return web.json_response(
6
+ data,
7
+ status=http_status_code,
8
+ content_type="application/json",
9
+ )
10
+
11
+
12
+ def OKResponse():
13
+ return JsonResponse(200, {"message": "success", "data": {}})
14
+
15
+
16
+ def ErrResponse(err_code):
17
+ return JsonResponse(err_code, {"message": "", "data": {}})
bizydraft/server.py ADDED
@@ -0,0 +1,41 @@
1
+ import os
2
+
3
+ from loguru import logger
4
+
5
+ try:
6
+ from server import PromptServer
7
+ except ImportError:
8
+ logger.error(
9
+ "Failed to import ComfyUI server modules, ensure PYTHONPATH is set correctly. (export PYTHONPATH=$PYTHONPATH:/path/to/ComfyUI)"
10
+ )
11
+ exit(1)
12
+
13
+
14
+ from .resp import OKResponse, ErrResponse
15
+
16
+ _API_PREFIX = "bizyair"
17
+ _SERVER_MODE_HC_FLAG = True
18
+
19
+ BIZYAIR_MAGIC_STRING = os.getenv("BIZYAIR_MAGIC_STRING", "QtDtsxAc8JI1bTb7")
20
+
21
+
22
+ class BizyDraftServer:
23
+ def __init__(self):
24
+ BizyDraftServer.instance = self
25
+ self.prompt_server = PromptServer.instance
26
+ self.setup_routes()
27
+
28
+ def setup_routes(self):
29
+ @self.prompt_server.routes.get(f"/{_API_PREFIX}/are_you_alive")
30
+ async def are_you_alive(request):
31
+ if _SERVER_MODE_HC_FLAG:
32
+ return OKResponse()
33
+ return ErrResponse(500)
34
+
35
+ @self.prompt_server.routes.post(
36
+ f"/{_API_PREFIX}/are_you_alive_{BIZYAIR_MAGIC_STRING}"
37
+ )
38
+ async def toggle_are_you_alive(request):
39
+ global _SERVER_MODE_HC_FLAG
40
+ _SERVER_MODE_HC_FLAG = not _SERVER_MODE_HC_FLAG
41
+ return OKResponse()
@@ -0,0 +1,49 @@
1
+ import { app } from "../../scripts/app.js";
2
+ import { $el } from "../../scripts/ui.js";
3
+ const styleMenus = `
4
+ .p-panel-content-container{
5
+ display: none;
6
+ }
7
+ // .side-tool-bar-container.small-sidebar{
8
+ // display: none;
9
+ // }
10
+ .comfyui-menu.flex.items-center{
11
+ display: none;
12
+ }
13
+ .p-dialog-mask.p-overlay-mask.p-overlay-mask-enter.p-dialog-bottomright{
14
+ display: none !important;
15
+ }
16
+ body .bizyair-comfy-floating-button{
17
+ display: none;
18
+ }
19
+ .bizy-select-title-container{
20
+ display: none;
21
+ }
22
+ .p-button.p-component.p-button-outlined.p-button-sm{
23
+ display: none;
24
+ }
25
+ .workflow-tabs-container{
26
+ display: none;
27
+ }
28
+ body .comfyui-body-bottom{
29
+ display: none;
30
+ }
31
+ #comfyui-body-bottom{
32
+ display: none;
33
+ }
34
+ .p-dialog-mask.p-overlay-mask.p-overlay-mask-enter{
35
+ display: none !important;
36
+ }
37
+ `
38
+ app.registerExtension({
39
+ name: "comfy.BizyAir.Style",
40
+ async setup() {
41
+ $el("style", {
42
+ textContent: styleMenus,
43
+ parent: document.head,
44
+ });
45
+ window.addEventListener('load', () => {
46
+ document.querySelector('[data-pc-section=mask]').style.display = 'none'
47
+ });
48
+ },
49
+ });
@@ -0,0 +1,99 @@
1
+ import { app } from "../../scripts/app.js";
2
+ import { fileToOss } from "./uploadFile.js";
3
+ import { getCookie } from './tool.js';
4
+
5
+ app.registerExtension({
6
+ name: "bizyair.image.to.oss",
7
+ async beforeRegisterNodeDef(nodeType, nodeData) {
8
+ if (nodeData.name === 'LoadImage') {
9
+ nodeType.prototype.onNodeCreated = async function() {
10
+ // const apiHost = 'http://localhost:3000/api'
11
+ const apiHost = 'https://uat87.bizyair.cn/api'
12
+ const getData = async () => {
13
+ const res = await fetch(`${apiHost}/community/commit_input_resource?${
14
+ new URLSearchParams({
15
+ url: '',
16
+ ext: '',
17
+ current: 1,
18
+ page_size: 100
19
+
20
+ }).toString()
21
+ }`, {
22
+ method: 'GET',
23
+ headers: {
24
+ 'Content-Type': 'application/json',
25
+ 'Authorization': `Bearer ${getCookie('bizy_token')}`
26
+ }
27
+ })
28
+ const {data} = await res.json()
29
+ const list = data.data.data.list || []
30
+ const image_list = list.filter(item => item.name).map(item => {
31
+ return {
32
+ url: item.url,
33
+ name: item.name
34
+ }
35
+ // return item.url
36
+ })
37
+ const image_widget = this.widgets.find(w => w.name === 'image');
38
+
39
+ const node = this;
40
+
41
+ image_widget.options.values = image_list.map(item => item.name);
42
+
43
+ // image_widget.value = image_list[0].url;
44
+ // image_widget.value = image_list[0];
45
+ if (image_list[0] && image_list[0].url) {
46
+ previewImage(node, decodeURIComponent(image_list[0].url))
47
+ }
48
+ image_widget.callback = function(e) {
49
+ const image_url = decodeURIComponent(image_list.find(item => item.name === e).url);
50
+ previewImage(node, image_url)
51
+ }
52
+ }
53
+ getData()
54
+
55
+
56
+ const upload_widget = this.widgets.find(w => w.name === 'upload');
57
+ upload_widget.callback = async function() {
58
+ const input = document.createElement('input');
59
+ input.type = 'file';
60
+ input.accept = 'image/*';
61
+ input.onchange = async (e) => {
62
+ const file = e.target.files[0];
63
+ await fileToOss(file);
64
+
65
+ getData()
66
+ }
67
+ input.click();
68
+ }
69
+ }
70
+ }
71
+ }
72
+ })
73
+
74
+ function previewImage(node, image_url) {
75
+ const img = new Image();
76
+ img.onload = function() {
77
+ node.imgs = [img];
78
+ if (node.graph) {
79
+ node.graph.setDirtyCanvas(true);
80
+ } else {
81
+ console.warn('[BizyAir] 无法访问graph对象进行重绘');
82
+ }
83
+ const imageOutputStore =
84
+ node.nodeOutputStore ||
85
+ window.app?.nodeOutputStore ||
86
+ app?.nodeOutputStore;
87
+
88
+ if (imageOutputStore) {
89
+ console.log('[BizyAir] 设置节点输出数据');
90
+ imageOutputStore.setNodeOutputs(node, image_url, { isAnimated: false });
91
+ } else {
92
+ console.warn('[BizyAir] 未找到nodeOutputStore');
93
+ }
94
+ };
95
+ img.onerror = function(err) {
96
+ console.error('[BizyAir] 图片加载失败:', image_url, err);
97
+ };
98
+ img.src = image_url;
99
+ }
@@ -0,0 +1,5 @@
1
+ // 主入口文件,导入所有模块
2
+ import "./hookLoadImage.js";
3
+ import "./hookSaveImage.js";
4
+ import "./postEvent.js";
5
+ import "./handleStyle.js";
@@ -0,0 +1,412 @@
1
+ import { app } from "../../scripts/app.js";
2
+ // import { $el } from "../../scripts/ui.js";
3
+
4
+ // import { WebSocketClient } from './socket.js';
5
+
6
+
7
+
8
+ app.registerExtension({
9
+ name: "comfy.BizyAir.Socket",
10
+
11
+ dispatchCustomEvent(type, detail) {
12
+ app.api.dispatchCustomEvent(type, detail);
13
+ },
14
+
15
+ customSocket(callback, customUrl) {
16
+ const url = customUrl || app.api.socket.url;
17
+ // const clientId = 'e07abdf5f465462f8dc43ca0812e9284';
18
+ // const socket = new WebSocket(url + "?clientId=" + sessionStorage.getItem("clientId"));
19
+ // const socket = new WebSocket(url + "?clientId=" + clientId);
20
+ const socket = new WebSocket(url);
21
+
22
+ const dispatchCustomEvent = this.dispatchCustomEvent;
23
+
24
+ socket.onmessage = function (event) {
25
+ try {
26
+ if (event.data instanceof ArrayBuffer) {
27
+ const view = new DataView(event.data);
28
+ const eventType = view.getUint32(0);
29
+
30
+ let imageMime;
31
+ switch (eventType) {
32
+ case 3:
33
+ const decoder = new TextDecoder();
34
+ const data = event.data.slice(4);
35
+ const nodeIdLength = view.getUint32(4);
36
+ dispatchCustomEvent('progress_text', {
37
+ nodeId: decoder.decode(data.slice(4, 4 + nodeIdLength)),
38
+ text: decoder.decode(data.slice(4 + nodeIdLength))
39
+ });
40
+ break;
41
+ case 1:
42
+ const imageType = view.getUint32(4);
43
+ const imageData = event.data.slice(8);
44
+ switch (imageType) {
45
+ case 2:
46
+ imageMime = 'image/png';
47
+ break;
48
+ case 1:
49
+ default:
50
+ imageMime = 'image/jpeg';
51
+ break;
52
+ }
53
+ const imageBlob = new Blob([imageData], {
54
+ type: imageMime
55
+ });
56
+ dispatchCustomEvent('b_preview', imageBlob);
57
+ break;
58
+ default:
59
+ throw new Error(
60
+ `Unknown binary websocket message of type ${eventType}`
61
+ );
62
+ }
63
+ } else {
64
+ const msg = JSON.parse(event.data);
65
+ switch (msg.type) {
66
+ case 'status':
67
+ if (msg.data.sid) {
68
+ const clientId = msg.data.sid;
69
+ window.name = clientId; // use window name so it isnt reused when duplicating tabs
70
+ sessionStorage.setItem('clientId', clientId); // store in session storage so duplicate tab can load correct workflow
71
+ socket.clientId = clientId;
72
+ }
73
+ dispatchCustomEvent('status', msg.data.status ?? null);
74
+ break;
75
+ case 'executing':
76
+ // msg.data.prompt_id && (msg.data.prompt_id = '');
77
+
78
+ dispatchCustomEvent(
79
+ 'executing',
80
+ msg.data.display_node || msg.data.node
81
+ );
82
+ break;
83
+ case 'execution_start':
84
+ case 'execution_error':
85
+ case 'execution_interrupted':
86
+ case 'execution_cached':
87
+ case 'execution_success':
88
+ case 'progress':
89
+ case 'executed':
90
+ case 'graphChanged':
91
+ case 'promptQueued':
92
+ case 'logs':
93
+ case 'b_preview':
94
+ dispatchCustomEvent(msg.type, msg.data);
95
+ break;
96
+ default:
97
+ const registeredTypes = socket.registeredTypes || new Set();
98
+ const reportedUnknownMessageTypes = socket.reportedUnknownMessageTypes || new Set();
99
+
100
+ if (registeredTypes.has(msg.type)) {
101
+ app.dispatchEvent(
102
+ new CustomEvent(msg.type, { detail: msg.data })
103
+ );
104
+ } else if (!reportedUnknownMessageTypes.has(msg.type)) {
105
+ reportedUnknownMessageTypes.add(msg.type);
106
+ console.warn(`Unknown message type ${msg.type}`);
107
+ }
108
+ }
109
+ }
110
+ } catch (error) {
111
+ console.warn('Unhandled message:', event.data, error);
112
+ }
113
+ };
114
+
115
+ socket.registeredTypes = new Set();
116
+ socket.reportedUnknownMessageTypes = new Set();
117
+
118
+ // 替换app.api.socket
119
+ app.api.socket = socket;
120
+
121
+ if (typeof callback === 'function') {
122
+ callback(socket);
123
+ }
124
+
125
+ return socket;
126
+ },
127
+
128
+ startSocket(callback) {
129
+ if (app.api.socket.readyState === WebSocket.CLOSED || app.api.socket.readyState === WebSocket.CLOSING) {
130
+ return this.customSocket(callback);
131
+ }
132
+ return app.api.socket;
133
+ },
134
+
135
+ closeSocket() {
136
+ if (app.api.socket && (app.api.socket.readyState === WebSocket.OPEN || app.api.socket.readyState === WebSocket.CONNECTING)) {
137
+ app.api.socket.close();
138
+ return true;
139
+ }
140
+ return false;
141
+ },
142
+
143
+ changeSocketUrl(newUrl, callback) {
144
+ this.closeSocket();
145
+ const clientId = sessionStorage.getItem("clientId");
146
+ const socket = new WebSocket(newUrl + "?clientId=" + clientId + "&a=1");
147
+ const send = app.api.socket.send;
148
+ const onopen = app.api.socket.onopen;
149
+ const onmessage = app.api.socket.onmessage;
150
+ const onerror = app.api.socket.onerror;
151
+ const onclose = app.api.socket.onclose;
152
+
153
+ app.api.socket = socket;
154
+ app.api.socket.send = send;
155
+ app.api.socket.onopen = onopen;
156
+ app.api.socket.onmessage = onmessage;
157
+ app.api.socket.onerror = onerror;
158
+ app.api.socket.onclose = onclose;
159
+
160
+ if (typeof callback === 'function') {
161
+ callback(socket);
162
+ }
163
+
164
+ return socket;
165
+ },
166
+
167
+ sendSocketMessage(message) {
168
+ if (app.api.socket && app.api.socket.readyState === WebSocket.OPEN) {
169
+ app.api.socket.send(typeof message === 'string' ? message : JSON.stringify(message));
170
+ return true;
171
+ }
172
+ return false;
173
+ },
174
+
175
+ sendPrompt(prompt) {
176
+ app.queuePrompt(prompt);
177
+ },
178
+ getCookie(name) {
179
+ const value = `; ${document.cookie}`;
180
+ const parts = value.split(`; ${name}=`);
181
+ if (parts.length === 2) return parts.pop().split(';').shift();
182
+ },
183
+ // doSendSocket() {
184
+ // const socket = new WebSocketClient(`/w/v1/comfy/draft/ws?clientId=${sessionStorage.getItem("clientId")
185
+ // }&userId=${this.getCookie("user_id")
186
+ // }`);
187
+ // const customSocket = this.customSocket.bind(this);
188
+ // socket.on('message', (message) => {
189
+ // let data = JSON.parse(message.data);
190
+ // if (data.status == "Running") {
191
+ // customSocket(() => {}, data.wsUrl);
192
+ // }
193
+ // });
194
+ // },
195
+
196
+
197
+ async setup() {
198
+ const customSocket = this.customSocket.bind(this);
199
+ const startSocket = this.startSocket.bind(this);
200
+ const closeSocket = this.closeSocket.bind(this);
201
+ const changeSocketUrl = this.changeSocketUrl.bind(this);
202
+ const sendSocketMessage = this.sendSocketMessage.bind(this);
203
+ // let iTimer = null;
204
+
205
+ // // 直接检查一次
206
+ // const initialUserId = this.getCookie("user_id");
207
+ // if (initialUserId) {
208
+ // // 初始检查到 userId
209
+ // this.doSendSocket();
210
+ // }
211
+
212
+ // // 使用定时器监听cookie变化
213
+ // let lastCookieValue = this.getCookie("user_id");
214
+ // iTimer = setInterval(() => {
215
+ // const currentCookieValue = this.getCookie("user_id");
216
+ // if (currentCookieValue && currentCookieValue !== lastCookieValue) {
217
+ // // 检测到 cookie user_id 变化
218
+ // lastCookieValue = currentCookieValue;
219
+ // this.doSendSocket();
220
+ // clearInterval(iTimer);
221
+ // }
222
+ // }, 300); // 每秒检查一次
223
+
224
+ const methods = {
225
+ customSocket: function (params) {
226
+ const callback = params.callback ? new Function('socket', params.callback) : null;
227
+ const socket = customSocket(callback, params.url);
228
+ window.parent.postMessage({
229
+ type: 'functionResult',
230
+ method: 'customSocket',
231
+ result: '自定义socket执行结果'
232
+ }, '*');
233
+ return socket;
234
+ },
235
+
236
+ startSocket: function (params) {
237
+ const callback = params.callback ? new Function('socket', params.callback) : null;
238
+ const socket = startSocket(callback);
239
+ window.parent.postMessage({
240
+ type: 'functionResult',
241
+ method: 'startSocket',
242
+ result: 'Socket连接已启动'
243
+ }, '*');
244
+ return socket;
245
+ },
246
+
247
+ closeSocket: function () {
248
+ const result = closeSocket();
249
+ window.parent.postMessage({
250
+ type: 'functionResult',
251
+ method: 'closeSocket',
252
+ result: result ? 'Socket连接已关闭' : 'Socket连接关闭失败或已关闭'
253
+ }, '*');
254
+ return result;
255
+ },
256
+
257
+ changeSocketUrl: function (params) {
258
+ if (!params.url) {
259
+ console.error('缺少url参数');
260
+ return false;
261
+ }
262
+ const callback = params.callback ? new Function('socket', params.callback) : null;
263
+ const socket = changeSocketUrl(params.url, callback);
264
+ window.parent.postMessage({
265
+ type: 'functionResult',
266
+ method: 'changeSocketUrl',
267
+ result: 'Socket URL已更改为' + params.url
268
+ }, '*');
269
+ return socket;
270
+ },
271
+
272
+ sendSocketMessage: function (params) {
273
+ if (!params.message) {
274
+ console.error('缺少message参数');
275
+ return false;
276
+ }
277
+ const result = sendSocketMessage(params.message);
278
+ window.parent.postMessage({
279
+ type: 'functionResult',
280
+ method: 'sendSocketMessage',
281
+ result: result ? '消息发送成功' : '消息发送失败'
282
+ }, '*');
283
+ return result;
284
+ },
285
+
286
+ clearCanvas: function () {
287
+ app.graph.clear();
288
+ window.parent.postMessage({
289
+ type: 'functionResult',
290
+ method: 'clearCanvas',
291
+ result: true
292
+ }, '*');
293
+ return true;
294
+ },
295
+
296
+ loadWorkflow: function (params) {
297
+ app.graph.clear();
298
+ if (params.json.version) {
299
+ app.loadGraphData(params.json);
300
+ } else {
301
+ app.loadApiJson(params.json, 'bizyair');
302
+ }
303
+ console.log("-----------loadWorkflow-----------", params.json)
304
+ window.parent.postMessage({
305
+ type: 'functionResult',
306
+ method: 'loadWorkflow',
307
+ result: true
308
+ }, '*');
309
+ return true;
310
+ },
311
+
312
+ saveWorkflow: async function () {
313
+ const graph = await app.graphToPrompt();
314
+ window.parent.postMessage({
315
+ type: 'functionResult',
316
+ method: 'saveWorkflow',
317
+ result: graph.workflow
318
+ }, '*');
319
+ return graph.workflow;
320
+ },
321
+ getWorkflow: async function () {
322
+ const graph = await app.graphToPrompt();
323
+ window.parent.postMessage({
324
+ type: 'functionResult',
325
+ method: 'getWorkflow',
326
+ result: graph.workflow
327
+ }, '*');
328
+ return graph.workflow;
329
+ },
330
+ saveApiJson: async function (params) {
331
+ const graph = await app.graphToPrompt();
332
+ window.parent.postMessage({
333
+ type: 'functionResult',
334
+ method: 'saveApiJson',
335
+ result: graph.output
336
+ }, '*');
337
+ return graph.output;
338
+ },
339
+ getClientId: function () {
340
+ const clientId = sessionStorage.getItem("clientId");
341
+ window.parent.postMessage({
342
+ type: 'functionResult',
343
+ method: 'getClientId',
344
+ result: clientId
345
+ }, '*');
346
+ return clientId;
347
+ },
348
+ runWorkflow: async function () {
349
+ const graph = await app.graphToPrompt();
350
+ const res = await app.queuePrompt(graph.output);
351
+ console.log("-----------queuePrompt-----------", res)
352
+ const clientId = sessionStorage.getItem("clientId");
353
+ window.parent.postMessage({
354
+ type: 'functionResult',
355
+ method: 'runWorkflow',
356
+ result: {
357
+ clientId: clientId,
358
+ jsonWorkflow: graph.output,
359
+ workflow: graph.workflow
360
+ }
361
+ }, '*');
362
+ return true;
363
+ },
364
+ setCookie: function (params) {
365
+ const setCookie = (name, value, days) => {
366
+ let expires = "";
367
+ if (days) {
368
+ const date = new Date();
369
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
370
+ expires = "; expires=" + date.toUTCString();
371
+ }
372
+ document.cookie = name + "=" + (value || "") + expires + "; path=/";
373
+ };
374
+ console.log("-----------setCookie-----------", params)
375
+ setCookie(params.name, params.value, params.days);
376
+ // window.parent.postMessage({
377
+ // type: 'functionResult',
378
+ // method: 'setCookie',
379
+ // result: true
380
+ // }, '*');
381
+ return true;
382
+ },
383
+ fitView: function () {
384
+ // window.app.canvas.ds.offset = [0, 0];
385
+ // window.app.canvas.ds.scale = 1;
386
+ // window.app.canvas.setDirty(true, true);
387
+ app.canvas.fitViewToSelectionAnimated()
388
+
389
+ window.parent.postMessage({
390
+ type: 'functionResult',
391
+ method: 'fitView',
392
+ result: true
393
+ }, '*');
394
+ return true;
395
+ }
396
+ };
397
+
398
+ window.addEventListener('message', function (event) {
399
+ if (event.data && event.data.type === 'callMethod') {
400
+ const methodName = event.data.method;
401
+ const params = event.data.params || {};
402
+
403
+ if (methods[methodName]) {
404
+ methods[methodName](params);
405
+ } else {
406
+ console.error('方法不存在:', methodName);
407
+ }
408
+ }
409
+ });
410
+ window.parent.postMessage({ type: 'iframeReady' }, '*');
411
+ }
412
+ });
@@ -0,0 +1,120 @@
1
+ export class WebSocketClient {
2
+ constructor(url, protocols) {
3
+
4
+ const host = 'uat-api.bizyair.cn';
5
+
6
+ if (url.startsWith('ws://') || url.startsWith('wss://')) {
7
+ this.url = url;
8
+ } else {
9
+ this.url = `${location.protocol == 'http:' ? 'wss' : 'wss'}://${host}${url}`
10
+ }
11
+ this.protocols = protocols
12
+ this.reconnectDelay = 1000
13
+ this.maxReconnectDelay = 30000
14
+ this.keepAliveInterval = 10000
15
+ this.ws = null
16
+ this.keepAliveTimer = null
17
+ this.reconnectTimer = null
18
+
19
+ this.connect()
20
+ }
21
+
22
+ connect() {
23
+ this.ws = new WebSocket(this.url, this.protocols)
24
+ this.ws.onopen = () => {
25
+ this.onOpen()
26
+ }
27
+
28
+ this.ws.onmessage = (message) => {
29
+ if (message.data !== 'pong') {
30
+ this.onMessage(message)
31
+ }
32
+ }
33
+
34
+ this.ws.onerror = (error) => {
35
+ this.onError(error)
36
+ }
37
+
38
+ this.ws.onclose = () => {
39
+ console.warn('The WebSocket connection has been closed and is ready to be reconnected')
40
+ this.onClose()
41
+ this.scheduleReconnect()
42
+ }
43
+ }
44
+
45
+ startKeepAlive() {
46
+ if (this.keepAliveTimer) return
47
+
48
+ this.keepAliveTimer = setInterval(() => {
49
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
50
+ this.ws.send('ping')
51
+ }
52
+ }, this.keepAliveInterval)
53
+ }
54
+
55
+ stopKeepAlive() {
56
+ if (this.keepAliveTimer) {
57
+ clearInterval(this.keepAliveTimer)
58
+ this.keepAliveTimer = null
59
+ }
60
+ }
61
+
62
+ scheduleReconnect() {
63
+ if (this.reconnectTimer) return
64
+
65
+ this.reconnectTimer = setTimeout(() => {
66
+ console.log(`Attempt to reconnect...`)
67
+ this.connect()
68
+ this.reconnectTimer = null
69
+
70
+ this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay)
71
+ }, this.reconnectDelay)
72
+ }
73
+
74
+ onOpen() {
75
+ this.reconnectDelay = 2000
76
+ this.startKeepAlive()
77
+ }
78
+
79
+ onMessage(message) {
80
+ message
81
+ // const data = JSON.parse(message.data);
82
+ // if (data === 'pong') {
83
+ // // Do nothing
84
+ // } else {
85
+ // console.log('message:', data);
86
+ // }
87
+ }
88
+
89
+ onError(error) {
90
+ console.error('WebSocket Error: ', error)
91
+ }
92
+
93
+ onClose() {
94
+ this.stopKeepAlive()
95
+ }
96
+
97
+ close() {
98
+ if (this.ws) {
99
+ this.ws.close()
100
+ }
101
+ this.stopKeepAlive()
102
+ if (this.reconnectTimer) {
103
+ clearTimeout(this.reconnectTimer)
104
+ this.reconnectTimer = null
105
+ }
106
+ }
107
+
108
+ on(event, callback) {
109
+ if (event === 'message') {
110
+ this.onMessage = callback;
111
+ } else if (event === 'open') {
112
+ this.onOpen = callback;
113
+ } else if (event === 'error') {
114
+ this.onError = callback;
115
+ } else if (event === 'close') {
116
+ this.onClose = callback;
117
+ }
118
+ return this;
119
+ }
120
+ }
@@ -0,0 +1,6 @@
1
+ export function getCookie(name) {
2
+ const value = `; ${document.cookie}`;
3
+ const parts = value.split(`; ${name}=`);
4
+ if (parts.length === 2) return parts.pop().split(';').shift();
5
+ return null;
6
+ }
@@ -0,0 +1,165 @@
1
+ import { getCookie } from './tool.js';
2
+ export async function fileToOss(file) {
3
+ try {
4
+
5
+ // 检查token是否存在
6
+ const apiHost = 'https://uat87.bizyair.cn/api'
7
+ // const apiHost = 'http://localhost:3000/api'
8
+ const authToken = getCookie('bizy_token')
9
+ console.log(authToken)
10
+ if (!authToken) {
11
+ throw new Error('未找到认证Token,请先登录');
12
+ }
13
+
14
+ // 获取上传凭证
15
+ const uploadToken = await fetch(`${apiHost}/community/upload_token?file_name=${encodeURIComponent(file.name)}&file_type=inputs`, {
16
+ method: 'GET',
17
+ headers: {
18
+ 'Content-Type': 'application/json',
19
+ 'Authorization': `Bearer ${authToken}`
20
+ }
21
+ });
22
+
23
+ // 检查响应状态
24
+ if (!uploadToken.ok) {
25
+ const errorText = await uploadToken.text();
26
+ console.error('获取上传凭证失败:', uploadToken.status, errorText);
27
+ throw new Error(`获取上传凭证失败: ${uploadToken.status} ${uploadToken.statusText}`);
28
+ }
29
+
30
+ const {data} = await uploadToken.json();
31
+ console.log('上传凭证响应:', data);
32
+
33
+ // 使用STS凭证上传
34
+ const ossConfig = {
35
+ accessKeyId: data.data.file.access_key_id,
36
+ accessKeySecret: data.data.file.access_key_secret,
37
+ securityToken: data.data.file.security_token,
38
+ bucket: data.data.storage.bucket,
39
+ region: data.data.storage.region,
40
+ objectKey: data.data.file.object_key
41
+ };
42
+
43
+ console.log('OSS配置:', ossConfig);
44
+
45
+ // 改用官方推荐的表单上传方式
46
+ const formData = new FormData();
47
+
48
+ // 构建Policy
49
+ const expiration = new Date();
50
+ expiration.setHours(expiration.getHours() + 1); // Policy过期时间1小时
51
+
52
+ const policyObj = {
53
+ expiration: expiration.toISOString(),
54
+ conditions: [
55
+ // 文件大小限制
56
+ ['content-length-range', 0, 1048576000], // 最大1000MB
57
+ // 指定允许的文件名前缀
58
+ ['starts-with', '$key', ossConfig.objectKey.split('/')[0]]
59
+ ]
60
+ };
61
+
62
+ // Policy Base64编码
63
+ const policy = btoa(JSON.stringify(policyObj));
64
+ console.log('Policy:', policy);
65
+
66
+ // 构建表单字段
67
+ formData.append('key', ossConfig.objectKey);
68
+ formData.append('OSSAccessKeyId', ossConfig.accessKeyId);
69
+ formData.append('policy', policy);
70
+ formData.append('success_action_status', '200');
71
+
72
+ // 如果有临时token,需要添加
73
+ if (ossConfig.securityToken) {
74
+ formData.append('x-oss-security-token', ossConfig.securityToken);
75
+ }
76
+
77
+ // 计算签名 - 阿里云官方要求使用HMAC-SHA1
78
+ const signature = await hmacSha1(policy, ossConfig.accessKeySecret);
79
+ console.log('计算的签名:', signature);
80
+ formData.append('signature', signature);
81
+
82
+ // 最后添加文件内容
83
+ formData.append('file', file);
84
+
85
+ // OSS服务端点
86
+ const host = `https://${ossConfig.bucket}.${ossConfig.region}.aliyuncs.com`;
87
+ console.log('上传地址:', host);
88
+
89
+ // 开始上传
90
+ const uploadResponse = await fetch(host, {
91
+ method: 'POST',
92
+ body: formData
93
+ });
94
+
95
+ // 检查响应
96
+ if (!uploadResponse.ok) {
97
+ const errorText = await uploadResponse.text();
98
+ console.error('上传失败:', uploadResponse.status, errorText);
99
+ throw new Error(`上传失败: ${uploadResponse.status} ${uploadResponse.statusText}`);
100
+ }
101
+
102
+ // 构建公开访问URL
103
+ const fileUrl = `${host}/${ossConfig.objectKey}`;
104
+
105
+ // 提交资源
106
+ await fetch(`${apiHost}/community/commit_input_resource`, {
107
+ method: 'POST',
108
+ headers: {
109
+ 'Content-Type': 'application/json',
110
+ 'Authorization': `Bearer ${authToken}`
111
+ },
112
+ body: JSON.stringify({
113
+ object_key: data.data.file.object_key,
114
+ name: file.name,
115
+ })
116
+ })
117
+ return {
118
+ url: fileUrl,
119
+ ossTokenFile: data.data.file,
120
+ ossTokenStorage: data.data.storage
121
+ };
122
+ } catch (error) {
123
+ console.error('文件上传到OSS失败:', error);
124
+
125
+ throw error;
126
+ }
127
+ }
128
+
129
+ // 使用标准的HMAC-SHA1签名算法
130
+ async function hmacSha1(message, key) {
131
+ // 使用浏览器原生的SubtleCrypto API
132
+ const encoder = new TextEncoder();
133
+ const keyData = encoder.encode(key);
134
+ const messageData = encoder.encode(message);
135
+
136
+ // 导入密钥
137
+ const cryptoKey = await window.crypto.subtle.importKey(
138
+ 'raw',
139
+ keyData,
140
+ { name: 'HMAC', hash: 'SHA-1' },
141
+ false,
142
+ ['sign']
143
+ );
144
+
145
+ // 计算签名
146
+ const signature = await window.crypto.subtle.sign(
147
+ 'HMAC',
148
+ cryptoKey,
149
+ messageData
150
+ );
151
+
152
+ // 转换为Base64编码
153
+ const base64Signature = arrayBufferToBase64(signature);
154
+ return base64Signature;
155
+ }
156
+
157
+ // 将ArrayBuffer转换为Base64字符串
158
+ function arrayBufferToBase64(buffer) {
159
+ const bytes = new Uint8Array(buffer);
160
+ let binary = '';
161
+ for (let i = 0; i < bytes.byteLength; i++) {
162
+ binary += String.fromCharCode(bytes[i]);
163
+ }
164
+ return btoa(binary);
165
+ }
@@ -0,0 +1,3 @@
1
+ Metadata-Version: 2.4
2
+ Name: bizydraft
3
+ Version: 0.1.0
@@ -0,0 +1,16 @@
1
+ bizydraft/__init__.py,sha256=qV8OhBrI5PgWcmvkYd5E0L2IiYjtbDSK3zyWpKspv0w,74
2
+ bizydraft/hijack_nodes.py,sha256=CrvATjtlfgvlCcd-7TawWCBlVwBVvsnNCFgGgccuLb8,752
3
+ bizydraft/hijack_routes.py,sha256=rXCtb9T0eZ2FCV9DymkIV9xlXGcgNU86lcxFubGRvxw,6152
4
+ bizydraft/resp.py,sha256=8INvKOe5Dgai3peKfqKjrhUoYeuXWXn358w30-_cY-A,369
5
+ bizydraft/server.py,sha256=wbpK_fJVgnvYHQieZvFN_TCvrdyN5Rsmv0DL9waoIXU,1166
6
+ bizydraft/static/js/handleStyle.js,sha256=RJbDRZMeb3_32JqPfOzxnZGVONb-WnXYrQDxIeu0Miw,1263
7
+ bizydraft/static/js/hookLoadImage.js,sha256=cEaqedTnngieI-Kb0PVgLor1nVDkFQx1_7AiurwtRwI,3878
8
+ bizydraft/static/js/main.js,sha256=cZ-7wR9T8aNLzIrTjc-g9xVZf7z6TXWl1zhP_wXSSVo,150
9
+ bizydraft/static/js/postEvent.js,sha256=4PVl929jU1m3ooKA1lFXNWgv62mtKAFnhqbsHVBUYi8,16488
10
+ bizydraft/static/js/socket.js,sha256=iNxbUPSQluIlx1x0MIVL7UJ35BXqLH7Z2s8vmfmbyyc,2643
11
+ bizydraft/static/js/tool.js,sha256=IlDVjddodT9DtfdIGiIzSIKdxbUMztDLQ4jI0uFJCwk,206
12
+ bizydraft/static/js/uploadFile.js,sha256=7PXMYRlgxgDWFFbsaasjf3TelsW6r9mD1TFTjQI6X0E,4957
13
+ bizydraft-0.1.0.dist-info/METADATA,sha256=XouCMG6uu1cvKr8HJvUTPpx4EqAtJMlgYfBXmC2d2tE,53
14
+ bizydraft-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ bizydraft-0.1.0.dist-info/top_level.txt,sha256=XtoBq6hjZhXIM7aas4GtPDtAiKo8FdLzMABXW8qqQ8M,10
16
+ bizydraft-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ bizydraft