bizyengine 1.2.6__py3-none-any.whl → 1.2.8__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.
Files changed (32) hide show
  1. bizyengine/bizy_server/api_client.py +125 -57
  2. bizyengine/bizy_server/errno.py +9 -0
  3. bizyengine/bizy_server/server.py +353 -239
  4. bizyengine/bizyair_extras/__init__.py +1 -0
  5. bizyengine/bizyair_extras/nodes_flux.py +1 -1
  6. bizyengine/bizyair_extras/nodes_image_utils.py +2 -2
  7. bizyengine/bizyair_extras/nodes_nunchaku.py +1 -5
  8. bizyengine/bizyair_extras/nodes_segment_anything.py +1 -0
  9. bizyengine/bizyair_extras/nodes_trellis.py +1 -1
  10. bizyengine/bizyair_extras/nodes_ultimatesdupscale.py +1 -1
  11. bizyengine/bizyair_extras/nodes_wan_i2v.py +222 -0
  12. bizyengine/core/__init__.py +2 -0
  13. bizyengine/core/commands/processors/prompt_processor.py +21 -18
  14. bizyengine/core/commands/servers/prompt_server.py +28 -13
  15. bizyengine/core/common/client.py +14 -2
  16. bizyengine/core/common/env_var.py +2 -0
  17. bizyengine/core/nodes_base.py +85 -7
  18. bizyengine/core/nodes_io.py +2 -2
  19. bizyengine/misc/llm.py +48 -85
  20. bizyengine/misc/mzkolors.py +27 -19
  21. bizyengine/misc/nodes.py +41 -21
  22. bizyengine/misc/nodes_controlnet_aux.py +18 -18
  23. bizyengine/misc/nodes_controlnet_union_sdxl.py +5 -12
  24. bizyengine/misc/segment_anything.py +29 -25
  25. bizyengine/misc/supernode.py +36 -30
  26. bizyengine/misc/utils.py +33 -21
  27. bizyengine/version.txt +1 -1
  28. bizyengine-1.2.8.dist-info/METADATA +211 -0
  29. {bizyengine-1.2.6.dist-info → bizyengine-1.2.8.dist-info}/RECORD +31 -30
  30. {bizyengine-1.2.6.dist-info → bizyengine-1.2.8.dist-info}/WHEEL +1 -1
  31. bizyengine-1.2.6.dist-info/METADATA +0 -19
  32. {bizyengine-1.2.6.dist-info → bizyengine-1.2.8.dist-info}/top_level.txt +0 -0
@@ -4,8 +4,11 @@ import warnings
4
4
  from functools import wraps
5
5
  from typing import List
6
6
 
7
+ from bizyengine.core.common.env_var import BIZYAIR_DEBUG, BIZYAIR_SERVER_MODE
7
8
  from bizyengine.core.configs.conf import config_manager
9
+ from server import PromptServer
8
10
 
11
+ from .common.client import get_api_key
9
12
  from .data_types import is_send_request_datatype
10
13
  from .nodes_io import BizyAirNodeIO, create_node_data
11
14
 
@@ -23,6 +26,37 @@ PREFIX = f"BizyAir"
23
26
  NODE_CLASS_MAPPINGS = {}
24
27
  NODE_DISPLAY_NAME_MAPPINGS = {}
25
28
 
29
+ BIZYAIR_PROMPT_KEY = "bizyair_prompt"
30
+ BIZYAIR_PARAM_MAGIC_NODE_ID = "bizyair_magic_node"
31
+
32
+
33
+ def pop_api_key_and_prompt_id(kwargs):
34
+ extra_data = {}
35
+ prompt = None
36
+ if BIZYAIR_PROMPT_KEY in kwargs:
37
+ prompt = kwargs.pop(BIZYAIR_PROMPT_KEY)
38
+ if BIZYAIR_SERVER_MODE:
39
+ if BIZYAIR_PARAM_MAGIC_NODE_ID in prompt:
40
+ extra_data["api_key"] = prompt[BIZYAIR_PARAM_MAGIC_NODE_ID]["_meta"][
41
+ "api_key"
42
+ ]
43
+ extra_data["prompt_id"] = prompt[BIZYAIR_PARAM_MAGIC_NODE_ID]["_meta"][
44
+ "prompt_id"
45
+ ]
46
+ logging.debug(
47
+ "Using server mode passed in prompt_id: " + extra_data["prompt_id"]
48
+ )
49
+ else:
50
+ extra_data["api_key"] = get_api_key()
51
+ if (
52
+ PromptServer.instance is not None
53
+ and PromptServer.instance.last_prompt_id is not None
54
+ ):
55
+ extra_data["prompt_id"] = PromptServer.instance.last_prompt_id
56
+ print("Processing prompt with ID: " + PromptServer.instance.last_prompt_id)
57
+
58
+ return extra_data
59
+
26
60
 
