From 0e34f00fee44c6ae0d1d64c030cdfc5321319ce5 Mon Sep 17 00:00:00 2001 From: Jedrzej Kosinski Date: Mon, 5 May 2025 06:34:32 -0500 Subject: [PATCH] Apply small fixes and most prompt validation (if needed to avoid API error) (#135) --- comfy_api_nodes/apinode_utils.py | 11 +++++++++++ comfy_api_nodes/nodes_bfl.py | 3 +++ comfy_api_nodes/nodes_luma.py | 5 ++++- comfy_api_nodes/nodes_minimax.py | 3 +++ comfy_api_nodes/nodes_openai.py | 6 +++++- comfy_api_nodes/nodes_pixverse.py | 4 ++++ comfy_api_nodes/nodes_recraft.py | 6 +++++- comfy_api_nodes/nodes_stability.py | 5 +++++ 8 files changed, 40 insertions(+), 3 deletions(-) diff --git a/comfy_api_nodes/apinode_utils.py b/comfy_api_nodes/apinode_utils.py index 04884d610..bd3b8908b 100644 --- a/comfy_api_nodes/apinode_utils.py +++ b/comfy_api_nodes/apinode_utils.py @@ -562,3 +562,14 @@ def resize_mask_to_image(mask: torch.Tensor, image: torch.Tensor, if not allow_gradient: mask = (mask > 0.5).float() return mask + + +def validate_string(string: str, strip_whitespace=True, field_name="prompt", min_length=None, max_length=None): + if strip_whitespace: + string = string.strip() + if min_length and len(string) < min_length: + raise Exception(f"Field '{field_name}' cannot be shorter than {min_length} characters; was {len(string)} characters long.") + if max_length and len(string) > max_length: + raise Exception(f" Field '{field_name} cannot be longer than {max_length} characters; was {len(string)} characters long.") + if not string: + raise Exception(f"Field '{field_name}' cannot be empty.") diff --git a/comfy_api_nodes/nodes_bfl.py b/comfy_api_nodes/nodes_bfl.py index f1014459a..6b7866741 100644 --- a/comfy_api_nodes/nodes_bfl.py +++ b/comfy_api_nodes/nodes_bfl.py @@ -21,6 +21,7 @@ from comfy_api_nodes.apinode_utils import ( validate_aspect_ratio, process_image_response, resize_mask_to_image, + validate_string, ) import numpy as np @@ -213,6 +214,8 @@ class FluxProUltraImageNode(ComfyNodeABC): auth_token=None, **kwargs, ): + if image_prompt is None: + validate_string(prompt, strip_whitespace=False) operation = SynchronousOperation( endpoint=ApiEndpoint( path="/proxy/bfl/flux-pro-1.1-ultra/generate", diff --git a/comfy_api_nodes/nodes_luma.py b/comfy_api_nodes/nodes_luma.py index 874a414ad..6a9d46fdc 100644 --- a/comfy_api_nodes/nodes_luma.py +++ b/comfy_api_nodes/nodes_luma.py @@ -32,6 +32,7 @@ from comfy_api_nodes.apis.client import ( from comfy_api_nodes.apinode_utils import ( upload_images_to_comfyapi, process_image_response, + validate_string, ) import requests @@ -216,6 +217,7 @@ class LumaImageGenerationNode(ComfyNodeABC): auth_token=None, **kwargs, ): + validate_string(prompt, strip_whitespace=True, min_length=3) # handle image_luma_ref api_image_ref = None if image_luma_ref is not None: @@ -327,7 +329,7 @@ class LumaImageModifyNode(ComfyNodeABC): IO.FLOAT, { "default": 1.0, - "min": 0.2, + "min": 0.02, "max": 1.0, "step": 0.01, "tooltip": "Weight of the image; the closer to 0.0, the less the image will be modified.", @@ -484,6 +486,7 @@ class LumaTextToVideoGenerationNode(ComfyNodeABC): auth_token=None, **kwargs, ): + validate_string(prompt, strip_whitespace=False, min_length=3) duration = duration if model != LumaVideoModel.ray_1_6 else None resolution = resolution if model != LumaVideoModel.ray_1_6 else None diff --git a/comfy_api_nodes/nodes_minimax.py b/comfy_api_nodes/nodes_minimax.py index 449ae1473..37bfce72d 100644 --- a/comfy_api_nodes/nodes_minimax.py +++ b/comfy_api_nodes/nodes_minimax.py @@ -18,6 +18,7 @@ from comfy_api_nodes.apis.client import ( from comfy_api_nodes.apinode_utils import ( download_url_to_bytesio, upload_images_to_comfyapi, + validate_string, ) import torch @@ -88,6 +89,8 @@ class MinimaxTextToVideoNode: ''' Function used between Minimax nodes - supports T2V, I2V, and S2V, based on provided arguments. ''' + if image is None: + validate_string(prompt_text, field_name="prompt_text") # upload image, if passed in image_url = None if image is not None: diff --git a/comfy_api_nodes/nodes_openai.py b/comfy_api_nodes/nodes_openai.py index de912af11..ccdc2bdbf 100644 --- a/comfy_api_nodes/nodes_openai.py +++ b/comfy_api_nodes/nodes_openai.py @@ -21,7 +21,8 @@ from comfy_api_nodes.apis.client import ( from comfy_api_nodes.apinode_utils import ( downscale_image_tensor, - validate_and_cast_response + validate_and_cast_response, + validate_string, ) class OpenAIDalle2(ComfyNodeABC): @@ -114,6 +115,7 @@ class OpenAIDalle2(ComfyNodeABC): size="1024x1024", auth_token=None, ): + validate_string(prompt, strip_whitespace=False) model = "dall-e-2" path = "/proxy/openai/images/generations" content_type = "application/json" @@ -258,6 +260,7 @@ class OpenAIDalle3(ComfyNodeABC): size="1024x1024", auth_token=None, ): + validate_string(prompt, strip_whitespace=False) model = "dall-e-3" # build the operation @@ -393,6 +396,7 @@ class OpenAIGPTImage1(ComfyNodeABC): size="1024x1024", auth_token=None, ): + validate_string(prompt, strip_whitespace=False) model = "gpt-image-1" path = "/proxy/openai/images/generations" content_type="application/json" diff --git a/comfy_api_nodes/nodes_pixverse.py b/comfy_api_nodes/nodes_pixverse.py index 8064b8f9f..b2db3f321 100644 --- a/comfy_api_nodes/nodes_pixverse.py +++ b/comfy_api_nodes/nodes_pixverse.py @@ -24,6 +24,7 @@ from comfy_api_nodes.apis.client import ( ) from comfy_api_nodes.apinode_utils import ( tensor_to_bytesio, + validate_string, ) from comfy.comfy_types.node_typing import IO, ComfyNodeABC from comfy_api.input_impl import VideoFromFile @@ -163,6 +164,7 @@ class PixverseTextToVideoNode(ComfyNodeABC): auth_token=None, **kwargs, ): + validate_string(prompt, strip_whitespace=False) # 1080p is limited to 5 seconds duration # only normal motion_mode supported for 1080p or for non-5 second duration if quality == PixverseQuality.res_1080p: @@ -292,6 +294,7 @@ class PixverseImageToVideoNode(ComfyNodeABC): auth_token=None, **kwargs, ): + validate_string(prompt, strip_whitespace=False) img_id = upload_image_to_pixverse(image, auth_token=auth_token) # 1080p is limited to 5 seconds duration @@ -427,6 +430,7 @@ class PixverseTransitionVideoNode(ComfyNodeABC): auth_token=None, **kwargs, ): + validate_string(prompt, strip_whitespace=False) first_frame_id = upload_image_to_pixverse(first_frame, auth_token=auth_token) last_frame_id = upload_image_to_pixverse(last_frame, auth_token=auth_token) diff --git a/comfy_api_nodes/nodes_recraft.py b/comfy_api_nodes/nodes_recraft.py index d8ac68797..a5e513e05 100644 --- a/comfy_api_nodes/nodes_recraft.py +++ b/comfy_api_nodes/nodes_recraft.py @@ -26,6 +26,7 @@ from comfy_api_nodes.apinode_utils import ( download_url_to_bytesio, tensor_to_bytesio, resize_mask_to_image, + validate_string, ) import folder_paths import json @@ -455,6 +456,7 @@ class RecraftTextToImageNode: auth_token=None, **kwargs, ): + validate_string(prompt, strip_whitespace=False, max_length=1000) default_style = RecraftStyle(RecraftStyleV3.realistic_image) if recraft_style is None: recraft_style = default_style @@ -589,6 +591,7 @@ class RecraftImageToImageNode: recraft_controls: RecraftControls = None, **kwargs, ): + validate_string(prompt, strip_whitespace=False, max_length=1000) default_style = RecraftStyle(RecraftStyleV3.realistic_image) if recraft_style is None: recraft_style = default_style @@ -702,6 +705,7 @@ class RecraftImageInpaintingNode: negative_prompt: str = None, **kwargs, ): + validate_string(prompt, strip_whitespace=False, max_length=1000) default_style = RecraftStyle(RecraftStyleV3.realistic_image) if recraft_style is None: recraft_style = default_style @@ -717,7 +721,6 @@ class RecraftImageInpaintingNode: style=recraft_style.style, substyle=recraft_style.substyle, style_id=recraft_style.style_id, - random_seed=seed, ) # prepare mask tensor @@ -825,6 +828,7 @@ class RecraftTextToVectorNode: auth_token=None, **kwargs, ): + 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) diff --git a/comfy_api_nodes/nodes_stability.py b/comfy_api_nodes/nodes_stability.py index 50d264b5d..4f1676a6a 100644 --- a/comfy_api_nodes/nodes_stability.py +++ b/comfy_api_nodes/nodes_stability.py @@ -23,6 +23,7 @@ from comfy_api_nodes.apis.client import ( from comfy_api_nodes.apinode_utils import ( bytesio_to_image_tensor, tensor_to_bytesio, + validate_string, ) import torch @@ -125,6 +126,7 @@ class StabilityStableImageUltraNode: def api_call(self, prompt: str, aspect_ratio: str, style_preset: str, seed: int, negative_prompt: str=None, image: torch.Tensor = None, image_denoise: float=None, auth_token=None): + validate_string(prompt, strip_whitespace=False) # prepare image binary if image present image_binary = None if image is not None: @@ -256,6 +258,7 @@ class StabilityStableImageSD_3_5Node: def api_call(self, model: str, prompt: str, aspect_ratio: str, style_preset: str, seed: int, cfg_scale: float, negative_prompt: str=None, image: torch.Tensor = None, image_denoise: float=None, auth_token=None): + validate_string(prompt, strip_whitespace=False) # prepare image binary if image present image_binary = None mode = Stability_SD3_5_GenerationMode.text_to_image @@ -370,6 +373,7 @@ class StabilityUpscaleConservativeNode: def api_call(self, image: torch.Tensor, prompt: str, creativity: float, seed: int, negative_prompt: str=None, auth_token=None): + validate_string(prompt, strip_whitespace=False) image_binary = tensor_to_bytesio(image, total_pixels=1024*1024).read() if not negative_prompt: @@ -474,6 +478,7 @@ class StabilityUpscaleCreativeNode: def api_call(self, image: torch.Tensor, prompt: str, creativity: float, style_preset: str, seed: int, negative_prompt: str=None, auth_token=None): + validate_string(prompt, strip_whitespace=False) image_binary = tensor_to_bytesio(image, total_pixels=1024*1024).read() if not negative_prompt: