bizyengine 1.2.58__py3-none-any.whl → 1.2.60__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.
@@ -33,6 +33,8 @@ modules = [
33
33
  ".nodes_wan_i2v",
34
34
  ".nodes_wan_video",
35
35
  ".route_bizyair_tools",
36
+ ".nodes_veo3",
37
+ ".nodes_sora2",
36
38
  ]
37
39
  from bizyengine.core.common.utils import safe_star_import
38
40
 
@@ -226,7 +226,7 @@ class NanoBanana(BizyAirBaseNode):
226
226
  **kwargs,
227
227
  ):
228
228
  try:
229
- url = f"{BIZYAIR_SERVER_ADDRESS}/proxy_inference/VertexAI/gemini-2.5-flash-image-preview"
229
+ url = f"{BIZYAIR_SERVER_ADDRESS}/proxy_inference/VertexAI/gemini-2.5-flash-image"
230
230
  extra_data = pop_api_key_and_prompt_id(kwargs)
231
231
 
232
232
  parts = []
@@ -0,0 +1,217 @@
1
+ import io
2
+ import json
3
+ import logging
4
+ import time
5
+
6
+ import requests
7
+ from comfy_api.latest._input_impl import VideoFromFile
8
+ from comfy_api_nodes.apinode_utils import tensor_to_bytesio
9
+
10
+ from bizyengine.bizyair_extras.nodes_veo3 import _GRSAI_FAILED_STATUS
11
+ from bizyengine.bizyair_extras.utils.audio import save_audio
12
+ from bizyengine.core import BizyAirBaseNode, pop_api_key_and_prompt_id
13
+ from bizyengine.core.common import client
14
+ from bizyengine.core.common.client import send_request
15
+ from bizyengine.core.common.env_var import BIZYAIR_X_SERVER
16
+
17
+ from .utils.aliyun_oss import parse_upload_token, upload_file_without_sdk
18
+
19
+
20
+ def sora2_create_task_and_wait_for_completion(data, model, prompt, headers):
21
+ # 创建任务
22
+ create_task_url = f"{BIZYAIR_X_SERVER}/proxy_inference/GRSAI/{model}"
23
+ json_payload = json.dumps(data).encode("utf-8")
24
+ logging.debug(f"json_payload: {json_payload}")
25
+ create_api_resp = send_request(
26
+ url=create_task_url,
27
+ data=json_payload,
28
+ headers=headers,
29
+ )
30
+ logging.debug(f"create task api resp: {create_api_resp}")
31
+
32
+ # 检查任务创建是否成功
33
+ if (
34
+ "code" not in create_api_resp
35
+ or create_api_resp["code"] != 0
36
+ or "data" not in create_api_resp
37
+ or "id" not in create_api_resp["data"]
38
+ ):
39
+ raise ValueError(f"Invalid response: {create_api_resp}")
40
+
41
+ # 轮询获取结果,最多等待1小时
42
+ task_id = create_api_resp["data"]["id"]
43
+ logging.info(f"Sora2 task created, task_id: {task_id}")
44
+ start_time = time.time()
45
+ status_url = f"{BIZYAIR_X_SERVER}/proxy_inference/GRSAI/{model}/{task_id}"
46
+ while time.time() - start_time < 3600:
47
+ time.sleep(10)
48
+ try:
49
+ status_api_resp = send_request(
50
+ method="GET",
51
+ url=status_url,
52
+ headers=headers,
53
+ )
54
+ logging.debug(f"status api resp: {status_api_resp}")
55
+ except Exception as e:
56
+ logging.error(f"Sora2 task {task_id} status api error: {e}")
57
+ continue
58
+
59
+ if (
60
+ "data" in status_api_resp
61
+ and "status" in status_api_resp["data"]
62
+ and status_api_resp["data"]["status"] == "succeeded"
63
+ and "results" in status_api_resp["data"]
64
+ and len(status_api_resp["data"]["results"]) > 0
65
+ and "url" in status_api_resp["data"]["results"][0]
66
+ and status_api_resp["data"]["results"][0]["url"]
67
+ ):
68
+ video_url = status_api_resp["data"]["results"][0]["url"]
69
+ logging.info(f"Sora2 task {task_id} success, video_url: {video_url}")
70
+ # 下载视频
71
+ video_resp = requests.get(video_url, stream=True, timeout=3600)
72
+ video_resp.raise_for_status() # 非 2xx 会抛异常
73
+ return (VideoFromFile(io.BytesIO(video_resp.content)),)
74
+ if (
75
+ "data" not in status_api_resp
76
+ or "status" not in status_api_resp["data"]
77
+ or "code" not in status_api_resp
78
+ or status_api_resp["code"] != 0
79
+ ):
80
+ raise ValueError(f"Invalid response: {status_api_resp}")
81
+ if status_api_resp["data"]["status"] in _GRSAI_FAILED_STATUS:
82
+ raise ValueError(f"Sora2 task failed: {status_api_resp}")
83
+ logging.debug(
84
+ f"Sora2 task {task_id} status: {status_api_resp['data']['status']}"
85
+ )
86
+
87
+ raise ValueError(f"Sora2 task timed out, request ID: {task_id}")
88
+
89
+
90
+ class Sora_V2_I2V_API(BizyAirBaseNode):
91
+ @classmethod
92
+ def INPUT_TYPES(cls):
93
+ return {
94
+ "required": {
95
+ "prompt": (
96
+ "STRING",
97
+ {
98
+ "multiline": True,
99
+ "default": "",
100
+ },
101
+ ),
102
+ "image": ("IMAGE", {"tooltip": "首帧图片"}),
103
+ "model": (["sora-2"], {"default": "sora-2"}),
104
+ },
105
+ "optional": {
106
+ "aspect_ratio": (
107
+ ["9:16", "16:9"],
108
+ {"default": "16:9"},
109
+ ),
110
+ "duration": ([10, 15], {"default": 10}),
111
+ "size": (["small", "large"], {"default": "small"}),
112
+ },
113
+ }
114
+
115
+ NODE_DISPLAY_NAME = "Sora2 Image To Video"
116
+ RETURN_TYPES = ("VIDEO",)
117
+ RETURN_NAMES = ("video",)
118
+ CATEGORY = "☁️BizyAir/External APIs/Sora"
119
+ FUNCTION = "api_call"
120
+
121
+ def api_call(self, image, model, prompt, **kwargs):
122
+ extra_data = pop_api_key_and_prompt_id(kwargs)
123
+ headers = client.headers(api_key=extra_data["api_key"])
124
+ prompt_id = extra_data["prompt_id"]
125
+ headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
126
+ headers["X-Bizyair-Async-Result"] = "enable"
127
+
128
+ # 参数
129
+ aspect_ratio = kwargs.get("aspect_ratio", "16:9")
130
+ duration = kwargs.get("duration", 10)
131
+ size = kwargs.get("size", "small")
132
+
133
+ input = {
134
+ "webHook": "-1",
135
+ "aspectRatio": aspect_ratio,
136
+ "duration": duration,
137
+ "size": size,
138
+ "model": model,
139
+ }
140
+ if prompt is not None and prompt.strip() != "":
141
+ input["prompt"] = prompt
142
+ else:
143
+ raise ValueError("Prompt is required")
144
+
145
+ # 上传图片
146
+ if image is not None:
147
+ oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}.png&file_type=inputs"
148
+ token_resp = send_request("GET", oss_token_url, headers=headers)
149
+ auth_info = parse_upload_token(token_resp)
150
+ input["url"] = upload_file_without_sdk(
151
+ tensor_to_bytesio(image), **auth_info
152
+ )
153
+
154
+ # 调用API
155
+ return sora2_create_task_and_wait_for_completion(
156
+ data=input, model=model, prompt=prompt, headers=headers
157
+ )
158
+
159
+
160
+ class Sora_V2_T2V_API(BizyAirBaseNode):
161
+ @classmethod
162
+ def INPUT_TYPES(cls):
163
+ return {
164
+ "required": {
165
+ "prompt": (
166
+ "STRING",
167
+ {
168
+ "multiline": True,
169
+ "default": "",
170
+ },
171
+ ),
172
+ "model": (["sora-2"], {"default": "sora-2"}),
173
+ },
174
+ "optional": {
175
+ "aspect_ratio": (
176
+ ["9:16", "16:9"],
177
+ {"default": "16:9"},
178
+ ),
179
+ "duration": ([10, 15], {"default": 10}),
180
+ "size": (["small", "large"], {"default": "small"}),
181
+ },
182
+ }
183
+
184
+ NODE_DISPLAY_NAME = "Sora2 Text To Video"
185
+ RETURN_TYPES = ("VIDEO",)
186
+ RETURN_NAMES = ("video",)
187
+ CATEGORY = "☁️BizyAir/External APIs/Sora"
188
+ FUNCTION = "api_call"
189
+
190
+ def api_call(self, prompt, model, **kwargs):
191
+ extra_data = pop_api_key_and_prompt_id(kwargs)
192
+ headers = client.headers(api_key=extra_data["api_key"])
193
+ prompt_id = extra_data["prompt_id"]
194
+ headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
195
+ headers["X-Bizyair-Async-Result"] = "enable"
196
+
197
+ # 参数
198
+ aspect_ratio = kwargs.get("aspect_ratio", "16:9")
199
+ duration = kwargs.get("duration", 10)
200
+ size = kwargs.get("size", "small")
201
+
202
+ input = {
203
+ "webHook": "-1",
204
+ "aspectRatio": aspect_ratio,
205
+ "duration": duration,
206
+ "size": size,
207
+ "model": model,
208
+ }
209
+ if prompt is not None and prompt.strip() != "":
210
+ input["prompt"] = prompt
211
+ else:
212
+ raise ValueError("Prompt is required")
213
+
214
+ # 调用API
215
+ return sora2_create_task_and_wait_for_completion(
216
+ data=input, model=model, prompt=prompt, headers=headers
217
+ )
@@ -0,0 +1,297 @@
1
+ import io
2
+ import json
3
+ import logging
4
+ import time
5
+
6
+ import requests
7
+ from comfy_api.latest._input_impl import VideoFromFile
8
+ from comfy_api_nodes.apinode_utils import tensor_to_bytesio
9
+
10
+ from bizyengine.bizyair_extras.utils.audio import save_audio
11
+ from bizyengine.core import BizyAirBaseNode, pop_api_key_and_prompt_id
12
+ from bizyengine.core.common import client
13
+ from bizyengine.core.common.client import send_request
14
+ from bizyengine.core.common.env_var import BIZYAIR_X_SERVER
15
+
16
+ from .utils.aliyun_oss import parse_upload_token, upload_file_without_sdk
17
+
18
+ _GRSAI_FAILED_STATUS = ["failed"]
19
+
20
+
21
+ def veo_create_task_and_wait_for_completion(data, model, prompt, headers):
22
+ # 创建任务
23
+ create_task_url = f"{BIZYAIR_X_SERVER}/proxy_inference/GRSAI/{model}"
24
+ json_payload = json.dumps(data).encode("utf-8")
25
+ logging.debug(f"json_payload: {json_payload}")
26
+ create_api_resp = send_request(
27
+ url=create_task_url,
28
+ data=json_payload,
29
+ headers=headers,
30
+ )
31
+ logging.debug(f"create task api resp: {create_api_resp}")
32
+
33
+ # 检查任务创建是否成功
34
+ if (
35
+ "code" not in create_api_resp
36
+ or create_api_resp["code"] != 0
37
+ or "data" not in create_api_resp
38
+ or "id" not in create_api_resp["data"]
39
+ ):
40
+ raise ValueError(f"Invalid response: {create_api_resp}")
41
+
42
+ # 轮询获取结果,最多等待1小时
43
+ task_id = create_api_resp["data"]["id"]
44
+ logging.info(f"Veo3.1 task created, task_id: {task_id}")
45
+ start_time = time.time()
46
+ status_url = f"{BIZYAIR_X_SERVER}/proxy_inference/GRSAI/{model}/{task_id}"
47
+ while time.time() - start_time < 3600:
48
+ time.sleep(10)
49
+ try:
50
+ status_api_resp = send_request(
51
+ method="GET",
52
+ url=status_url,
53
+ headers=headers,
54
+ )
55
+ logging.debug(f"status api resp: {status_api_resp}")
56
+ except Exception as e:
57
+ logging.error(f"Veo3.1 task {task_id} status api error: {e}")
58
+ continue
59
+
60
+ if (
61
+ "data" in status_api_resp
62
+ and "status" in status_api_resp["data"]
63
+ and status_api_resp["data"]["status"] == "succeeded"
64
+ and "url" in status_api_resp["data"]
65
+ and status_api_resp["data"]["url"]
66
+ ):
67
+ video_url = status_api_resp["data"]["url"]
68
+ logging.info(f"Veo3.1 task {task_id} success, video_url: {video_url}")
69
+ # 下载视频
70
+ video_resp = requests.get(video_url, stream=True, timeout=3600)
71
+ video_resp.raise_for_status() # 非 2xx 会抛异常
72
+ return (VideoFromFile(io.BytesIO(video_resp.content)),)
73
+ if (
74
+ "data" not in status_api_resp
75
+ or "status" not in status_api_resp["data"]
76
+ or "code" not in status_api_resp
77
+ or status_api_resp["code"] != 0
78
+ ):
79
+ raise ValueError(f"Invalid response: {status_api_resp}")
80
+ if status_api_resp["data"]["status"] in _GRSAI_FAILED_STATUS:
81
+ raise ValueError(f"Veo3.1 task failed: {status_api_resp}")
82
+ logging.debug(
83
+ f"Veo3.1 task {task_id} status: {status_api_resp['data']['status']}"
84
+ )
85
+
86
+ raise ValueError(f"Veo3.1 task timed out, request ID: {task_id}")
87
+
88
+
89
+ class Veo_V3_1_I2V_API(BizyAirBaseNode):
90
+ @classmethod
91
+ def INPUT_TYPES(cls):
92
+ return {
93
+ "required": {
94
+ "prompt": (
95
+ "STRING",
96
+ {
97
+ "multiline": True,
98
+ "default": "",
99
+ },
100
+ ),
101
+ "first_frame_image": ("IMAGE", {"tooltip": "首帧图片"}),
102
+ "model": (["veo3.1-fast", "veo3.1-pro"], {"default": "veo3.1-fast"}),
103
+ },
104
+ "optional": {
105
+ "last_frame_image": ("IMAGE", {"tooltip": "尾帧图片"}),
106
+ "aspect_ratio": (
107
+ ["9:16", "16:9"],
108
+ {"default": "16:9"},
109
+ ),
110
+ },
111
+ }
112
+
113
+ NODE_DISPLAY_NAME = "Veo3.1 Image To Video"
114
+ RETURN_TYPES = ("VIDEO",)
115
+ RETURN_NAMES = ("video",)
116
+ CATEGORY = "☁️BizyAir/External APIs/Veo"
117
+ FUNCTION = "api_call"
118
+
119
+ def api_call(self, first_frame_image, model, prompt, **kwargs):
120
+ extra_data = pop_api_key_and_prompt_id(kwargs)
121
+ headers = client.headers(api_key=extra_data["api_key"])
122
+ prompt_id = extra_data["prompt_id"]
123
+ headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
124
+ headers["X-Bizyair-Async-Result"] = "enable"
125
+
126
+ # 参数
127
+ aspect_ratio = kwargs.get("aspect_ratio", "16:9")
128
+ last_frame_image = kwargs.get("last_frame_image", None)
129
+
130
+ input = {
131
+ "webHook": "-1",
132
+ "aspectRatio": aspect_ratio,
133
+ "model": model,
134
+ }
135
+ if prompt is not None and prompt.strip() != "":
136
+ input["prompt"] = prompt
137
+ else:
138
+ raise ValueError("Prompt is required")
139
+
140
+ # 上传图片
141
+ if first_frame_image is not None:
142
+ oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}_first.png&file_type=inputs"
143
+ token_resp = send_request("GET", oss_token_url, headers=headers)
144
+ auth_info = parse_upload_token(token_resp)
145
+ input["firstFrameUrl"] = upload_file_without_sdk(
146
+ tensor_to_bytesio(first_frame_image), **auth_info
147
+ )
148
+ if last_frame_image is not None:
149
+ oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}_last.png&file_type=inputs"
150
+ token_resp = send_request("GET", oss_token_url, headers=headers)
151
+ auth_info = parse_upload_token(token_resp)
152
+ input["lastFrameUrl"] = upload_file_without_sdk(
153
+ tensor_to_bytesio(last_frame_image), **auth_info
154
+ )
155
+
156
+ # 调用API
157
+ return veo_create_task_and_wait_for_completion(
158
+ data=input, model=model, prompt=prompt, headers=headers
159
+ )
160
+
161
+
162
+ class Veo_V3_1_I2V_REF_API(BizyAirBaseNode):
163
+ @classmethod
164
+ def INPUT_TYPES(cls):
165
+ return {
166
+ "required": {
167
+ "prompt": (
168
+ "STRING",
169
+ {
170
+ "multiline": True,
171
+ "default": "",
172
+ },
173
+ ),
174
+ "ref_image_1": ("IMAGE", {"tooltip": "参考图片1"}),
175
+ "model": (["veo3.1-fast"], {"default": "veo3.1-fast"}),
176
+ },
177
+ "optional": {
178
+ "ref_image_2": ("IMAGE", {"tooltip": "参考图片2"}),
179
+ "ref_image_3": ("IMAGE", {"tooltip": "参考图片3"}),
180
+ "aspect_ratio": (
181
+ ["9:16", "16:9"],
182
+ {"default": "16:9"},
183
+ ),
184
+ },
185
+ }
186
+
187
+ NODE_DISPLAY_NAME = "Veo3.1 Image To Video (Reference Images)"
188
+ RETURN_TYPES = ("VIDEO",)
189
+ RETURN_NAMES = ("video",)
190
+ CATEGORY = "☁️BizyAir/External APIs/Veo"
191
+ FUNCTION = "api_call"
192
+
193
+ def api_call(self, ref_image_1, model, prompt, **kwargs):
194
+ extra_data = pop_api_key_and_prompt_id(kwargs)
195
+ headers = client.headers(api_key=extra_data["api_key"])
196
+ prompt_id = extra_data["prompt_id"]
197
+ headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
198
+ headers["X-Bizyair-Async-Result"] = "enable"
199
+
200
+ # 参数
201
+ aspect_ratio = kwargs.get("aspect_ratio", "16:9")
202
+ ref_image_2 = kwargs.get("ref_image_2", None)
203
+ ref_image_3 = kwargs.get("ref_image_3", None)
204
+
205
+ input = {
206
+ "webHook": "-1",
207
+ "aspectRatio": aspect_ratio,
208
+ "model": model,
209
+ }
210
+ if prompt is not None and prompt.strip() != "":
211
+ input["prompt"] = prompt
212
+ else:
213
+ raise ValueError("Prompt is required")
214
+
215
+ # 上传图片
216
+ ref_images = []
217
+ if ref_image_1 is not None:
218
+ oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}_ref_1.png&file_type=inputs"
219
+ token_resp = send_request("GET", oss_token_url, headers=headers)
220
+ auth_info = parse_upload_token(token_resp)
221
+ ref_images.append(
222
+ upload_file_without_sdk(tensor_to_bytesio(ref_image_1), **auth_info)
223
+ )
224
+ if ref_image_2 is not None:
225
+ oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}_ref_2.png&file_type=inputs"
226
+ token_resp = send_request("GET", oss_token_url, headers=headers)
227
+ auth_info = parse_upload_token(token_resp)
228
+ ref_images.append(
229
+ upload_file_without_sdk(tensor_to_bytesio(ref_image_2), **auth_info)
230
+ )
231
+ if ref_image_3 is not None:
232
+ oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}_ref_3.png&file_type=inputs"
233
+ token_resp = send_request("GET", oss_token_url, headers=headers)
234
+ auth_info = parse_upload_token(token_resp)
235
+ ref_images.append(
236
+ upload_file_without_sdk(tensor_to_bytesio(ref_image_3), **auth_info)
237
+ )
238
+ input["urls"] = ref_images
239
+
240
+ # 调用API
241
+ return veo_create_task_and_wait_for_completion(
242
+ data=input, model=model, prompt=prompt, headers=headers
243
+ )
244
+
245
+
246
+ class Veo_V3_1_T2V_API(BizyAirBaseNode):
247
+ @classmethod
248
+ def INPUT_TYPES(cls):
249
+ return {
250
+ "required": {
251
+ "prompt": (
252
+ "STRING",
253
+ {
254
+ "multiline": True,
255
+ "default": "",
256
+ },
257
+ ),
258
+ "model": (["veo3.1-fast", "veo3.1-pro"], {"default": "veo3.1-fast"}),
259
+ },
260
+ "optional": {
261
+ "aspect_ratio": (
262
+ ["9:16", "16:9"],
263
+ {"default": "16:9"},
264
+ ),
265
+ },
266
+ }
267
+
268
+ NODE_DISPLAY_NAME = "Veo3.1 Text To Video"
269
+ RETURN_TYPES = ("VIDEO",)
270
+ RETURN_NAMES = ("video",)
271
+ CATEGORY = "☁️BizyAir/External APIs/Veo"
272
+ FUNCTION = "api_call"
273
+
274
+ def api_call(self, prompt, model, **kwargs):
275
+ extra_data = pop_api_key_and_prompt_id(kwargs)
276
+ headers = client.headers(api_key=extra_data["api_key"])
277
+ prompt_id = extra_data["prompt_id"]
278
+ headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
279
+ headers["X-Bizyair-Async-Result"] = "enable"
280
+
281
+ # 参数
282
+ aspect_ratio = kwargs.get("aspect_ratio", "16:9")
283
+
284
+ input = {
285
+ "webHook": "-1",
286
+ "aspectRatio": aspect_ratio,
287
+ "model": model,
288
+ }
289
+ if prompt is not None and prompt.strip() != "":
290
+ input["prompt"] = prompt
291
+ else:
292
+ raise ValueError("Prompt is required")
293
+
294
+ # 调用API
295
+ return veo_create_task_and_wait_for_completion(
296
+ data=input, model=model, prompt=prompt, headers=headers
297
+ )
@@ -1,6 +1,7 @@
1
1
  import io