27
61
  def process_kwargs(kwargs):
28
62
  possibleWidgetNames = [
@@ -91,7 +125,7 @@ def ensure_unique_id(org_func, original_has_unique_id=False):
91
125
  return new_func
92
126
 
93
127
 
94
- def ensure_hidden_unique_id(org_input_types_func):
128
+ def ensure_hidden_unique_id_and_prompt(org_input_types_func):
95
129
  original_has_unique_id = False
96
130
 
97
131
  @wraps(org_input_types_func)
@@ -105,6 +139,9 @@ def ensure_hidden_unique_id(org_input_types_func):
105
139
  result["hidden"]["unique_id"] = "UNIQUE_ID"
106
140
  else:
107
141
  original_has_unique_id = True
142
+ # Also set prompt, but to avoid naming conflict prefix with 'bizyair'
143
+ if BIZYAIR_PROMPT_KEY not in result["hidden"]:
144
+ result["hidden"][BIZYAIR_PROMPT_KEY] = "PROMPT"
108
145
  return result
109
146
 
110
147
  # Ensure original_has_unique_id is correctly set before returning
@@ -121,11 +158,19 @@ class BizyAirBaseNode:
121
158
  register_node(cls, PREFIX)
122
159
  cls.setup_input_types()
123
160
 
161
+ # 验证FUNCTION接受**kwargs
162
+ if BIZYAIR_DEBUG:
163
+ import inspect
164
+
165
+ sig = inspect.signature(getattr(cls, cls.FUNCTION))
166
+ params = sig.parameters.values()
167
+ assert any([True for p in params if p.kind == p.VAR_KEYWORD])
168
+
124
169
  @classmethod
125
170
  def setup_input_types(cls):
126
- # https://docs.comfy.org/essentials/custom_node_more_on_inputs#hidden-inputs
127
- new_input_types_func, original_has_unique_id = ensure_hidden_unique_id(
128
- cls.INPUT_TYPES
171
+ # https://docs.comfy.org/custom-nodes/backend/more_on_inputs#hidden-and-flexible-inputs
172
+ new_input_types_func, original_has_unique_id = (
173
+ ensure_hidden_unique_id_and_prompt(cls.INPUT_TYPES)
129
174
  )
130
175
  cls.INPUT_TYPES = new_input_types_func
131
176
  setattr(
@@ -140,13 +185,14 @@ class BizyAirBaseNode:
140
185
  return str(self._assigned_id)
141
186
 
142
187
  def default_function(self, **kwargs):
188
+ extra_data = pop_api_key_and_prompt_id(kwargs)
143
189
  class_type = self._determine_class_type()
144
190
  kwargs = process_kwargs(kwargs)
145
191
  node_ios = self._process_non_send_request_types(class_type, kwargs)
146
192
  # TODO: add processing for send_request_types
147
193
  send_request_datatype_list = self._get_send_request_datatypes()
148
194
  if len(send_request_datatype_list) == len(self.RETURN_TYPES):
149
- return self._process_all_send_request_types(node_ios)
195
+ return self._process_all_send_request_types(node_ios, **extra_data)
150
196
  return node_ios
151
197
 
152
198
  def _get_send_request_datatypes(self):
@@ -172,7 +218,39 @@ class BizyAirBaseNode:
172
218
  outs.append(node)
173
219
  return tuple(outs)
174
220
 
175
- def _process_all_send_request_types(self, node_ios: List[BizyAirNodeIO]):
176
- out = node_ios[0].send_request()
221
+ def _process_all_send_request_types(self, node_ios: List[BizyAirNodeIO], **kwargs):
222
+ out = node_ios[0].send_request(**kwargs)
177
223
  assert len(out) == len(self.RETURN_TYPES)
178
224
  return out
225
+
226
+
227
+ class BizyAirMiscBaseNode:
228
+ # 作为Misc节点基类来保证hidden prompt, unique id存在
229
+ def __init_subclass__(cls, **kwargs):
230
+ if hasattr(cls, "CATEGORY"):
231
+ if not cls.CATEGORY.startswith(f"{LOGO}{PREFIX}"):
232
+ cls.CATEGORY = f"{LOGO}{PREFIX}/{cls.CATEGORY}"
233
+ cls.setup_input_types()
234
+
235
+ # 验证FUNCTION接受**kwargs
236
+ if BIZYAIR_DEBUG:
237
+ import inspect
238
+
239
+ sig = inspect.signature(getattr(cls, cls.FUNCTION))
240
+ params = sig.parameters.values()
241
+ assert any([True for p in params if p.kind == p.VAR_KEYWORD])
242
+
243
+ @classmethod
244
+ def setup_input_types(cls):
245
+ if not hasattr(cls, "INPUT_TYPES"):
246
+ cls.INPUT_TYPES = lambda: {}
247
+ # https://docs.comfy.org/custom-nodes/backend/more_on_inputs#hidden-and-flexible-inputs
248
+ new_input_types_func, original_has_unique_id = (
249
+ ensure_hidden_unique_id_and_prompt(cls.INPUT_TYPES)
250
+ )
251
+ cls.INPUT_TYPES = new_input_types_func
252
+ setattr(
253
+ cls,
254
+ cls.FUNCTION,
255
+ ensure_unique_id(getattr(cls, cls.FUNCTION), original_has_unique_id),
256
+ )
@@ -82,10 +82,10 @@ class BizyAirNodeIO:
82
82
  self.nodes.update(other.nodes)
83
83
 
84
84
  def send_request(
85
- self, url=None, headers=None, *, progress_callback=None, stream=False
85
+ self, url=None, headers=None, *, progress_callback=None, stream=False, **kwargs
86
86
  ) -> any:
87
87
  out = invoker.prompt_server.execute(
88
- prompt=self.nodes, last_node_ids=[self.node_id]
88
+ prompt=self.nodes, last_node_ids=[self.node_id], **kwargs
89
89
  )
90
90
  return out
91
91
 
bizyengine/misc/llm.py CHANGED
@@ -3,13 +3,14 @@ import json
3
3
 
4
4
  import aiohttp
5
5
  from aiohttp import web
6
+ from bizyengine.core import BizyAirMiscBaseNode, pop_api_key_and_prompt_id
7
+ from bizyengine.core.common import client
6
8
  from bizyengine.core.common.env_var import BIZYAIR_SERVER_ADDRESS
7
9
  from bizyengine.core.image_utils import decode_data, encode_comfy_image, encode_data
8
10
  from server import PromptServer
9
11
 
10
12
  from .utils import (
11
13
  decode_and_deserialize,
12
- get_api_key,
13
14
  get_llm_response,
14
15
  get_vlm_response,
15
16
  send_post_request,
@@ -17,52 +18,7 @@ from .utils import (
17
18
  )
18
19
 
19
20
 
20
- async def fetch_all_models(api_key):
21
- url = f"{BIZYAIR_SERVER_ADDRESS}/llm/models"
22
- headers = {"accept": "application/json", "authorization": f"Bearer {api_key}"}
23
- params = {"type": "text", "sub_type": "chat"}
24
-
25
- try:
26
- async with aiohttp.ClientSession() as session:
27
- async with session.get(
28
- url, headers=headers, params=params, timeout=10
29
- ) as response:
30
- if response.status == 200:
31
- data = await response.json()
32
- all_models = [model["id"] for model in data["data"]]
33
- return all_models
34
- else:
35
- print(f"Error fetching models: HTTP Status {response.status}")
36
- return []
37
- except aiohttp.ClientError as e:
38
- print(f"Error fetching models: {e}")
39
- return []
40
- except asyncio.exceptions.TimeoutError:
41
- print("Request to fetch models timed out")
42
- return []
43
-
44
-
45
- @PromptServer.instance.routes.post("/bizyair/get_silicon_cloud_llm_models")
46
- async def get_silicon_cloud_llm_models_endpoint(request):
47
- data = await request.json()
48
- api_key = data.get("api_key", get_api_key())
49
- all_models = await fetch_all_models(api_key)
50
- llm_models = [model for model in all_models if "vl" not in model.lower()]
51
- llm_models.append("No LLM Enhancement")
52
- return web.json_response(llm_models)
53
-
54
-
55
- @PromptServer.instance.routes.post("/bizyair/get_silicon_cloud_vlm_models")
56
- async def get_silicon_cloud_vlm_models_endpoint(request):
57
- data = await request.json()
58
- api_key = data.get("api_key", get_api_key())
59
- all_models = await fetch_all_models(api_key)
60
- vlm_models = [model for model in all_models if "vl" in model.lower()]
61
- vlm_models.append("No VLM Enhancement")
62
- return web.json_response(vlm_models)
63
-
64
-
65
- class SiliconCloudLLMAPI:
21
+ class SiliconCloudLLMAPI(BizyAirMiscBaseNode):
66
22
  def __init__(self):
67
23
  pass
68
24
 
@@ -93,7 +49,7 @@ class SiliconCloudLLMAPI:
93
49
  "FLOAT",
94
50
  {"default": 0.7, "min": 0.0, "max": 2.0, "step": 0.01},
95
51
  ),
96
- }
52
+ },
97
53
  }
