[Partner Nodes] feat(ByteDance): add Seedream 5 Pro model support (#14832)

This commit is contained in:
Alexander Piskun 2026-07-09 00:04:19 +03:00 committed by GitHub
parent c6cb904994
commit 24d3ea3265
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 111 additions and 46 deletions

View File

@ -24,8 +24,8 @@ class Seedream4TaskCreationRequest(BaseModel):
image: list[str] | None = Field(None, description="Image URLs") image: list[str] | None = Field(None, description="Image URLs")
size: str = Field(...) size: str = Field(...)
seed: int = Field(..., ge=0, le=2147483647) seed: int = Field(..., ge=0, le=2147483647)
sequential_image_generation: str = Field("disabled") sequential_image_generation: str | None = Field("disabled")
sequential_image_generation_options: Seedream4Options = Field(Seedream4Options(max_images=15)) sequential_image_generation_options: Seedream4Options | None = Field(Seedream4Options(max_images=15))
watermark: bool = Field(False) watermark: bool = Field(False)
output_format: str | None = None output_format: str | None = None
@ -261,6 +261,19 @@ _PRESETS_SEEDREAM_4K = [
_CUSTOM_PRESET = [("Custom", None, None)] _CUSTOM_PRESET = [("Custom", None, None)]
_PRESETS_SEEDREAM_2K_PRO = [
("(2K) 2048x2048 (1:1)", 2048, 2048),
("(2K) 1728x2304 (3:4)", 1728, 2304),
("(2K) 2304x1728 (4:3)", 2304, 1728),
# ("(2K) 2848x1600 (16:9)", 2848, 1600), # 4,556,800 px - temporarily unavailable
# ("(2K) 1600x2848 (9:16)", 1600, 2848), # 4,556,800 px - temporarily unavailable
("(2K) 1664x2496 (2:3)", 1664, 2496),
("(2K) 2496x1664 (3:2)", 2496, 1664),
# ("(2K) 3136x1344 (21:9)", 3136, 1344), # 4,214,784 px - temporarily unavailable
]
RECOMMENDED_PRESETS_SEEDREAM_5_PRO = (
_PRESETS_SEEDREAM_1K + _PRESETS_SEEDREAM_2K_PRO + _CUSTOM_PRESET
)
RECOMMENDED_PRESETS_SEEDREAM_5_LITE = ( RECOMMENDED_PRESETS_SEEDREAM_5_LITE = (
_PRESETS_SEEDREAM_2K + _PRESETS_SEEDREAM_3K + _PRESETS_SEEDREAM_4K + _CUSTOM_PRESET _PRESETS_SEEDREAM_2K + _PRESETS_SEEDREAM_3K + _PRESETS_SEEDREAM_4K + _CUSTOM_PRESET
) )

View File

@ -16,6 +16,7 @@ from comfy_api_nodes.apis.bytedance import (
RECOMMENDED_PRESETS_SEEDREAM_4_0, RECOMMENDED_PRESETS_SEEDREAM_4_0,
RECOMMENDED_PRESETS_SEEDREAM_4_5, RECOMMENDED_PRESETS_SEEDREAM_4_5,
RECOMMENDED_PRESETS_SEEDREAM_5_LITE, RECOMMENDED_PRESETS_SEEDREAM_5_LITE,
RECOMMENDED_PRESETS_SEEDREAM_5_PRO,
SEEDANCE2_REF_VIDEO_PIXEL_LIMITS, SEEDANCE2_REF_VIDEO_PIXEL_LIMITS,
VIDEO_TASKS_EXECUTION_TIME, VIDEO_TASKS_EXECUTION_TIME,
GetAssetResponse, GetAssetResponse,
@ -80,12 +81,14 @@ _VERIFICATION_POLL_TIMEOUT_SEC = 120
_VERIFICATION_POLL_INTERVAL_SEC = 3 _VERIFICATION_POLL_INTERVAL_SEC = 3
SEEDREAM_MODELS = { SEEDREAM_MODELS = {
"seedream 5.0 pro": "seedream-5-0-pro-260628",
"seedream 5.0 lite": "seedream-5-0-260128", "seedream 5.0 lite": "seedream-5-0-260128",
"seedream-4-5-251128": "seedream-4-5-251128", "seedream-4-5-251128": "seedream-4-5-251128",
"seedream-4-0-250828": "seedream-4-0-250828", "seedream-4-0-250828": "seedream-4-0-250828",
} }
SEEDREAM_PRESETS = { SEEDREAM_PRESETS = {
"seedream-5-0-pro-260628": RECOMMENDED_PRESETS_SEEDREAM_5_PRO,
"seedream-5-0-260128": RECOMMENDED_PRESETS_SEEDREAM_5_LITE, "seedream-5-0-260128": RECOMMENDED_PRESETS_SEEDREAM_5_LITE,
"seedream-4-5-251128": RECOMMENDED_PRESETS_SEEDREAM_4_5, "seedream-4-5-251128": RECOMMENDED_PRESETS_SEEDREAM_4_5,
"seedream-4-0-250828": RECOMMENDED_PRESETS_SEEDREAM_4_0, "seedream-4-0-250828": RECOMMENDED_PRESETS_SEEDREAM_4_0,
@ -743,8 +746,15 @@ class ByteDanceSeedreamNode(IO.ComfyNode):
return IO.NodeOutput(torch.cat([await download_url_to_image_tensor(i) for i in urls])) return IO.NodeOutput(torch.cat([await download_url_to_image_tensor(i) for i in urls]))
def _seedream_model_inputs(*, max_ref_images: int, presets: list): def _seedream_model_inputs(
return [ *,
max_ref_images: int,
presets: list,
max_width: int = 6240,
max_height: int = 4992,
supports_batch: bool = True,
):
inputs = [
IO.Combo.Input( IO.Combo.Input(
"size_preset", "size_preset",
options=[label for label, _, _ in presets], options=[label for label, _, _ in presets],
@ -754,7 +764,7 @@ def _seedream_model_inputs(*, max_ref_images: int, presets: list):
"width", "width",
default=2048, default=2048,
min=1024, min=1024,
max=6240, max=max_width,
step=2, step=2,
tooltip="Custom width for image. Value is working only if `size_preset` is set to `Custom`", tooltip="Custom width for image. Value is working only if `size_preset` is set to `Custom`",
), ),
@ -762,22 +772,27 @@ def _seedream_model_inputs(*, max_ref_images: int, presets: list):
"height", "height",
default=2048, default=2048,
min=1024, min=1024,
max=4992, max=max_height,
step=2, step=2,
tooltip="Custom height for image. Value is working only if `size_preset` is set to `Custom`", tooltip="Custom height for image. Value is working only if `size_preset` is set to `Custom`",
), ),
IO.Int.Input( ]
"max_images", if supports_batch:
default=1, inputs.append(
min=1, IO.Int.Input(
max=max_ref_images, "max_images",
step=1, default=1,
display_mode=IO.NumberDisplay.number, min=1,
tooltip="Maximum number of images to generate. With 1, exactly one image is produced. " max=max_ref_images,
"With >1, the model generates between 1 and max_images related images " step=1,
"(e.g., story scenes, character variations). " display_mode=IO.NumberDisplay.number,
"Total images (input + generated) cannot exceed 15.", tooltip="Maximum number of images to generate. With 1, exactly one image is produced. "
), "With >1, the model generates between 1 and max_images related images "
"(e.g., story scenes, character variations). "
"Total images (input + generated) cannot exceed 15.",
)
)
inputs.append(
IO.Autogrow.Input( IO.Autogrow.Input(
"images", "images",
template=IO.Autogrow.TemplateNames( template=IO.Autogrow.TemplateNames(
@ -787,14 +802,18 @@ def _seedream_model_inputs(*, max_ref_images: int, presets: list):
), ),
tooltip=f"Optional reference image(s) for image-to-image or multi-reference generation. " tooltip=f"Optional reference image(s) for image-to-image or multi-reference generation. "
f"Up to {max_ref_images} images.", f"Up to {max_ref_images} images.",
), )
IO.Boolean.Input( )
"fail_on_partial", if supports_batch:
default=False, inputs.append(
tooltip="If enabled, abort execution if any requested images are missing or return an error.", IO.Boolean.Input(
advanced=True, "fail_on_partial",
), default=False,
] tooltip="If enabled, abort execution if any requested images are missing or return an error.",
advanced=True,
)
)
return inputs
class ByteDanceSeedreamNodeV2(IO.ComfyNode): class ByteDanceSeedreamNodeV2(IO.ComfyNode):
@ -816,6 +835,16 @@ class ByteDanceSeedreamNodeV2(IO.ComfyNode):
IO.DynamicCombo.Input( IO.DynamicCombo.Input(
"model", "model",
options=[ options=[
IO.DynamicCombo.Option(
"seedream 5.0 pro",
_seedream_model_inputs(
max_ref_images=10,
presets=RECOMMENDED_PRESETS_SEEDREAM_5_PRO,
max_width=3136,
max_height=2496,
supports_batch=False,
),
),
IO.DynamicCombo.Option( IO.DynamicCombo.Option(
"seedream 5.0 lite", "seedream 5.0 lite",
_seedream_model_inputs(max_ref_images=14, presets=RECOMMENDED_PRESETS_SEEDREAM_5_LITE), _seedream_model_inputs(max_ref_images=14, presets=RECOMMENDED_PRESETS_SEEDREAM_5_LITE),
@ -857,15 +886,27 @@ class ByteDanceSeedreamNodeV2(IO.ComfyNode):
], ],
is_api_node=True, is_api_node=True,
price_badge=IO.PriceBadge( price_badge=IO.PriceBadge(
depends_on=IO.PriceBadgeDepends(widgets=["model"]), depends_on=IO.PriceBadgeDepends(
widgets=["model", "model.size_preset", "model.width", "model.height"]
),
expr=""" expr="""
( (
$price := $contains(widgets.model, "5.0 lite") ? 0.035 : $sp := $lookup(widgets, "model.size_preset");
$contains(widgets.model, "4-5") ? 0.04 : 0.03; $px := $lookup(widgets, "model.width") * $lookup(widgets, "model.height");
$isPro := $contains(widgets.model, "5.0 pro");
$price := $isPro
? (
$contains($sp, "custom")
? ($px <= 2360000 ? 0.045 : 0.09)
: ($contains($sp, "1k") ? 0.045 : 0.09)
)
: $contains(widgets.model, "5.0 lite") ? 0.035
: $contains(widgets.model, "4-5") ? 0.04
: 0.03;
{ {
"type":"usd", "type": "usd",
"usd": $price, "usd": $price,
"format": { "suffix":" x images/Run", "approximate": true } "format": { "suffix": $isPro ? "/Image" : " x images/Run", "approximate": true }
} }
) )
""", """,
@ -883,6 +924,7 @@ class ByteDanceSeedreamNodeV2(IO.ComfyNode):
validate_string(prompt, strip_whitespace=True, min_length=1) validate_string(prompt, strip_whitespace=True, min_length=1)
model_id = SEEDREAM_MODELS[model["model"]] model_id = SEEDREAM_MODELS[model["model"]]
presets = SEEDREAM_PRESETS[model_id] presets = SEEDREAM_PRESETS[model_id]
is_pro = "seedream-5-0-pro" in model_id
size_preset = model.get("size_preset", presets[0][0]) size_preset = model.get("size_preset", presets[0][0])
width = model.get("width", 2048) width = model.get("width", 2048)
@ -902,19 +944,29 @@ class ByteDanceSeedreamNodeV2(IO.ComfyNode):
out_num_pixels = w * h out_num_pixels = w * h
mp_provided = out_num_pixels / 1_000_000.0 mp_provided = out_num_pixels / 1_000_000.0
if ("seedream-4-5" in model_id or "seedream-5-0" in model_id) and out_num_pixels < 3686400: if is_pro:
raise ValueError( if out_num_pixels < 921_600:
f"Minimum image resolution for the selected model is 3.68MP, but {mp_provided:.2f}MP provided." raise ValueError(
) f"Minimum image resolution for the selected model is 0.92MP, but {mp_provided:.2f}MP provided."
if "seedream-4-0" in model_id and out_num_pixels < 921600: )
raise ValueError( if out_num_pixels > 4_194_304:
f"Minimum image resolution that the selected model can generate is 0.92MP, " raise ValueError(
f"but {mp_provided:.2f}MP provided." f"Maximum image resolution for the selected model is 4.19MP, but {mp_provided:.2f}MP provided."
) )
if out_num_pixels > 16_777_216: else:
raise ValueError( if ("seedream-4-5" in model_id or "seedream-5-0" in model_id) and out_num_pixels < 3_686_400:
f"Maximum image resolution for the selected model is 16.78MP, but {mp_provided:.2f}MP provided." raise ValueError(
) f"Minimum image resolution for the selected model is 3.68MP, but {mp_provided:.2f}MP provided."
)
if "seedream-4-0" in model_id and out_num_pixels < 921_600:
raise ValueError(
f"Minimum image resolution that the selected model can generate is 0.92MP, "
f"but {mp_provided:.2f}MP provided."
)
if out_num_pixels > 16_777_216:
raise ValueError(
f"Maximum image resolution for the selected model is 16.78MP, but {mp_provided:.2f}MP provided."
)
image_tensors: list[Input.Image] = [t for t in images_dict.values() if t is not None] image_tensors: list[Input.Image] = [t for t in images_dict.values() if t is not None]
n_input_images = sum(get_number_of_images(t) for t in image_tensors) n_input_images = sum(get_number_of_images(t) for t in image_tensors)
@ -950,8 +1002,8 @@ class ByteDanceSeedreamNodeV2(IO.ComfyNode):
image=reference_images_urls, image=reference_images_urls,
size=f"{w}x{h}", size=f"{w}x{h}",
seed=seed, seed=seed,
sequential_image_generation=sequential_image_generation, sequential_image_generation=None if is_pro else sequential_image_generation,
sequential_image_generation_options=Seedream4Options(max_images=max_images), sequential_image_generation_options=None if is_pro else Seedream4Options(max_images=max_images),
watermark=watermark, watermark=watermark,
), ),
) )