bizyengine 1.2.68__py3-none-any.whl → 1.2.69__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,294 +0,0 @@
1
- import io
2
- import json
3
- import logging
4
- import time
5
-
6
- import requests
7
- from bizyairsdk import tensor_to_bytesio
8
- from comfy_api.latest._input_impl import VideoFromFile
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": (["16:9"], {"default": "16:9"}),
181
- },
182
- }
183
-
184
- NODE_DISPLAY_NAME = "Veo3.1 Image To Video (Reference Images)"
185
- RETURN_TYPES = ("VIDEO",)
186
- RETURN_NAMES = ("video",)
187
- CATEGORY = "☁️BizyAir/External APIs/Veo"
188
- FUNCTION = "api_call"
189
-
190
- def api_call(self, ref_image_1, model, prompt, **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
- ref_image_2 = kwargs.get("ref_image_2", None)
200
- ref_image_3 = kwargs.get("ref_image_3", None)
201
-
202
- input = {
203
- "webHook": "-1",
204
- "aspectRatio": aspect_ratio,
205
- "model": model,
206
- }
207
- if prompt is not None and prompt.strip() != "":
208
- input["prompt"] = prompt
209
- else:
210
- raise ValueError("Prompt is required")
211
-
212
- # 上传图片
213
- ref_images = []
214
- if ref_image_1 is not None:
215
- oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}_ref_1.png&file_type=inputs"
216
- token_resp = send_request("GET", oss_token_url, headers=headers)
217
- auth_info = parse_upload_token(token_resp)
218
- ref_images.append(
219
- upload_file_without_sdk(tensor_to_bytesio(ref_image_1), **auth_info)
220
- )
221
- if ref_image_2 is not None:
222
- oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}_ref_2.png&file_type=inputs"
223
- token_resp = send_request("GET", oss_token_url, headers=headers)
224
- auth_info = parse_upload_token(token_resp)
225
- ref_images.append(
226
- upload_file_without_sdk(tensor_to_bytesio(ref_image_2), **auth_info)
227
- )
228
- if ref_image_3 is not None:
229
- oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}_ref_3.png&file_type=inputs"
230
- token_resp = send_request("GET", oss_token_url, headers=headers)
231
- auth_info = parse_upload_token(token_resp)
232
- ref_images.append(
233
- upload_file_without_sdk(tensor_to_bytesio(ref_image_3), **auth_info)
234
- )
235
- input["urls"] = ref_images
236
-
237
- # 调用API
238
- return veo_create_task_and_wait_for_completion(
239
- data=input, model=model, prompt=prompt, headers=headers
240
- )
241
-
242
-
243
- class Veo_V3_1_T2V_API(BizyAirBaseNode):
244
- @classmethod
245
- def INPUT_TYPES(cls):
246
- return {
247
- "required": {
248
- "prompt": (
249
- "STRING",
250
- {
251
- "multiline": True,
252
- "default": "",
253
- },
254
- ),
255
- "model": (["veo3.1-fast", "veo3.1-pro"], {"default": "veo3.1-fast"}),
256
- },
257
- "optional": {
258
- "aspect_ratio": (
259
- ["9:16", "16:9"],
260
- {"default": "16:9"},
261
- ),
262
- },
263
- }
264
-
265
- NODE_DISPLAY_NAME = "Veo3.1 Text To Video"
266
- RETURN_TYPES = ("VIDEO",)
267
- RETURN_NAMES = ("video",)
268
- CATEGORY = "☁️BizyAir/External APIs/Veo"
269
- FUNCTION = "api_call"
270
-
271
- def api_call(self, prompt, model, **kwargs):
272
- extra_data = pop_api_key_and_prompt_id(kwargs)
273
- headers = client.headers(api_key=extra_data["api_key"])
274
- prompt_id = extra_data["prompt_id"]
275
- headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
276
- headers["X-Bizyair-Async-Result"] = "enable"
277
-
278
- # 参数
279
- aspect_ratio = kwargs.get("aspect_ratio", "16:9")
280
-
281
- input = {
282
- "webHook": "-1",
283
- "aspectRatio": aspect_ratio,
284
- "model": model,
285
- }
286
- if prompt is not None and prompt.strip() != "":
287
- input["prompt"] = prompt
288
- else:
289
- raise ValueError("Prompt is required")
290
-
291
- # 调用API
292
- return veo_create_task_and_wait_for_completion(
293
- data=input, model=model, prompt=prompt, headers=headers
294
- )
@@ -1,299 +0,0 @@
1
- import io
2
- import json
3
- import logging
4
- import time
5
-
6
- import requests
7
- from bizyairsdk import tensor_to_bytesio
8
- from comfy_api.latest._input_impl import VideoFromFile
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
- _FAILED_STATUS = ["FAILED", "CANCELED", "UNKNOWN"]
19
-
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}")
84
-
85
-
86
- class Wan_V2_5_I2V_API(BizyAirBaseNode):
87
- @classmethod
88
- def INPUT_TYPES(cls):
89
- return {
90
- "required": {
91
- "image": ("IMAGE",),
92
- },
93
- "optional": {
94
- "audio": ("AUDIO",),
95
- "prompt": (
96
- "STRING",
97
- {
98
- "multiline": True,
99
- "default": "",
100
- },
101
- ),
102
- "negative_prompt": (
103
- "STRING",
104
- {
105
- "multiline": True,
106
- "default": "",
107
- },
108
- ),
109
- "resolution": (
110
- ["480P", "720P", "1080P"],
111
- {"default": "1080P"},
112
- ),
113
- "duration": ([5, 10], {"default": 5}),
114
- "prompt_extend": (
115
- "BOOLEAN",
116
- {
117
- "default": True,
118
- "tooltip": "是否开启prompt智能改写。开启后使用大模型对输入prompt进行智能改写。对于较短的prompt生成效果提升明显,但会增加耗时。",
119
- },
120
- ),
121
- "auto_audio": (
122
- "BOOLEAN",
123
- {
124
- "default": True,
125
- "tooltip": "是否由模型自动生成声音,优先级低于audio参数。",
126
- },
127
- ),
128
- },
129
- }
130
-
131
- NODE_DISPLAY_NAME = "Wan2.5 Image To Video"
132
- RETURN_TYPES = ("VIDEO", "STRING")
133
- RETURN_NAMES = ("video", "actual_prompt")
134
- CATEGORY = "☁️BizyAir/External APIs/WanVideo"
135
- FUNCTION = "api_call"
136
-
137
- def api_call(self, image, **kwargs):
138
- extra_data = pop_api_key_and_prompt_id(kwargs)
139
- headers = client.headers(api_key=extra_data["api_key"])
140
- prompt_id = extra_data["prompt_id"]
141
- headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
142
- headers["X-Bizyair-Async-Result"] = "enable"
143
-
144
- # 参数
145
- prompt = kwargs.get("prompt", "")
146
- negative_prompt = kwargs.get("negative_prompt", "")
147
- audio = kwargs.get("audio", None)
148
- resolution = kwargs.get("resolution", "1080P")
149
- duration = kwargs.get("duration", 5)
150
- prompt_extend = kwargs.get("prompt_extend", True)
151
- auto_audio = kwargs.get("auto_audio", True)
152
-
153
- input = {}
154
- if prompt is not None and prompt.strip() != "":
155
- input["prompt"] = prompt
156
- if negative_prompt is not None and negative_prompt.strip() != "":
157
- input["negative_prompt"] = negative_prompt
158
-
159
- # 上传图片&音频
160
- if image is not None:
161
- oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}.png&file_type=inputs"
162
- token_resp = send_request("GET", oss_token_url, headers=headers)
163
- auth_info = parse_upload_token(token_resp)
164
- input["img_url"] = upload_file_without_sdk(
165
- tensor_to_bytesio(image), **auth_info
166
- )
167
- if audio is not None:
168
- oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}.flac&file_type=inputs"
169
- token_resp = send_request("GET", oss_token_url, headers=headers)
170
- auth_info = parse_upload_token(token_resp)
171
- audio_bytes = save_audio(audio)
172
- input["audio_url"] = upload_file_without_sdk(audio_bytes, **auth_info)
173
-
174
- # 调用API
175
- model = "wan2.5-i2v-preview"
176
- data = {
177
- "model": model,
178
- "input": input,
179
- "parameters": {
180
- "resolution": resolution,
181
- "prompt_extend": prompt_extend,
182
- "duration": duration,
183
- "audio": auto_audio,
184
- },
185
- }
186
-
187
- return wan_create_task_and_wait_for_completion(
188
- data=data, model=model, prompt=prompt, headers=headers
189
- )
190
-
191
-
192
- class Wan_V2_5_T2V_API(BizyAirBaseNode):
193
- @classmethod
194
- def INPUT_TYPES(cls):
195
- return {
196
- "required": {
197
- "prompt": (
198
- "STRING",
199
- {
200
- "multiline": True,
201
- "default": "",
202
- },
203
- ),
204
- },
205
- "optional": {
206
- "audio": ("AUDIO",),
207
- "negative_prompt": (
208
- "STRING",
209
- {
210
- "multiline": True,
211
- "default": "",
212
- },
213
- ),
214
- "size": (
215
- [
216
- "832*480",
217
- "480*832",
218
- "624*624",
219
- "1280*720",
220
- "720*1280",
221
- "960*960",
222
- "1088*832",
223
- "832*1088",
224
- "1920*1080",
225
- "1080*1920",
226
- "1440*1440",
227
- "1632*1248",
228
- "1248*1632",
229
- ],
230
- {"default": "1920*1080"},
231
- ),
232
- "duration": ([5, 10], {"default": 5}),
233
- "prompt_extend": (
234
- "BOOLEAN",
235
- {
236
- "default": True,
237
- "tooltip": "是否开启prompt智能改写。开启后使用大模型对输入prompt进行智能改写。对于较短的prompt生成效果提升明显,但会增加耗时。",
238
- },
239
- ),
240
- "auto_audio": (
241
- "BOOLEAN",
242
- {
243
- "default": True,
244
- "tooltip": "是否由模型自动生成声音,优先级低于audio参数。",
245
- },
246
- ),
247
- },
248
- }
249
-
250
- NODE_DISPLAY_NAME = "Wan2.5 Text To Video"
251
- RETURN_TYPES = ("VIDEO", "STRING")
252
- RETURN_NAMES = ("video", "actual_prompt")
253
- CATEGORY = "☁️BizyAir/External APIs/WanVideo"
254
- FUNCTION = "api_call"
255
-
256
- def api_call(self, prompt, **kwargs):
257
- extra_data = pop_api_key_and_prompt_id(kwargs)
258
- headers = client.headers(api_key=extra_data["api_key"])
259
- prompt_id = extra_data["prompt_id"]
260
- headers["X-BIZYAIR-PROMPT-ID"] = prompt_id
261
- headers["X-Bizyair-Async-Result"] = "enable"
262
-
263
- # 参数
264
- negative_prompt = kwargs.get("negative_prompt", "")
265
- audio = kwargs.get("audio", None)
266
- size = kwargs.get("size", "1920*1080")
267
- duration = kwargs.get("duration", 5)
268
- prompt_extend = kwargs.get("prompt_extend", True)
269
- auto_audio = kwargs.get("auto_audio", True)
270
-
271
- input = {}
272
- if prompt is not None and prompt.strip() != "":
273
- input["prompt"] = prompt
274
- if negative_prompt is not None and negative_prompt.strip() != "":
275
- input["negative_prompt"] = negative_prompt
276
-
277
- # 上传音频
278
- if audio is not None:
279
- oss_token_url = f"{BIZYAIR_X_SERVER}/upload/token?file_name={prompt_id}.flac&file_type=inputs"
280
- token_resp = send_request("GET", oss_token_url, headers=headers)
281
- auth_info = parse_upload_token(token_resp)
282
- audio_bytes = save_audio(audio)
283
- input["audio_url"] = upload_file_without_sdk(audio_bytes, **auth_info)
284
-
285
- # 调用API
286
- model = "wan2.5-t2v-preview"
287
- data = {
288
- "model": model,
289
- "input": input,
290
- "parameters": {
291
- "size": size,
292
- "prompt_extend": prompt_extend,
293
- "duration": duration,
294
- "audio": auto_audio,
295
- },
296
- }
297
- return wan_create_task_and_wait_for_completion(
298
- data=data, model=model, prompt=prompt, headers=headers
299
- )