bizyengine 1.2.2__py3-none-any.whl → 1.2.4__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.
@@ -1,3 +1,5 @@
1
+ import asyncio
2
+ import json
1
3
  import os
2
4
  import urllib
3
5
 
@@ -19,6 +21,10 @@ version_path = os.path.join(os.path.dirname(__file__), "..", "version.txt")
19
21
  with open(version_path, "r") as file:
20
22
  CLIENT_VERSION = file.read().strip()
21
23
 
24
+ # API请求地址
25
+ QWEN_MODEL_API_URL = "https://api.siliconflow.cn/v1/chat/completions"
26
+ QWEN_IMAGE_API_URL = "https://api.siliconflow.cn/v1/images/generations"
27
+
22
28
 
23
29
  class APIClient:
24
30
  def __init__(self):
@@ -1071,3 +1077,139 @@ class APIClient:
1071
1077
  except Exception as e:
1072
1078
  print(f"\033[31m[BizyAir]\033[0m Fail to get recent cost: {str(e)}")
1073
1079
  return None, errnos.GET_RECENT_COST
1080
+
1081
+ async def forward_model_request(self, request_data):
1082
+ try:
1083
+ import asyncio
1084
+ import json
1085
+
1086
+ from .stream_response import StreamResponse
1087
+
1088
+ request_data["stream"] = True
1089
+ # 参数检查
1090
+ if "messages" not in request_data:
1091
+ return None, errnos.MODEL_API_ERROR
1092
+
1093
+ if (
1094
+ not isinstance(request_data["messages"], list)
1095
+ or len(request_data["messages"]) == 0
1096
+ ):
1097
+ return None, errnos.MODEL_API_ERROR
1098
+
1099
+ # 获取用户API密钥
1100
+ api_key = get_api_key()
1101
+
1102
+ # 创建自定义流式响应对象,设置60秒超时
1103
+ response_stream = StreamResponse(request_data, timeout=60)
1104
+
1105
+ # 异步启动连接和数据请求
1106
+ asyncio.create_task(response_stream.connect_and_request(api_key))
1107
+
1108
+ # 返回流式响应对象
1109
+ return response_stream, None
1110
+
1111
+ except Exception as e:
1112
+ print(f"\033[31m[BizyAir]\033[0m Model API forwarding failed: {str(e)}")
1113
+ return None, errnos.MODEL_API_ERROR
1114
+
1115
+ async def stream_model_response(self, response):
1116
+ """
1117
+ 流式传输模型响应
1118
+
1119
+ Args:
1120
+ response: 从API获取的StreamResponse对象
1121
+
1122
+ Returns:
1123
+ 一个异步生成器,用于流式传输响应数据
1124
+ """
1125
+ # 生成请求ID用于日志
1126
+ req_id = f"stream-{id(response)}"
1127
+
1128
+ # 验证response对象是否有效
1129
+ if not response:
1130
+ print(f"\033[31m[BizyAir-{req_id}]\033[0m 无效的response对象 (为None)")
1131
+ yield b'data: {"error": "Invalid response object (None)"}\n\n'
1132
+ yield b"data: [DONE]\n\n"
1133
+ return
1134
+
1135
+ if not hasattr(response, "content") or not hasattr(
1136
+ response.content, "iter_any"
1137
+ ):
1138
+ print(
1139
+ f"\033[31m[BizyAir-{req_id}]\033[0m 无效的response对象 (缺少必要方法)"
1140
+ )
1141
+ yield b'data: {"error": "Invalid response object (missing methods)"}\n\n'
1142
+ yield b"data: [DONE]\n\n"
1143
+ return
1144
+
1145
+ error_occurred = False
1146
+ chunks_forwarded = 0
1147
+ chunk = None # 定义在外部,以便finally块可以访问
1148
+
1149
+ try:
1150
+ # 使用StreamResponse.iter_any方法创建流式传输生成器
1151
+ async for chunk in response.content.iter_any():
1152
+ chunks_forwarded += 1
1153
+
1154
+ yield chunk
1155
+ # 是否是结束标记
1156
+ if b"data: [DONE]" in chunk:
1157
+ break
1158
+ # 是否包含错误
1159
+ if b'data: {"error"' in chunk or b'data: {"message":' in chunk:
1160
+ error_occurred = True
1161
+
1162
+ except Exception as e:
1163
+ error_occurred = True
1164
+ error_msg = f"读取流式数据失败: {str(e)}"
1165
+ print(f"\033[31m[BizyAir-{req_id}]\033[0m {error_msg}")
1166
+
1167
+ # 返回错误消息
1168
+ error_json = json.dumps({"error": error_msg})
1169
+ yield f"data: {error_json}\n\n".encode("utf-8")
1170
+
1171
+ # 如果还没有发送过DONE,则发送
1172
+ if chunks_forwarded == 0 or (chunk and not b"data: [DONE]" in chunk):
1173
+ yield b"data: [DONE]\n\n"
1174
+
1175
+ finally:
1176
+ # 如果没有发生错误,但也没有转发任何数据,发送一个空响应
1177
+ if not error_occurred and chunks_forwarded == 0:
1178
+ yield b'data: {"content": ""}\n\n'
1179
+ yield b"data: [DONE]\n\n"
1180
+
1181
+ async def release(self):
1182
+ """关闭连接"""
1183
+ if self.writer and not self.closed:
1184
+ self.writer.close()
1185
+ try:
1186
+ await self.writer.wait_closed()
1187
+ except Exception:
1188
+ pass
1189
+ self.closed = True
1190
+
1191
+ async def forward_image_request(self, request_data):
1192
+ try:
1193
+ api_key = get_api_key()
1194
+ headers = {
1195
+ "Content-Type": "application/json",
1196
+ "Authorization": f"Bearer {api_key}",
1197
+ }
1198
+ # 创建异步HTTP会话
1199
+ async with aiohttp.ClientSession() as session:
1200
+ async with session.post(
1201
+ QWEN_IMAGE_API_URL, headers=headers, json=request_data
1202
+ ) as response:
1203
+ # 读取并解析响应
1204
+ if response.status != 200:
1205
+ error_text = await response.text()
1206
+ print(
1207
+ f"\033[31m[BizyAir]\033[0m Image generation failed: {error_text}"
1208
+ )
1209
+ return None, errnos.MODEL_API_ERROR
1210
+
1211
+ result = await response.json()
1212
+ return result, None
1213
+ except Exception as e:
1214
+ print(f"\033[31m[BizyAir]\033[0m Image generation request failed: {str(e)}")
1215
+ return None, errnos.MODEL_API_ERROR
@@ -442,3 +442,18 @@ class errnos:
442
442
  GET_RECENT_COST = ErrorNo(
443
443
  500, 500157, None, {"en": "Failed to get recent cost", "zh": "获取最近消费失败"}
444
444
  )
445
+
446
+ MODEL_API_ERROR = ErrorNo(
447
+ 500, 500158, None, {"en": "Failed to call model API", "zh": "调用模型API失败"}
448
+ )
449
+
450
+ MODEL_API_TIMEOUT = ErrorNo(
451
+ 500, 500159, None, {"en": "Model API request timeout", "zh": "模型API请求超时"}
452
+ )
453
+
454
+ STREAMING_CONNECTION_ERROR = ErrorNo(
455
+ 500,
456
+ 500160,
457
+ None,
458
+ {"en": "Streaming connection closed unexpectedly", "zh": "流式连接异常关闭"},
459
+ )
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  import configparser
3
+ import json
3
4
  import logging
4
5
  import os
5
6
  import shutil