2
2
  import json
3
3
  import logging
4
+ import time
4
5
 
5
6
  import requests
6
7
  from comfy_api.latest._input_impl import VideoFromFile
@@ -12,24 +13,74 @@ from bizyengine.core.common import client
12
13
  from bizyengine.core.common.client import send_request
13
14
  from bizyengine.core.common.env_var import BIZYAIR_X_SERVER
14
15
 
15
- from .utils.aliyun_oss import upload_file_without_sdk
16
+ from .utils.aliyun_oss import parse_upload_token, upload_file_without_sdk
16
17
 
18
+ _FAILED_STATUS = ["FAILED", "CANCELED", "UNKNOWN"]
17
19
 
18
- def parse_upload_token(resp) -> dict:
19
- logging.debug(f"parsing token resp: {resp}")
20
- if "data" not in resp:
21
- logging.error(f"Invalid response, data not found: {resp}")
22
- raise ValueError(f"Invalid response: {resp}")
23
- data = resp["data"]
24
- if "file" not in data:
25
- logging.error(f"Invalid response, file not found: {resp}")
26
- raise ValueError(f"Invalid response: {resp}")
27
- file = data["file"]
28
- if "storage" not in data:
29
- logging.error(f"Invalid response, storage not found: {resp}")
30
- raise ValueError(f"Invalid response: {resp}")
31
- storage = data["storage"]
32
- return file | storage
20
+
21
+ def wan_create_task_and_wait_for_completion(data, model, prompt, headers):
22
+ # 创建任务
23
+ create_task_url = f"{BIZYAIR_X_SERVER}/proxy_inference/Wan/{model}"
24
+ json_payload = json.dumps(data).encode("utf-8")
25
+ logging.debug(f"json_payload: {json_payload}")
26
+ create_api_resp = send_request(
27
+ url=create_task_url,
28
+ data=json_payload,
29
+ headers=headers,
30
+ )
31
+ logging.debug(f"create task api resp: {create_api_resp}")
32
+
33
+ # 检查任务创建是否成功
34
+ if (
35
+ "request_id" not in create_api_resp
36
+ or "output" not in create_api_resp
37
+ or "task_status" not in create_api_resp["output"]
38
+ or "task_id" not in create_api_resp["output"]
39
+ ):
40
+ raise ValueError(f"Invalid response: {create_api_resp}")
41
+ # 检查任务状态,是否已经报错,如果报错则抛出异常
42
+ if create_api_resp["output"]["task_status"] in _FAILED_STATUS:
43
+ raise ValueError(f"Wan2.5 create task failed: {create_api_resp}")
44
+
45
+ # 轮询获取结果,最多等待1小时
46
+ task_id = create_api_resp["output"]["task_id"]
47
+ logging.info(
48
+ f'Wan2.5 task created, task_id: {task_id}, request_id: {create_api_resp["request_id"]}'
49
+ )
50
+ start_time = time.time()
51
+ status_url = f"{BIZYAIR_X_SERVER}/proxy_inference/Wan/{model}/{task_id}"
52
+ while time.time() - start_time < 3600:
53
+ time.sleep(10)
54
+ try:
55
+ status_api_resp = send_request(
56
+ method="GET",
57
+ url=status_url,
58
+ headers=headers,
59
+ )
60
+ except Exception as e:
61
+ logging.error(f"Wan2.5 task {task_id} status api error: {e}")
62
+ continue
63
+
64
+ if "output" in status_api_resp and "video_url" in status_api_resp["output"]:
65
+ video_url = status_api_resp["output"]["video_url"]
66
+ logging.info(f"Wan2.5 task {task_id} success, video_url: {video_url}")
67
+ actual_prompt = status_api_resp["output"].get("actual_prompt", prompt)
68
+ # 下载视频
69
+ video_resp = requests.get(video_url, stream=True, timeout=3600)
70
+ video_resp.raise_for_status() # 非 2xx 会抛异常
71
+ return (VideoFromFile(io.BytesIO(video_resp.content)), actual_prompt)
72
+ if (
73
+ "output" not in status_api_resp
74
+ or "task_status" not in status_api_resp["output"]
75
+ ):
76
+ raise ValueError(f"Invalid response: {status_api_resp}")
77
+ if status_api_resp["output"]["task_status"] in _FAILED_STATUS:
78
+ raise ValueError(f"Wan2.5 task failed: {status_api_resp}")
79
+ logging.debug(
80
+ f"Wan2.5 task {task_id} status: {status_api_resp['output']['task_status']}"
81
+ )
82
+
83
+ raise ValueError(f"Wan2.5 task timed out, request ID: {task_id}")
33
84
 
