Skip to content

Commit 9b05538

Browse files
authored
add new ByteDanceSeedream (4.0) node (#9802)
1 parent 8d7c930 commit 9b05538

File tree

1 file changed

+207
-1
lines changed

1 file changed

+207
-1
lines changed

comfy_api_nodes/nodes_bytedance.py

Lines changed: 207 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,22 @@ class Image2ImageTaskCreationRequest(BaseModel):
7777
watermark: Optional[bool] = Field(True)
7878

7979

80+
class Seedream4Options(BaseModel):
81+
max_images: int = Field(15)
82+
83+
84+
class Seedream4TaskCreationRequest(BaseModel):
85+
model: str = Field("seedream-4-0-250828")
86+
prompt: str = Field(...)
87+
response_format: str = Field("url")
88+
image: Optional[list[str]] = Field(None, description="Image URLs")
89+
size: str = Field(...)
90+
seed: int = Field(..., ge=0, le=2147483647)
91+
sequential_image_generation: str = Field("disabled")
92+
sequential_image_generation_options: Seedream4Options = Field(Seedream4Options(max_images=15))
93+
watermark: bool = Field(True)
94+
95+
8096
class ImageTaskCreationResponse(BaseModel):
8197
model: str = Field(...)
8298
created: int = Field(..., description="Unix timestamp (in seconds) indicating time when the request was created.")
@@ -143,6 +159,19 @@ class TaskStatusResponse(BaseModel):
143159
("Custom", None, None),
144160
]
145161