@@ -23,6 +24,7 @@ COMMUNITY_API = f"{API_PREFIX}/community"
23
24
  MODEL_HOST_API = f"{API_PREFIX}/modelhost"
24
25
  USER_API = f"{API_PREFIX}/user"
25
26
  INVOICE_API = f"{API_PREFIX}/invoices"
27
+ MODEL_API = f"{API_PREFIX}/model"
26
28
 
27
29
  logging.basicConfig(level=logging.DEBUG)
28
30
 
@@ -957,6 +959,163 @@ class BizyAirServer:
957
959
 
958
960
  return OKResponse(resp)
959
961
 
962
+ @self.prompt_server.routes.post(f"/{MODEL_API}/chat")
963
+ async def chat_completions(request):
964
+ response = None # 确保变量在退出前定义
965
+ resp = None # 响应对象引用
966
+ req_id = f"req-{id(request)}" # 为请求生成唯一ID
967
+
968
+ try:
969
+ # 解析请求数据
970
+ request_data = await request.json()
971
+
972
+ # 转发请求到模型服务
973
+ response, err = await self.api_client.forward_model_request(
974
+ request_data
975
+ )
976
+ if err is not None:
977
+ print(
978
+ f"\033[31m[聊天请求-{req_id}]\033[0m 转发请求失败: {err.message}"
979
+ )
980
+ return ErrResponse(err)
981
+
982
+ # 创建并准备流式响应
983
+ resp = aiohttp.web.StreamResponse(
984
+ status=200,
985
+ reason="OK",
986
+ headers={
987
+ "Content-Type": "text/event-stream",
988
+ "Cache-Control": "no-cache",
989
+ "Connection": "keep-alive",
990
+ "X-Accel-Buffering": "no", # 禁用Nginx缓冲
991
+ },
992
+ )
993
+ await resp.prepare(request)
994
+
995
+ # 确保异步生成器正确创建
996
+ generator = self.api_client.stream_model_response(response)
997
+ if not generator:
998
+ print(f"\033[31m[聊天请求-{req_id}]\033[0m 创建异步生成器失败")
999
+ # 返回错误响应
1000
+ if not resp.prepared:
1001
+ return ErrResponse(errnos.MODEL_API_ERROR)
1002
+ else:
1003
+ # 如果响应已准备,发送错误数据帧
1004
+ try:
1005
+ error_msg = json.dumps({"error": "创建数据流失败"})
1006
+ await resp.write(f"data: {error_msg}\n\n".encode("utf-8"))
1007
+ await resp.write(b"data: [DONE]\n\n")
1008
+ except Exception as e:
1009
+ print(
1010
+ f"\033[31m[聊天请求-{req_id}]\033[0m 写入错误消息时出错: {str(e)}"
1011
+ )
1012
+ finally:
1013
+ try:
1014
+ await resp.write_eof()
1015
+ except:
1016
+ pass
1017
+ return resp
1018
+
1019
+ # 开始流式传输
1020
+ any_chunk_sent = False # 跟踪是否发送了任何数据块
1021
+
1022
+ try:
1023
+ async for chunk in generator:
1024
+ if chunk:
1025
+ try:
1026
+ await resp.write(chunk)
1027
+ any_chunk_sent = True
1028
+ await resp.drain() # 确保数据被立即发送
1029
+ except (
1030
+ ConnectionResetError,
1031
+ ConnectionError,
1032
+ aiohttp.ClientOSError,
1033
+ ) as e:
1034
+ print(
1035
+ f"\033[31m[聊天请求-{req_id}]\033[0m 流式传输中连接错误: {str(e)}"
1036
+ )
1037
+ break
1038
+ except Exception as e:
1039
+ print(f"\033[31m[聊天请求-{req_id}]\033[0m 流式传输错误: {str(e)}")
1040
+ # 如果尚未发送任何数据块,尝试发送错误信息
1041
+ if not any_chunk_sent and not resp.prepared:
1042
+ return ErrResponse(errnos.MODEL_API_ERROR)
1043
+ elif not any_chunk_sent:
1044
+ try:
1045
+ error_msg = json.dumps({"error": f"流式传输错误: {str(e)}"})
1046
+ await resp.write(f"data: {error_msg}\n\n".encode("utf-8"))
1047
+ await resp.write(b"data: [DONE]\n\n")
1048
+ except Exception as write_err:
1049
+ print(
1050
+ f"\033[31m[聊天请求-{req_id}]\033[0m 写入错误消息时出错: {str(write_err)}"
1051
+ )
1052
+
1053
+ # 检查是否发送了数据
1054
+ if not any_chunk_sent:
1055
+ print(
1056
+ f"\033[33m[聊天请求-{req_id}]\033[0m 警告: 没有发送任何数据块"
1057
+ )
1058
+ try:
1059
+ await resp.write(b'data: {"content": ""}\n\n')
1060
+ await resp.write(b"data: [DONE]\n\n")
1061
+ except Exception as e:
1062
+ print(
1063
+ f"\033[31m[聊天请求-{req_id}]\033[0m 写入空响应时出错: {str(e)}"
1064
+ )
1065
+
1066
+ try:
1067
+ await resp.write_eof()
1068
+ except Exception as e:
1069
+ print(
1070
+ f"\033[31m[聊天请求-{req_id}]\033[0m 结束响应时出错: {str(e)}"
1071
+ )
1072
+
1073
+ return resp
1074
+
1075
+ except Exception as e:
1076
+ print(
1077
+ f"\033[31m[聊天请求-{req_id}]\033[0m 处理请求时发生错误: {str(e)}"
1078
+ )
1079
+ # 如果响应已经准备好,尝试发送错误信息
1080
+ if resp and resp.prepared:
1081
+ try:
1082
+ error_msg = json.dumps({"error": f"服务器错误: {str(e)}"})
1083
+ await resp.write(f"data: {error_msg}\n\n".encode("utf-8"))
1084
+ await resp.write(b"data: [DONE]\n\n")
1085
+ await resp.write_eof()
1086
+ except:
1087
+ pass
1088
+ return resp
1089
+
1090
+ return ErrResponse(errnos.MODEL_API_ERROR)
1091
+
1092
+ finally:
1093
+ # 确保所有资源被释放
1094
+ if response and hasattr(response, "release"):
1095
+ try:
1096
+ await response.release()
1097
+ except Exception as e:
1098
+ print(
1099
+ f"\033[31m[聊天请求-{req_id}]\033[0m 关闭连接时出错: {str(e)}"
1100
+ )
1101
+
1102
+ @self.prompt_server.routes.post(f"/{MODEL_API}/images")
1103
+ async def image_generations(request):
1104
+ try:
1105
+ # 解析请求数据
1106
+ request_data = await request.json()
1107
+
1108
+ # 转发图像生成请求
1109
+ result, err = await self.api_client.forward_image_request(request_data)
1110
+ if err is not None:
1111
+ return ErrResponse(err)
1112
+
1113
+ # 返回结果
1114
+ return OKResponse(result)
1115
+
1116
+ except Exception:
1117
+ return ErrResponse(errnos.MODEL_API_ERROR)
1118
+
960
1119
  async def send_json(self, event, data, sid=None):
961
1120
  message = {"type": event, "data": data}
962
1121
 