34
85
 
35
86
  class Wan_V2_5_I2V_API(BizyAirBaseNode):
@@ -88,6 +139,7 @@ class Wan_V2_5_I2V_API(BizyAirBaseNode):
88
139
  headers = client.headers(api_key=extra_data["api_key"])
89
140
  prompt_id = extra_data["prompt_id"]
90
141
  headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
142
+ headers["X-Bizyair-Async-Result"] = "enable"
91
143
 
92
144
  # 参数
93
145
  prompt = kwargs.get("prompt", "")
@@ -121,7 +173,6 @@ class Wan_V2_5_I2V_API(BizyAirBaseNode):
121
173
 
122
174
  # 调用API
123
175
  model = "wan2.5-i2v-preview"
124
- api_url = f"{BIZYAIR_X_SERVER}/proxy_inference/Wan/{model}"
125
176
  data = {
126
177
  "model": model,
127
178
  "input": input,
@@ -132,23 +183,10 @@ class Wan_V2_5_I2V_API(BizyAirBaseNode):
132
183
  "audio": auto_audio,
133
184
  },
134
185
  }
135
- json_payload = json.dumps(data).encode("utf-8")
136
- logging.debug(f"json_payload: {json_payload}")
137
- api_resp = send_request(
138
- url=api_url,
139
- data=json_payload,
140
- headers=headers,
186
+
187
+ return wan_create_task_and_wait_for_completion(
188
+ data=data, model=model, prompt=prompt, headers=headers
141
189
  )
142
- logging.debug(f"api resp: {api_resp}")
143
- if "output" not in api_resp or "video_url" not in api_resp["output"]:
144
- raise ValueError(f"Invalid response: {api_resp}")
145
- video_url = api_resp["output"]["video_url"]
146
- logging.info(f"video_url: {video_url}")
147
- actual_prompt = api_resp["output"].get("actual_prompt", prompt)
148
- # 下载视频
149
- video_resp = requests.get(video_url, stream=True, timeout=3600)
150
- video_resp.raise_for_status() # 非 2xx 会抛异常
151
- return (VideoFromFile(io.BytesIO(video_resp.content)), actual_prompt)
152
190
 
153
191
 
154
192
  class Wan_V2_5_T2V_API(BizyAirBaseNode):
@@ -215,27 +253,12 @@ class Wan_V2_5_T2V_API(BizyAirBaseNode):
215
253
  CATEGORY = "☁️BizyAir/External APIs/WanVideo"
216
254
  FUNCTION = "api_call"
217
255
 
218
- def parse_upload_token(self, resp) -> dict:
219
- logging.debug(f"parsing token resp: {resp}")
220
- if "data" not in resp:
221
- logging.error(f"Invalid response, data not found: {resp}")
222
- raise ValueError(f"Invalid response: {resp}")
223
- data = resp["data"]
224
- if "file" not in data:
225
- logging.error(f"Invalid response, file not found: {resp}")
226
- raise ValueError(f"Invalid response: {resp}")
227
- file = data["file"]
228
- if "storage" not in data:
229
- logging.error(f"Invalid response, storage not found: {resp}")
230
- raise ValueError(f"Invalid response: {resp}")
231
- storage = data["storage"]
232
- return file | storage
233
-
234
256
  def api_call(self, prompt, **kwargs):
235
257
  extra_data = pop_api_key_and_prompt_id(kwargs)
236
258
  headers = client.headers(api_key=extra_data["api_key"])
237
259
  prompt_id = extra_data["prompt_id"]
238
260
  headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
261
+ headers["X-Bizyair-Async-Result"] = "enable"
239
262
 
240
263
  # 参数
241
264
  negative_prompt = kwargs.get("negative_prompt", "")
@@ -261,7 +284,6 @@ class Wan_V2_5_T2V_API(BizyAirBaseNode):
261
284
 
262
285
  # 调用API
263
286
  model = "wan2.5-t2v-preview"
264
- api_url = f"{BIZYAIR_X_SERVER}/proxy_inference/Wan/{model}"
265
287
  data = {
266
288
  "model": model,
267
289
  "input": input,
@@ -272,20 +294,6 @@ class Wan_V2_5_T2V_API(BizyAirBaseNode):
272
294
  "audio": auto_audio,
273
295
  },
274
296
  }
