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,192 +0,0 @@
1
- import base64
2
- import io
3
- import json
4
- import logging
5
- import re
6
- from pathlib import Path
7
-
8
- import requests
9
- import torch
10
- from bizyairsdk import bytesio_to_image_tensor, tensor_to_base64_string
11
-
12
- from bizyengine.core import BizyAirBaseNode, pop_api_key_and_prompt_id
13
- from bizyengine.core.common import client
14
- from bizyengine.core.common.env_var import BIZYAIR_SERVER_ADDRESS
15
-
16
-
17
- def download_png(url: str) -> bytes:
18
- """下载 PNG 图片"""
19
- resp = requests.get(url, stream=True, timeout=30)
20
- resp.raise_for_status() # 非 2xx 会抛异常
21
- return resp.content
22
-
23
-
24
- class Seedream4(BizyAirBaseNode):
25
- def __init__(self):
26
- pass
27
-
28
- @classmethod
29
- def INPUT_TYPES(s):
30
- return {
31
- "required": {
32
- "prompt": (
33
- "STRING",
34
- {
35
- "multiline": True,
36
- "default": "",
37
- },
38
- ),
39
- "size": (
40
- [
41
- "1K Square (1024x1024)",
42
- "2K Square (2048x2048)",
43
- "4K Square (4096x4096)",
44
- "HD 16:9 (1920x1080)",
45
- "2K 16:9 (2560x1440)",
46
- "4K 16:9 (3840x2160)",
47
- "Portrait 9:16 (1080x1920)",
48
- "Portrait 3:4 (1536x2048)",
49
- "Landscape 4:3 (2048x1536)",
50
- "Ultra-wide 21:9 (3440x1440)",
51
- "Custom",
52
- ],
53
- {
54
- "default": "HD 16:9 (1920x1080)",
55
- },
56
- ),
57
- "custom_width": ("INT", {"default": 1920, "min": 1024, "max": 4096}),
58
- "custom_height": ("INT", {"default": 1080, "min": 1024, "max": 4096}),
59
- "model": (
60
- ["doubao-seedream-4-0-250828"],
61
- {"default": "doubao-seedream-4-0-250828"},
62
- ),
63
- },
64
- "optional": {
65
- "image": ("IMAGE",),
66
- "image2": ("IMAGE",),
67
- "image3": ("IMAGE",),
68
- "image4": ("IMAGE",),
69
- "image5": ("IMAGE",),
70
- "image6": ("IMAGE",),
71
- "image7": ("IMAGE",),
72
- "image8": ("IMAGE",),
73
- "image9": ("IMAGE",),
74
- "image10": ("IMAGE",),
75
- },
76
- }
77
-
78
- RETURN_TYPES = ("IMAGE",)
79
- FUNCTION = "execute"
80
- OUTPUT_NODE = False
81
- CATEGORY = "☁️BizyAir/External APIs/Doubao"
82
-
83
- def execute(self, **kwargs):
84
- try:
85
- model = kwargs.get("model", "doubao-seedream-4-0-250828")
86
- url = f"{BIZYAIR_SERVER_ADDRESS}/proxy_inference/Doubao/{model}"
87
- extra_data = pop_api_key_and_prompt_id(kwargs)
88
-
89
- prompt = kwargs.get("prompt", "")
90
- size = kwargs.get("size", "1K Square (1024x1024)")
91
-
92
- match size:
93
- case "1K Square (1024x1024)":
94
- width = 1024
95
- height = 1024
96
- case "2K Square (2048x2048)":
97
- width = 2048
98
- height = 2048
99
- case "4K Square (4096x4096)":
100
- width = 4096
101
- height = 4096
102
- case "HD 16:9 (1920x1080)":
103
- width = 1920
104
- height = 1080
105
- case "2K 16:9 (2560x1440)":
106
- width = 2560
107
- height = 1440
108
- case "4K 16:9 (3840x2160)":
109
- width = 3840
110
- height = 2160
111
- case "Portrait 9:16 (1080x1920)":
112
- width = 1080
113
- height = 1920
114
- case "Portrait 3:4 (1536x2048)":
115
- width = 1536
116
- height = 2048
117
- case "Landscape 4:3 (2048x1536)":
118
- width = 2048
119
- height = 1536
120
- case "Ultra-wide 21:9 (3440x1440)":
121
- width = 3440
122
- height = 1440
123
- case "Custom":
124
- width = kwargs.get("custom_width", 1920)
125
- height = kwargs.get("custom_height", 1080)
126
-
127
- case _:
128
- raise ValueError(f"Invalid size: {size}")
129
-
130
- sizeStr = f"{width}x{height}"
131
-
132
- images = []
133
- total_size = 0
134
- for _, img in enumerate(
135
- [
136
- kwargs.get("image", None),
137
- kwargs.get("image2", None),
138
- kwargs.get("image3", None),
139
- kwargs.get("image4", None),
140
- kwargs.get("image5", None),
141
- kwargs.get("image6", None),
142
- kwargs.get("image7", None),
143
- kwargs.get("image8", None),
144
- kwargs.get("image9", None),
145
- kwargs.get("image10", None),
146
- ],
147
- 1,
148
- ):
149
- if img is not None:
150
- # 都当作PNG就行
151
- b64_data = tensor_to_base64_string(img)
152
- if len(b64_data) > 10 * 1024 * 1024:
153
- raise ValueError(
154
- "Image size is too large, Seedream 4.0 only supports up to 10MB"
155
- )
156
- images.append(f"data:image/png;base64,{b64_data}")
157
- total_size += len(b64_data)
158
- if total_size > 50 * 1024 * 1024:
159
- raise ValueError(
160
- "Total size of images is too large, BizyAir only supports up to 50MB"
161
- )
162
-
163
- data = {
164
- "prompt": prompt,
165
- "size": sizeStr,
166
- "image": images,
167
- "model": model,
168
- "watermark": False,
169
- "response_format": "url",
170
- }
171
-
172
- json_payload = json.dumps(data).encode("utf-8")
173
- headers = client.headers(api_key=extra_data["api_key"])
174
- headers["X-BIZYAIR-PROMPT-ID"] = extra_data["prompt_id"]
175
- resp = client.send_request(
176
- url=url,
177
- data=json_payload,
178
- headers=headers,
179
- )
180
-
181
- # 结果会包含图片URL,客户端这里负责下载
182
- if not "data" in resp:
183
- raise ValueError(f"Invalid response: {resp}")
184
- if not "url" in resp["data"][0]:
185
- raise ValueError(f"Invalid response: {resp}")
186
-
187
- image_data = download_png(resp["data"][0]["url"])
188
- return (bytesio_to_image_tensor(io.BytesIO(image_data)),)
189
-
190
- except Exception as e:
191
- logging.error(f"Seedream 4.0 API error: {e}")
192
- raise e
@@ -1,217 +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.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
- )