mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-03-04 00:37:32 +08:00
feat(api-nodes): add "viduq3-turbo" model and Vidu3StartEnd node; fix the price badges (#12482)
This commit is contained in:
parent
44f8598521
commit
5284e6bf69
@ -54,6 +54,7 @@ async def execute_task(
|
|||||||
response_model=TaskStatusResponse,
|
response_model=TaskStatusResponse,
|
||||||
status_extractor=lambda r: r.state,
|
status_extractor=lambda r: r.state,
|
||||||
progress_extractor=lambda r: r.progress,
|
progress_extractor=lambda r: r.progress,
|
||||||
|
price_extractor=lambda r: r.credits * 0.005 if r.credits is not None else None,
|
||||||
max_poll_attempts=max_poll_attempts,
|
max_poll_attempts=max_poll_attempts,
|
||||||
)
|
)
|
||||||
if not response.creations:
|
if not response.creations:
|
||||||
@ -1306,6 +1307,36 @@ class Vidu3TextToVideoNode(IO.ComfyNode):
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
IO.DynamicCombo.Option(
|
||||||
|
"viduq3-turbo",
|
||||||
|
[
|
||||||
|
IO.Combo.Input(
|
||||||
|
"aspect_ratio",
|
||||||
|
options=["16:9", "9:16", "3:4", "4:3", "1:1"],
|
||||||
|
tooltip="The aspect ratio of the output video.",
|
||||||
|
),
|
||||||
|
IO.Combo.Input(
|
||||||
|
"resolution",
|
||||||
|
options=["720p", "1080p"],
|
||||||
|
tooltip="Resolution of the output video.",
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"duration",
|
||||||
|
default=5,
|
||||||
|
min=1,
|
||||||
|
max=16,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.slider,
|
||||||
|
tooltip="Duration of the output video in seconds.",
|
||||||
|
),
|
||||||
|
IO.Boolean.Input(
|
||||||
|
"audio",
|
||||||
|
default=False,
|
||||||
|
tooltip="When enabled, outputs video with sound "
|
||||||
|
"(including dialogue and sound effects).",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
tooltip="Model to use for video generation.",
|
tooltip="Model to use for video generation.",
|
||||||
),
|
),
|
||||||
@ -1334,13 +1365,20 @@ class Vidu3TextToVideoNode(IO.ComfyNode):
|
|||||||
],
|
],
|
||||||
is_api_node=True,
|
is_api_node=True,
|
||||||
price_badge=IO.PriceBadge(
|
price_badge=IO.PriceBadge(
|
||||||
depends_on=IO.PriceBadgeDepends(widgets=["model.duration", "model.resolution"]),
|
depends_on=IO.PriceBadgeDepends(widgets=["model", "model.duration", "model.resolution"]),
|
||||||
expr="""
|
expr="""
|
||||||
(
|
(
|
||||||
$res := $lookup(widgets, "model.resolution");
|
$res := $lookup(widgets, "model.resolution");
|
||||||
$base := $lookup({"720p": 0.075, "1080p": 0.1}, $res);
|
$d := $lookup(widgets, "model.duration");
|
||||||
$perSec := $lookup({"720p": 0.025, "1080p": 0.05}, $res);
|
$contains(widgets.model, "turbo")
|
||||||
{"type":"usd","usd": $base + $perSec * ($lookup(widgets, "model.duration") - 1)}
|
? (
|
||||||
|
$rate := $lookup({"720p": 0.06, "1080p": 0.08}, $res);
|
||||||
|
{"type":"usd","usd": $rate * $d}
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
$rate := $lookup({"720p": 0.15, "1080p": 0.16}, $res);
|
||||||
|
{"type":"usd","usd": $rate * $d}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
""",
|
""",
|
||||||
),
|
),
|
||||||
@ -1409,6 +1447,31 @@ class Vidu3ImageToVideoNode(IO.ComfyNode):
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
IO.DynamicCombo.Option(
|
||||||
|
"viduq3-turbo",
|
||||||
|
[
|
||||||
|
IO.Combo.Input(
|
||||||
|
"resolution",
|
||||||
|
options=["720p", "1080p"],
|
||||||
|
tooltip="Resolution of the output video.",
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"duration",
|
||||||
|
default=5,
|
||||||
|
min=1,
|
||||||
|
max=16,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.slider,
|
||||||
|
tooltip="Duration of the output video in seconds.",
|
||||||
|
),
|
||||||
|
IO.Boolean.Input(
|
||||||
|
"audio",
|
||||||
|
default=False,
|
||||||
|
tooltip="When enabled, outputs video with sound "
|
||||||
|
"(including dialogue and sound effects).",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
tooltip="Model to use for video generation.",
|
tooltip="Model to use for video generation.",
|
||||||
),
|
),
|
||||||
@ -1442,13 +1505,20 @@ class Vidu3ImageToVideoNode(IO.ComfyNode):
|
|||||||
],
|
],
|
||||||
is_api_node=True,
|
is_api_node=True,
|
||||||
price_badge=IO.PriceBadge(
|
price_badge=IO.PriceBadge(
|
||||||
depends_on=IO.PriceBadgeDepends(widgets=["model.duration", "model.resolution"]),
|
depends_on=IO.PriceBadgeDepends(widgets=["model", "model.duration", "model.resolution"]),
|
||||||
expr="""
|
expr="""
|
||||||
(
|
(
|
||||||
$res := $lookup(widgets, "model.resolution");
|
$res := $lookup(widgets, "model.resolution");
|
||||||
$base := $lookup({"720p": 0.075, "1080p": 0.275, "2k": 0.35}, $res);
|
$d := $lookup(widgets, "model.duration");
|
||||||
$perSec := $lookup({"720p": 0.05, "1080p": 0.075, "2k": 0.075}, $res);
|
$contains(widgets.model, "turbo")
|
||||||
{"type":"usd","usd": $base + $perSec * ($lookup(widgets, "model.duration") - 1)}
|
? (
|
||||||
|
$rate := $lookup({"720p": 0.06, "1080p": 0.08}, $res);
|
||||||
|
{"type":"usd","usd": $rate * $d}
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
$rate := $lookup({"720p": 0.15, "1080p": 0.16, "2k": 0.2}, $res);
|
||||||
|
{"type":"usd","usd": $rate * $d}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
""",
|
""",
|
||||||
),
|
),
|
||||||
@ -1481,6 +1551,145 @@ class Vidu3ImageToVideoNode(IO.ComfyNode):
|
|||||||
return IO.NodeOutput(await download_url_to_video_output(results[0].url))
|
return IO.NodeOutput(await download_url_to_video_output(results[0].url))
|
||||||
|
|
||||||
|
|
||||||
|
class Vidu3StartEndToVideoNode(IO.ComfyNode):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="Vidu3StartEndToVideoNode",
|
||||||
|
display_name="Vidu Q3 Start/End Frame-to-Video Generation",
|
||||||
|
category="api node/video/Vidu",
|
||||||
|
description="Generate a video from a start frame, an end frame, and a prompt.",
|
||||||
|
inputs=[
|
||||||
|
IO.DynamicCombo.Input(
|
||||||
|
"model",
|
||||||
|
options=[
|
||||||
|
IO.DynamicCombo.Option(
|
||||||
|
"viduq3-pro",
|
||||||
|
[
|
||||||
|
IO.Combo.Input(
|
||||||
|
"resolution",
|
||||||
|
options=["720p", "1080p"],
|
||||||
|
tooltip="Resolution of the output video.",
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"duration",
|
||||||
|
default=5,
|
||||||
|
min=1,
|
||||||
|
max=16,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.slider,
|
||||||
|
tooltip="Duration of the output video in seconds.",
|
||||||
|
),
|
||||||
|
IO.Boolean.Input(
|
||||||
|
"audio",
|
||||||
|
default=False,
|
||||||
|
tooltip="When enabled, outputs video with sound "
|
||||||
|
"(including dialogue and sound effects).",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
IO.DynamicCombo.Option(
|
||||||
|
"viduq3-turbo",
|
||||||
|
[
|
||||||
|
IO.Combo.Input(
|
||||||
|
"resolution",
|
||||||
|
options=["720p", "1080p"],
|
||||||
|
tooltip="Resolution of the output video.",
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"duration",
|
||||||
|
default=5,
|
||||||
|
min=1,
|
||||||
|
max=16,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.slider,
|
||||||
|
tooltip="Duration of the output video in seconds.",
|
||||||
|
),
|
||||||
|
IO.Boolean.Input(
|
||||||
|
"audio",
|
||||||
|
default=False,
|
||||||
|
tooltip="When enabled, outputs video with sound "
|
||||||
|
"(including dialogue and sound effects).",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
tooltip="Model to use for video generation.",
|
||||||
|
),
|
||||||
|
IO.Image.Input("first_frame"),
|
||||||
|
IO.Image.Input("end_frame"),
|
||||||
|
IO.String.Input(
|
||||||
|
"prompt",
|
||||||
|
multiline=True,
|
||||||
|
tooltip="Prompt description (max 2000 characters).",
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"seed",
|
||||||
|
default=1,
|
||||||
|
min=0,
|
||||||
|
max=2147483647,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
control_after_generate=True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
IO.Video.Output(),
|
||||||
|
],
|
||||||
|
hidden=[
|
||||||
|
IO.Hidden.auth_token_comfy_org,
|
||||||
|
IO.Hidden.api_key_comfy_org,
|
||||||
|
IO.Hidden.unique_id,
|
||||||
|
],
|
||||||
|
is_api_node=True,
|
||||||
|
price_badge=IO.PriceBadge(
|
||||||
|
depends_on=IO.PriceBadgeDepends(widgets=["model", "model.duration", "model.resolution"]),
|
||||||
|
expr="""
|
||||||
|
(
|
||||||
|
$res := $lookup(widgets, "model.resolution");
|
||||||
|
$d := $lookup(widgets, "model.duration");
|
||||||
|
$contains(widgets.model, "turbo")
|
||||||
|
? (
|
||||||
|
$rate := $lookup({"720p": 0.06, "1080p": 0.08}, $res);
|
||||||
|
{"type":"usd","usd": $rate * $d}
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
$rate := $lookup({"720p": 0.15, "1080p": 0.16}, $res);
|
||||||
|
{"type":"usd","usd": $rate * $d}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(
|
||||||
|
cls,
|
||||||
|
model: dict,
|
||||||
|
first_frame: Input.Image,
|
||||||
|
end_frame: Input.Image,
|
||||||
|
prompt: str,
|
||||||
|
seed: int,
|
||||||
|
) -> IO.NodeOutput:
|
||||||
|
validate_string(prompt, max_length=2000)
|
||||||
|
validate_images_aspect_ratio_closeness(first_frame, end_frame, min_rel=0.8, max_rel=1.25, strict=False)
|
||||||
|
payload = TaskCreationRequest(
|
||||||
|
model=model["model"],
|
||||||
|
prompt=prompt,
|
||||||
|
duration=model["duration"],
|
||||||
|
seed=seed,
|
||||||
|
resolution=model["resolution"],
|
||||||
|
audio=model["audio"],
|
||||||
|
images=[
|
||||||
|
(await upload_images_to_comfyapi(cls, frame, max_images=1, mime_type="image/png"))[0]
|
||||||
|
for frame in (first_frame, end_frame)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
results = await execute_task(cls, VIDU_START_END_VIDEO, payload)
|
||||||
|
return IO.NodeOutput(await download_url_to_video_output(results[0].url))
|
||||||
|
|
||||||
|
|
||||||
class ViduExtension(ComfyExtension):
|
class ViduExtension(ComfyExtension):
|
||||||
@override
|
@override
|
||||||
async def get_node_list(self) -> list[type[IO.ComfyNode]]:
|
async def get_node_list(self) -> list[type[IO.ComfyNode]]:
|
||||||
@ -1497,6 +1706,7 @@ class ViduExtension(ComfyExtension):
|
|||||||
ViduMultiFrameVideoNode,
|
ViduMultiFrameVideoNode,
|
||||||
Vidu3TextToVideoNode,
|
Vidu3TextToVideoNode,
|
||||||
Vidu3ImageToVideoNode,
|
Vidu3ImageToVideoNode,
|
||||||
|
Vidu3StartEndToVideoNode,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user