98
54
 
99
55
  RETURN_TYPES = ("STRING",)
@@ -102,23 +58,18 @@ class SiliconCloudLLMAPI:
102
58
  CATEGORY = "☁️BizyAir/AI Assistants"
103
59
 
104
60
  def get_llm_model_response(
105
- self, model, system_prompt, user_prompt, max_tokens, temperature
61
+ self, model, system_prompt, user_prompt, max_tokens, temperature, **kwargs
106
62
  ):
107
63
  if model == "No LLM Enhancement":
108
64
  return {"ui": {"text": (user_prompt,)}, "result": (user_prompt,)}
109
- response = get_llm_response(
110
- model,
111
- system_prompt,
112
- user_prompt,
113
- max_tokens,
114
- temperature,
65
+ ret = get_llm_response(
66
+ model, system_prompt, user_prompt, max_tokens, temperature, **kwargs
115
67
  )
116
- ret = json.loads(response)
117
68
  text = ret["choices"][0]["message"]["content"]
118
69
  return (text,) # if update ui: {"ui": {"text": (text,)}, "result": (text,)}
119
70
 
120
71
 
121
- class SiliconCloudVLMAPI:
72
+ class SiliconCloudVLMAPI(BizyAirMiscBaseNode):
122
73
  def __init__(self):
123
74
  pass
124
75
 
@@ -148,7 +99,7 @@ class SiliconCloudVLMAPI:
148
99
  {"default": 0.7, "min": 0.0, "max": 2.0, "step": 0.01},
149
100
  ),