@@ -0,0 +1,268 @@
1
+ import asyncio
2
+ import json
3
+ import ssl
4
+ from typing import Any, Dict, List, Optional
5
+
6
+
7
+ class ConnectionState:
8
+ """连接状态枚举"""
9
+
10
+ INIT = "初始化"
11
+ CONNECTING = "连接中"
12
+ CONNECTED = "已连接"
13
+ READING = "读取中"
14
+ CLOSING = "关闭中"
15
+ CLOSED = "已关闭"
16
+ ERROR = "错误"
17
+
18
+
19
+ class StreamResponse:
20
+ """自定义流式响应类,支持状态管理和错误处理"""
21
+
22
+ def __init__(self, request_data: Dict[str, Any], timeout: int = 60):
23
+ # 请求和连接数据
24
+ self.request_data = request_data
25
+ self.reader = None
26
+ self.writer = None
27
+ self.timeout = timeout
28
+
29
+ # 连接状态管理
30
+ self.state = ConnectionState.INIT
31
+ self.state_lock = asyncio.Lock() # 状态修改锁
32
+ self.connection_event = asyncio.Event()
33
+ self.error = None
34
+
35
+ # 数据相关
36
+ self.content = self
37
+ self.buffer = b""
38
+ self.chunks_received = 0
39
+ self.done_received = False
40
+
41
+ # 调试信息
42
+ self.debug_id = id(self) # 用于日志区分不同实例
43
+
44
+ async def _set_state(self, new_state: str, error: Exception = None) -> None:
45
+ """线程安全地设置连接状态"""
46
+ async with self.state_lock:
47
+ self.state = new_state
48
+ if error:
49
+ self.error = error
50
+
51
+ # 如果状态为已连接,触发连接事件
52
+ if new_state == ConnectionState.CONNECTED:
53
+ self.connection_event.set()
54
+
55
+ # 如果状态为错误,也触发连接事件,让等待连接的代码继续执行并处理错误
56
+ if new_state == ConnectionState.ERROR:
57
+ self.connection_event.set()
58
+
59
+ async def connect_and_request(self, api_key: str):
60
+ """建立连接并发送请求,包含严格的状态管理"""
61
+ # 设置状态为连接中
62
+ await self._set_state(ConnectionState.CONNECTING)
63
+
64
+ try:
65
+ # 建立SSL连接,添加超时控制
66
+ connect_coro = asyncio.open_connection("api.siliconflow.cn", 443, ssl=True)
67
+ self.reader, self.writer = await asyncio.wait_for(
68
+ connect_coro, timeout=self.timeout
69
+ )
70
+
71
+ # 准备HTTP请求
72
+ json_data = json.dumps(self.request_data)
73
+ request = (
74
+ f"POST /v1/chat/completions HTTP/1.1\r\n"
75
+ f"Host: api.siliconflow.cn\r\n"
76
+ f"Authorization: Bearer {api_key}\r\n"
77
+ f"Accept: text/event-stream\r\n"
78
+ f"Content-Type: application/json\r\n"
79
+ f"Content-Length: {len(json_data)}\r\n"
80
+ f"Connection: keep-alive\r\n"
81
+ f"\r\n"
82
+ f"{json_data}"
83
+ )
84
+
85
+ # 检查是否仍在连接状态
86
+ async with self.state_lock:
87
+ if self.state != ConnectionState.CONNECTING:
88
+ raise Exception(f"连接状态已变更为 {self.state},无法发送请求")
89
+
90
+ # 发送请求
91
+ self.writer.write(request.encode("utf-8"))
92
+ await asyncio.wait_for(self.writer.drain(), timeout=self.timeout)
93
+
94
+ # 读取HTTP响应头
95
+ response_line = await asyncio.wait_for(
96
+ self.reader.readline(), timeout=self.timeout
97
+ )
98
+ if not response_line:
99
+ raise Exception("服务器关闭了连接")
100
+
101
+ status_line = response_line.decode("utf-8").strip()
102
+
103
+ if not status_line.startswith("HTTP/1.1 200"):
104
+ raise Exception(f"API请求失败: {status_line}")
105
+
106
+ # 读取响应头
107
+ headers = {}
108
+ while True:
109
+ # 再次检查状态
110
+ async with self.state_lock:
111
+ if self.state != ConnectionState.CONNECTING:
112
+ raise Exception(
113
+ f"连接状态已变更为 {self.state},停止读取响应头"
114
+ )
115
+
116
+ line = await asyncio.wait_for(
117
+ self.reader.readline(), timeout=self.timeout
118
+ )
119
+ if line == b"\r\n" or not line:
120
+ break
121
+
122
+ try:
123
+ header_line = line.decode("utf-8").strip()
124
+ if ":" in header_line:
125
+ key, value = header_line.split(":", 1)
126
+ headers[key.strip()] = value.strip()
127
+ except Exception:
128
+ pass
129
+
130
+ # 成功连接
131
+ await self._set_state(ConnectionState.CONNECTED)
132
+
133
+ except asyncio.TimeoutError as e:
134
+ await self._set_state(ConnectionState.ERROR, e)
135
+ await self.release()
136
+ raise Exception(f"连接超时 (>{self.timeout}秒)") from e
137
+
138
+ except Exception as e:
139
+ await self._set_state(ConnectionState.ERROR, e)
140
+ await self.release()
141
+ raise Exception(f"连接失败: {str(e)}") from e
142
+
143
+ async def iter_any(self):
144
+ """模拟aiohttp的iter_any方法"""
145
+ # 等待连接完成
146
+ if not self.connection_event.is_set():
147
+ try:
148
+ await asyncio.wait_for(
149
+ self.connection_event.wait(), timeout=self.timeout
150
+ )
151
+ except asyncio.TimeoutError as e:
152
+ await self._set_state(ConnectionState.ERROR, e)
153
+ await self.release()
154
+ raise Exception(f"等待连接超时 (>{self.timeout}秒)") from e
155
+
156
+ # 检查连接状态
157
+ async with self.state_lock:
158
+ if self.state == ConnectionState.ERROR:
159
+ error_msg = f"连接发生错误: {str(self.error)}"
160
+ raise Exception(error_msg) from self.error
161
+
162
+ if self.state != ConnectionState.CONNECTED:
163
+ error_msg = f"连接状态为 {self.state},无法读取数据"
164
+ raise Exception(error_msg)
165
+
166
+ # 设置状态为读取中
167
+ self.state = ConnectionState.READING
168
+
169
+ # 读取数据
170
+ try:
171
+ max_empty_chunks = 3 # 连续空块计数,防止无限循环
172
+ empty_chunk_count = 0
173
+
174
+ while True:
175
+ # 检查状态
176
+ async with self.state_lock:
177
+ if self.state != ConnectionState.READING:
178
+ break
179
+
180
+ try:
181
+ # 读取一段数据,添加超时控制
182
+ chunk = await asyncio.wait_for(
183
+ self.reader.read(1024), timeout=self.timeout
184
+ )
185
+
186
+ # 检测连续空块,防止无限循环
187
+ if not chunk:
188
+ empty_chunk_count += 1
189
+ if empty_chunk_count >= max_empty_chunks:
190
+ break
191
+ # 给个短暂的休息,避免CPU过度使用
192
+ await asyncio.sleep(0.05)
193
+ continue
194
+ else:
195
+ empty_chunk_count = 0
196
+
197
+ # 更新计数并生成数据
198
+ self.chunks_received += 1
199
+ yield chunk
200
+
201
+ # 检查是否接收到了结束标记 [DONE]
202
+ if b"data: [DONE]" in chunk:
203
+ self.done_received = True
204
+ break
205
+
206
+ except asyncio.TimeoutError as e:
207
+ await self._set_state(ConnectionState.ERROR, e)
208
+ break
209
+
210
+ except (ConnectionError, OSError) as e:
211
+ await self._set_state(ConnectionState.ERROR, e)
212
+ break
213
+
214
+ except Exception as e:
215
+ await self._set_state(ConnectionState.ERROR, e)
216
+ error_msg = f"读取数据失败: {str(e)}"
217
+ raise
218
+ finally:
219
+ # 关闭连接
220
+ await self.release()
221
+
222
+ async def release(self):
223
+ """安全关闭连接并释放资源"""
224
+ async with self.state_lock:
225
+ # 检查是否已经在关闭或已关闭状态
226
+ if self.state in [ConnectionState.CLOSING, ConnectionState.CLOSED]:
227
+ return
228
+
229
+ # 设置状态为关闭中
230
+ self.state = ConnectionState.CLOSING
231
+
232
+ # 关闭写入端
233
+ if self.writer:
234
+ writer = self.writer
235
+ self.writer = None # 清除引用
236
+ self.reader = None # 清除引用
237
+
238
+ try:
239
+ # 尝试优雅关闭
240
+ if not writer.is_closing():
241
+ # 先确保发送所有数据
242
+ try:
243
+ await asyncio.wait_for(writer.drain(), timeout=1.0)
244
+ except (asyncio.TimeoutError, ConnectionError, OSError):
245
+ # 忽略drain错误
246
+ pass
247
+
248
+ # 写入EOF标记
249
+ try:
250
+ writer.write_eof()
251
+ except (OSError, RuntimeError):
252
+ # 忽略无法写入EOF的错误
253
+ pass
254
+
255
+ # 关闭连接
256
+ writer.close()
257
+
258
+ # 等待连接关闭完成
259
+ try:
260
+ await asyncio.wait_for(writer.wait_closed(), timeout=2.0)
261
+ except (asyncio.TimeoutError, ConnectionError, OSError, RuntimeError):
262
+ # 忽略等待关闭的错误
263
+ pass
264
+ except Exception:
265
+ pass
266
+
267
+ # 设置为已关闭状态
268
+ await self._set_state(ConnectionState.CLOSED)
@@ -15,6 +15,7 @@ from .nodes_ipadapter_plus.nodes_ipadapter_plus import *
15
15
  from .nodes_janus_pro import *
