bizyengine 1.2.58__py3-none-any.whl → 1.2.71__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.
- bizyengine/bizy_server/server.py +2 -2
- bizyengine/bizy_server/utils.py +3 -0
- bizyengine/bizyair_extras/__init__.py +1 -3
- bizyengine/bizyair_extras/third_party_api/__init__.py +15 -0
- bizyengine/bizyair_extras/third_party_api/nodes_doubao.py +535 -0
- bizyengine/bizyair_extras/third_party_api/nodes_flux.py +173 -0
- bizyengine/bizyair_extras/third_party_api/nodes_gemini.py +403 -0
- bizyengine/bizyair_extras/third_party_api/nodes_gpt.py +101 -0
- bizyengine/bizyair_extras/third_party_api/nodes_hailuo.py +115 -0
- bizyengine/bizyair_extras/third_party_api/nodes_kling.py +404 -0
- bizyengine/bizyair_extras/third_party_api/nodes_sora.py +218 -0
- bizyengine/bizyair_extras/third_party_api/nodes_veo3.py +193 -0
- bizyengine/bizyair_extras/third_party_api/nodes_wan_api.py +198 -0
- bizyengine/bizyair_extras/third_party_api/trd_nodes_base.py +183 -0
- bizyengine/bizyair_extras/utils/aliyun_oss.py +17 -0
- bizyengine/core/__init__.py +1 -0
- bizyengine/core/commands/servers/prompt_server.py +10 -1
- bizyengine/version.txt +1 -1
- {bizyengine-1.2.58.dist-info → bizyengine-1.2.71.dist-info}/METADATA +3 -3
- {bizyengine-1.2.58.dist-info → bizyengine-1.2.71.dist-info}/RECORD +22 -14
- bizyengine/bizyair_extras/nodes_gemini.py +0 -311
- bizyengine/bizyair_extras/nodes_seedream.py +0 -195
- bizyengine/bizyair_extras/nodes_wan_api.py +0 -291
- {bizyengine-1.2.58.dist-info → bizyengine-1.2.71.dist-info}/WHEEL +0 -0
- {bizyengine-1.2.58.dist-info → bizyengine-1.2.71.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import io
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import time
|
|
6
|
+
from typing import List, Tuple
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
import torch
|
|
10
|
+
from bizyairsdk import bytesio_to_image_tensor, common_upscale
|
|
11
|
+
from comfy_api.latest._input_impl import VideoFromFile
|
|
12
|
+
|
|
13
|
+
from bizyengine.core import (
|
|
14
|
+
BizyAirMiscBaseNode,
|
|
15
|
+
pop_api_key_and_prompt_id,
|
|
16
|
+
register_node,
|
|
17
|
+
)
|
|
18
|
+
from bizyengine.core.common import client
|
|
19
|
+
from bizyengine.core.common.client import send_request
|
|
20
|
+
from bizyengine.core.common.env_var import BIZYAIR_X_SERVER
|
|
21
|
+
from bizyengine.core.nodes_base import PREFIX
|
|
22
|
+
|
|
23
|
+
from ..utils.aliyun_oss import parse_upload_token, upload_file_without_sdk
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TrdBase(abc.ABC):
|
|
27
|
+
@abc.abstractmethod
|
|
28
|
+
# Return: data, model, prompt
|
|
29
|
+
def handle_inputs(self, headers, prompt_id, **kwargs) -> Tuple[dict, str]:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
@abc.abstractmethod
|
|
33
|
+
# Return: videos, images, texts
|
|
34
|
+
def handle_outputs(
|
|
35
|
+
self, outputs: Tuple[List[VideoFromFile], List[torch.Tensor], List[str]]
|
|
36
|
+
) -> Tuple:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class BizyAirTrdApiBaseNode(BizyAirMiscBaseNode, TrdBase):
|
|
41
|
+
FUNCTION = "api_call"
|
|
42
|
+
OUTPUT_NODE = False
|
|
43
|
+
|
|
44
|
+
def __init_subclass__(cls, **kwargs):
|
|
45
|
+
super().__init_subclass__(**kwargs)
|
|
46
|
+
register_node(cls, PREFIX)
|
|
47
|
+
|
|
48
|
+
def api_call(self, **kwargs):
|
|
49
|
+
extra_data = pop_api_key_and_prompt_id(kwargs)
|
|
50
|
+
headers = client.headers(api_key=extra_data["api_key"])
|
|
51
|
+
prompt_id = extra_data["prompt_id"]
|
|
52
|
+
headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
|
|
53
|
+
|
|
54
|
+
data, model = self.handle_inputs(headers, prompt_id, **kwargs)
|
|
55
|
+
outputs = self.create_task_and_wait_for_completion(data, model, headers)
|
|
56
|
+
return self.handle_outputs(outputs)
|
|
57
|
+
|
|
58
|
+
def create_task_and_wait_for_completion(
|
|
59
|
+
self, data, model, headers
|
|
60
|
+
) -> Tuple[List[VideoFromFile], List[torch.Tensor], List[str]]:
|
|
61
|
+
# 创建任务
|
|
62
|
+
create_task_url = f"{BIZYAIR_X_SERVER}/trd_api/{model}"
|
|
63
|
+
json_payload = json.dumps(data).encode("utf-8")
|
|
64
|
+
logging.debug(f"json_payload: {json_payload}")
|
|
65
|
+
create_api_resp = send_request(
|
|
66
|
+
url=create_task_url,
|
|
67
|
+
data=json_payload,
|
|
68
|
+
headers=headers,
|
|
69
|
+
)
|
|
70
|
+
logging.debug(
|
|
71
|
+
f"{self.NODE_DISPLAY_NAME} create task api resp: {create_api_resp}"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# 检查任务创建是否成功
|
|
75
|
+
if "data" not in create_api_resp or "request_id" not in create_api_resp["data"]:
|
|
76
|
+
raise ValueError(f"Invalid response: {create_api_resp}")
|
|
77
|
+
|
|
78
|
+
# 轮询获取结果,最多等待1小时
|
|
79
|
+
request_id = create_api_resp["data"]["request_id"]
|
|
80
|
+
logging.info(f"{self.NODE_DISPLAY_NAME} task created, request_id: {request_id}")
|
|
81
|
+
start_time = time.time()
|
|
82
|
+
status_url = f"{BIZYAIR_X_SERVER}/trd_api/{request_id}"
|
|
83
|
+
while time.time() - start_time < 3600:
|
|
84
|
+
time.sleep(10)
|
|
85
|
+
try:
|
|
86
|
+
status_api_resp = send_request(
|
|
87
|
+
method="GET",
|
|
88
|
+
url=status_url,
|
|
89
|
+
headers=headers,
|
|
90
|
+
)
|
|
91
|
+
except Exception as e:
|
|
92
|
+
logging.error(
|
|
93
|
+
f"{self.NODE_DISPLAY_NAME} task {request_id} status api error: {e}"
|
|
94
|
+
)
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
if "data" not in status_api_resp:
|
|
98
|
+
logging.error(
|
|
99
|
+
f"{self.NODE_DISPLAY_NAME} task {request_id} status api resp no data: {status_api_resp}"
|
|
100
|
+
)
|
|
101
|
+
continue
|
|
102
|
+
if "status" not in status_api_resp["data"]:
|
|
103
|
+
logging.error(
|
|
104
|
+
f"{self.NODE_DISPLAY_NAME} task {request_id} status api resp no status: {status_api_resp}"
|
|
105
|
+
)
|
|
106
|
+
continue
|
|
107
|
+
status = status_api_resp["data"]["status"]
|
|
108
|
+
if status == "failed":
|
|
109
|
+
raise ValueError(
|
|
110
|
+
f"{self.NODE_DISPLAY_NAME} task {request_id} failed: {status_api_resp}"
|
|
111
|
+
)
|
|
112
|
+
if status == "running":
|
|
113
|
+
continue
|
|
114
|
+
|
|
115
|
+
# 成功,获取输出结果
|
|
116
|
+
if "outputs" not in status_api_resp["data"]:
|
|
117
|
+
raise ValueError(
|
|
118
|
+
f"{self.NODE_DISPLAY_NAME} task {request_id} no outputs: {status_api_resp}"
|
|
119
|
+
)
|
|
120
|
+
logging.info(
|
|
121
|
+
f"{self.NODE_DISPLAY_NAME} task {request_id} success: {status_api_resp}"
|
|
122
|
+
)
|
|
123
|
+
# 分别处理视频、图片、文本
|
|
124
|
+
videos = []
|
|
125
|
+
images = []
|
|
126
|
+
texts = []
|
|
127
|
+
outputs = status_api_resp["data"]["outputs"]
|
|
128
|
+
try:
|
|
129
|
+
if "videos" in outputs:
|
|
130
|
+
for video_url in outputs["videos"]:
|
|
131
|
+
video_resp = requests.get(video_url, stream=True, timeout=3600)
|
|
132
|
+
video_resp.raise_for_status() # 非 2xx 会抛异常
|
|
133
|
+
videos.append(VideoFromFile(io.BytesIO(video_resp.content)))
|
|
134
|
+
if "images" in outputs:
|
|
135
|
+
for image_url in outputs["images"]:
|
|
136
|
+
image_resp = requests.get(image_url, stream=True, timeout=3600)
|
|
137
|
+
image_resp.raise_for_status() # 非 2xx 会抛异常
|
|
138
|
+
images.append(
|
|
139
|
+
bytesio_to_image_tensor(io.BytesIO(image_resp.content))
|
|
140
|
+
)
|
|
141
|
+
if "texts" in outputs:
|
|
142
|
+
for text in outputs["texts"]:
|
|
143
|
+
texts.append(text)
|
|
144
|
+
except Exception as e:
|
|
145
|
+
logging.error(
|
|
146
|
+
f"{self.NODE_DISPLAY_NAME} task {request_id} handle outputs error: {e}"
|
|
147
|
+
)
|
|
148
|
+
raise ValueError(
|
|
149
|
+
f"{self.NODE_DISPLAY_NAME} task {request_id} handle outputs error: {e}, please download the outputs manually, outputs: {outputs}"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
return (videos, images, texts)
|
|
153
|
+
|
|
154
|
+
raise ValueError(
|
|
155
|
+
f"{self.NODE_DISPLAY_NAME} task timed out, request ID: {request_id}"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def upload_file(self, bytes, file_name, headers):
|
|
159
|
+
oss_token_url = (
|
|
160
|
+
f"{BIZYAIR_X_SERVER}/upload/token?file_name={file_name}&file_type=inputs"
|
|
161
|
+
)
|
|
162
|
+
token_resp = send_request("GET", oss_token_url, headers=headers)
|
|
163
|
+
auth_info = parse_upload_token(token_resp)
|
|
164
|
+
return upload_file_without_sdk(file_content=bytes, **auth_info)
|
|
165
|
+
|
|
166
|
+
def combine_images(self, images: List[torch.Tensor]) -> torch.Tensor:
|
|
167
|
+
s = None
|
|
168
|
+
if images is not None and len(images) > 0:
|
|
169
|
+
for _, image in enumerate(images):
|
|
170
|
+
if s is None:
|
|
171
|
+
s = image
|
|
172
|
+
else:
|
|
173
|
+
# ComfyUI BatchImage logic
|
|
174
|
+
if s.shape[1:] != image.shape[1:]:
|
|
175
|
+
image = common_upscale(
|
|
176
|
+
image.movedim(-1, 1),
|
|
177
|
+
s.shape[2],
|
|
178
|
+
image.shape[1],
|
|
179
|
+
"bilinear",
|
|
180
|
+
"center",
|
|
181
|
+
).movedim(1, -1)
|
|
182
|
+
s = torch.cat((s, image), dim=0)
|
|
183
|
+
return s
|
|
@@ -73,3 +73,20 @@ def upload_file_without_sdk(
|
|
|
73
73
|
if response is not None:
|
|
74
74
|
logging.error(f"Response content: {response.text}")
|
|
75
75
|
raise e
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def parse_upload_token(resp) -> dict:
|
|
79
|
+
logging.debug(f"parsing token resp: {resp}")
|
|
80
|
+
if "data" not in resp:
|
|
81
|
+
logging.error(f"Invalid response, data not found: {resp}")
|
|
82
|
+
raise ValueError(f"Invalid response: {resp}")
|
|
83
|
+
data = resp["data"]
|
|
84
|
+
if "file" not in data:
|
|
85
|
+
logging.error(f"Invalid response, file not found: {resp}")
|
|
86
|
+
raise ValueError(f"Invalid response: {resp}")
|
|
87
|
+
file = data["file"]
|
|
88
|
+
if "storage" not in data:
|
|
89
|
+
logging.error(f"Invalid response, storage not found: {resp}")
|
|
90
|
+
raise ValueError(f"Invalid response: {resp}")
|
|
91
|
+
storage = data["storage"]
|
|
92
|
+
return file | storage
|
bizyengine/core/__init__.py
CHANGED
|
@@ -294,7 +294,16 @@ class PromptServer(Command):
|
|
|
294
294
|
|
|
295
295
|
try:
|
|
296
296
|
real_out = decode_data(out)
|
|
297
|
-
|
|
297
|
+
out_lst = []
|
|
298
|
+
for x in real_out:
|
|
299
|
+
if (
|
|
300
|
+
x is None
|
|
301
|
+
): # ref: https://github.com/siliconflow/comfybridge/blob/ecf2e835d4db9816514078f9eed98ab8ba12e23e/custom_plugins/comfy_pipeline/executor.py#L75-L78
|
|
302
|
+
out_lst.append(None)
|
|
303
|
+
else:
|
|
304
|
+
# ref: https://github.com/comfyanonymous/ComfyUI/blob/c170fd2db598a0bdce56f80e22e83e10ad731421/execution.py#L312
|
|
305
|
+
out_lst.append(x[0])
|
|
306
|
+
return out_lst
|
|
298
307
|
except Exception as e:
|
|
299
308
|
print("Exception occurred while decoding data")
|
|
300
309
|
self.cache_manager.delete(sh256)
|
bizyengine/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.2.
|
|
1
|
+
1.2.71
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bizyengine
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.71
|
|
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
|
|
@@ -13,8 +13,8 @@ Requires-Dist: requests
|
|
|
13
13
|
Requires-Dist: inputimeout
|
|
14
14
|
Requires-Dist: openai>=1.77.0
|
|
15
15
|
Requires-Dist: pycryptodome
|
|
16
|
-
Requires-Dist: mcp>=1.
|
|
17
|
-
Requires-Dist: bizyairsdk>=0.
|
|
16
|
+
Requires-Dist: mcp>=1.18.0
|
|
17
|
+
Requires-Dist: bizyairsdk>=0.1.5
|
|
18
18
|
|
|
19
19
|
## BizyEngine
|
|
20
20
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
bizyengine/__init__.py,sha256=GP9V-JM07fz7uv_qTB43QEA2rKdrVJxi5I7LRnn_3ZQ,914
|
|
2
|
-
bizyengine/version.txt,sha256=
|
|
2
|
+
bizyengine/version.txt,sha256=VZ2LG2EeQz_WRAh5_a0VSfKb4zrw1bm78ky8aM0_qL8,7
|
|
3
3
|
bizyengine/bizy_server/__init__.py,sha256=SP9oSblnPo4KQyh7yOGD26YCskFAcQHAZy04nQBNRIw,200
|
|
4
4
|
bizyengine/bizy_server/api_client.py,sha256=Z7G5IjaEqSJkF6nLLw2R3bpgBAOi5ClQiUbel6NMXmE,43932
|
|
5
5
|
bizyengine/bizy_server/errno.py,sha256=RIyvegX3lzpx_1L1q2XVvu3on0kvYgKiUQ8U3ZtyF68,16823
|
|
@@ -7,10 +7,10 @@ bizyengine/bizy_server/error_handler.py,sha256=MGrfO1AEqbfEgMWPL8B6Ypew_zHiQAdYG
|
|
|
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=
|
|
10
|
+
bizyengine/bizy_server/server.py,sha256=ZLWTDRtTGV601JGcJYJsp_NUgsJyKoDdR7KrStLzW5g,57490
|
|
11
11
|
bizyengine/bizy_server/stream_response.py,sha256=H2XHqlVRtQMhgdztAuG7l8-iV_Pm42u2x6WJ0gNVIW0,9654
|
|
12
|
-
bizyengine/bizy_server/utils.py,sha256=
|
|
13
|
-
bizyengine/bizyair_extras/__init__.py,sha256=
|
|
12
|
+
bizyengine/bizy_server/utils.py,sha256=t3y3ZTDzFa8K4wXlzgLVaFNCizgylsKsd9K3rLL4sGw,3986
|
|
13
|
+
bizyengine/bizyair_extras/__init__.py,sha256=9iPmEyR7F1IXbUaBNS90ivW9ul18GcuWFxRfFv2ieAw,1011
|
|
14
14
|
bizyengine/bizyair_extras/nodes_advanced_refluxcontrol.py,sha256=cecfjrtnjJAty9aNkhz8BlmHUC1NImkFlUDiA0COEa4,2242
|
|
15
15
|
bizyengine/bizyair_extras/nodes_cogview4.py,sha256=Ni0TDOycczyDhYPvSR68TxGV_wE2uhaxd8MIj-J4-3o,2031
|
|
16
16
|
bizyengine/bizyair_extras/nodes_comfyui_detail_daemon.py,sha256=i71it24tiGvZ3h-XFWISr4CpZszUtPuz3UrZARYluLk,6169
|
|
@@ -22,7 +22,6 @@ bizyengine/bizyair_extras/nodes_custom_sampler.py,sha256=NK-7sdcp8oxJisjTEFfBskk
|
|
|
22
22
|
bizyengine/bizyair_extras/nodes_dataset.py,sha256=htF0YZb_FHncLhLDEbJfNCVqJ6rvlo1ZLk7iY42Rylc,3440
|
|
23
23
|
bizyengine/bizyair_extras/nodes_differential_diffusion.py,sha256=nSrbD-w0XtrwktwzME5M0Vmi1sI7Z08AqwgymTdThqo,370
|
|
24
24
|
bizyengine/bizyair_extras/nodes_flux.py,sha256=ls94kGBuBNgW5c6uhG36iZLk1TTM2TIoTTcpERgEE5E,2683
|
|
25
|
-
bizyengine/bizyair_extras/nodes_gemini.py,sha256=g1LBpAs5vbORJJZjxt0iv5uNvs8mOQL_-88JL_wA5MY,10602
|
|
26
25
|
bizyengine/bizyair_extras/nodes_hunyuan3d.py,sha256=dWHLeqX68N7zKnfDMzm9nutmCNtFT6-wwt7P5cPDu7Q,2058
|
|
27
26
|
bizyengine/bizyair_extras/nodes_image_utils.py,sha256=BldF_CKD2M01K8-SnG-QV86u3HZqFz_GP5GrCQ5CFDQ,2875
|
|
28
27
|
bizyengine/bizyair_extras/nodes_ip2p.py,sha256=GSEFJvrs4f2tv0xwYkWqc8uhsXrzAJVPvvwcw0gTjR0,619
|
|
@@ -32,7 +31,6 @@ bizyengine/bizyair_extras/nodes_nunchaku.py,sha256=iI1Qe_5fQ_43QdUS_reCIOyRFv9-B
|
|
|
32
31
|
bizyengine/bizyair_extras/nodes_reactor.py,sha256=hbm0HGQWAr_qMcWjp0nMZMtF4mUjTfPw8yK1rq1miAI,8157
|
|
33
32
|
bizyengine/bizyair_extras/nodes_sam2.py,sha256=JTrB7ELwhw6_uOjykRWK9KyOqpYoOtJiGKMxFUbHnNQ,10554
|
|
34
33
|
bizyengine/bizyair_extras/nodes_sd3.py,sha256=lZCxj0IFmuxk1fZTDcRKgVV5QWHjkUdpR4w9-DZbMf4,1727
|
|
35
|
-
bizyengine/bizyair_extras/nodes_seedream.py,sha256=-I22lrdR0S6oRCgN7e5HD8pOJhuGBxDMlhX2S-CyOhY,6855
|
|
36
34
|
bizyengine/bizyair_extras/nodes_segment_anything.py,sha256=x1ei2UggHnB8T6aUtK_ZcUehMALEyLUnDoD5SNJCbFU,7249
|
|
37
35
|
bizyengine/bizyair_extras/nodes_segment_anything_utils.py,sha256=ZefAqrFrevDH3XY_wipr_VwKfeXrgpZEUFaqg_JGOdU,4714
|
|
38
36
|
bizyengine/bizyair_extras/nodes_testing_utils.py,sha256=lYmcyCIkTkQ7WOZfpEPU9wUbEvC_mL6_A46ks68WzZA,3988
|
|
@@ -40,7 +38,6 @@ bizyengine/bizyair_extras/nodes_trellis.py,sha256=GqSRM8FobuziOIxwyAs3BLztpjVIP4
|
|
|
40
38
|
bizyengine/bizyair_extras/nodes_ultimatesdupscale.py,sha256=-_SsLTAWAQDv4uw-4Z7IGP2tXTe73BJ3N5D6RqVVAK4,4133
|
|
41
39
|
bizyengine/bizyair_extras/nodes_upscale_model.py,sha256=lrzA1BFI2w5aEPCmNPMh07s-WDzG-xTT49uU6WCnlP8,1151
|
|
42
40
|
bizyengine/bizyair_extras/nodes_utils.py,sha256=whog_tmV-q7JvLEdb03JL3KKsC7wKe3kImzx_jPaQD8,2613
|
|
43
|
-
bizyengine/bizyair_extras/nodes_wan_api.py,sha256=RMC1xUgvNjI6_jdX4gIyiwMvjWrf2yw9gya9axQYUXo,11188
|
|
44
41
|
bizyengine/bizyair_extras/nodes_wan_i2v.py,sha256=3XwcxLHmgrihgXDEzcVOjU6VjqnZa3mErINlY014PFA,8435
|
|
45
42
|
bizyengine/bizyair_extras/nodes_wan_video.py,sha256=aE2JBF0ZT-6BOM0bGu9R4yZ_eMeMnnjCW-YzFe4qg8Q,2804
|
|
46
43
|
bizyengine/bizyair_extras/route_bizyair_tools.py,sha256=EiP5pS6xoE3tULoNSN2hYZA29vgt7yCErsbRp34gGEg,3898
|
|
@@ -48,7 +45,18 @@ bizyengine/bizyair_extras/nodes_ipadapter_plus/__init__.py,sha256=ECKATm_EKi_4G4
|
|
|
48
45
|
bizyengine/bizyair_extras/nodes_ipadapter_plus/nodes_ipadapter_plus.py,sha256=lOKRem7oiPs8ZkA_p68HxagAgiCSvn3Rk-L4fSXIjyE,54846
|
|
49
46
|
bizyengine/bizyair_extras/nodes_kolors_mz/__init__.py,sha256=HsCCCphW8q0SrWEiFlZKK_W2lQr1T0UJIJL7gEn37ME,3729
|
|
50
47
|
bizyengine/bizyair_extras/oauth_callback/main.py,sha256=KQOZWor3kyNx8xvUNHYNMoHfCF9g_ht13_iPk4K_5YM,3633
|
|
51
|
-
bizyengine/bizyair_extras/
|
|
48
|
+
bizyengine/bizyair_extras/third_party_api/__init__.py,sha256=etiPBCIxOBD6hbrVhdivaRVOPrAp6z79YDWyJgqr_b4,320
|
|
49
|
+
bizyengine/bizyair_extras/third_party_api/nodes_doubao.py,sha256=FtpAnxOuAND_xUgrdovw6hz5wHUm4VC92pd-fynpJpM,19239
|
|
50
|
+
bizyengine/bizyair_extras/third_party_api/nodes_flux.py,sha256=9o7imVDn9qXnUokkAjTH9yNdpXwcuQ8p3rsv5Y5eywQ,6135
|
|
51
|
+
bizyengine/bizyair_extras/third_party_api/nodes_gemini.py,sha256=-P6PO0-qwwUbOYaqbS6SSg3w6_yAkLpBtL3mNq0PNSc,14587
|
|
52
|
+
bizyengine/bizyair_extras/third_party_api/nodes_gpt.py,sha256=pvIlwjjHnk_XCa4eJERBcsWonaBd24xP0jFVQLJXdQc,3098
|
|
53
|
+
bizyengine/bizyair_extras/third_party_api/nodes_hailuo.py,sha256=hBmt6AHVXzsbO-Uq3Go-06yNLocV6sCtutKCVUz4P9E,3746
|
|
54
|
+
bizyengine/bizyair_extras/third_party_api/nodes_kling.py,sha256=sbGBpUDPR_9Qp3ALgHEy9l_rTmVtZa_mrI-K1a9vPMQ,14669
|
|
55
|
+
bizyengine/bizyair_extras/third_party_api/nodes_sora.py,sha256=alxI3zNDSUKdc2IOOv5csIWFcHSAqL_55H9Zp4BdcN4,6976
|
|
56
|
+
bizyengine/bizyair_extras/third_party_api/nodes_veo3.py,sha256=H-6zWsUSTKaMMIUrMaH205-hnegvXxs1SQmKi4uY8rI,6489
|
|
57
|
+
bizyengine/bizyair_extras/third_party_api/nodes_wan_api.py,sha256=qkbXFHlnirqUTqnN-X5mu7MyHRYjtGv6e233PjlyUxg,6776
|
|
58
|
+
bizyengine/bizyair_extras/third_party_api/trd_nodes_base.py,sha256=dOCSi1lBVjMMRk7u4V3JyfI3qWWMeTnnW5X6azUEVtg,7124
|
|
59
|
+
bizyengine/bizyair_extras/utils/aliyun_oss.py,sha256=H6wGZq1DqP7BHJ_frBJVvUVttgXprJprOnxytePIuos,3050
|
|
52
60
|
bizyengine/bizyair_extras/utils/audio.py,sha256=cCmX080jtxsHFa7mCgn13R6cyfqE-1Gq37ZnRJdZNU8,3183
|
|
53
61
|
bizyengine/bizybot/__init__.py,sha256=NINN_7QECKQwtAwKPBTrrSiAK6KbxaZCkIvJ-e1J1xk,262
|
|
54
62
|
bizyengine/bizybot/client.py,sha256=PWdcjslMaW4xmNaAq3TwRGV8twg9yPEfDNyfuZzpCyY,26029
|
|
@@ -61,7 +69,7 @@ bizyengine/bizybot/mcp/manager.py,sha256=uPpqtJpCbr5u9Ey5qtDHKX2mt_ifNzD50kczITC
|
|
|
61
69
|
bizyengine/bizybot/mcp/models.py,sha256=Ybo7QK4T32YpYwcUs88d5Hi39pz7yEu7qIeaQ5BkX4M,998
|
|
62
70
|
bizyengine/bizybot/mcp/registry.py,sha256=jUqny2Km9EcvHmpBZl06HqNxWm0PQT6TZS8EOiiBVAw,4855
|
|
63
71
|
bizyengine/bizybot/mcp/routing.py,sha256=COgeao02y-oIiHpcXEZGl2cccgcR1u343BEcJ95sCJw,13780
|
|
64
|
-
bizyengine/core/__init__.py,sha256=
|
|
72
|
+
bizyengine/core/__init__.py,sha256=EygpO-kvl5-4rk44rP8_s0GBDd_TF7FMvrl2exBSWWM,378
|
|
65
73
|
bizyengine/core/data_types.py,sha256=2f7QqqZvhKmXw3kZV1AvXuPTda34b4wXQE9tyO8nUSM,1595
|
|
66
74
|
bizyengine/core/image_utils.py,sha256=vJt42FcEDD8-fQumuogZM1XXwgYseSQ79_9Qzu9YTQk,409
|
|
67
75
|
bizyengine/core/nodes_base.py,sha256=h2f_FWTWj6lpdKjwHRuOmoRifqwkV59ovM2ZxPK4h9c,9019
|
|
@@ -72,7 +80,7 @@ bizyengine/core/commands/invoker.py,sha256=8wcIMd8k44o96LAvxFrIiKOlVtf1MW-AcMDXs
|
|
|
72
80
|
bizyengine/core/commands/processors/model_hosting_processor.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
81
|
bizyengine/core/commands/processors/prompt_processor.py,sha256=jG0EuphvtycH5Dm-frBGtlIcxkTCXiFMQ1vFMvi_Re0,4963
|
|
74
82
|
bizyengine/core/commands/servers/model_server.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
75
|
-
bizyengine/core/commands/servers/prompt_server.py,sha256=
|
|
83
|
+
bizyengine/core/commands/servers/prompt_server.py,sha256=5R4a5EU5z5lqGNoDlGRtUGGHRojFWAtm3rdslqxpebU,11366
|
|
76
84
|
bizyengine/core/common/__init__.py,sha256=GicZw6YeAZk1PsKmFDt9dm1F75zPUlpia9Q_ki5vW1Y,179
|
|
77
85
|
bizyengine/core/common/caching.py,sha256=hRNsSrfNxgc1zzvBzLVjMY0iMkKqA0TBCr-iYhEpzik,6946
|
|
78
86
|
bizyengine/core/common/client.py,sha256=5wp_gsyvnSQxETCjUayYe536taOhaVP0zonPvW_asdA,10701
|
|
@@ -95,7 +103,7 @@ bizyengine/misc/route_sam.py,sha256=-bMIR2QalfnszipGxSxvDAHGJa5gPSrjkYPb5baaRg4,
|
|
|
95
103
|
bizyengine/misc/segment_anything.py,sha256=wNKYwlYPMszfwj23524geFZJjZaG4eye65SGaUnh77I,8941
|
|
96
104
|
bizyengine/misc/supernode.py,sha256=STN9gaxfTSErH8OiHeZa47d8z-G9S0I7fXuJvHQOBFM,4532
|
|
97
105
|
bizyengine/misc/utils.py,sha256=nXXTPkj4WBvds4EWjI9c-ydeWwmXl8Vwrdu-4Fh62g8,12914
|
|
98
|
-
bizyengine-1.2.
|
|
99
|
-
bizyengine-1.2.
|
|
100
|
-
bizyengine-1.2.
|
|
101
|
-
bizyengine-1.2.
|
|
106
|
+
bizyengine-1.2.71.dist-info/METADATA,sha256=tYEVOG70_usULu73h-QnlY6D7NWCEsOPDZ7OMO-6sgs,735
|
|
107
|
+
bizyengine-1.2.71.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
108
|
+
bizyengine-1.2.71.dist-info/top_level.txt,sha256=2zapzqxX-we5cRyJkGf9bd5JinRtXp3-_uDI-xCAnc0,11
|
|
109
|
+
bizyengine-1.2.71.dist-info/RECORD,,
|
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import base64
|
|
2
|
-
import io
|
|
3
|
-
import json
|
|
4
|
-
import logging
|
|
5
|
-
import re
|
|
6
|
-
|
|
7
|
-
import numpy as np
|
|
8
|
-
import torch
|
|
9
|
-
from comfy_api_nodes.apinode_utils import (
|
|
10
|
-
bytesio_to_image_tensor,
|
|
11
|
-
tensor_to_base64_string,
|
|
12
|
-
)
|
|
13
|
-
from PIL import Image, ImageOps
|
|
14
|
-
|
|
15
|
-
from bizyengine.core import BizyAirBaseNode, pop_api_key_and_prompt_id
|
|
16
|
-
from bizyengine.core.common import client
|
|
17
|
-
from bizyengine.core.common.env_var import BIZYAIR_SERVER_ADDRESS
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# Tensor to PIL
|
|
21
|
-
def tensor_to_pil(image):
|
|
22
|
-
return Image.fromarray(
|
|
23
|
-
np.clip(255.0 * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8)
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def image_to_base64(pil_image, pnginfo=None):
|
|
28
|
-
# 创建一个BytesIO对象,用于临时存储图像数据
|
|
29
|
-
image_data = io.BytesIO()
|
|
30
|
-
|
|
31
|
-
# 将图像保存到BytesIO对象中,格式为PNG
|
|
32
|
-
pil_image.save(image_data, format="PNG", pnginfo=pnginfo)
|
|
33
|
-
|
|
34
|
-
# 将BytesIO对象的内容转换为字节串
|
|
35
|
-
image_data_bytes = image_data.getvalue()
|
|
36
|
-
|
|
37
|
-
# 将图像数据编码为Base64字符串
|
|
38
|
-
encoded_image = "data:image/png;base64," + base64.b64encode(
|
|
39
|
-
image_data_bytes
|
|
40
|
-
).decode("utf-8")
|
|
41
|
-
|
|
42
|
-
return encoded_image
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def base64_to_image(base64_string):
|
|
46
|
-
# 去除前缀
|
|
47
|
-
base64_list = base64_string.split(",", 1)
|
|
48
|
-
if len(base64_list) == 2:
|
|
49
|
-
prefix, base64_data = base64_list
|
|
50
|
-
else:
|
|
51
|
-
base64_data = base64_list[0]
|
|
52
|
-
|
|
53
|
-
# 从base64字符串中解码图像数据
|
|
54
|
-
image_data = base64.b64decode(base64_data)
|
|
55
|
-
|
|
56
|
-
# 创建一个内存流对象
|
|
57
|
-
image_stream = io.BytesIO(image_data)
|
|
58
|
-
|
|
59
|
-
# 使用PIL的Image模块打开图像数据
|
|
60
|
-
image = Image.open(image_stream)
|
|
61
|
-
|
|
62
|
-
return image
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def get_parts_from_response(
|
|
66
|
-
response: dict,
|
|
67
|
-
):
|
|
68
|
-
return response["candidates"][0]["content"]["parts"]
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def get_parts_by_type(response: dict, part_type: str):
|
|
72
|
-
parts = []
|
|
73
|
-
for part in get_parts_from_response(response):
|
|
74
|
-
if part_type == "text" and part.get("text", None):
|
|
75
|
-
parts.append(part)
|
|
76
|
-
elif (
|
|
77
|
-
part.get("inlineData", None) and part["inlineData"]["mimeType"] == part_type
|
|
78
|
-
):
|
|
79
|
-
parts.append(part)
|
|
80
|
-
# Skip parts that don't match the requested type
|
|
81
|
-
return parts
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def get_text_from_response(response: dict) -> str:
|
|
85
|
-
parts = get_parts_by_type(response, "text")
|
|
86
|
-
logging.debug(f"Text parts: {parts}")
|
|
87
|
-
return "\n".join([part["text"] for part in parts])
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def get_image_from_response(response: dict) -> torch.Tensor:
|
|
91
|
-
image_tensors: list[torch.Tensor] = []
|
|
92
|
-
parts = get_parts_by_type(response, "image/png")
|
|
93
|
-
for part in parts:
|
|
94
|
-
b64_data = part["inlineData"]["data"]
|
|
95
|
-
if b64_data:
|
|
96
|
-
image_data = base64.b64decode(b64_data)
|
|
97
|
-
returned_image = bytesio_to_image_tensor(io.BytesIO(image_data))
|
|
98
|
-
image_tensors.append(returned_image)
|
|
99
|
-
if len(image_tensors) == 0:
|
|
100
|
-
return torch.zeros((1, 1024, 1024, 4))
|
|
101
|
-
return torch.cat(image_tensors, dim=0)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
# FROM: https://github.com/ShmuelRonen/ComfyUI-NanoBanano/blob/9eeb8f2411fd0ff08791bdf5e24eec347456c8b8/nano_banano.py#L191
|
|
105
|
-
def build_prompt_for_operation(
|
|
106
|
-
prompt,
|
|
107
|
-
operation,
|
|
108
|
-
has_references=False,
|
|
109
|
-
aspect_ratio="1:1",
|
|
110
|
-
character_consistency=True,
|
|
111
|
-
):
|
|
112
|
-
"""Build optimized prompt based on operation type"""
|
|
113
|
-
|
|
114
|
-
aspect_instructions = {
|
|
115
|
-
"1:1": "square format",
|
|
116
|
-
"16:9": "widescreen landscape format",
|
|
117
|
-
"9:16": "portrait format",
|
|
118
|
-
"4:3": "standard landscape format",
|
|
119
|
-
"3:4": "standard portrait format",
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
base_quality = "Generate a high-quality, photorealistic image"
|
|
123
|
-
format_instruction = f"in {aspect_instructions.get(aspect_ratio, 'square format')}"
|
|
124
|
-
|
|
125
|
-
if operation == "generate":
|
|
126
|
-
if has_references:
|
|
127
|
-
final_prompt = f"{base_quality} inspired by the style and elements of the reference images. {prompt}. {format_instruction}."
|
|
128
|
-
else:
|
|
129
|
-
final_prompt = f"{base_quality} of: {prompt}. {format_instruction}."
|
|
130
|
-
|
|
131
|
-
elif operation == "edit":
|
|
132
|
-
if not has_references:
|
|
133
|
-
return "Error: Edit operation requires reference images"
|
|
134
|
-
# No aspect ratio for edit - preserve original image dimensions
|
|
135
|
-
final_prompt = f"Edit the provided reference image(s). {prompt}. Maintain the original composition and quality while making the requested changes."
|
|
136
|
-
|
|
137
|
-
elif operation == "style_transfer":
|
|
138
|
-
if not has_references:
|
|
139
|
-
return "Error: Style transfer requires reference images"
|
|
140
|
-
final_prompt = f"Apply the style from the reference images to create: {prompt}. Blend the stylistic elements naturally. {format_instruction}."
|
|
141
|
-
|
|
142
|
-
elif operation == "object_insertion":
|
|
143
|
-
if not has_references:
|
|
144
|
-
return "Error: Object insertion requires reference images"
|
|
145
|
-
final_prompt = f"Insert or blend the following into the reference image(s): {prompt}. Ensure natural lighting, shadows, and perspective. {format_instruction}."
|
|
146
|
-
|
|
147
|
-
if character_consistency and has_references:
|
|
148
|
-
final_prompt += " Maintain character consistency and visual identity from the reference images."
|
|
149
|
-
|
|
150
|
-
return final_prompt
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
class NanoBanana(BizyAirBaseNode):
|
|
154
|
-
def __init__(self):
|
|
155
|
-
pass
|
|
156
|
-
|
|
157
|
-
@classmethod
|
|
158
|
-
def INPUT_TYPES(s):
|
|
159
|
-
return {
|
|
160
|
-
"required": {
|
|
161
|
-
"prompt": (
|
|
162
|
-
"STRING",
|
|
163
|
-
{
|
|
164
|
-
"multiline": True,
|
|
165
|
-
"default": "",
|
|
166
|
-
},
|
|
167
|
-
),
|
|
168
|
-
"operation": (
|
|
169
|
-
["generate", "edit", "style_transfer", "object_insertion"],
|
|
170
|
-
{
|
|
171
|
-
"default": "generate",
|
|
172
|
-
"tooltip": "Choose the type of image operation",
|
|
173
|
-
},
|
|
174
|
-
),
|
|
175
|
-
"temperature": (
|
|
176
|
-
"FLOAT",
|
|
177
|
-
{"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.05},
|
|
178
|
-
),
|
|
179
|
-
"top_p": (
|
|
180
|
-
"FLOAT",
|
|
181
|
-
{"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.05},
|
|
182
|
-
),
|
|
183
|
-
"seed": ("INT", {"default": 0, "min": 0, "max": 2147483647}),
|
|
184
|
-
"max_tokens": ("INT", {"default": 8192, "min": 1, "max": 8192}),
|
|
185
|
-
},
|
|
186
|
-
"optional": {
|
|
187
|
-
"image": ("IMAGE",),
|
|
188
|
-
"image2": ("IMAGE",),
|
|
189
|
-
"image3": ("IMAGE",),
|
|
190
|
-
"image4": ("IMAGE",),
|
|
191
|
-
"image5": ("IMAGE",),
|
|
192
|
-
"quality": (
|
|
193
|
-
["standard", "high"],
|
|
194
|
-
{"default": "high", "tooltip": "Image generation quality"},
|
|
195
|
-
),
|
|
196
|
-
"aspect_ratio": (
|
|
197
|
-
["1:1", "16:9", "9:16", "4:3", "3:4"],
|
|
198
|
-
{"default": "1:1", "tooltip": "Output image aspect ratio"},
|
|
199
|
-
),
|
|
200
|
-
"character_consistency": (
|
|
201
|
-
"BOOLEAN",
|
|
202
|
-
{
|
|
203
|
-
"default": True,
|
|
204
|
-
"tooltip": "Maintain character consistency across edits",
|
|
205
|
-
},
|
|
206
|
-
),
|
|
207
|
-
},
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
RETURN_TYPES = ("IMAGE", "STRING")
|
|
211
|
-
FUNCTION = "execute"
|
|
212
|
-
OUTPUT_NODE = False
|
|
213
|
-
CATEGORY = "☁️BizyAir/External APIs/Gemini"
|
|
214
|
-
|
|
215
|
-
def execute(
|
|
216
|
-
self,
|
|
217
|
-
prompt,
|
|
218
|
-
operation,
|
|
219
|
-
temperature,
|
|
220
|
-
top_p,
|
|
221
|
-
seed,
|
|
222
|
-
max_tokens,
|
|
223
|
-
quality=None,
|
|
224
|
-
aspect_ratio=None,
|
|
225
|
-
character_consistency=None,
|
|
226
|
-
**kwargs,
|
|
227
|
-
):
|
|
228
|
-
try:
|
|
229
|
-
url = f"{BIZYAIR_SERVER_ADDRESS}/proxy_inference/VertexAI/gemini-2.5-flash-image-preview"
|
|
230
|
-
extra_data = pop_api_key_and_prompt_id(kwargs)
|
|
231
|
-
|
|
232
|
-
parts = []
|
|
233
|
-
for _, img in enumerate(
|
|
234
|
-
[
|
|
235
|
-
kwargs.get("image", None),
|
|
236
|
-
kwargs.get("image2", None),
|
|
237
|
-
kwargs.get("image3", None),
|
|
238
|
-
kwargs.get("image4", None),
|
|
239
|
-
kwargs.get("image5", None),
|
|
240
|
-
],
|
|
241
|
-
1,
|
|
242
|
-
):
|
|
243
|
-
if img is not None:
|
|
244
|
-
parts.append(
|
|
245
|
-
{
|
|
246
|
-
"inline_data": {
|
|
247
|
-
"mime_type": "image/png",
|
|
248
|
-
"data": tensor_to_base64_string(img),
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
prompt = build_prompt_for_operation(
|
|
254
|
-
prompt,
|
|
255
|
-
operation,
|
|
256
|
-
has_references=len(parts) > 0,
|
|
257
|
-
aspect_ratio=aspect_ratio,
|
|
258
|
-
character_consistency=character_consistency,
|
|
259
|
-
)
|
|
260
|
-
if quality == "high":
|
|
261
|
-
prompt += " Use the highest quality settings available."
|
|
262
|
-
parts.append({"text": prompt})
|
|
263
|
-
|
|
264
|
-
data = {
|
|
265
|
-
"contents": {
|
|
266
|
-
"parts": parts,
|
|
267
|
-
"role": "user",
|
|
268
|
-
},
|
|
269
|
-
"generationConfig": {
|
|
270
|
-
"seed": seed,
|
|
271
|
-
"responseModalities": ["TEXT", "IMAGE"],
|
|
272
|
-
"temperature": temperature,
|
|
273
|
-
"topP": top_p,
|
|
274
|
-
"maxOutputTokens": max_tokens,
|
|
275
|
-
},
|
|
276
|
-
}
|
|
277
|
-
json_payload = json.dumps(data).encode("utf-8")
|
|
278
|
-
headers = client.headers(api_key=extra_data["api_key"])
|
|
279
|
-
headers["X-BIZYAIR-PROMPT-ID"] = extra_data[
|
|
280
|
-
"prompt_id"
|
|
281
|
-
] # 额外参数vertexai会拒绝,所以用请求头传
|
|
282
|
-
resp = client.send_request(
|
|
283
|
-
url=url,
|
|
284
|
-
data=json_payload,
|
|
285
|
-
headers=headers,
|
|
286
|
-
)
|
|
287
|
-
# 解析潜在错误
|
|
288
|
-
prompt_feedback = resp.get("promptFeedback", None)
|
|
289
|
-
if prompt_feedback:
|
|
290
|
-
logging.error(f"Response: {resp}")
|
|
291
|
-
raise ValueError(f"Prompt blocked: {prompt_feedback}")
|
|
292
|
-
if len(resp.get("candidates", [])) == 0:
|
|
293
|
-
logging.error(f"Response: {resp}")
|
|
294
|
-
raise ValueError("No candidates found in response")
|
|
295
|
-
if resp["candidates"][0]["finishReason"] != "STOP":
|
|
296
|
-
logging.error(f"Response: {resp}")
|
|
297
|
-
raise ValueError(
|
|
298
|
-
f"Erroneous finish reason: {resp['candidates'][0]['finishReason']}"
|
|
299
|
-
)
|
|
300
|
-
|
|
301
|
-
# 解析文本
|
|
302
|
-
text = get_text_from_response(resp)
|
|
303
|
-
|
|
304
|
-
# 解析base64图片
|
|
305
|
-
image = get_image_from_response(resp)
|
|
306
|
-
|
|
307
|
-
return (image, text)
|
|
308
|
-
|
|
309
|
-
except Exception as e:
|
|
310
|
-
logging.error(f"Gemini API error: {e}")
|
|
311
|
-
raise e
|