bizyengine 1.2.68__py3-none-any.whl → 1.2.70__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.
@@ -10,7 +10,6 @@ modules = [
10
10
  ".nodes_dataset",
11
11
  ".nodes_differential_diffusion",
12
12
  ".nodes_flux",
13
- ".nodes_gemini",
14
13
  ".nodes_hunyuan3d",
15
14
  ".nodes_image_utils",
16
15
  ".nodes_ip2p",
@@ -22,19 +21,16 @@ modules = [
22
21
  ".nodes_reactor",
23
22
  ".nodes_sam2",
24
23
  ".nodes_sd3",
25
- ".nodes_seedream",
26
24
  ".nodes_segment_anything",
27
25
  ".nodes_testing_utils",
28
26
  ".nodes_trellis",
29
27
  ".nodes_ultimatesdupscale",
30
28
  ".nodes_upscale_model",
31
29
  ".nodes_utils",
32
- ".nodes_wan_api",
33
30
  ".nodes_wan_i2v",
34
31
  ".nodes_wan_video",
35
32
  ".route_bizyair_tools",
36
- ".nodes_veo3",
37
- ".nodes_sora2",
33
+ ".third_party_api",
38
34
  ]
39
35
  from bizyengine.core.common.utils import safe_star_import
40
36
 
@@ -0,0 +1,15 @@
1
+ modules = [
2
+ ".nodes_hailuo",
3
+ ".nodes_gemini",
4
+ ".nodes_gpt",
5
+ ".nodes_kling",
6
+ ".nodes_doubao",
7
+ ".nodes_flux",
8
+ ".nodes_sora",
9
+ ".nodes_veo3",
10
+ ".nodes_wan_api",
11
+ ]
12
+ from bizyengine.core.common.utils import safe_star_import
13
+
14
+ for mod in modules:
15
+ safe_star_import(mod, package=__package__)
@@ -0,0 +1,404 @@
1
+ from bizyairsdk import tensor_to_bytesio
2
+
3
+ from .trd_nodes_base import BizyAirTrdApiBaseNode
4
+
5
+
6
+ class Seedream4(BizyAirTrdApiBaseNode):
7
+ RETURN_TYPES = ("IMAGE",)
8
+ RETURN_NAMES = ("images",)
9
+ CATEGORY = "☁️BizyAir/External APIs/Doubao"
10
+ NODE_DISPLAY_NAME = "Seedream4"
11
+
12
+ @classmethod
13
+ def INPUT_TYPES(s):
14
+ return {
15
+ "required": {
16
+ "prompt": (
17
+ "STRING",
18
+ {
19
+ "multiline": True,
20
+ "default": "",
21
+ },
22
+ ),
23
+ "size": (
24
+ [
25
+ "1K Square (1024x1024)",
26
+ "2K Square (2048x2048)",
27
+ "4K Square (4096x4096)",
28
+ "HD 16:9 (1920x1080)",
29
+ "2K 16:9 (2560x1440)",
30
+ "4K 16:9 (3840x2160)",
31
+ "Portrait 9:16 (1080x1920)",
32
+ "Portrait 3:4 (1536x2048)",
33
+ "Landscape 4:3 (2048x1536)",
34
+ "Ultra-wide 21:9 (3440x1440)",
35
+ "Custom",
36
+ ],
37
+ {
38
+ "default": "HD 16:9 (1920x1080)",
39
+ },
40
+ ),
41
+ "custom_width": ("INT", {"default": 1920, "min": 1024, "max": 4096}),
42
+ "custom_height": ("INT", {"default": 1080, "min": 1024, "max": 4096}),
43
+ "model": (
44
+ ["doubao-seedream-4-0-250828"],
45
+ {"default": "doubao-seedream-4-0-250828"},
46
+ ),
47
+ },
48
+ "optional": {
49
+ "image": ("IMAGE",),
50
+ "image2": ("IMAGE",),
51
+ "image3": ("IMAGE",),
52
+ "image4": ("IMAGE",),
53
+ "image5": ("IMAGE",),
54
+ "image6": ("IMAGE",),
55
+ "image7": ("IMAGE",),
56
+ "image8": ("IMAGE",),
57
+ "image9": ("IMAGE",),
58
+ "image10": ("IMAGE",),
59
+ },
60
+ }
61
+
62
+ def handle_inputs(self, headers, prompt_id, **kwargs):
63
+ model = kwargs.get("model", "doubao-seedream-4-0-250828")
64
+ prompt = kwargs.get("prompt", "")
65
+ size = kwargs.get("size", "1K Square (1024x1024)")
66
+
67
+ match size:
68
+ case "1K Square (1024x1024)":
69
+ width = 1024
70
+ height = 1024
71
+ case "2K Square (2048x2048)":
72
+ width = 2048
73
+ height = 2048
74
+ case "4K Square (4096x4096)":
75
+ width = 4096
76
+ height = 4096
77
+ case "HD 16:9 (1920x1080)":
78
+ width = 1920
79
+ height = 1080
80
+ case "2K 16:9 (2560x1440)":
81
+ width = 2560
82
+ height = 1440
83
+ case "4K 16:9 (3840x2160)":
84
+ width = 3840
85
+ height = 2160
86
+ case "Portrait 9:16 (1080x1920)":
87
+ width = 1080
88
+ height = 1920
89
+ case "Portrait 3:4 (1536x2048)":
90
+ width = 1536
91
+ height = 2048
92
+ case "Landscape 4:3 (2048x1536)":
93
+ width = 2048
94
+ height = 1536
95
+ case "Ultra-wide 21:9 (3440x1440)":
96
+ width = 3440
97
+ height = 1440
98
+ case "Custom":
99
+ width = kwargs.get("custom_width", 1920)
100
+ height = kwargs.get("custom_height", 1080)
101
+
102
+ case _:
103
+ raise ValueError(f"Invalid size: {size}")
104
+
105
+ sizeStr = f"{width}x{height}"
106
+
107
+ images = []
108
+ total_size = 0
109
+ for i, img in enumerate(
110
+ [
111
+ kwargs.get("image", None),
112
+ kwargs.get("image2", None),
113
+ kwargs.get("image3", None),
114
+ kwargs.get("image4", None),
115
+ kwargs.get("image5", None),
116
+ kwargs.get("image6", None),
117
+ kwargs.get("image7", None),
118
+ kwargs.get("image8", None),
119
+ kwargs.get("image9", None),
120
+ kwargs.get("image10", None),
121
+ ],
122
+ 1,
123
+ ):
124
+ if img is not None:
125
+ # 都当作PNG就行
126
+ bio = tensor_to_bytesio(image=img, total_pixels=4096 * 4096)
127
+ length = bio.getbuffer().nbytes
128
+ if length > 10 * 1024 * 1024:
129
+ raise ValueError(
130
+ "Image size is too large, Seedream 4.0 only supports up to 10MB"
131
+ )
132
+ total_size += length
133
+ if total_size > 50 * 1024 * 1024:
134
+ raise ValueError(
135
+ "Total size of images is too large, BizyAir only supports up to 50MB"
136
+ )
137
+ images.append(self.upload_file(bio, f"{prompt_id}_{i}.png", headers))
138
+
139
+ data = {
140
+ "prompt": prompt,
141
+ "size": sizeStr,
142
+ "image": images,
143
+ "model": model,
144
+ "watermark": False,
145
+ "response_format": "url",
146
+ }
147
+
148
+ return data, model
149
+
150
+ def handle_outputs(self, outputs):
151
+ images = self.combine_images(outputs[1])
152
+ return (images,)
153
+
154
+
155
+ class Seededit3(BizyAirTrdApiBaseNode):
156
+ RETURN_TYPES = ("IMAGE",)
157
+ RETURN_NAMES = ("image",)
158
+ CATEGORY = "☁️BizyAir/External APIs/Doubao"
159
+ NODE_DISPLAY_NAME = "Seededit3"
160
+
161
+ @classmethod
162
+ def INPUT_TYPES(cls):
163
+ return {
164
+ "required": {
165
+ "image": ("IMAGE",),
166
+ "prompt": (
167
+ "STRING",
168
+ {
169
+ "multiline": True,
170
+ "default": "",
171
+ },
172
+ ),
173
+ "model": (
174
+ ["doubao-seededit-3-0-i2i-250628"],
175
+ {"default": "doubao-seededit-3-0-i2i-250628"},
176
+ ),
177
+ "seed": ("INT", {"default": -1, "min": -1, "max": 2147483647}),
178
+ "guidance_scale": ("FLOAT", {"default": 5.5, "min": 1.0, "max": 10.0}),
179
+ },
180
+ }
181
+
182
+ def handle_inputs(self, headers, prompt_id, **kwargs):
183
+ model = kwargs.get("model", "doubao-seededit-3-0-i2i-250628")
184
+ prompt = kwargs.get("prompt", "")
185
+ image = kwargs.get("image", None)
186
+ seed = kwargs.get("seed", -1)
187
+ guidance_scale = kwargs.get("guidance_scale", 5.5)
188
+ if image is None:
189
+ raise ValueError("Image is required")
190
+ # 上传图片
191
+ image_url = self.upload_file(
192
+ tensor_to_bytesio(image=image, total_pixels=4096 * 4096),
193
+ f"{prompt_id}.png",
194
+ headers,
195
+ )
196
+ data = {
197
+ "prompt": prompt,
198
+ "model": model,
199
+ "image": image_url,
200
+ "seed": seed,
201
+ "guidance_scale": guidance_scale,
202
+ "size": "adaptive",
203
+ "response_format": "url",
204
+ "watermark": False,
205
+ }
206
+ return data, model
207
+
208
+ def handle_outputs(self, outputs):
209
+ images = self.combine_images(outputs[1])
210
+ return (images,)
211
+
212
+
213
+ class Seedance_1_0_T2V_API(BizyAirTrdApiBaseNode):
214
+ RETURN_TYPES = ("VIDEO",)
215
+ RETURN_NAMES = ("video",)
216
+ CATEGORY = "☁️BizyAir/External APIs/Doubao"
217
+ NODE_DISPLAY_NAME = "Seedance 1.0 Pro Text To Video"
218
+
219
+ @classmethod
220
+ def INPUT_TYPES(cls):
221
+ return {
222
+ "required": {
223
+ "prompt": (
224
+ "STRING",
225
+ {
226
+ "multiline": True,
227
+ "default": "",
228
+ },
229
+ ),
230
+ "model": (
231
+ [
232
+ "doubao-seedance-1-0-pro-250528",
233
+ "doubao-seedance-1-0-pro-fast-251015",
234
+ ],
235
+ {"default": "doubao-seedance-1-0-pro-250528"},
236
+ ),
237
+ "resolution": (
238
+ ["480p", "720p", "1080p"],
239
+ {
240
+ "default": "1080p",
241
+ "tooltip": "分辨率+比例共同决定视频尺寸,具体尺寸请参考官方文档说明",
242
+ },
243
+ ),
244
+ "ratio": (
245
+ ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"],
246
+ {
247
+ "default": "adaptive",
248
+ "tooltip": "比例+分辨率共同决定视频尺寸,具体尺寸请参考官方文档说明",
249
+ },
250
+ ),
251
+ "duration": ("INT", {"default": 12, "min": 2, "max": 12}),
252
+ "fps": (
253
+ [24],
254
+ {
255
+ "default": 24,
256
+ "tooltip": "帧率固定24",
257
+ },
258
+ ),
259
+ "camerafixed": (
260
+ "BOOLEAN",
261
+ {
262
+ "default": False,
263
+ "tooltip": "平台可能在提示词中追加固定摄像机指令(效果不保证) ",
264
+ },
265
+ ),
266
+ "seed": ("INT", {"default": -1, "min": -1, "max": 2147483647}),
267
+ },
268
+ }
269
+
270
+ def handle_inputs(self, headers, prompt_id, **kwargs):
271
+ model = kwargs.get("model", "doubao-seedance-1-0-pro-250528")
272
+ prompt = kwargs.get("prompt", "")
273
+ resolution = kwargs.get("resolution", "1080p")
274
+ ratio = kwargs.get("ratio", "adaptive")
275
+ duration = kwargs.get("duration", 12)
276
+ camerafixed = kwargs.get("camerafixed", False)
277
+ seed = kwargs.get("seed", -1)
278
+ if prompt is None or prompt.strip() == "":
279
+ raise ValueError("Prompt is required")
280
+ data = {
281
+ "prompt": prompt,
282
+ "model": model,
283
+ "resolution": resolution,
284
+ "ratio": ratio,
285
+ "duration": duration,
286
+ "camerafixed": camerafixed,
287
+ "seed": seed,
288
+ "watermark": False,
289
+ "fps": 24,
290
+ }
291
+ return data, "doubao-seedance-1-0"
292
+
293
+ def handle_outputs(self, outputs):
294
+ return (outputs[0][0],)
295
+
296
+
297
+ class Seedance_1_0_I2V_API(BizyAirTrdApiBaseNode):
298
+ RETURN_TYPES = ("VIDEO",)
299
+ RETURN_NAMES = ("video",)
300
+ CATEGORY = "☁️BizyAir/External APIs/Doubao"
301
+ NODE_DISPLAY_NAME = "Seedance 1.0 Pro Image To Video"
302
+
303
+ @classmethod
304
+ def INPUT_TYPES(cls):
305
+ return {
306
+ "required": {
307
+ "first_frame_image": ("IMAGE",),
308
+ "prompt": (
309
+ "STRING",
310
+ {
311
+ "multiline": True,
312
+ "default": "",
313
+ },
314
+ ),
315
+ "model": (
316
+ [
317
+ "doubao-seedance-1-0-pro-250528",
318
+ "doubao-seedance-1-0-pro-fast-251015",
319
+ ],
320
+ {"default": "doubao-seedance-1-0-pro-250528"},
321
+ ),
322
+ "resolution": (
323
+ ["480p", "720p", "1080p"],
324
+ {
325
+ "default": "1080p",
326
+ "tooltip": "分辨率+比例共同决定视频尺寸,具体尺寸请参考官方文档说明",
327
+ },
328
+ ),
329
+ "ratio": (
330
+ ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"],
331
+ {
332
+ "default": "adaptive",
333
+ "tooltip": "比例+分辨率共同决定视频尺寸,具体尺寸请参考官方文档说明",
334
+ },
335
+ ),
336
+ "duration": ("INT", {"default": 12, "min": 2, "max": 12}),
337
+ "fps": (
338
+ [24],
339
+ {
340
+ "default": 24,
341
+ "tooltip": "帧率固定24",
342
+ },
343
+ ),
344
+ "camerafixed": (
345
+ "BOOLEAN",
346
+ {
347
+ "default": False,
348
+ "tooltip": "平台可能在提示词中追加固定摄像机指令(效果不保证) ",
349
+ },
350
+ ),
351
+ "seed": ("INT", {"default": -1, "min": -1, "max": 2147483647}),
352
+ },
353
+ "optional": {
354
+ "last_frame_image": ("IMAGE",),
355
+ },
356
+ }
357
+
358
+ def handle_inputs(self, headers, prompt_id, **kwargs):
359
+ model = kwargs.get("model", "doubao-seedance-1-0-pro-250528")
360
+ prompt = kwargs.get("prompt", "")
361
+ resolution = kwargs.get("resolution", "1080p")
362
+ ratio = kwargs.get("ratio", "adaptive")
363
+ duration = kwargs.get("duration", 12)
364
+ camerafixed = kwargs.get("camerafixed", False)
365
+ seed = kwargs.get("seed", -1)
366
+ first_frame_image = kwargs.get("first_frame_image", None)
367
+ last_frame_image = kwargs.get("last_frame_image", None)
368
+ if first_frame_image is None:
369
+ raise ValueError("First frame image is required")
370
+ if (
371
+ last_frame_image is not None
372
+ and model == "doubao-seedance-1-0-pro-fast-251015"
373
+ ):
374
+ raise ValueError(
375
+ "Last frame image is not supported for doubao-seedance-1-0-pro-fast-251015"
376
+ )
377
+ first_frame_image_url = self.upload_file(
378
+ tensor_to_bytesio(image=first_frame_image, total_pixels=4096 * 4096),
379
+ f"{prompt_id}_first.png",
380
+ headers,
381
+ )
382
+ data = {
383
+ "prompt": prompt,
384
+ "model": model,
385
+ "resolution": resolution,
386
+ "ratio": ratio,
387
+ "duration": duration,
388
+ "camerafixed": camerafixed,
389
+ "seed": seed,
390
+ "watermark": False,
391
+ "fps": 24,
392
+ "first_frame_image": first_frame_image_url,
393
+ }
394
+ if last_frame_image is not None:
395
+ last_frame_image_url = self.upload_file(
396
+ tensor_to_bytesio(image=last_frame_image, total_pixels=4096 * 4096),
397
+ f"{prompt_id}_last.png",
398
+ headers,
399
+ )
400
+ data["last_frame_image"] = last_frame_image_url
401
+ return data, "doubao-seedance-1-0"
402
+
403
+ def handle_outputs(self, outputs):
404
+ return (outputs[0][0],)
@@ -0,0 +1,173 @@
1
+ from bizyairsdk import tensor_to_bytesio
2
+
3
+ from .trd_nodes_base import BizyAirTrdApiBaseNode
4
+
5
+
6
+ class Flux_Kontext_API(BizyAirTrdApiBaseNode):
7
+ NODE_DISPLAY_NAME = "Flux Kontext API"
8
+ RETURN_TYPES = ("IMAGE",)
9
+ RETURN_NAMES = ("image",)
10
+ CATEGORY = "☁️BizyAir/External APIs/Flux"
11
+
12
+ @classmethod
13
+ def INPUT_TYPES(cls):
14
+ return {
15
+ "required": {
16
+ "prompt": (
17
+ "STRING",
18
+ {
19
+ "multiline": True,
20
+ "default": "",
21
+ },
22
+ ),
23
+ "model": (
24
+ ["flux-kontext-pro", "flux-kontext-max"],
25
+ {"default": "flux-kontext-pro"},
26
+ ),
27
+ "aspect_ratio": (
28
+ ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"],
29
+ {"default": "16:9"},
30
+ ),
31
+ "seed": ("INT", {"default": 0, "min": 0, "max": 2147483647}),
32
+ },
33
+ "optional": {
34
+ "image": ("IMAGE",),
35
+ },
36
+ }
37
+
38
+ def handle_inputs(self, headers, prompt_id, **kwargs):
39
+ prompt = kwargs.get("prompt", "")
40
+ image = kwargs.get("image", None)
41
+ model = kwargs.get("model", "flux-kontext-pro")
42
+ aspect_ratio = kwargs.get("aspect_ratio", "16:9")
43
+ seed = kwargs.get("seed", 0)
44
+ data = {
45
+ "prompt": prompt,
46
+ "model": model,
47
+ "aspect_ratio": aspect_ratio,
48
+ "seed": seed,
49
+ }
50
+ if image is not None:
51
+ image_url = self.upload_file(
52
+ tensor_to_bytesio(image=image, total_pixels=4096 * 4096),
53
+ f"{prompt_id}.png",
54
+ headers,
55
+ )
56
+ data["image"] = image_url
57
+ return data, "flux-kontext"
58
+
59
+ def handle_outputs(self, outputs):
60
+ images = self.combine_images(outputs[1])
61
+ return (images,)
62
+
63
+
64
+ class Flux_2_API(BizyAirTrdApiBaseNode):
65
+ NODE_DISPLAY_NAME = "Flux 2 API"
66
+ RETURN_TYPES = ("IMAGE",)
67
+ RETURN_NAMES = ("image",)
68
+ CATEGORY = "☁️BizyAir/External APIs/Flux"
69
+
70
+ @classmethod
71
+ def INPUT_TYPES(cls):
72
+ return {
73
+ "required": {
74
+ "prompt": (
75
+ "STRING",
76
+ {
77
+ "multiline": True,
78
+ "default": "",
79
+ },
80
+ ),
81
+ "model": (
82
+ ["flux-2-pro", "flux-2-flex"],
83
+ {"default": "flux-2-pro"},
84
+ ),
85
+ "seed": ("INT", {"default": 0, "min": 0, "max": 2147483647}),
86
+ "width": (
87
+ "INT",
88
+ {
89
+ "default": 1024,
90
+ "min": 0,
91
+ "step": 16,
92
+ "tooltip": "必须为16的倍数,0代表使用输入图片宽度",
93
+ },
94
+ ),
95
+ "height": (
96
+ "INT",
97
+ {
98
+ "default": 1024,
99
+ "min": 0,
100
+ "step": 16,
101
+ "tooltip": "必须为16的倍数,0代表使用输入图片高度",
102
+ },
103
+ ),
104
+ "safety_tolerance": (
105
+ "INT",
106
+ {"min": 0, "max": 5, "default": 2, "tooltip": "值越大越宽松"},
107
+ ),
108
+ "guidance": (
109
+ "FLOAT",
110
+ {"min": 1.5, "max": 10, "default": 4.5, "tooltip": "仅flex支持"},
111
+ ),
112
+ "steps": (
113
+ "INT",
114
+ {"min": 1, "max": 50, "default": 50, "tooltip": "仅flex支持"},
115
+ ),
116
+ },
117
+ "optional": {
118
+ "images": ("IMAGE",),
119
+ },
120
+ }
121
+
122
+ def handle_inputs(self, headers, prompt_id, **kwargs):
123
+ images = kwargs.get("images", None)
124
+ prompt = kwargs.get("prompt", "")
125
+ model = kwargs.get("model", "flux-2-pro")
126
+ width = kwargs.get("width", 1024)
127
+ height = kwargs.get("height", 1024)
128
+ safety_tolerance = kwargs.get("safety_tolerance", 2)
129
+ guidance = kwargs.get("guidance", 4.5)
130
+ steps = kwargs.get("steps", 50)
131
+ seed = kwargs.get("seed", 0)
132
+ if images is not None and len(images) > 8 and model == "flux-2-pro":
133
+ raise ValueError("Maximum number of images is 8 for flux-2-pro")
134
+ if images is not None and len(images) > 10 and model == "flux-2-flex":
135
+ raise ValueError("Maximum number of images is 10 for flux-2-flex")
136
+ if width < 0 or height < 0:
137
+ raise ValueError(
138
+ "Width and height must be greater than 0, or supply 0 value to use input image's original size"
139
+ )
140
+ if safety_tolerance < 0 or safety_tolerance > 6:
141
+ raise ValueError("Safety tolerance must be between 0 and 6")
142
+ if guidance < 1.5 or guidance > 10:
143
+ raise ValueError("Guidance must be between 1.5 and 10")
144
+ if steps < 1 or steps > 50:
145
+ raise ValueError("Steps must be between 1 and 50")
146
+ parts = []
147
+ for batch_number, img in enumerate(images if images is not None else []):
148
+ if img is not None:
149
+ url = self.upload_file(
150
+ tensor_to_bytesio(image=img, total_pixels=4096 * 4096),
151
+ f"{prompt_id}_{batch_number}.png",
152
+ headers,
153
+ )
154
+ parts.append(url)
155
+ data = {
156
+ "prompt": prompt,
157
+ "model": model,
158
+ "safety_tolerance": safety_tolerance,
159
+ "guidance": guidance,
160
+ "steps": steps,
161
+ "seed": seed,
162
+ }
163
+ if width > 0:
164
+ data["width"] = width
165
+ if height > 0:
166
+ data["height"] = height
167
+ if len(parts) > 0:
168
+ data["urls"] = parts
169
+ return data, "flux-2"
170
+
171
+ def handle_outputs(self, outputs):
172
+ images = self.combine_images(outputs[1])
173
+ return (images,)