16
16
  from .nodes_kolors_mz import *
17
17
  from .nodes_model_advanced import *
18
+ from .nodes_nunchaku import *
18
19
  from .nodes_sd3 import *
19
20
  from .nodes_segment_anything import *
20
21
  from .nodes_testing_utils import *
@@ -0,0 +1,193 @@
1
+ from bizyengine.core import BizyAirBaseNode, BizyAirNodeIO, data_types
2
+ from bizyengine.core.configs.conf import config_manager
3
+ from bizyengine.core.path_utils import path_manager as folder_paths
4
+
5
+
6
+ class NunchakuFluxDiTLoader(BizyAirBaseNode):
7
+ @classmethod
8
+ def INPUT_TYPES(s):
9
+ attention_options = ["nunchaku-fp16"]
10
+ dtype_options = ["bfloat16"]
11
+ return {
12
+ "required": {
13
+ "model_path": (
14
+ ["svdq-int4-flux.1-dev"],
15
+ {"tooltip": "The SVDQuant quantized FLUX.1 models."},
16
+ ),
17
+ "cache_threshold": (
18
+ "FLOAT",
19
+ {
20
+ "default": 0,
21
+ "min": 0,
22
+ "max": 1,
23
+ "step": 0.001,
24
+ "tooltip": "Adjusts the caching tolerance like `residual_diff_threshold` in WaveSpeed. "
25
+ "Increasing the value enhances speed at the cost of quality. "
26
+ "A typical setting is 0.12. Setting it to 0 disables the effect.",
27
+ },
28
+ ),
29
+ "attention": (
30
+ attention_options,
31
+ {
32
+ "default": attention_options[0],
33
+ "tooltip": "Attention implementation. The default implementation is `flash-attention2`. "
34
+ "`nunchaku-fp16` use FP16 attention, offering ~1.2× speedup. "
35
+ "Note that 20-series GPUs can only use `nunchaku-fp16`.",
36
+ },
37
+ ),
38
+ "cpu_offload": (
39
+ ["disable"],
40
+ {
41
+ "default": "auto",
42
+ "tooltip": "Whether to enable CPU offload for the transformer model."
43
+ "auto' will enable it if the GPU memory is less than 14G.",
44
+ },
45
+ ),
46
+ "device_id": (
47
+ "INT",
48
+ {
49
+ "default": 0,
50
+ "min": 0,
51
+ "max": 0,
52
+ "step": 1,
53
+ "display": "number",
54
+ "lazy": True,
55
+ "tooltip": "The GPU device ID to use for the model.",
56
+ },
57
+ ),
58
+ "data_type": (
59
+ dtype_options,
60
+ {
61
+ "default": dtype_options[0],
62
+ "tooltip": "Specifies the model's data type. Default is `bfloat16`. "
63
+ "For 20-series GPUs, which do not support `bfloat16`, use `float16` instead.",
64
+ },
65
+ ),
66
+ },
67
+ "optional": {
68
+ "i2f_mode": (
69
+ ["enabled", "always"],
70
+ {
71
+ "default": "enabled",
72
+ "tooltip": "The GEMM implementation for 20-series GPUs"
73
+ "— this option is only applicable to these GPUs.",
74
+ },
75
+ )
76
+ },
77
+ }
78
+
79
+ RETURN_TYPES = (data_types.MODEL,)
80
+ CATEGORY = "Nunchaku"
81
+ NODE_DISPLAY_NAME = "Nunchaku FLUX DiT Loader"
82
+
83
+
84
+ class NunchakuTextEncoderLoader(BizyAirBaseNode):
85
+ @classmethod
86
+ def INPUT_TYPES(s):
87
+ return {
88
+ "required": {
89
+ "model_type": (["flux"],),
90
+ "text_encoder1": (folder_paths.get_filename_list("text_encoders"),),
91
+ "text_encoder2": (folder_paths.get_filename_list("text_encoders"),),
92
+ "t5_min_length": (
93
+ "INT",
94
+ {
95
+ "default": 512,
96
+ "min": 256,
97
+ "max": 1024,
98
+ "step": 128,
99
+ "display": "number",
100
+ "lazy": True,
101
+ },
102
+ ),
103
+ "use_4bit_t5": (["disable"],),
104
+ "int4_model": (
105
+ ["none"],
106
+ {"tooltip": "The name of the 4-bit T5 model."},
107
+ ),
108
+ }
109
+ }
110
+
111
+ RETURN_TYPES = (data_types.CLIP,)
112
+ # FUNCTION = "load_text_encoder"
113
+ CATEGORY = "Nunchaku"
114
+ NODE_DISPLAY_NAME = "Nunchaku Text Encoder Loader"
115
+
116
+
117
+ class NunchakuFluxLoraLoader(BizyAirBaseNode):
118
+ @classmethod
119
+ def INPUT_TYPES(s):
120
+ return {
121
+ "required": {
122
+ "model": (
123
+ data_types.MODEL,
124
+ {"tooltip": "The diffusion model the LoRA will be applied to."},
125
+ ),
126
+ "lora_name": (
127
+ [
128
+ "to choose",
129
+ ],
130
+ {"tooltip": "The name of the LoRA."},
131
+ ),
132
+ "lora_strength": (
133
+ "FLOAT",
134
+ {
135
+ "default": 1.0,
136
+ "min": -100.0,
137
+ "max": 100.0,
138
+ "step": 0.01,
139
+ "tooltip": "How strongly to modify the diffusion model. This value can be negative.",
140
+ },
141
+ ),
142
+ "model_version_id": (
143
+ "STRING",
144
+ {
145
+ "default": "",
146
+ },
147
+ ),
148
+ }
149
+ }
150
+
151
+ RETURN_TYPES = (data_types.MODEL,)
152
+ OUTPUT_TOOLTIPS = ("The modified diffusion model.",)
153
+ FUNCTION = "load_lora"
154
+ NODE_DISPLAY_NAME = "Nunchaku FLUX.1 LoRA Loader"
155
+
156
+ CATEGORY = "Nunchaku"
157
+ DESCRIPTION = (
158
+ "LoRAs are used to modify the diffusion model, "
159
+ "altering the way in which latents are denoised such as applying styles. "
160
+ "You can link multiple LoRA nodes."
161
+ )
162
+
163
+ @classmethod
164
+ def VALIDATE_INPUTS(cls, lora_name, **kwargs):
165
+ if lora_name == "" or lora_name is None:
166
+ return False
167
+ return True
168
+
169
+ def load_lora(
170
+ self,
171
+ model,
172
+ lora_name,
173
+ lora_strength,
174
+ model_version_id: str = None,
175
+ ):
176
+ assigned_id = self.assigned_id
177
+ new_model: BizyAirNodeIO = model.copy(assigned_id)
178
+
179
+ if model_version_id is not None and model_version_id != "":
180
+ # use model version id as lora name
181
+ lora_name = (
182
+ f"{config_manager.get_model_version_id_prefix()}{model_version_id}"
183
+ )
184
+ new_model.add_node_data(
185
+ class_type="NunchakuFluxLoraLoader",
186
+ inputs={
187
+ "model": model,
188
+ "lora_name": lora_name,
189
+ "lora_strength": lora_strength,
190
+ },
191
+ outputs={"slot_index": 0},
192
+ )
193
+ return (new_model,)
@@ -104,7 +104,7 @@ class BizyAirTask:
104
104
  return self.get_data(len(self.data_pool) - 1)
