[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 <bigcat88@icloud.com>

* [Partner Nodes] chore(Recraft): change old nodes names to contain "V3"

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* [Partner Nodes] fix(Recraft): remove v4 model from the image edit nodes; fix the default "strength" value

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* [Partner Nodes] chore(Recraft): remove new image edit nodes

Signed-off-by: bigcat88 <bigcat88@icloud.com>

---------

Signed-off-by: bigcat88 <bigcat88@icloud.com>
This commit is contained in:
Alexander Piskun
2026-07-28 18:39:34 +03:00
committed by GitHub
parent cd0eddaf16
commit f4509ff213
2 changed files with 118 additions and 16 deletions

View File

@@ -244,10 +244,10 @@ RECRAFT_V4_PRO_SIZES = [
"2304x1792", "2304x1792",
"1792x2304", "1792x2304",
"1664x2688", "1664x2688",
"1434x1024",
"1024x1434",
"2560x1792", "2560x1792",
"1792x2560", "1792x2560",
"2688x1536",
"1536x2688",
] ]

View File

@@ -399,7 +399,7 @@ class RecraftTextToImageNode(IO.ComfyNode):
def define_schema(cls): def define_schema(cls):
return IO.Schema( return IO.Schema(
node_id="RecraftTextToImageNode", node_id="RecraftTextToImageNode",
display_name="Recraft Text to Image", display_name="Recraft V3 Text to Image",
category="partner/image/Recraft", category="partner/image/Recraft",
description="Generates images synchronously based on prompt and resolution.", description="Generates images synchronously based on prompt and resolution.",
inputs=[ inputs=[
@@ -511,7 +511,7 @@ class RecraftImageToImageNode(IO.ComfyNode):
def define_schema(cls): def define_schema(cls):
return IO.Schema( return IO.Schema(
node_id="RecraftImageToImageNode", node_id="RecraftImageToImageNode",
display_name="Recraft Image to Image", display_name="Recraft V3 Image to Image",
category="partner/image/Recraft", category="partner/image/Recraft",
description="Modify image based on prompt and strength.", description="Modify image based on prompt and strength.",
inputs=[ inputs=[
@@ -731,7 +731,7 @@ class RecraftTextToVectorNode(IO.ComfyNode):
def define_schema(cls): def define_schema(cls):
return IO.Schema( return IO.Schema(
node_id="RecraftTextToVectorNode", node_id="RecraftTextToVectorNode",
display_name="Recraft Text to Vector", display_name="Recraft V3 Text to Vector",
category="partner/image/Recraft", category="partner/image/Recraft",
description="Generates SVG synchronously based on prompt and resolution.", description="Generates SVG synchronously based on prompt and resolution.",
inputs=[ inputs=[
@@ -1087,7 +1087,7 @@ class RecraftV4TextToImageNode(IO.ComfyNode):
node_id="RecraftV4TextToImageNode", node_id="RecraftV4TextToImageNode",
display_name="Recraft V4 Text to Image", display_name="Recraft V4 Text to Image",
category="partner/image/Recraft", 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=[ inputs=[
IO.String.Input( IO.String.Input(
"prompt", "prompt",
@@ -1097,11 +1097,56 @@ class RecraftV4TextToImageNode(IO.ComfyNode):
IO.String.Input( IO.String.Input(
"negative_prompt", "negative_prompt",
multiline=True, 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( IO.DynamicCombo.Input(
"model", "model",
options=[ 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( IO.DynamicCombo.Option(
"recraftv4", "recraftv4",
[ [
@@ -1162,7 +1207,14 @@ class RecraftV4TextToImageNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["model", "n"]), depends_on=IO.PriceBadgeDepends(widgets=["model", "n"]),
expr=""" 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} {"type":"usd","usd": $lookup($prices, widgets.model) * widgets.n}
) )
""", """,
@@ -1179,14 +1231,13 @@ class RecraftV4TextToImageNode(IO.ComfyNode):
seed: int, seed: int,
recraft_controls: RecraftControls | None = None, recraft_controls: RecraftControls | None = None,
) -> IO.NodeOutput: ) -> 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( response = await sync_op(
cls, cls,
ApiEndpoint(path="/proxy/recraft/image_generation", method="POST"), ApiEndpoint(path="/proxy/recraft/image_generation", method="POST"),
response_model=RecraftImageGenerationResponse, response_model=RecraftImageGenerationResponse,
data=RecraftImageGenerationRequest( data=RecraftImageGenerationRequest(
prompt=prompt, prompt=prompt,
negative_prompt=negative_prompt if negative_prompt else None,
model=model["model"], model=model["model"],
size=model["size"], size=model["size"],
n=n, n=n,
@@ -1211,7 +1262,7 @@ class RecraftV4TextToVectorNode(IO.ComfyNode):
node_id="RecraftV4TextToVectorNode", node_id="RecraftV4TextToVectorNode",
display_name="Recraft V4 Text to Vector", display_name="Recraft V4 Text to Vector",
category="partner/image/Recraft", 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=[ inputs=[
IO.String.Input( IO.String.Input(
"prompt", "prompt",
@@ -1221,11 +1272,56 @@ class RecraftV4TextToVectorNode(IO.ComfyNode):
IO.String.Input( IO.String.Input(
"negative_prompt", "negative_prompt",
multiline=True, 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( IO.DynamicCombo.Input(
"model", "model",
options=[ 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( IO.DynamicCombo.Option(
"recraftv4", "recraftv4",
[ [
@@ -1286,7 +1382,14 @@ class RecraftV4TextToVectorNode(IO.ComfyNode):
depends_on=IO.PriceBadgeDepends(widgets=["model", "n"]), depends_on=IO.PriceBadgeDepends(widgets=["model", "n"]),
expr=""" 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} {"type":"usd","usd": $lookup($prices, widgets.model) * widgets.n}
) )
""", """,
@@ -1303,18 +1406,17 @@ class RecraftV4TextToVectorNode(IO.ComfyNode):
seed: int, seed: int,
recraft_controls: RecraftControls | None = None, recraft_controls: RecraftControls | None = None,
) -> IO.NodeOutput: ) -> 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( response = await sync_op(
cls, cls,
ApiEndpoint(path="/proxy/recraft/image_generation", method="POST"), ApiEndpoint(path="/proxy/recraft/image_generation", method="POST"),
response_model=RecraftImageGenerationResponse, response_model=RecraftImageGenerationResponse,
data=RecraftImageGenerationRequest( data=RecraftImageGenerationRequest(
prompt=prompt, prompt=prompt,
negative_prompt=negative_prompt if negative_prompt else None,
model=model["model"], model=model["model"],
size=model["size"], size=model["size"],
n=n, n=n,
style="vector_illustration", style=None if model["model"].endswith("_vector") else "vector_illustration",
substyle=None, substyle=None,
controls=recraft_controls.create_api_model() if recraft_controls else None, controls=recraft_controls.create_api_model() if recraft_controls else None,
), ),