mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-01-23 12:50:18 +08:00
implement LtxvEditVideo API node
This commit is contained in:
parent
35fa091340
commit
caab292e0c
@ -5,14 +5,17 @@ import torch
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
from comfy_api.input_impl import VideoFromFile
|
from comfy_api.latest import IO, ComfyExtension, Input, InputImpl
|
||||||
from comfy_api.latest import IO, ComfyExtension
|
|
||||||
from comfy_api_nodes.util import (
|
from comfy_api_nodes.util import (
|
||||||
ApiEndpoint,
|
ApiEndpoint,
|
||||||
get_number_of_images,
|
get_number_of_images,
|
||||||
sync_op_raw,
|
sync_op_raw,
|
||||||
upload_images_to_comfyapi,
|
upload_images_to_comfyapi,
|
||||||
validate_string,
|
validate_string,
|
||||||
|
validate_video_duration,
|
||||||
|
validate_video_dimensions,
|
||||||
|
validate_video_frame_count,
|
||||||
|
upload_video_to_comfyapi,
|
||||||
)
|
)
|
||||||
|
|
||||||
MODELS_MAP = {
|
MODELS_MAP = {
|
||||||
@ -31,6 +34,14 @@ class ExecuteTaskRequest(BaseModel):
|
|||||||
image_uri: Optional[str] = Field(None)
|
image_uri: Optional[str] = Field(None)
|
||||||
|
|
||||||
|
|
||||||
|
class VideoEditRequest(BaseModel):
|
||||||
|
video_uri: str = Field(...)
|
||||||
|
prompt: str = Field(...)
|
||||||
|
start_time: int = Field(...)
|
||||||
|
duration: int = Field(...)
|
||||||
|
mode: str = Field(...)
|
||||||
|
|
||||||
|
|
||||||
class TextToVideoNode(IO.ComfyNode):
|
class TextToVideoNode(IO.ComfyNode):
|
||||||
@classmethod
|
@classmethod
|
||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
@ -103,7 +114,7 @@ class TextToVideoNode(IO.ComfyNode):
|
|||||||
as_binary=True,
|
as_binary=True,
|
||||||
max_retries=1,
|
max_retries=1,
|
||||||
)
|
)
|
||||||
return IO.NodeOutput(VideoFromFile(BytesIO(response)))
|
return IO.NodeOutput(InputImpl.VideoFromFile(BytesIO(response)))
|
||||||
|
|
||||||
|
|
||||||
class ImageToVideoNode(IO.ComfyNode):
|
class ImageToVideoNode(IO.ComfyNode):
|
||||||
@ -183,7 +194,76 @@ class ImageToVideoNode(IO.ComfyNode):
|
|||||||
as_binary=True,
|
as_binary=True,
|
||||||
max_retries=1,
|
max_retries=1,
|
||||||
)
|
)
|
||||||
return IO.NodeOutput(VideoFromFile(BytesIO(response)))
|
return IO.NodeOutput(InputImpl.VideoFromFile(BytesIO(response)))
|
||||||
|
|
||||||
|
|
||||||
|
class EditVideoNode(IO.ComfyNode):
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="LtxvApiEditVideoNode",
|
||||||
|
display_name="LTXV Video To Video",
|
||||||
|
category="api node/video/LTXV",
|
||||||
|
description="Edit a specific section of a video by replacing audio, video, or both using AI generation.",
|
||||||
|
inputs=[
|
||||||
|
IO.Video.Input("video"),
|
||||||
|
IO.String.Input(
|
||||||
|
"prompt",
|
||||||
|
multiline=True,
|
||||||
|
default="",
|
||||||
|
),
|
||||||
|
IO.Combo.Input("mode", options=["replace_video", "replace_audio", "replace_audio_and_video"]),
|
||||||
|
IO.Float.Input("start_time", min=0.0, default=0.0),
|
||||||
|
IO.Float.Input("duration", min=1.0, max=20.0, default=3),
|
||||||
|
],
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(
|
||||||
|
cls,
|
||||||
|
video: Input.Video,
|
||||||
|
prompt: str,
|
||||||
|
mode: str,
|
||||||
|
start_time: float,
|
||||||
|
duration: float,
|
||||||
|
) -> IO.NodeOutput:
|
||||||
|
validate_string(prompt, min_length=1, max_length=10000)
|
||||||
|
validate_video_dimensions(video, max_width=3840, max_height=2160)
|
||||||
|
validate_video_duration(video, max_duration=20)
|
||||||
|
validate_video_frame_count(video, max_frame_count=505)
|
||||||
|
video_duration = video.get_duration()
|
||||||
|
if start_time >= video_duration:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid start_time ({start_time}). Start time is greater than input video duration ({video_duration})"
|
||||||
|
)
|
||||||
|
response = await sync_op_raw(
|
||||||
|
cls,
|
||||||
|
# ApiEndpoint(
|
||||||
|
# "https://api.ltx.video/v1/retake",
|
||||||
|
# "POST",
|
||||||
|
# headers={"Authorization": "Bearer PLACE_YOUR_API_KEY"},
|
||||||
|
# ),
|
||||||
|
ApiEndpoint("/proxy/ltx/v1/retake", "POST"),
|
||||||
|
data=VideoEditRequest(
|
||||||
|
video_uri=await upload_video_to_comfyapi(cls, video),
|
||||||
|
prompt=prompt,
|
||||||
|
mode=mode,
|
||||||
|
start_time=int(start_time),
|
||||||
|
duration=int(duration),
|
||||||
|
),
|
||||||
|
as_binary=True,
|
||||||
|
max_retries=1,
|
||||||
|
)
|
||||||
|
return IO.NodeOutput(InputImpl.VideoFromFile(BytesIO(response)))
|
||||||
|
|
||||||
|
|
||||||
class LtxvApiExtension(ComfyExtension):
|
class LtxvApiExtension(ComfyExtension):
|
||||||
@ -192,6 +272,7 @@ class LtxvApiExtension(ComfyExtension):
|
|||||||
return [
|
return [
|
||||||
TextToVideoNode,
|
TextToVideoNode,
|
||||||
ImageToVideoNode,
|
ImageToVideoNode,
|
||||||
|
EditVideoNode,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user