275
- json_payload = json.dumps(data).encode("utf-8")
276
- logging.debug(f"json_payload: {json_payload}")
277
- api_resp = send_request(
278
- url=api_url,
279
- data=json_payload,
280
- headers=headers,
297
+ return wan_create_task_and_wait_for_completion(
298
+ data=data, model=model, prompt=prompt, headers=headers
281
299
  )
282
- logging.debug(f"api resp: {api_resp}")
283
- if "output" not in api_resp or "video_url" not in api_resp["output"]:
284
- raise ValueError(f"Invalid response: {api_resp}")
285
- video_url = api_resp["output"]["video_url"]
286
- logging.info(f"video_url: {video_url}")
287
- actual_prompt = api_resp["output"].get("actual_prompt", prompt)
288
- # 下载视频
289
- video_resp = requests.get(video_url, stream=True, timeout=3600)
290
- video_resp.raise_for_status() # 非 2xx 会抛异常
291
- return (VideoFromFile(io.BytesIO(video_resp.content)), actual_prompt)
@@ -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/version.txt CHANGED
@@ -1 +1 @@
1
- 1.2.58
1
+ 1.2.60
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bizyengine
3
- Version: 1.2.58
3
+ Version: 1.2.60
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,7 +13,7 @@ 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.8.0
16
+ Requires-Dist: mcp>=1.18.0
17
17
  Requires-Dist: bizyairsdk>=0.0.4
18
18
 
19
19
  ## BizyEngine
@@ -1,5 +1,5 @@
1
1
  bizyengine/__init__.py,sha256=GP9V-JM07fz7uv_qTB43QEA2rKdrVJxi5I7LRnn_3ZQ,914
2
- bizyengine/version.txt,sha256=GOmifuSbInFqnoj8v1bW8vErzt0ii5bOQn0qEbp5dEg,7
2
+ bizyengine/version.txt,sha256=JHeNk_etjoxv23C-wCL_VMjUK-lNi-zHLdEMcrgk8I8,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
@@ -10,7 +10,7 @@ bizyengine/bizy_server/resp.py,sha256=iOFT5Ud7VJBP2uqkojJIgc3y2ifMjjEXoj0ewneL9l
10
10
  bizyengine/bizy_server/server.py,sha256=isOzHDk2kD6WjdlemeOA7j_xLnZ2vat_NvE1I0bsOFw,57490
11
11
  bizyengine/bizy_server/stream_response.py,sha256=H2XHqlVRtQMhgdztAuG7l8-iV_Pm42u2x6WJ0gNVIW0,9654
12
12
  bizyengine/bizy_server/utils.py,sha256=Kkn-AATZcdaDhg8Rg_EJW6aKqkyiSE2EYmuyOhUwXso,3863
13
- bizyengine/bizyair_extras/__init__.py,sha256=ZeUPmpn_6aVM9luC-k2jAl017RP2ihYtlLRLKrofryE,1053
13
+ bizyengine/bizyair_extras/__init__.py,sha256=GNmQ3C0fG8pIGgAMV6M9Jp89fOOVd-YpsLOuIWgjxF4,1092
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,7 @@ 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
25
+ bizyengine/bizyair_extras/nodes_gemini.py,sha256=XWp3Y7aKF_TDSM2QthOhUqMQN1s4FWWac98JkL8Hxxc,10594
26
26
  bizyengine/bizyair_extras/nodes_hunyuan3d.py,sha256=dWHLeqX68N7zKnfDMzm9nutmCNtFT6-wwt7P5cPDu7Q,2058
27
27
  bizyengine/bizyair_extras/nodes_image_utils.py,sha256=BldF_CKD2M01K8-SnG-QV86u3HZqFz_GP5GrCQ5CFDQ,2875
28
28
  bizyengine/bizyair_extras/nodes_ip2p.py,sha256=GSEFJvrs4f2tv0xwYkWqc8uhsXrzAJVPvvwcw0gTjR0,619
@@ -35,12 +35,14 @@ bizyengine/bizyair_extras/nodes_sd3.py,sha256=lZCxj0IFmuxk1fZTDcRKgVV5QWHjkUdpR4
35
35
  bizyengine/bizyair_extras/nodes_seedream.py,sha256=-I22lrdR0S6oRCgN7e5HD8pOJhuGBxDMlhX2S-CyOhY,6855
36
36
  bizyengine/bizyair_extras/nodes_segment_anything.py,sha256=x1ei2UggHnB8T6aUtK_ZcUehMALEyLUnDoD5SNJCbFU,7249
37
37
  bizyengine/bizyair_extras/nodes_segment_anything_utils.py,sha256=ZefAqrFrevDH3XY_wipr_VwKfeXrgpZEUFaqg_JGOdU,4714
38
+ bizyengine/bizyair_extras/nodes_sora2.py,sha256=ehIZNZyh0Dgvf74LUSCq9FeqdCHzdU6CqcouQzjrAqQ,7703
38
39
  bizyengine/bizyair_extras/nodes_testing_utils.py,sha256=lYmcyCIkTkQ7WOZfpEPU9wUbEvC_mL6_A46ks68WzZA,3988
39
40
  bizyengine/bizyair_extras/nodes_trellis.py,sha256=GqSRM8FobuziOIxwyAs3BLztpjVIP4rFT0ZWbfqJAfY,6065
40
41
  bizyengine/bizyair_extras/nodes_ultimatesdupscale.py,sha256=-_SsLTAWAQDv4uw-4Z7IGP2tXTe73BJ3N5D6RqVVAK4,4133
41
42
  bizyengine/bizyair_extras/nodes_upscale_model.py,sha256=lrzA1BFI2w5aEPCmNPMh07s-WDzG-xTT49uU6WCnlP8,1151
42
43
  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
+ bizyengine/bizyair_extras/nodes_veo3.py,sha256=C3aS20yylRAvV9gTXUyhvnXWIRZshZzLbRll7vqYEOY,10936
45
+ bizyengine/bizyair_extras/nodes_wan_api.py,sha256=nPTbPf6NU5ykCk43O49gLnjzIfOBsR5jjL0ON95n-nM,11265
44
46
  bizyengine/bizyair_extras/nodes_wan_i2v.py,sha256=3XwcxLHmgrihgXDEzcVOjU6VjqnZa3mErINlY014PFA,8435
45
47
  bizyengine/bizyair_extras/nodes_wan_video.py,sha256=aE2JBF0ZT-6BOM0bGu9R4yZ_eMeMnnjCW-YzFe4qg8Q,2804
46
48
  bizyengine/bizyair_extras/route_bizyair_tools.py,sha256=EiP5pS6xoE3tULoNSN2hYZA29vgt7yCErsbRp34gGEg,3898
@@ -48,7 +50,7 @@ bizyengine/bizyair_extras/nodes_ipadapter_plus/__init__.py,sha256=ECKATm_EKi_4G4
48
50
  bizyengine/bizyair_extras/nodes_ipadapter_plus/nodes_ipadapter_plus.py,sha256=lOKRem7oiPs8ZkA_p68HxagAgiCSvn3Rk-L4fSXIjyE,54846
49
51
  bizyengine/bizyair_extras/nodes_kolors_mz/__init__.py,sha256=HsCCCphW8q0SrWEiFlZKK_W2lQr1T0UJIJL7gEn37ME,3729
50
52
  bizyengine/bizyair_extras/oauth_callback/main.py,sha256=KQOZWor3kyNx8xvUNHYNMoHfCF9g_ht13_iPk4K_5YM,3633
51
- bizyengine/bizyair_extras/utils/aliyun_oss.py,sha256=NBC8tB_xG33X9nAuoSzzgkN2VHSOpEMqOH8wTIAERCE,2407
53
+ bizyengine/bizyair_extras/utils/aliyun_oss.py,sha256=H6wGZq1DqP7BHJ_frBJVvUVttgXprJprOnxytePIuos,3050
52
54
  bizyengine/bizyair_extras/utils/audio.py,sha256=cCmX080jtxsHFa7mCgn13R6cyfqE-1Gq37ZnRJdZNU8,3183
53
55
  bizyengine/bizybot/__init__.py,sha256=NINN_7QECKQwtAwKPBTrrSiAK6KbxaZCkIvJ-e1J1xk,262
54
56
  bizyengine/bizybot/client.py,sha256=PWdcjslMaW4xmNaAq3TwRGV8twg9yPEfDNyfuZzpCyY,26029
@@ -95,7 +97,7 @@ bizyengine/misc/route_sam.py,sha256=-bMIR2QalfnszipGxSxvDAHGJa5gPSrjkYPb5baaRg4,
95
97
  bizyengine/misc/segment_anything.py,sha256=wNKYwlYPMszfwj23524geFZJjZaG4eye65SGaUnh77I,8941
96
98
  bizyengine/misc/supernode.py,sha256=STN9gaxfTSErH8OiHeZa47d8z-G9S0I7fXuJvHQOBFM,4532
97
99
  bizyengine/misc/utils.py,sha256=nXXTPkj4WBvds4EWjI9c-ydeWwmXl8Vwrdu-4Fh62g8,12914
98
- bizyengine-1.2.58.dist-info/METADATA,sha256=xjje03R1xq0NXcgJWKZ916QclolZOmQDmoyk4f7TEkw,734
99
- bizyengine-1.2.58.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
100
- bizyengine-1.2.58.dist-info/top_level.txt,sha256=2zapzqxX-we5cRyJkGf9bd5JinRtXp3-_uDI-xCAnc0,11
101
- bizyengine-1.2.58.dist-info/RECORD,,
100
+ bizyengine-1.2.60.dist-info/METADATA,sha256=ggF_2atIDhQRk-HVJdyB33p7344pVbG8wc5pffPZSxU,735
101
+ bizyengine-1.2.60.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
102
+ bizyengine-1.2.60.dist-info/top_level.txt,sha256=2zapzqxX-we5cRyJkGf9bd5JinRtXp3-_uDI-xCAnc0,11
103
+ bizyengine-1.2.60.dist-info/RECORD,,