Compare commits

..

3 Commits

7 changed files with 117 additions and 87 deletions

View File

@ -322,11 +322,14 @@ class String(ComfyTypeIO):
'''String input.'''
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
multiline=False, placeholder: str=None, default: str=None, dynamic_prompts: bool=None,
min_length: int=None, max_length: int=None,
socketless: bool=None, force_input: bool=None, extra_dict=None, raw_link: bool=None, advanced: bool=None):
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, None, force_input, extra_dict, raw_link, advanced)
self.multiline = multiline
self.placeholder = placeholder
self.dynamic_prompts = dynamic_prompts
self.min_length = min_length
self.max_length = max_length
self.default: str
def as_dict(self):
@ -334,6 +337,8 @@ class String(ComfyTypeIO):
"multiline": self.multiline,
"placeholder": self.placeholder,
"dynamicPrompts": self.dynamic_prompts,
"minLength": self.min_length,
"maxLength": self.max_length,
})
@comfytype(io_type="COMBO")

View File

@ -23,7 +23,6 @@ from comfy_api_nodes.util import (
upload_3d_model_to_comfyapi,
upload_image_to_comfyapi,
validate_image_dimensions,
validate_string,
)
@ -61,7 +60,7 @@ class TencentTextToModelNode(IO.ComfyNode):
options=["3.0", "3.1"],
tooltip="The LowPoly option is unavailable for the `3.1` model.",
),
IO.String.Input("prompt", multiline=True, default="", tooltip="Supports up to 1024 characters."),
IO.String.Input("prompt", multiline=True, default="", min_length=1, max_length=1024),
IO.Int.Input("face_count", default=500000, min=40000, max=1500000),
IO.DynamicCombo.Input(
"generate_type",
@ -123,7 +122,6 @@ class TencentTextToModelNode(IO.ComfyNode):
seed: int,
) -> IO.NodeOutput:
_ = seed
validate_string(prompt, field_name="prompt", min_length=1, max_length=1024)
if model == "3.1" and generate_type["generate_type"].lower() == "lowpoly":
raise ValueError("The LowPoly option is currently unavailable for the 3.1 model.")
response = await sync_op(
@ -417,7 +415,9 @@ class Tencent3DTextureEditNode(IO.ComfyNode):
"prompt",
multiline=True,
default="",
tooltip="Describes texture editing. Supports up to 1024 UTF-8 characters.",
min_length=1,
max_length=1024,
tooltip="Describes texture editing.",
),
IO.Int.Input(
"seed",
@ -456,7 +456,6 @@ class Tencent3DTextureEditNode(IO.ComfyNode):
file_format = model_3d.format.lower()
if file_format != "fbx":
raise ValueError(f"Unsupported file format: '{file_format}'. Only FBX format is supported.")
validate_string(prompt, field_name="prompt", min_length=1, max_length=1024)
model_url = await upload_3d_model_to_comfyapi(cls, model_3d, file_format)
response = await sync_op(
cls,

View File

@ -91,7 +91,8 @@ def _generate_storyboard_inputs(count: int) -> list:
f"storyboard_{i}_prompt",
multiline=True,
default="",
tooltip=f"Prompt for storyboard segment {i}. Max 512 characters.",
max_length=512,
tooltip=f"Prompt for storyboard segment {i}.",
),
IO.Int.Input(
f"storyboard_{i}_duration",
@ -309,19 +310,6 @@ def is_valid_image_response(response: KlingVirtualTryOnResponse) -> bool:
)
def validate_prompts(prompt: str, negative_prompt: str, max_length: int) -> bool:
"""Verifies that the positive prompt is not empty and that neither promt is too long."""
if not prompt:
raise ValueError("Positive prompt is empty")
if len(prompt) > max_length:
raise ValueError(f"Positive prompt is too long: {len(prompt)} characters")
if negative_prompt and len(negative_prompt) > max_length:
raise ValueError(
f"Negative prompt is too long: {len(negative_prompt)} characters"
)
return True
def validate_task_creation_response(response) -> None:
"""Validates that the Kling task creation request was successful."""
if not is_valid_task_creation_response(response):
@ -424,7 +412,6 @@ async def execute_text2video(
aspect_ratio: str,
camera_control: KlingCameraControl | None = None,
) -> IO.NodeOutput:
validate_prompts(prompt, negative_prompt, MAX_PROMPT_LENGTH_T2V)
task_creation_response = await sync_op(
cls,
ApiEndpoint(path=PATH_TEXT_TO_VIDEO, method="POST"),
@ -470,7 +457,6 @@ async def execute_image2video(
camera_control: KlingCameraControl | None = None,
end_frame: torch.Tensor | None = None,
) -> IO.NodeOutput:
validate_prompts(prompt, negative_prompt, MAX_PROMPT_LENGTH_I2V)
validate_input_image(start_frame)
if camera_control is not None:
@ -580,8 +566,6 @@ async def execute_lipsync(
voice_speed: float | None = None,
voice_id: str | None = None,
) -> IO.NodeOutput:
if text:
validate_string(text, field_name="Text", max_length=MAX_PROMPT_LENGTH_LIP_SYNC)
validate_video_dimensions(video, 720, 1920)
validate_video_duration(video, 2, 10)
@ -763,8 +747,8 @@ class KlingTextToVideoNode(IO.ComfyNode):
category="api node/video/Kling",
description="Kling Text to Video Node",
inputs=[
IO.String.Input("prompt", multiline=True, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, tooltip="Negative text prompt"),
IO.String.Input("prompt", multiline=True, min_length=1, max_length=2500, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, max_length=2500, tooltip="Negative text prompt"),
IO.Float.Input("cfg_scale", default=1.0, min=0.0, max=1.0),
IO.Combo.Input(
"aspect_ratio",
@ -1352,6 +1336,8 @@ class OmniProVideoToVideoNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
min_length=1,
max_length=2500,
tooltip="A text prompt describing the video content. "
"This can include both positive and negative descriptions.",
),
@ -1413,7 +1399,6 @@ class OmniProVideoToVideoNode(IO.ComfyNode):
) -> IO.NodeOutput:
_ = seed
prompt = normalize_omni_prompt_references(prompt)
validate_string(prompt, min_length=1, max_length=2500)
validate_video_duration(reference_video, min_duration=3.0, max_duration=10.05)
validate_video_dimensions(reference_video, min_width=720, min_height=720, max_width=2160, max_height=2160)
image_list: list[OmniParamImage] = []
@ -1463,6 +1448,8 @@ class OmniProEditVideoNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
min_length=1,
max_length=2500,
tooltip="A text prompt describing the video content. "
"This can include both positive and negative descriptions.",
),
@ -1520,7 +1507,6 @@ class OmniProEditVideoNode(IO.ComfyNode):
) -> IO.NodeOutput:
_ = seed
prompt = normalize_omni_prompt_references(prompt)
validate_string(prompt, min_length=1, max_length=2500)
validate_video_duration(video, min_duration=3.0, max_duration=10.05)
validate_video_dimensions(video, min_width=720, min_height=720, max_width=2160, max_height=2160)
image_list: list[OmniParamImage] = []
@ -1570,6 +1556,8 @@ class OmniProImageNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
min_length=1,
max_length=2500,
tooltip="A text prompt describing the image content. "
"This can include both positive and negative descriptions.",
),
@ -1638,7 +1626,6 @@ class OmniProImageNode(IO.ComfyNode):
if model_name == "kling-image-o1" and resolution == "4K":
raise ValueError("4K resolution is not supported for kling-image-o1 model.")
prompt = normalize_omni_prompt_references(prompt)
validate_string(prompt, min_length=1, max_length=2500)
image_list: list[OmniImageParamImage] = []
if reference_images is not None:
if get_number_of_images(reference_images) > 10:
@ -1694,8 +1681,8 @@ class KlingCameraControlT2VNode(IO.ComfyNode):
category="api node/video/Kling",
description="Transform text into cinematic videos with professional camera movements that simulate real-world cinematography. Control virtual camera actions including zoom, rotation, pan, tilt, and first-person view, while maintaining focus on your original text.",
inputs=[
IO.String.Input("prompt", multiline=True, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, tooltip="Negative text prompt"),
IO.String.Input("prompt", multiline=True, min_length=1, max_length=2500, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, max_length=2500, tooltip="Negative text prompt"),
IO.Float.Input("cfg_scale", default=0.75, min=0.0, max=1.0),
IO.Combo.Input(
"aspect_ratio",
@ -1756,8 +1743,8 @@ class KlingImage2VideoNode(IO.ComfyNode):
category="api node/video/Kling",
inputs=[
IO.Image.Input("start_frame", tooltip="The reference image used to generate the video."),
IO.String.Input("prompt", multiline=True, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, tooltip="Negative text prompt"),
IO.String.Input("prompt", multiline=True, min_length=1, max_length=500, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, max_length=500, tooltip="Negative text prompt"),
IO.Combo.Input(
"model_name",
options=KlingVideoGenModelName,
@ -1859,8 +1846,8 @@ class KlingCameraControlI2VNode(IO.ComfyNode):
"start_frame",
tooltip="Reference Image - URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1. Base64 should not include data:image prefix.",
),
IO.String.Input("prompt", multiline=True, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, tooltip="Negative text prompt"),
IO.String.Input("prompt", multiline=True, min_length=1, max_length=500, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, max_length=500, tooltip="Negative text prompt"),
IO.Float.Input("cfg_scale", default=0.75, min=0.0, max=1.0),
IO.Combo.Input(
"aspect_ratio",
@ -1934,8 +1921,8 @@ class KlingStartEndFrameNode(IO.ComfyNode):
"end_frame",
tooltip="Reference Image - End frame control. URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px. Base64 should not include data:image prefix.",
),
IO.String.Input("prompt", multiline=True, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, tooltip="Negative text prompt"),
IO.String.Input("prompt", multiline=True, min_length=1, max_length=500, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, max_length=500, tooltip="Negative text prompt"),
IO.Float.Input("cfg_scale", default=0.5, min=0.0, max=1.0),
IO.Combo.Input("aspect_ratio", options=["16:9", "9:16", "1:1"]),
IO.Combo.Input(
@ -2023,11 +2010,14 @@ class KlingVideoExtendNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
min_length=1,
max_length=2500,
tooltip="Positive text prompt for guiding the video extension",
),
IO.String.Input(
"negative_prompt",
multiline=True,
max_length=2500,
tooltip="Negative text prompt for elements to avoid in the extended video",
),
IO.Float.Input("cfg_scale", default=0.5, min=0.0, max=1.0),
@ -2061,7 +2051,6 @@ class KlingVideoExtendNode(IO.ComfyNode):
cfg_scale: float,
video_id: str,
) -> IO.NodeOutput:
validate_prompts(prompt, negative_prompt, MAX_PROMPT_LENGTH_T2V)
task_creation_response = await sync_op(
cls,
ApiEndpoint(path=PATH_VIDEO_EXTEND, method="POST"),
@ -2320,7 +2309,8 @@ class KlingLipSyncTextToVideoNode(IO.ComfyNode):
IO.String.Input(
"text",
multiline=True,
tooltip="Text Content for Lip-Sync Video Generation. Required when mode is text2video. Maximum length is 120 characters.",
max_length=120,
tooltip="Text Content for Lip-Sync Video Generation. Required when mode is text2video.",
),
IO.Combo.Input(
"voice",
@ -2451,8 +2441,8 @@ class KlingImageGenerationNode(IO.ComfyNode):
category="api node/image/Kling",
description="Kling Image Generation Node. Generate an image from a text prompt with an optional reference image.",
inputs=[
IO.String.Input("prompt", multiline=True, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, tooltip="Negative text prompt"),
IO.String.Input("prompt", multiline=True, min_length=1, max_length=500, tooltip="Positive text prompt"),
IO.String.Input("negative_prompt", multiline=True, max_length=500, tooltip="Negative text prompt"),
IO.Combo.Input(
"image_type",
options=[i.value for i in KlingImageGenImageReferenceType],
@ -2543,8 +2533,6 @@ class KlingImageGenerationNode(IO.ComfyNode):
seed: int = 0,
) -> IO.NodeOutput:
_ = seed
validate_string(prompt, field_name="prompt", min_length=1, max_length=MAX_PROMPT_LENGTH_IMAGE_GEN)
validate_string(negative_prompt, field_name="negative_prompt", max_length=MAX_PROMPT_LENGTH_IMAGE_GEN)
task_creation_response = await sync_op(
cls,
ApiEndpoint(path=PATH_IMAGE_GENERATIONS, method="POST"),
@ -2588,7 +2576,7 @@ class TextToVideoWithAudio(IO.ComfyNode):
category="api node/video/Kling",
inputs=[
IO.Combo.Input("model_name", options=["kling-v2-6"]),
IO.String.Input("prompt", multiline=True, tooltip="Positive text prompt."),
IO.String.Input("prompt", multiline=True, min_length=1, max_length=2500, tooltip="Positive text prompt."),
IO.Combo.Input("mode", options=["pro"]),
IO.Combo.Input("aspect_ratio", options=["16:9", "9:16", "1:1"]),
IO.Combo.Input("duration", options=[5, 10]),
@ -2619,7 +2607,6 @@ class TextToVideoWithAudio(IO.ComfyNode):
duration: int,
generate_audio: bool,
) -> IO.NodeOutput:
validate_string(prompt, min_length=1, max_length=2500)
response = await sync_op(
cls,
ApiEndpoint(path="/proxy/kling/v1/videos/text2video", method="POST"),
@ -2657,7 +2644,7 @@ class ImageToVideoWithAudio(IO.ComfyNode):
inputs=[
IO.Combo.Input("model_name", options=["kling-v2-6"]),
IO.Image.Input("start_frame"),
IO.String.Input("prompt", multiline=True, tooltip="Positive text prompt."),
IO.String.Input("prompt", multiline=True, min_length=1, max_length=2500, tooltip="Positive text prompt."),
IO.Combo.Input("mode", options=["pro"]),
IO.Combo.Input("duration", options=[5, 10]),
IO.Boolean.Input("generate_audio", default=True, advanced=True),
@ -2687,7 +2674,6 @@ class ImageToVideoWithAudio(IO.ComfyNode):
duration: int,
generate_audio: bool,
) -> IO.NodeOutput:
validate_string(prompt, min_length=1, max_length=2500)
validate_image_dimensions(start_frame, min_width=300, min_height=300)
validate_image_aspect_ratio(start_frame, (1, 2.5), (2.5, 1))
response = await sync_op(
@ -2725,7 +2711,7 @@ class MotionControl(IO.ComfyNode):
display_name="Kling Motion Control",
category="api node/video/Kling",
inputs=[
IO.String.Input("prompt", multiline=True),
IO.String.Input("prompt", multiline=True, max_length=2500),
IO.Image.Input("reference_image"),
IO.Video.Input(
"reference_video",
@ -2776,7 +2762,6 @@ class MotionControl(IO.ComfyNode):
character_orientation: str,
mode: str,
) -> IO.NodeOutput:
validate_string(prompt, max_length=2500)
validate_image_dimensions(reference_image, min_width=340, min_height=340)
validate_image_aspect_ratio(reference_image, (1, 2.5), (2.5, 1))
if character_orientation == "image":
@ -3034,7 +3019,7 @@ class KlingFirstLastFrameNode(IO.ComfyNode):
category="api node/video/Kling",
description="Generate videos with Kling V3 using first and last frames.",
inputs=[
IO.String.Input("prompt", multiline=True, default=""),
IO.String.Input("prompt", multiline=True, default="", min_length=1, max_length=2500),
IO.Int.Input(
"duration",
default=5,
@ -3105,7 +3090,6 @@ class KlingFirstLastFrameNode(IO.ComfyNode):
seed: int,
) -> IO.NodeOutput:
_ = seed
validate_string(prompt, min_length=1, max_length=2500)
validate_image_dimensions(first_frame, min_width=300, min_height=300)
validate_image_aspect_ratio(first_frame, (1, 2.5), (2.5, 1))
validate_image_dimensions(end_frame, min_width=300, min_height=300)

View File

@ -36,7 +36,7 @@ class MeshyTextToModelNode(IO.ComfyNode):
category="api node/3d/Meshy",
inputs=[
IO.Combo.Input("model", options=["latest"]),
IO.String.Input("prompt", multiline=True, default=""),
IO.String.Input("prompt", multiline=True, default="", min_length=1, max_length=600),
IO.Combo.Input("style", options=["realistic", "sculpture"]),
IO.DynamicCombo.Input(
"should_remesh",
@ -105,7 +105,6 @@ class MeshyTextToModelNode(IO.ComfyNode):
pose_mode: str,
seed: int,
) -> IO.NodeOutput:
validate_string(prompt, field_name="prompt", min_length=1, max_length=600)
response = await sync_op(
cls,
ApiEndpoint(path="/proxy/meshy/openapi/v2/text-to-3d", method="POST"),
@ -162,8 +161,9 @@ class MeshyRefineNode(IO.ComfyNode):
"texture_prompt",
default="",
multiline=True,
max_length=600,
tooltip="Provide a text prompt to guide the texturing process. "
"Maximum 600 characters. Cannot be used at the same time as 'texture_image'.",
"Cannot be used at the same time as 'texture_image'.",
),
IO.Image.Input(
"texture_image",
@ -201,8 +201,6 @@ class MeshyRefineNode(IO.ComfyNode):
if texture_prompt and texture_image is not None:
raise ValueError("texture_prompt and texture_image cannot be used at the same time")
texture_image_url = None
if texture_prompt:
validate_string(texture_prompt, field_name="texture_prompt", max_length=600)
if texture_image is not None:
texture_image_url = (await upload_images_to_comfyapi(cls, texture_image, wait_label="Uploading texture"))[0]
response = await sync_op(
@ -281,8 +279,9 @@ class MeshyImageToModelNode(IO.ComfyNode):
"texture_prompt",
default="",
multiline=True,
max_length=600,
tooltip="Provide a text prompt to guide the texturing process. "
"Maximum 600 characters. Cannot be used at the same time as 'texture_image'.",
"Cannot be used at the same time as 'texture_image'.",
),
IO.Image.Input(
"texture_image",
@ -449,8 +448,9 @@ class MeshyMultiImageToModelNode(IO.ComfyNode):
"texture_prompt",
default="",
multiline=True,
max_length=600,
tooltip="Provide a text prompt to guide the texturing process. "
"Maximum 600 characters. Cannot be used at the same time as 'texture_image'.",
"Cannot be used at the same time as 'texture_image'.",
),
IO.Image.Input(
"texture_image",
@ -739,8 +739,9 @@ class MeshyTextureNode(IO.ComfyNode):
"text_style_prompt",
default="",
multiline=True,
tooltip="Describe your desired texture style of the object using text. Maximum 600 characters."
"Maximum 600 characters. Cannot be used at the same time as 'image_style'.",
max_length=600,
tooltip="Describe your desired texture style of the object using text. "
"Cannot be used at the same time as 'image_style'.",
),
IO.Image.Input(
"image_style",

View File

@ -30,7 +30,6 @@ from comfy_api_nodes.util import (
resize_mask_to_image,
sync_op,
tensor_to_bytesio,
validate_string,
)
from comfy_extras.nodes_images import SVG
@ -403,7 +402,14 @@ class RecraftTextToImageNode(IO.ComfyNode):
category="api node/image/Recraft",
description="Generates images synchronously based on prompt and resolution.",
inputs=[
IO.String.Input("prompt", multiline=True, default="", tooltip="Prompt for the image generation."),
IO.String.Input(
"prompt",
multiline=True,
default="",
min_length=1,
max_length=1000,
tooltip="Prompt for the image generation.",
),
IO.Combo.Input(
"size",
options=[res.value for res in RecraftImageSize],
@ -466,7 +472,6 @@ class RecraftTextToImageNode(IO.ComfyNode):
negative_prompt: str = None,
recraft_controls: RecraftControls = None,
) -> IO.NodeOutput:
validate_string(prompt, strip_whitespace=False, min_length=1, max_length=1000)
default_style = RecraftStyle(RecraftStyleV3.realistic_image)
if recraft_style is None:
recraft_style = default_style
@ -516,7 +521,9 @@ class RecraftImageToImageNode(IO.ComfyNode):
description="Modify image based on prompt and strength.",
inputs=[
IO.Image.Input("image"),
IO.String.Input("prompt", multiline=True, default="", tooltip="Prompt for the image generation."),
IO.String.Input(
"prompt", multiline=True, default="", max_length=1000, tooltip="Prompt for the image generation."
),
IO.Int.Input(
"n",
default=1,
@ -583,7 +590,6 @@ class RecraftImageToImageNode(IO.ComfyNode):
negative_prompt: str = None,
recraft_controls: RecraftControls = None,
) -> IO.NodeOutput:
validate_string(prompt, strip_whitespace=False, max_length=1000)
default_style = RecraftStyle(RecraftStyleV3.realistic_image)
if recraft_style is None:
recraft_style = default_style
@ -635,7 +641,9 @@ class RecraftImageInpaintingNode(IO.ComfyNode):
inputs=[
IO.Image.Input("image"),
IO.Mask.Input("mask"),
IO.String.Input("prompt", multiline=True, default="", tooltip="Prompt for the image generation."),
IO.String.Input(
"prompt", multiline=True, default="", max_length=1000, tooltip="Prompt for the image generation."
),
IO.Int.Input(
"n",
default=1,
@ -687,7 +695,6 @@ class RecraftImageInpaintingNode(IO.ComfyNode):
recraft_style: RecraftStyle = None,
negative_prompt: str = None,
) -> IO.NodeOutput:
validate_string(prompt, strip_whitespace=False, max_length=1000)
default_style = RecraftStyle(RecraftStyleV3.realistic_image)
if recraft_style is None:
recraft_style = default_style
@ -735,7 +742,9 @@ class RecraftTextToVectorNode(IO.ComfyNode):
category="api node/image/Recraft",
description="Generates SVG synchronously based on prompt and resolution.",
inputs=[
IO.String.Input("prompt", default="", tooltip="Prompt for the image generation.", multiline=True),
IO.String.Input(
"prompt", default="", max_length=1000, tooltip="Prompt for the image generation.", multiline=True
),
IO.Combo.Input("substyle", options=get_v3_substyles(RecraftStyleV3.vector_illustration)),
IO.Combo.Input(
"size",
@ -792,7 +801,6 @@ class RecraftTextToVectorNode(IO.ComfyNode):
negative_prompt: str = None,
recraft_controls: RecraftControls = None,
) -> IO.NodeOutput:
validate_string(prompt, strip_whitespace=False, max_length=1000)
# create RecraftStyle so strings will be formatted properly (i.e. "None" will become None)
recraft_style = RecraftStyle(RecraftStyleV3.vector_illustration, substyle=substyle)
@ -1091,7 +1099,9 @@ class RecraftV4TextToImageNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
tooltip="Prompt for the image generation. Maximum 10,000 characters.",
min_length=1,
max_length=10000,
tooltip="Prompt for the image generation.",
),
IO.String.Input(
"negative_prompt",
@ -1178,7 +1188,6 @@ class RecraftV4TextToImageNode(IO.ComfyNode):
seed: int,
recraft_controls: RecraftControls | None = None,
) -> IO.NodeOutput:
validate_string(prompt, strip_whitespace=False, min_length=1, max_length=10000)
response = await sync_op(
cls,
ApiEndpoint(path="/proxy/recraft/image_generation", method="POST"),
@ -1215,7 +1224,9 @@ class RecraftV4TextToVectorNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
tooltip="Prompt for the image generation. Maximum 10,000 characters.",
min_length=1,
max_length=10000,
tooltip="Prompt for the image generation.",
),
IO.String.Input(
"negative_prompt",
@ -1302,7 +1313,6 @@ class RecraftV4TextToVectorNode(IO.ComfyNode):
seed: int,
recraft_controls: RecraftControls | None = None,
) -> IO.NodeOutput:
validate_string(prompt, strip_whitespace=False, min_length=1, max_length=10000)
response = await sync_op(
cls,
ApiEndpoint(path="/proxy/recraft/image_generation", method="POST"),

View File

@ -499,7 +499,9 @@ class Vidu2TextToVideoNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
tooltip="A textual description for video generation, with a maximum length of 2000 characters.",
min_length=1,
max_length=2000,
tooltip="A textual description for video generation.",
),
IO.Int.Input(
"duration",
@ -560,7 +562,6 @@ class Vidu2TextToVideoNode(IO.ComfyNode):
resolution: str,
background_music: bool,
) -> IO.NodeOutput:
validate_string(prompt, min_length=1, max_length=2000)
results = await execute_task(
cls,
VIDU_TEXT_TO_VIDEO,
@ -596,7 +597,8 @@ class Vidu2ImageToVideoNode(IO.ComfyNode):
"prompt",
multiline=True,
default="",
tooltip="An optional text prompt for video generation (max 2000 characters).",
max_length=2000,
tooltip="An optional text prompt for video generation.",
),
IO.Int.Input(
"duration",
@ -685,7 +687,6 @@ class Vidu2ImageToVideoNode(IO.ComfyNode):
if get_number_of_images(image) > 1:
raise ValueError("Only one input image is allowed.")
validate_image_aspect_ratio(image, (1, 4), (4, 1))
validate_string(prompt, max_length=2000)
results = await execute_task(
cls,
VIDU_IMAGE_TO_VIDEO,
@ -731,6 +732,8 @@ class Vidu2ReferenceVideoNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
min_length=1,
max_length=2000,
tooltip="When enabled, the video will include generated speech and background music "
"based on the prompt.",
),
@ -802,7 +805,6 @@ class Vidu2ReferenceVideoNode(IO.ComfyNode):
resolution: str,
movement_amplitude: str,
) -> IO.NodeOutput:
validate_string(prompt, min_length=1, max_length=2000)
total_images = 0
for i in subjects:
if get_number_of_images(subjects[i]) > 3:
@ -858,7 +860,8 @@ class Vidu2StartEndToVideoNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
tooltip="Prompt description (max 2000 characters).",
max_length=2000,
tooltip="Prompt description.",
),
IO.Int.Input(
"duration",
@ -940,7 +943,6 @@ class Vidu2StartEndToVideoNode(IO.ComfyNode):
resolution: str,
movement_amplitude: str,
) -> IO.NodeOutput:
validate_string(prompt, max_length=2000)
if get_number_of_images(first_frame) > 1:
raise ValueError("Only one input image is allowed for `first_frame`.")
if get_number_of_images(end_frame) > 1:
@ -1024,7 +1026,8 @@ class ViduExtendVideoNode(IO.ComfyNode):
"prompt",
multiline=True,
default="",
tooltip="An optional text prompt for the extended video (max 2000 characters).",
max_length=2000,
tooltip="An optional text prompt for the extended video.",
),
IO.Int.Input(
"seed",
@ -1078,7 +1081,6 @@ class ViduExtendVideoNode(IO.ComfyNode):
seed: int,
end_frame: Input.Image | None = None,
) -> IO.NodeOutput:
validate_string(prompt, max_length=2000)
validate_video_duration(video, min_duration=4, max_duration=55)
image_url = None
if end_frame is not None:
@ -1357,7 +1359,9 @@ class Vidu3TextToVideoNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
tooltip="A textual description for video generation, with a maximum length of 2000 characters.",
min_length=1,
max_length=2000,
tooltip="A textual description for video generation.",
),
IO.Int.Input(
"seed",
@ -1405,7 +1409,6 @@ class Vidu3TextToVideoNode(IO.ComfyNode):
prompt: str,
seed: int,
) -> IO.NodeOutput:
validate_string(prompt, min_length=1, max_length=2000)
results = await execute_task(
cls,
VIDU_TEXT_TO_VIDEO,
@ -1497,7 +1500,8 @@ class Vidu3ImageToVideoNode(IO.ComfyNode):
"prompt",
multiline=True,
default="",
tooltip="An optional text prompt for video generation (max 2000 characters).",
max_length=2000,
tooltip="An optional text prompt for video generation.",
),
IO.Int.Input(
"seed",
@ -1547,7 +1551,6 @@ class Vidu3ImageToVideoNode(IO.ComfyNode):
seed: int,
) -> IO.NodeOutput:
validate_image_aspect_ratio(image, (1, 4), (4, 1))
validate_string(prompt, max_length=2000)
results = await execute_task(
cls,
VIDU_IMAGE_TO_VIDEO,
@ -1636,7 +1639,8 @@ class Vidu3StartEndToVideoNode(IO.ComfyNode):
IO.String.Input(
"prompt",
multiline=True,
tooltip="Prompt description (max 2000 characters).",
max_length=2000,
tooltip="Prompt description.",
),
IO.Int.Input(
"seed",
@ -1686,7 +1690,6 @@ class Vidu3StartEndToVideoNode(IO.ComfyNode):
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"],

View File

@ -944,6 +944,34 @@ async def validate_inputs(prompt_id, prompt, item, validated):
errors.append(error)
continue
if input_type == "STRING":
if "minLength" in extra_info and len(val.strip()) < extra_info["minLength"]:
error = {
"type": "value_shorter_than_min_length",
"message": "Value length {} shorter than min length of {}".format(len(val.strip()), extra_info["minLength"]),
"details": f"{x}",
"extra_info": {
"input_name": x,
"input_config": info,
"received_value": val,
}
}
errors.append(error)
continue
if "maxLength" in extra_info and len(val) > extra_info["maxLength"]:
error = {
"type": "value_longer_than_max_length",
"message": "Value length {} longer than max length of {}".format(len(val), extra_info["maxLength"]),
"details": f"{x}",
"extra_info": {
"input_name": x,
"input_config": info,
"received_value": val,
}
}
errors.append(error)
continue
if isinstance(input_type, list) or input_type == io.Combo.io_type:
if input_type == io.Combo.io_type:
combo_options = extra_info.get("options", [])