105
105
 
106
106
  def do_task_until_completed(
107
- self, *, timeout: int = 600, poll_interval: float = 1
107
+ self, *, timeout: int = 3600, poll_interval: float = 1
108
108
  ) -> list[dict]:
109
109
  offset = 0
110
110
  start_time = time.time()
@@ -169,7 +169,7 @@ class PromptServer(Command):
169
169
  if BizyAirTask.check_inputs(result):
170
170
  self.cache_manager.set(cache_key, result)
171
171
  bz_task = BizyAirTask.from_data(result, check_inputs=False)
172
- bz_task.do_task_until_completed(timeout=10 * 60) # 10 minutes
172
+ bz_task.do_task_until_completed(timeout=60 * 60) # 60 minutes
173
173
  last_data = bz_task.get_last_data()
174
174
  response_data = last_data.get("data")
175
175
  out = response_data["payload"]
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import logging
2
3
  import os
3
4
  import pprint
4
5
  import urllib.error
@@ -17,9 +18,12 @@ __all__ = ["send_request"]
17
18
 
18
19
  from dataclasses import dataclass, field
19
20
 
20
- from .env_var import BIZYAIR_API_KEY, BIZYAIR_DEBUG, BIZYAIR_SERVER_ADDRESS
21
-
22
- IS_API_KEY_VALID = None
21
+ from .env_var import (
22
+ BIZYAIR_API_KEY,
23
+ BIZYAIR_DEBUG,
24
+ BIZYAIR_SERVER_ADDRESS,
25
+ create_api_key_file,
26
+ )
23
27
 
24
28
  version_path = os.path.join(os.path.dirname(__file__), "..", "..", "version.txt")
25
29
  with open(version_path, "r") as file:
@@ -29,34 +33,39 @@ with open(version_path, "r") as file:
29
33
  @dataclass
30
34
  class APIKeyState:
31
35
  current_api_key: str = field(default=None)
32
- is_valid: bool = field(default=None)
36
+ is_valid: bool = field(default=False)
33
37
 
34
38
 
39
+ # Actual api key in use
35
40
  api_key_state = APIKeyState()
36
41
 
37
42
 
38
- def set_api_key(api_key: str = "YOUR_API_KEY", override: bool = False):
39
- global BIZYAIR_API_KEY, api_key_state
40
- if api_key_state.is_valid is not None and not override:
43
+ def set_api_key(api_key: str = "YOUR_API_KEY", override: bool = False) -> bool:
44
+ logging.debug("client.py set_api_key called")
45
+ global api_key_state
46
+ if api_key_state.is_valid and not override:
41
47
  warnings.warn("API key has already been set and will not be overridden.")
42
- return
48
+ return True
43
49
  if validate_api_key(api_key):
44
- BIZYAIR_API_KEY = api_key
50
+ create_api_key_file(api_key)
45
51
  api_key_state.is_valid = True
46
- print("\033[92mAPI key is set successfully.\033[0m")
52
+ api_key_state.current_api_key = api_key
53
+ logging.info("\033[92mAPI key is set successfully.\033[0m")
54
+ return True
47
55
  else:
48
- api_key_state.is_valid = False
49
56
  warnings.warn("Invalid API key provided.")
57
+ return False
50
58
 
51
59
 
52
60
  def validate_api_key(api_key: str = None) -> bool:
53
- global api_key_state
61
+ logging.debug("validating api key...")
54
62
  if not api_key or not isinstance(api_key, str):
55
- warnings.warn("API key is not set.")
63
+ warnings.warn("invalid api_key")
56
64
  return False
65
+
66
+ is_valid = False
57
67
  # if api_key_state.current_api_key == api_key and api_key_state.is_valid is not None:
58
68
  # return api_key_state.is_valid
59
- api_key_state.current_api_key = api_key
60
69
  url = f"{BIZYAIR_SERVER_ADDRESS}/user/info"
61
70
  headers = {"accept": "application/json", "authorization": f"Bearer {api_key}"}
62
71
  try:
@@ -64,34 +73,37 @@ def validate_api_key(api_key: str = None) -> bool:
64
73
  method="GET", url=url, headers=headers, callback=None
65
74
  )
66
75
  if "message" not in response_data or response_data["message"] != "Ok":
67
- api_key_state.is_valid = False
68
76
  raise ValueError(
69
77
  f"\033[91mAPI key validation failed. API Key: {api_key}\033[0m"
70
78
  )
71
79
  else:
72
- api_key_state.is_valid = True
80
+ is_valid = True
73
81
  except ConnectionError as ce:
74
- api_key_state.is_valid = False
75
82
  raise ValueError(f"\033[91mConnection error: {ce}\033[0m")
76
83
  except PermissionError as pe:
77
- api_key_state.is_valid = False
78
84
  raise ValueError(
79
85
  f"\033[91mError validating API key: {api_key}, error: {pe}\033[0m"
80
86
  )
81
87
  except Exception as e:
82
- api_key_state.is_valid = False
83
88
  raise ValueError(f"\033[91mOther error: {e}\033[0m")
84
- return api_key_state.is_valid
89
+
90
+ logging.debug(f"api key validated: {is_valid}")
91
+ return is_valid
85
92
 
86
93
 
87
94
  def get_api_key() -> str:
88
- global BIZYAIR_API_KEY
95
+ logging.debug("client.py get_api_key called")
96
+ global api_key_state
89
97
  try:
90
- validate_api_key(BIZYAIR_API_KEY)
98
+ if not api_key_state.is_valid:
99
+ if validate_api_key(BIZYAIR_API_KEY):
100
+ api_key_state.is_valid = True
101
+ api_key_state.current_api_key = BIZYAIR_API_KEY
102
+ logging.info("API key set successfully")
91
103
  except Exception as e:
92
- print(str(e))
104
+ logging.error(str(e))
93
105
  raise ValueError(str(e))
94
- return BIZYAIR_API_KEY
106
+ return api_key_state.current_api_key
95
107
 
96
108
 
97
109
  def _headers():
@@ -141,8 +153,8 @@ def send_request(
141
153
  error_message = str(e)
142
154
  response_body = e.read().decode("utf-8") if hasattr(e, "read") else "N/A"
143
155
  if verbose:
144
- print(f"URLError encountered: {error_message}")
145
- print(f"Response Body: {response_data}")
156
+ logging.error(f"URLError encountered: {error_message}")
157
+ logging.info(f"Response Body: {response_data}")
146
158
  code, message = "N/A", "N/A"
147
159
  try:
148
160
  response_dict = json.loads(response_body)
@@ -152,7 +164,7 @@ def send_request(
152
164
 
153
165
  except json.JSONDecodeError:
154
166
  if verbose:
155
- print("Failed to decode response body as JSON.")
167
+ logging.error("Failed to decode response body as JSON.")
156
168
 
157
169
  if "Unauthorized" in error_message:
158
170
  raise PermissionError(
@@ -234,7 +246,7 @@ async def async_send_request(
234
246
  if response.status != 200:
235
247
  error_message = f"HTTP Status {response.status}"
236
248
  if verbose:
237
- print(f"Error encountered: {error_message}")
249
+ logging.error(f"Error encountered: {error_message}")
238
250
  if response.status == 401:
239
251
  raise PermissionError(
240
252
  "Key is invalid, please refer to https://cloud.siliconflow.cn to get the API key.\n"
@@ -251,17 +263,18 @@ async def async_send_request(
251
263
  return callback(json.loads(response_data))
252
264
  return json.loads(response_data)
253
265
  except aiohttp.ClientError as e:
254
- print(f"Error fetching data: {e}")
266
+ logging.error(f"Error fetching data: {e}")
255
267
  return {}
256
268
  except Exception as e:
257
- print(f"Error fetching data: {str(e)}")
269
+ logging.error(f"Error fetching data: {str(e)}")
258
270
  return {}
259
271
 
260
272
 
261
273
  def fetch_models_by_type(
262
274
  url: str, model_type: str, *, method="GET", verbose=False
263
275
  ) -> dict:
264
- if not validate_api_key(BIZYAIR_API_KEY):
276
+ global api_key_state
277
+ if not api_key_state.is_valid:
265
278
  return {}
266
279
 
267
280
  payload = {"type": model_type}
@@ -1,4 +1,5 @@
1
1
  import configparser
2
+ import logging
2
3
  import os
3
4
  from os import environ
4
5
  from pathlib import Path
@@ -59,7 +60,7 @@ def env(key, type_, default=None):
59
60
 
60
61
 
61
62
  def load_api_key():
62
-
63
+ logging.debug("load_api_key called")
63
64
  file_path = BIZYAIR_COMFYUI_PATH / "api_key.ini"
64
65
 
65
66
  if file_path.is_file() and file_path.exists():
@@ -73,6 +74,7 @@ def load_api_key():
73
74
 
74
75
 
75
76
  def create_api_key_file(api_key):
77
+ logging.debug("create_api_key_file called")
76
78
  config = configparser.ConfigParser()
77
79
  config["auth"] = {"api_key": api_key}
78
80
  file_path = BIZYAIR_COMFYUI_PATH / "api_key.ini"
@@ -84,9 +86,9 @@ def create_api_key_file(api_key):
84
86
 
85
87
 
86
88
  # production:
87
- # service_address: https://bizyair-api.siliconflow.cn/x/v1
89
+ # service_address: https://api.bizyair.cn/x/v1
88
90
  # uat:
89
- # service_address: https://uat-bizyair-api.siliconflow.cn/x/v1
91
+ # service_address: https://uat-api.bizyair.cn/x/v1
90
92
  _BIZYAIR_DOMAIN = os.getenv("BIZYAIR_DOMAIN", "https://api.bizyair.cn")
91
93
  BIZYAIR_DOMAIN = ServerAddress(_BIZYAIR_DOMAIN)
92
94
  BIZYAIR_X_SERVER = f"{_BIZYAIR_DOMAIN}/x/v1"
@@ -94,6 +96,7 @@ BIZYAIR_Y_SERVER = f"{_BIZYAIR_DOMAIN}/y/v1"
94
96
 
95
97
  BIZYAIR_SERVER_ADDRESS = ServerAddress(BIZYAIR_X_SERVER)
96
98
 
99
+ # Initial value, DO NOT CHANGE IN ACTUAL CODE!!!
97
100
  BIZYAIR_API_KEY = env("BIZYAIR_API_KEY", str, load_api_key()[1])
98
101
  # Development Settings
99
102
  BIZYAIR_DEV_REQUEST_URL = env("BIZYAIR_DEV_REQUEST_URL", str, None)
@@ -82,6 +82,7 @@
82
82
  "t5xxl_fp16.safetensors",
83
83
  "t5xxl_fp8_e4m3fn.safetensors"
84
84
  ],
85
+ "text_encoders":["t5xxl_fp16.safetensors","clip_l.safetensors"],
85
86
  "upscale_models": [
86
87
  "4x_NMKD-Siax_200k.pth",
87
88
  "RealESRGAN_x4plus.pth",
@@ -52,6 +52,17 @@ model_rules:
52
52
  unet_name:
53
53
  - ^flux/flux1-schnell.sft$
54
54
 
55
+ - mode_type: unet
56
+ base_model: FLUX
57
+ describe: NunchakuFluxDiT
58
+ score: 5
59
+ route: /supernode/bizyair-flux-nunchaku1-unet
60
+ nodes:
61
+ - class_type: NunchakuFluxDiTLoader
62
+ inputs:
63
+ model_path:
64
+ - '.*'
65
+
55
66
  - mode_type: unet
56
67
  base_model: Shuttle
57
68
  describe: shuttle-3.1-aesthetic
bizyengine/misc/auth.py CHANGED
@@ -1,23 +1,17 @@
1
+ import logging
1
2
  import os
2
3
  import uuid
3
4
  from pathlib import Path
4
5
 
5
- import bizyengine.core
6
+ import bizyengine.core.common
6
7
  import server
7
8
  from aiohttp import web
8
- from bizyengine.core.common import create_api_key_file, load_api_key, validate_api_key
9
9
 
10
- API_KEY = None
11
10
  # html_file_path = Path(os.path.dirname(os.path.abspath(__file__))) / "set_api_key.html"
12
11
  # with open(html_file_path, "r", encoding="utf-8") as htmlfile:
13
12
  # set_api_key_html = htmlfile.read()
14
13
 
15
14
 
16
- has_key, api_key = load_api_key()
17
- if has_key:
18
- API_KEY = api_key
19
-
20
-
21
15
  # @server.PromptServer.instance.routes.get("/bizyair/set-api-key")
22
16
  # async def set_api_key_page(request):
23
17
  # return web.Response(text=set_api_key_html, content_type="text/html")
@@ -25,55 +19,50 @@ if has_key:
25
19
 
26
20
  @server.PromptServer.instance.routes.post("/bizyair/set_api_key")
27
21
  async def set_api_key(request):
28
- global API_KEY
29
22
  try:
30
23
  data = await request.post()
31
24
  api_key = data.get("api_key")
32
25
  if api_key:
33
- if not validate_api_key(api_key):
26
+ if not bizyengine.core.common.set_api_key(api_key, True):
34
27
  error_msg = "Wrong API key provided, please refer to cloud.siliconflow.cn to get the key"
35
- print("set_api_key:", error_msg)
28
+ logging.error("set_api_key:", error_msg)
36
29
  return web.Response(
37
30
  text=error_msg,
38
31
  status=400,
39
32
  )
40
- create_api_key_file(api_key)
41
- API_KEY = api_key
42
- bizyengine.core.set_api_key(API_KEY, override=True)
43
- print("Set the key sucessfully.")
33
+ logging.info("Set api key sucessfully.")
44
34
  return web.Response(text="ok")
45
35
  else:
46
36
  error_msg = "No API key provided, please refer to cloud.siliconflow.cn to get the key"
47
- print("set_api_key:", error_msg)
37
+ logging.error("set_api_key:", error_msg)
48
38
  return web.Response(
49
39
  text=error_msg,
50
40
  status=400,
51
41
  )
52
42
  except Exception as e:
53
- print(f"set api key error: {str(e)}")
43
+ logging.error(f"set api key error: {str(e)}")
54
44
  return web.Response(text=str(e), status=500)
55
45
 
56
46
 
57
47
  @server.PromptServer.instance.routes.get("/bizyair/get_api_key")
58
48
  async def get_api_key(request):
59
- global API_KEY
49
+ logging.debug("auth.py get_api_key called")
60
50
  try:
61
- has_key, api_key = load_api_key()
62
- if has_key:
63
- API_KEY = api_key
64
- bizyengine.core.set_api_key(API_KEY)
51
+ if bizyengine.core.common.get_api_key():
65
52
  return web.Response(text="Key has been loaded from the api_key.ini file")
66
53
  else:
54
+ logging.debug("getting api key from cookie")
67
55
  api_key = request.cookies.get("api_key")
68
56
  if not api_key:
69
- print("No api key found in cookies")
57
+ logging.error("No api key found in cookies")
70
58
  return web.Response(
71
59
  text="No api key found in cookies, please refer to cloud.siliconflow.cn to get the key",
72
60
  status=404,
73
61
  )
74
- API_KEY = api_key
75
- bizyengine.core.set_api_key(API_KEY)
76
- return web.Response(text="Key has been loaded from the cookies")
62
+ if bizyengine.core.common.set_api_key(api_key):
63
+ return web.Response(text="Key has been loaded from the cookies")
64
+ logging.error("cannot set api key")
65
+ return web.Response(text="Cannot set api key", status=500)
77
66
 
78
67
  except Exception as e:
79
68
  return web.Response(text=str(e), status=500)
bizyengine/misc/utils.py CHANGED
@@ -123,9 +123,9 @@ def format_bytes(num_bytes: int) -> str:
123
123
 
124
124
 
125
125
  def get_api_key():
126
- from .auth import API_KEY
126
+ from bizyengine.core.common import get_api_key as bcc_get_api_key
127
127
 
128
- return API_KEY
128
+ return bcc_get_api_key()
129
129
 
130
130
 
131
131
  def get_llm_response(
bizyengine/version.txt CHANGED
@@ -1 +1 @@
1
- 1.2.2
1
+ 1.2.4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bizyengine
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Summary: [a/BizyAir](https://github.com/siliconflow/BizyAir) Comfy Nodes that can run in any environment.
5
5
  Author-email: SiliconFlow <yaochi@siliconflow.cn>
6
6
  Project-URL: Repository, https://github.com/siliconflow/BizyAir
@@ -1,15 +1,16 @@
1
1
  bizyengine/__init__.py,sha256=GP9V-JM07fz7uv_qTB43QEA2rKdrVJxi5I7LRnn_3ZQ,914
2
- bizyengine/version.txt,sha256=xipcxhrEUlk1dT9ewoTAoFKksdpLOjWA3OK313ohVK4,6
2
+ bizyengine/version.txt,sha256=VjoLTuw8d7vDSsYw1PpSFPXGcmrgFGhAT9cERzEQCE4,6
3
3
  bizyengine/bizy_server/__init__.py,sha256=SP9oSblnPo4KQyh7yOGD26YCskFAcQHAZy04nQBNRIw,200
4
- bizyengine/bizy_server/api_client.py,sha256=sTX_LQq9JFLSRYjn6beaOw3x5F5JYp0iTehuzcUwyhg,37225
5
- bizyengine/bizy_server/errno.py,sha256=iiel-LhT2o7v2BJpJn_mbVLG9Ett8WbqrT21B9j8hpA,15375
4
+ bizyengine/bizy_server/api_client.py,sha256=VDdAwCi4NL1HtqVuIOopUBjxhRjLjhxBKVFraOXI01M,42386
5
+ bizyengine/bizy_server/errno.py,sha256=nEr_A6ARwgIwlr1PFP8eg-HNAzz9r7l00fTKaq-ipxM,15826
6
6
  bizyengine/bizy_server/error_handler.py,sha256=MGrfO1AEqbfEgMWPL8B6Ypew_zHiQAdYGlhN9bZohrY,167
7
7
  bizyengine/bizy_server/execution.py,sha256=ayaEf6eGJKQsVZV-1_UlGlvwwmlH7FEek31Uq-MbUjA,1644
8
8
  bizyengine/bizy_server/profile.py,sha256=f4juAzJ73gCm0AhagYpt9WnG8HEI6xze_U96-omBLqU,3044
9
9
  bizyengine/bizy_server/resp.py,sha256=iOFT5Ud7VJBP2uqkojJIgc3y2ifMjjEXoj0ewneL9lc,710
10
- bizyengine/bizy_server/server.py,sha256=0rI_8m3jR_x2DsVEN0czWWO2mdaF7OyzXnnCnL3YRQc,41483
10
+ bizyengine/bizy_server/server.py,sha256=qpbvT55Hp3C_XlEyQcW_XQVecOkn4dRzjhE0nA3Wd0g,48518
11
+ bizyengine/bizy_server/stream_response.py,sha256=H2XHqlVRtQMhgdztAuG7l8-iV_Pm42u2x6WJ0gNVIW0,9654
11
12
  bizyengine/bizy_server/utils.py,sha256=C5tnMhvdtrrvwuCex3oERIGWrTWVb5dkXD1Txb5sJaE,2568
12
- bizyengine/bizyair_extras/__init__.py,sha256=Lnf-6vOrpkmzZ1H_AiBKlRo0pPt_A8HyUqGDXCZKOIc,892
13
+ bizyengine/bizyair_extras/__init__.py,sha256=6Su2AZMMPlBcOdxgy-BWq89m9MJl7voLSWeDcdyagIo,922
13
14
  bizyengine/bizyair_extras/nodes_advanced_refluxcontrol.py,sha256=cecfjrtnjJAty9aNkhz8BlmHUC1NImkFlUDiA0COEa4,2242
14
15
  bizyengine/bizyair_extras/nodes_cogview4.py,sha256=Ni0TDOycczyDhYPvSR68TxGV_wE2uhaxd8MIj-J4-3o,2031
15
16
  bizyengine/bizyair_extras/nodes_comfyui_detail_daemon.py,sha256=i71it24tiGvZ3h-XFWISr4CpZszUtPuz3UrZARYluLk,6169
@@ -25,6 +26,7 @@ bizyengine/bizyair_extras/nodes_image_utils.py,sha256=f49VDIwI6opHwCuM4n8GKGtute
25
26
  bizyengine/bizyair_extras/nodes_ip2p.py,sha256=GSEFJvrs4f2tv0xwYkWqc8uhsXrzAJVPvvwcw0gTjR0,619
26
27
  bizyengine/bizyair_extras/nodes_janus_pro.py,sha256=hAdMsS09RkRHZn9cNwpmyOaH7ODOMjVt9SbBsD-UvbM,2665
27
28
  bizyengine/bizyair_extras/nodes_model_advanced.py,sha256=s-dbFRWCdsTxctFYaZtmVwZ8-xuPPHixtkHFCmR7zcs,1755
29
+ bizyengine/bizyair_extras/nodes_nunchaku.py,sha256=trvQyHwYcT3mxV9-t2SR0pXk_qj0UHLqirlj3htaRc8,6832
28
30
  bizyengine/bizyair_extras/nodes_sd3.py,sha256=lZCxj0IFmuxk1fZTDcRKgVV5QWHjkUdpR4w9-DZbMf4,1727
29
31
  bizyengine/bizyair_extras/nodes_segment_anything.py,sha256=9Aeu4A2c2hA-Gu6kY6cINmZ3Y6DVXhWJCLjcW4M_v5o,7231
30
32
  bizyengine/bizyair_extras/nodes_segment_anything_utils.py,sha256=ZefAqrFrevDH3XY_wipr_VwKfeXrgpZEUFaqg_JGOdU,4714
@@ -49,20 +51,20 @@ bizyengine/core/commands/invoker.py,sha256=8wcIMd8k44o96LAvxFrIiKOlVtf1MW-AcMDXs
49
51
  bizyengine/core/commands/processors/model_hosting_processor.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
52
  bizyengine/core/commands/processors/prompt_processor.py,sha256=0PxSCvhI4gZmV3cEjJl8lKNb08EFemFVRRXrupedNdU,4467
51
53
  bizyengine/core/commands/servers/model_server.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- bizyengine/core/commands/servers/prompt_server.py,sha256=P-kRDXSRUkQvyZY16XOGsM4RbOo3-NWM9exJT1kGVHE,8139
54
+ bizyengine/core/commands/servers/prompt_server.py,sha256=mGkwhY7qVeCDNFmmP-Bh-V_uX3cVkH7FAaIrjpcsEWg,8140
53
55
  bizyengine/core/common/__init__.py,sha256=GicZw6YeAZk1PsKmFDt9dm1F75zPUlpia9Q_ki5vW1Y,179
54
56
  bizyengine/core/common/caching.py,sha256=isliSZsQyrNjXmupW-BaZ2EoVF5G8t7aHAhbcELAn5M,6253
55
- bizyengine/core/common/client.py,sha256=SohohVYSAja8nHZpK1kaDNbdH0qPH638-a8xUDMxTqI,9761
56
- bizyengine/core/common/env_var.py,sha256=hKU1Wx5p3Ook1ydnpxmDSH828Kwy1r_fKgTpZWtDEWA,3138
57
+ bizyengine/core/common/client.py,sha256=Bf_UAosHXyYJ1YJ93ltsvvzJDawIPPmCjVaMOW1Gw-o,10114
58
+ bizyengine/core/common/env_var.py,sha256=ZiJc5G84MgVMRj7yxI7WWt8lmmanJiGSWl23NyWLbg4,3266
57
59
  bizyengine/core/common/utils.py,sha256=bm-XmSPy83AyjD0v5EfWp6jiO6_5p7rkZ_HQAuVmgmo,3086
58
60
  bizyengine/core/configs/conf.py,sha256=D_UWG9SSJnK5EhbrfNFryJQ8hUwwdvhOGlq1TielwpI,3830
59
- bizyengine/core/configs/models.json,sha256=ut_ZbbdSJtAiG6DSHYoKKR2MUN7j-vnklJQVfJ7rwbg,2589
60
- bizyengine/core/configs/models.yaml,sha256=cEPRq5lsFWohqmjwTd7aM9Vy-WXwEec0rX627dQG-XU,8154
61
+ bizyengine/core/configs/models.json,sha256=jCrqQgjVeHugLb191Xay5rg0m3duTVISPp_GxVGQ3HA,2656
62
+ bizyengine/core/configs/models.yaml,sha256=Gbr5k-Yak_ybbPK50eK5wb6gKfDIWjdQ9QCVc7BvZ0Y,8399
61
63
  bizyengine/core/path_utils/__init__.py,sha256=5K9n4sexva0rfuYj3HcxdYeWnA1TuLTjpGGMFBTgnhM,240
62
64
  bizyengine/core/path_utils/path_manager.py,sha256=tRVAcpsYvfWD-tK7khLvNCZayB0wpU9L0tRTH4ZESzM,10549
63
65
  bizyengine/core/path_utils/utils.py,sha256=ksgNPyQaqilOImscLkSYizbRfDQropfxpL8tqIXardM,881
64
66
  bizyengine/misc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
- bizyengine/misc/auth.py,sha256=d3ptxii981cdBq14p6nQnDMWkNsI0HmoWNOebwtcUQI,2814
67
+ bizyengine/misc/auth.py,sha256=V7VoHZ9-ljT_gUUOOh7AeNnAyVuyiK8fiqSM8T8k948,2671
66
68
  bizyengine/misc/llm.py,sha256=6QZZpZSrHY6rmA6bmB9_cuiu34zcDKw7mAdsGiElYWQ,14332
67
69
  bizyengine/misc/mzkolors.py,sha256=jnOHNvHzvPDqlKYFhPv4KKCuPV4izbuPPbykFsOcH-E,2588
68
70
  bizyengine/misc/nodes.py,sha256=9njflJfklynyY0XmOCCzxlq48EwaO9wfrQGyXMqxlXM,43186
@@ -71,8 +73,8 @@ bizyengine/misc/nodes_controlnet_union_sdxl.py,sha256=e6Zs7unfPU-18VCLGgZXFOa0x1
71
73
  bizyengine/misc/route_sam.py,sha256=-bMIR2QalfnszipGxSxvDAHGJa5gPSrjkYPb5baaRg4,1561
72
74
  bizyengine/misc/segment_anything.py,sha256=RRm8FOfDY9VxdVrLjcdzJRh2pSM-kmNcCySuYnx9l7w,8677
73
75
  bizyengine/misc/supernode.py,sha256=MPoJN6H_oCV00lmv1LWtGdQwTlyQPI6gXdMDXgkFd7g,4197
74
- bizyengine/misc/utils.py,sha256=FRDEy63vDpssQxSFXrlK6WuXu15dNitYDIGGNOqtdH8,6353
75
- bizyengine-1.2.2.dist-info/METADATA,sha256=xk30yqMzfcY4UR1DqbDNX-Fq61jOY4fWUPQ2_wYkEjo,574
76
- bizyengine-1.2.2.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
77
- bizyengine-1.2.2.dist-info/top_level.txt,sha256=2zapzqxX-we5cRyJkGf9bd5JinRtXp3-_uDI-xCAnc0,11
78
- bizyengine-1.2.2.dist-info/RECORD,,
76
+ bizyengine/misc/utils.py,sha256=T9fPmnwUNYqYx0VYMFC_F478ru9m-8kMo_sZUZixM5s,6403
77
+ bizyengine-1.2.4.dist-info/METADATA,sha256=sH5YllXjbdg1c1r3s-I_AKIZ5Q7NKCPqSh7Pb_T6o0s,574
78
+ bizyengine-1.2.4.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
79
+ bizyengine-1.2.4.dist-info/top_level.txt,sha256=2zapzqxX-we5cRyJkGf9bd5JinRtXp3-_uDI-xCAnc0,11
80
+ bizyengine-1.2.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.0)
2
+ Generator: setuptools (80.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5