150
101
  "detail": (["auto", "low", "high"], {"default": "auto"}),
151
- }
102
+ },
152
103
  }
153
104
 
154
105
  RETURN_TYPES = ("STRING",)
@@ -157,7 +108,15 @@ class SiliconCloudVLMAPI:
157
108
  CATEGORY = "☁️BizyAir/AI Assistants"
158
109
 
159
110
  def get_vlm_model_response(
160
- self, model, system_prompt, user_prompt, images, max_tokens, temperature, detail
111
+ self,
112
+ model,
113
+ system_prompt,
114
+ user_prompt,
115
+ images,
116
+ max_tokens,
117
+ temperature,
118
+ detail,
119
+ **kwargs,
161
120
  ):
162
121
  if model == "No VLM Enhancement":
163
122
  return (user_prompt,)
@@ -171,7 +130,7 @@ class SiliconCloudVLMAPI:
171
130
  # 提取所有编码后的图像
172
131
  base64_images = list(encoded_images_dict.values())
173
132
 
174
- response = get_vlm_response(
133
+ ret = get_vlm_response(
175
134
  model,
176
135
  system_prompt,
177
136
  user_prompt,
@@ -179,13 +138,13 @@ class SiliconCloudVLMAPI:
179
138
  max_tokens,
180
139
  temperature,
181
140
  detail,
141
+ **kwargs,
182
142
  )
183
- ret = json.loads(response)
184
143
  text = ret["choices"][0]["message"]["content"]
185
144
  return (text,)
186
145
 
187
146
 
188
- class BizyAirJoyCaption:
147
+ class BizyAirJoyCaption(BizyAirMiscBaseNode):
189
148
  # refer to: https://huggingface.co/spaces/fancyfeast/joy-caption-pre-alpha
190
149
  API_URL = f"{BIZYAIR_SERVER_ADDRESS}/supernode/joycaption2"
191
150
 
@@ -216,7 +175,7 @@ class BizyAirJoyCaption:
216
175
  "display": "number",
217
176
  },
