From f4509ff2136ba6bae8dd3d36a51e023c9414f794 Mon Sep 17 00:00:00 2001 From: Alexander Piskun <13381981+bigcat88@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:39:34 +0300 Subject: [PATCH] [Partner Nodes] feat(Recraft): add V4.1 model (#15105) * [Partner Nodes] feat(Recraft): add V4.1 models and V4 image edit nodes Signed-off-by: bigcat88 * [Partner Nodes] chore(Recraft): change old nodes names to contain "V3" Signed-off-by: bigcat88 * [Partner Nodes] fix(Recraft): remove v4 model from the image edit nodes; fix the default "strength" value Signed-off-by: bigcat88 * [Partner Nodes] chore(Recraft): remove new image edit nodes Signed-off-by: bigcat88 --------- Signed-off-by: bigcat88 --- comfy_api_nodes/apis/recraft.py | 4 +- comfy_api_nodes/nodes_recraft.py | 130 +++++++++++++++++++++++++++---- 2 files changed, 118 insertions(+), 16 deletions(-) diff --git a/comfy_api_nodes/apis/recraft.py b/comfy_api_nodes/apis/recraft.py index 78ededd94..64780d73b 100644 --- a/comfy_api_nodes/apis/recraft.py +++ b/comfy_api_nodes/apis/recraft.py @@ -244,10 +244,10 @@ RECRAFT_V4_PRO_SIZES = [ "2304x1792", "1792x2304", "1664x2688", - "1434x1024", - "1024x1434", "2560x1792", "1792x2560", + "2688x1536", + "1536x2688", ] diff --git a/comfy_api_nodes/nodes_recraft.py b/comfy_api_nodes/nodes_recraft.py index c44942f50..2605b9021 100644 --- a/comfy_api_nodes/nodes_recraft.py +++ b/comfy_api_nodes/nodes_recraft.py @@ -399,7 +399,7 @@ class RecraftTextToImageNode(IO.ComfyNode): def define_schema(cls): return IO.Schema( node_id="RecraftTextToImageNode", - display_name="Recraft Text to Image", + display_name="Recraft V3 Text to Image", category="partner/image/Recraft", description="Generates images synchronously based on prompt and resolution.", inputs=[ @@ -511,7 +511,7 @@ class RecraftImageToImageNode(IO.ComfyNode): def define_schema(cls): return IO.Schema( node_id="RecraftImageToImageNode", - display_name="Recraft Image to Image", + display_name="Recraft V3 Image to Image", category="partner/image/Recraft", description="Modify image based on prompt and strength.", inputs=[ @@ -731,7 +731,7 @@ class RecraftTextToVectorNode(IO.ComfyNode): def define_schema(cls): return IO.Schema( node_id="RecraftTextToVectorNode", - display_name="Recraft Text to Vector", + display_name="Recraft V3 Text to Vector", category="partner/image/Recraft", description="Generates SVG synchronously based on prompt and resolution.", inputs=[ @@ -1087,7 +1087,7 @@ class RecraftV4TextToImageNode(IO.ComfyNode): node_id="RecraftV4TextToImageNode", display_name="Recraft V4 Text to Image", category="partner/image/Recraft", - description="Generates images using Recraft V4 or V4 Pro models.", + description="Generates images using Recraft V4 and V4.1 models.", inputs=[ IO.String.Input( "prompt", @@ -1097,11 +1097,56 @@ class RecraftV4TextToImageNode(IO.ComfyNode): IO.String.Input( "negative_prompt", multiline=True, - tooltip="An optional text description of undesired elements on an image.", + tooltip="This input is ignored: negative prompt is not supported by " + "Recraft V4 and V4.1 models.", ), IO.DynamicCombo.Input( "model", options=[ + IO.DynamicCombo.Option( + "recraftv4_1", + [ + IO.Combo.Input( + "size", + options=RECRAFT_V4_SIZES, + default="1024x1024", + tooltip="The size of the generated image.", + ), + ], + ), + IO.DynamicCombo.Option( + "recraftv4_1_utility", + [ + IO.Combo.Input( + "size", + options=RECRAFT_V4_SIZES, + default="1024x1024", + tooltip="The size of the generated image.", + ), + ], + ), + IO.DynamicCombo.Option( + "recraftv4_1_pro", + [ + IO.Combo.Input( + "size", + options=RECRAFT_V4_PRO_SIZES, + default="2048x2048", + tooltip="The size of the generated image.", + ), + ], + ), + IO.DynamicCombo.Option( + "recraftv4_1_utility_pro", + [ + IO.Combo.Input( + "size", + options=RECRAFT_V4_PRO_SIZES, + default="2048x2048", + tooltip="The size of the generated image.", + ), + ], + ), IO.DynamicCombo.Option( "recraftv4", [ @@ -1162,7 +1207,14 @@ class RecraftV4TextToImageNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model", "n"]), expr=""" ( - $prices := {"recraftv4": 0.04, "recraftv4_pro": 0.25}; + $prices := { + "recraftv4_1": 0.035, + "recraftv4_1_utility": 0.035, + "recraftv4_1_pro": 0.21, + "recraftv4_1_utility_pro": 0.21, + "recraftv4": 0.04, + "recraftv4_pro": 0.25 + }; {"type":"usd","usd": $lookup($prices, widgets.model) * widgets.n} ) """, @@ -1179,14 +1231,13 @@ 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) + validate_string(prompt, strip_whitespace=True, min_length=1, max_length=10000) response = await sync_op( cls, ApiEndpoint(path="/proxy/recraft/image_generation", method="POST"), response_model=RecraftImageGenerationResponse, data=RecraftImageGenerationRequest( prompt=prompt, - negative_prompt=negative_prompt if negative_prompt else None, model=model["model"], size=model["size"], n=n, @@ -1211,7 +1262,7 @@ class RecraftV4TextToVectorNode(IO.ComfyNode): node_id="RecraftV4TextToVectorNode", display_name="Recraft V4 Text to Vector", category="partner/image/Recraft", - description="Generates SVG using Recraft V4 or V4 Pro models.", + description="Generates SVG using Recraft V4 and V4.1 models.", inputs=[ IO.String.Input( "prompt", @@ -1221,11 +1272,56 @@ class RecraftV4TextToVectorNode(IO.ComfyNode): IO.String.Input( "negative_prompt", multiline=True, - tooltip="An optional text description of undesired elements on an image.", + tooltip="This input is ignored: negative prompt is not supported by " + "Recraft V4 and V4.1 models.", ), IO.DynamicCombo.Input( "model", options=[ + IO.DynamicCombo.Option( + "recraftv4_1_vector", + [ + IO.Combo.Input( + "size", + options=RECRAFT_V4_SIZES, + default="1024x1024", + tooltip="The size of the generated image.", + ), + ], + ), + IO.DynamicCombo.Option( + "recraftv4_1_utility_vector", + [ + IO.Combo.Input( + "size", + options=RECRAFT_V4_SIZES, + default="1024x1024", + tooltip="The size of the generated image.", + ), + ], + ), + IO.DynamicCombo.Option( + "recraftv4_1_pro_vector", + [ + IO.Combo.Input( + "size", + options=RECRAFT_V4_PRO_SIZES, + default="2048x2048", + tooltip="The size of the generated image.", + ), + ], + ), + IO.DynamicCombo.Option( + "recraftv4_1_utility_pro_vector", + [ + IO.Combo.Input( + "size", + options=RECRAFT_V4_PRO_SIZES, + default="2048x2048", + tooltip="The size of the generated image.", + ), + ], + ), IO.DynamicCombo.Option( "recraftv4", [ @@ -1286,7 +1382,14 @@ class RecraftV4TextToVectorNode(IO.ComfyNode): depends_on=IO.PriceBadgeDepends(widgets=["model", "n"]), expr=""" ( - $prices := {"recraftv4": 0.08, "recraftv4_pro": 0.30}; + $prices := { + "recraftv4_1_vector": 0.08, + "recraftv4_1_utility_vector": 0.08, + "recraftv4_1_pro_vector": 0.30, + "recraftv4_1_utility_pro_vector": 0.30, + "recraftv4": 0.08, + "recraftv4_pro": 0.30 + }; {"type":"usd","usd": $lookup($prices, widgets.model) * widgets.n} ) """, @@ -1303,18 +1406,17 @@ 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) + validate_string(prompt, strip_whitespace=True, min_length=1, max_length=10000) response = await sync_op( cls, ApiEndpoint(path="/proxy/recraft/image_generation", method="POST"), response_model=RecraftImageGenerationResponse, data=RecraftImageGenerationRequest( prompt=prompt, - negative_prompt=negative_prompt if negative_prompt else None, model=model["model"], size=model["size"], n=n, - style="vector_illustration", + style=None if model["model"].endswith("_vector") else "vector_illustration", substyle=None, controls=recraft_controls.create_api_model() if recraft_controls else None, ),