162+
RECOMMENDED_PRESETS_SEEDREAM_4 = [
163+
("2048x2048 (1:1)", 2048, 2048),
164+
("2304x1728 (4:3)", 2304, 1728),
165+
("1728x2304 (3:4)", 1728, 2304),
166+
("2560x1440 (16:9)", 2560, 1440),
167+
("1440x2560 (9:16)", 1440, 2560),
168+
("2496x1664 (3:2)", 2496, 1664),
169+
("1664x2496 (2:3)", 1664, 2496),
170+
("3024x1296 (21:9)", 3024, 1296),
171+
("4096x4096 (1:1)", 4096, 4096),
172+
("Custom", None, None),
173+
]
174+
146175
# The time in this dictionary are given for 10 seconds duration.
147176
VIDEO_TASKS_EXECUTION_TIME = {
148177
"seedance-1-0-lite-t2v-250428": {
@@ -348,7 +377,7 @@ def define_schema(cls):
348377
return comfy_io.Schema(
349378
node_id="ByteDanceImageEditNode",
350379
display_name="ByteDance Image Edit",
351-
category="api node/video/ByteDance",
380+
category="api node/image/ByteDance",
352381
description="Edit images using ByteDance models via api based on prompt",
353382
inputs=[
354383
comfy_io.Combo.Input(
@@ -451,6 +480,182 @@ async def execute(
451480
return comfy_io.NodeOutput(await download_url_to_image_tensor(get_image_url_from_response(response)))
452481

453482

483+
class ByteDanceSeedreamNode(comfy_io.ComfyNode):
484+
485+
@classmethod
486+
def define_schema(cls):
487+
return comfy_io.Schema(
488+
node_id="ByteDanceSeedreamNode",
489+
display_name="ByteDance Seedream 4",
490+
category="api node/image/ByteDance",
491+
description="Unified text-to-image generation and precise single-sentence editing at up to 4K resolution.",
492+
inputs=[
493+
comfy_io.Combo.Input(
494+
"model",
495+
options=["seedream-4-0-250828"],
496+
tooltip="Model name",
497+
),
498+
comfy_io.String.Input(
499+
"prompt",
500+
multiline=True,
501+
default="",
502+
tooltip="Text prompt for creating or editing an image.",
503+
),
504+
comfy_io.Image.Input(
505+
"image",
506+
tooltip="Input image(s) for image-to-image generation. "
507+
"List of 1-10 images for single or multi-reference generation.",
508+
optional=True,
509+
),
510+
comfy_io.Combo.Input(
511+
"size_preset",
512+
options=[label for label, _, _ in RECOMMENDED_PRESETS_SEEDREAM_4],
513+
tooltip="Pick a recommended size. Select Custom to use the width and height below.",
514+
),
515+
comfy_io.Int.Input(
516+
"width",
517+
default=2048,
518+
min=1024,
519+
max=4096,
520+
step=64,
521+
tooltip="Custom width for image. Value is working only if `size_preset` is set to `Custom`",
522+
optional=True,
523+
),
524+
comfy_io.Int.Input(
525+
"height",
526+
default=2048,
527+
min=1024,
528+
max=4096,
529+
step=64,
530+
tooltip="Custom height for image. Value is working only if `size_preset` is set to `Custom`",
531+
optional=True,
532+
),
533+
comfy_io.Combo.Input(
534+
"sequential_image_generation",
535+
options=["disabled", "auto"],
536+
tooltip="Group image generation mode. "
537+
"'disabled' generates a single image. "
538+
"'auto' lets the model decide whether to generate multiple related images "
539+
"(e.g., story scenes, character variations).",
540+
optional=True,
541+
),
542+
comfy_io.Int.Input(
543+
"max_images",
544+
default=1,
545+
min=1,
546+
max=15,
547+
step=1,
548+
display_mode=comfy_io.NumberDisplay.number,
549+
tooltip="Maximum number of images to generate when sequential_image_generation='auto'. "
550+
"Total images (input + generated) cannot exceed 15.",
551+
optional=True,
552+
),
553+
comfy_io.Int.Input(
554+
"seed",
555+
default=0,
556+
min=0,
557+
max=2147483647,
558+
step=1,
559+
display_mode=comfy_io.NumberDisplay.number,
560+
control_after_generate=True,
561+
tooltip="Seed to use for generation.",
562+
optional=True,
563+
),
564+
comfy_io.Boolean.Input(
565+
"watermark",
566+
default=True,
567+
tooltip="Whether to add an \"AI generated\" watermark to the image.",
568+
optional=True,
569+
),
570+
],
571+
outputs=[
572+
comfy_io.Image.Output(),
573+
],
574+
hidden=[
575+
comfy_io.Hidden.auth_token_comfy_org,
576+
comfy_io.Hidden.api_key_comfy_org,
577+
comfy_io.Hidden.unique_id,
578+
],
579+
is_api_node=True,
580+
)
581+
582+
@classmethod
583+
async def execute(
584+
cls,
585+
model: str,
586+
prompt: str,
587+
image: torch.Tensor = None,
588+
size_preset: str = RECOMMENDED_PRESETS_SEEDREAM_4[0][0],
589+
width: int = 2048,
590+
height: int = 2048,
591+
sequential_image_generation: str = "disabled",
592+
max_images: int = 1,
593+
seed: int = 0,
594+
watermark: bool = True,
595+
) -> comfy_io.NodeOutput:
596+
validate_string(prompt, strip_whitespace=True, min_length=1)
597+
w = h = None
598+
for label, tw, th in RECOMMENDED_PRESETS_SEEDREAM_4:
599+
if label == size_preset:
600+
w, h = tw, th
601+
break
602+
603+
if w is None or h is None:
604+
w, h = width, height
605+
if not (1024 <= w <= 4096) or not (1024 <= h <= 4096):
606+
raise ValueError(
607+
f"Custom size out of range: {w}x{h}. "
608+
"Both width and height must be between 1024 and 4096 pixels."
609+
)
610+
n_input_images = get_number_of_images(image) if image is not None else 0
611+
if n_input_images > 10:
612+
raise ValueError(f"Maximum of 10 reference images are supported, but {n_input_images} received.")
613+
if sequential_image_generation == "auto" and n_input_images + max_images > 15:
614+
raise ValueError(
615+
"The maximum number of generated images plus the number of reference images cannot exceed 15."
616+
)
617+
auth_kwargs = {
618+
"auth_token": cls.hidden.auth_token_comfy_org,
619+
"comfy_api_key": cls.hidden.api_key_comfy_org,
620+
}
621+
reference_images_urls = []
622+
if n_input_images:
623+
for i in image:
624+
validate_image_aspect_ratio_range(i, (1, 3), (3, 1))
625+
reference_images_urls = (await upload_images_to_comfyapi(
626+
image,
627+
max_images=n_input_images,
628+
mime_type="image/png",
629+
auth_kwargs=auth_kwargs,
630+
))
631+
payload = Seedream4TaskCreationRequest(
632+
model=model,
633+
prompt=prompt,
634+
image=reference_images_urls,
635+
size=f"{w}x{h}",
636+
seed=seed,
637+
sequential_image_generation=sequential_image_generation,
638+
sequential_image_generation_options=Seedream4Options(max_images=max_images),
639+
watermark=watermark,
640+
)
641+
response = await SynchronousOperation(
642+
endpoint=ApiEndpoint(
643+
path=BYTEPLUS_IMAGE_ENDPOINT,
644+
method=HttpMethod.POST,
645+
request_model=Seedream4TaskCreationRequest,
646+
response_model=ImageTaskCreationResponse,
647+
),
648+
request=payload,
649+
auth_kwargs=auth_kwargs,
650+
).execute()
651+
652+
if len(response.data) == 1:
653+
return comfy_io.NodeOutput(await download_url_to_image_tensor(get_image_url_from_response(response)))
654+
return comfy_io.NodeOutput(
655+
torch.cat([await download_url_to_image_tensor(str(i["url"])) for i in response.data])
656+
)
657+
658+
454659
class ByteDanceTextToVideoNode(comfy_io.ComfyNode):
455660

456661
@classmethod
@@ -1001,6 +1206,7 @@ async def get_node_list(self) -> list[type[comfy_io.ComfyNode]]:
10011206
return [
10021207
ByteDanceImageNode,
10031208
ByteDanceImageEditNode,
1209+
ByteDanceSeedreamNode,
10041210
ByteDanceTextToVideoNode,
10051211
ByteDanceImageToVideoNode,
10061212
ByteDanceFirstLastFrameNode,

0 commit comments

Comments
 (0)