218
177
  ),
219
- }
178
+ },
220
179
  }
221
180
 
222
181
  RETURN_TYPES = ("STRING",)
@@ -224,8 +183,10 @@ class BizyAirJoyCaption:
224
183
 
225
184
  CATEGORY = "☁️BizyAir/AI Assistants"
226
185
 
227
- def joycaption(self, image, do_sample, temperature, max_tokens):
228
- API_KEY = get_api_key()
186
+ def joycaption(self, image, do_sample, temperature, max_tokens, **kwargs):
187
+ extra_data = pop_api_key_and_prompt_id(kwargs)
188
+ headers = client.headers(api_key=extra_data["api_key"])
189
+
229
190
  SIZE_LIMIT = 1536
230
191
  # device = image.device
231
192
  _, w, h, c = image.shape
@@ -244,17 +205,18 @@ class BizyAirJoyCaption:
244
205
  "name_input": "",
245
206
  "custom_prompt": "A descriptive caption for this image:\n",
246
207
  }
247
- auth = f"Bearer {API_KEY}"
248
- headers = {
249
- "accept": "application/json",
250
- "content-type": "application/json",
251
- "authorization": auth,
252
- }
253
208
  input_image = encode_data(image, disable_image_marker=True)
254
209
  payload["image"] = input_image
255
-
256
- ret: str = send_post_request(self.API_URL, payload=payload, headers=headers)
257
- ret = json.loads(ret)
210
+ if "prompt_id" in extra_data:
211
+ payload["prompt_id"] = extra_data["prompt_id"]
212
+ data = json.dumps(payload).encode("utf-8")
213
+
214
+ ret = client.send_request(
215
+ url=self.API_URL,
216
+ data=data,
217
+ headers=headers,
218
+ callback=None,
219
+ )
258
220
 
259
221
  try:
260
222
  if "result" in ret:
@@ -275,7 +237,7 @@ class BizyAirJoyCaption:
275
237
  return (caption,)
276
238
 
277
239
 
278
- class BizyAirJoyCaption2:
240
+ class BizyAirJoyCaption2(BizyAirMiscBaseNode):
279
241
  def __init__(self):
280
242
  pass
281
243
 
@@ -348,7 +310,7 @@ class BizyAirJoyCaption2:
348
310
  "multiline": True,
349
311
  },
350
312
  ),
351
- }
313
+ },
352
314
  }
353
315
 
354
316
  RETURN_TYPES = ("STRING",)
@@ -367,8 +329,11 @@ class BizyAirJoyCaption2:
367
329
  extra_options,
368
330
  name_input,
369
331
  custom_prompt,
332
+ **kwargs,
370
333
  ):
371
- API_KEY = get_api_key()
334
+ extra_data = pop_api_key_and_prompt_id(kwargs)
335
+ headers = client.headers(api_key=extra_data["api_key"])
336
+
372
337
  SIZE_LIMIT = 1536
373
338
  _, w, h, c = image.shape
374
339
  assert (
@@ -386,17 +351,15 @@ class BizyAirJoyCaption2:
386
351
  "name_input": name_input,
387
352
  "custom_prompt": custom_prompt,
388
353
  }
389
- auth = f"Bearer {API_KEY}"
390
- headers = {
391
- "accept": "application/json",
392
- "content-type": "application/json",
393
- "authorization": auth,
394
- }
395
354
  input_image = encode_data(image, disable_image_marker=True)
396
355
  payload["image"] = input_image
356
+ if "prompt_id" in extra_data:
357
+ payload["prompt_id"] = extra_data["prompt_id"]
358
+ data = json.dumps(payload).encode("utf-8")
397
359
 
398
- ret: str = send_post_request(self.API_URL, payload=payload, headers=headers)
399
- ret = json.loads(ret)
360
+ ret: str = client.send_request(
361
+ url=self.API_URL, data=data, headers=headers, callback=None
362
+ )
400
363
 
401
364
  try:
402
365
  if "result" in ret:
@@ -1,23 +1,29 @@
1
+ import json
1
2
  import os
2
3
  import uuid
3
4
 
4
5
  import torch
5
- from bizyengine.core import BizyAirBaseNode, BizyAirNodeIO, create_node_data
6
+ from bizyengine.core import (
7
+ BizyAirBaseNode,
8
+ BizyAirMiscBaseNode,
9
+ BizyAirNodeIO,
10
+ create_node_data,
11
+ )
12
+ from bizyengine.core.common import client
6
13
  from bizyengine.core.common.env_var import BIZYAIR_SERVER_ADDRESS
7
14
  from bizyengine.core.data_types import CONDITIONING
8
15
  from bizyengine.core.image_utils import encode_data
9
16
 
10
17
  from .utils import (
11
18
  decode_and_deserialize,
12
- get_api_key,
13
- send_post_request,
19
+ pop_api_key_and_prompt_id,
14
20
  serialize_and_encode,
15
21
  )
16
22
 
17
23
  CATEGORY_NAME = "☁️BizyAir/Kolors"
18
24
 
19
25
 
20
- class BizyAirMZChatGLM3TextEncode:
26
+ class BizyAirMZChatGLM3TextEncode(BizyAirMiscBaseNode):
21
27
  API_URL = f"{BIZYAIR_SERVER_ADDRESS}/supernode/mzkolorschatglm3"
22
28
 
23
29
  @classmethod
@@ -25,7 +31,7 @@ class BizyAirMZChatGLM3TextEncode:
25
31
  return {
26
32
  "required": {
27
33
  "text": ("STRING", {"multiline": True, "dynamicPrompts": True}),
28
- }
34
+ },
29
35
  }
30
36
 
31
37
  RETURN_TYPES = ("CONDITIONING",)
@@ -33,24 +39,26 @@ class BizyAirMZChatGLM3TextEncode:
33
39
  FUNCTION = "encode"
34
40
  CATEGORY = CATEGORY_NAME
35
41
 
36
- def encode(self, text):
37
- API_KEY = get_api_key()
42
+ def encode(self, text, **kwargs):
43
+ extra_data = pop_api_key_and_prompt_id(kwargs)
44
+ headers = client.headers(api_key=extra_data["api_key"])
45
+
38
46
  assert len(text) <= 4096, f"the prompt is too long, length: {len(text)}"
39
47
 
40
48
  payload = {
41
49
  "text": text,
42
50
  }
43
- auth = f"Bearer {API_KEY}"
44
- headers = {
45
- "accept": "application/json",
46
- "content-type": "application/json",
47
- "authorization": auth,
48
- }
49
-
50
- response: str = send_post_request(
51
- self.API_URL, payload=payload, headers=headers
51
+ if "prompt_id" in extra_data:
52
+ payload["prompt_id"] = extra_data["prompt_id"]
53
+ data = json.dumps(payload).encode("utf-8")
54
+
55
+ tensors_np = client.send_request(
56
+ url=self.API_URL,
57
+ data=data,
58
+ headers=headers,
59
+ callback=None,
60
+ response_handler=decode_and_deserialize,
52
61
  )
53
- tensors_np = decode_and_deserialize(response)
54
62
 
55
63
  ret_conditioning = []
56
64
  for item in tensors_np:
@@ -69,8 +77,8 @@ class BizyAir_MinusZoneChatGLM3TextEncode(BizyAirMZChatGLM3TextEncode, BizyAirBa
69
77
 
70
78
  FUNCTION = "mz_encode"
71
79
 
72
- def mz_encode(self, text):
73
- out = self.encode(text)[0]
80
+ def mz_encode(self, text, **kwargs):
81
+ out = self.encode(text=text, **kwargs)[0]
74
82
  node_data = create_node_data(
75
83
  class_type="ComfyAirLoadData",
76
84
  inputs={"conditioning": {"relay": out}},