mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-01-31 16:50:17 +08:00
feat(api-nodes): add RecraftCreateStyleNode node (#12055)
Co-authored-by: Jedrzej Kosinski <kosinkadink1@gmail.com>
This commit is contained in:
parent
0a7993729c
commit
0167653781
@ -1,11 +1,8 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from pydantic import BaseModel, Field, conint, confloat
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class RecraftColor:
|
class RecraftColor:
|
||||||
@ -229,24 +226,24 @@ class RecraftColorObject(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class RecraftControlsObject(BaseModel):
|
class RecraftControlsObject(BaseModel):
|
||||||
colors: Optional[list[RecraftColorObject]] = Field(None, description='An array of preferable colors')
|
colors: list[RecraftColorObject] | None = Field(None, description='An array of preferable colors')
|
||||||
background_color: Optional[RecraftColorObject] = Field(None, description='Use given color as a desired background color')
|
background_color: RecraftColorObject | None = Field(None, description='Use given color as a desired background color')
|
||||||
no_text: Optional[bool] = Field(None, description='Do not embed text layouts')
|
no_text: bool | None = Field(None, description='Do not embed text layouts')
|
||||||
artistic_level: Optional[conint(ge=0, le=5)] = Field(None, description='Defines artistic tone of your image. At a simple level, the person looks straight at the camera in a static and clean style. Dynamic and eccentric levels introduce movement and creativity. The value should be in range [0..5].')
|
artistic_level: int | None = Field(None, description='Defines artistic tone of your image. At a simple level, the person looks straight at the camera in a static and clean style. Dynamic and eccentric levels introduce movement and creativity. The value should be in range [0..5].')
|
||||||
|
|
||||||
|
|
||||||
class RecraftImageGenerationRequest(BaseModel):
|
class RecraftImageGenerationRequest(BaseModel):
|
||||||
prompt: str = Field(..., description='The text prompt describing the image to generate')
|
prompt: str = Field(..., description='The text prompt describing the image to generate')
|
||||||
size: Optional[RecraftImageSize] = Field(None, description='The size of the generated image (e.g., "1024x1024")')
|
size: RecraftImageSize | None = Field(None, description='The size of the generated image (e.g., "1024x1024")')
|
||||||
n: conint(ge=1, le=6) = Field(..., description='The number of images to generate')
|
n: int = Field(..., description='The number of images to generate')
|
||||||
negative_prompt: Optional[str] = Field(None, description='A text description of undesired elements on an image')
|
negative_prompt: str | None = Field(None, description='A text description of undesired elements on an image')
|
||||||
model: Optional[RecraftModel] = Field(RecraftModel.recraftv3, description='The model to use for generation (e.g., "recraftv3")')
|
model: RecraftModel | None = Field(RecraftModel.recraftv3, description='The model to use for generation (e.g., "recraftv3")')
|
||||||
style: Optional[str] = Field(None, description='The style to apply to the generated image (e.g., "digital_illustration")')
|
style: str | None = Field(None, description='The style to apply to the generated image (e.g., "digital_illustration")')
|
||||||
substyle: Optional[str] = Field(None, description='The substyle to apply to the generated image, depending on the style input')
|
substyle: str | None = Field(None, description='The substyle to apply to the generated image, depending on the style input')
|
||||||
controls: Optional[RecraftControlsObject] = Field(None, description='A set of custom parameters to tweak generation process')
|
controls: RecraftControlsObject | None = Field(None, description='A set of custom parameters to tweak generation process')
|
||||||
style_id: Optional[str] = Field(None, description='Use a previously uploaded style as a reference; UUID')
|
style_id: str | None = Field(None, description='Use a previously uploaded style as a reference; UUID')
|
||||||
strength: Optional[confloat(ge=0.0, le=1.0)] = Field(None, description='Defines the difference with the original image, should lie in [0, 1], where 0 means almost identical, and 1 means miserable similarity')
|
strength: float | None = Field(None, description='Defines the difference with the original image, should lie in [0, 1], where 0 means almost identical, and 1 means miserable similarity')
|
||||||
random_seed: Optional[int] = Field(None, description="Seed for video generation")
|
random_seed: int | None = Field(None, description="Seed for video generation")
|
||||||
# text_layout
|
# text_layout
|
||||||
|
|
||||||
|
|
||||||
@ -258,5 +255,13 @@ class RecraftReturnedObject(BaseModel):
|
|||||||
class RecraftImageGenerationResponse(BaseModel):
|
class RecraftImageGenerationResponse(BaseModel):
|
||||||
created: int = Field(..., description='Unix timestamp when the generation was created')
|
created: int = Field(..., description='Unix timestamp when the generation was created')
|
||||||
credits: int = Field(..., description='Number of credits used for the generation')
|
credits: int = Field(..., description='Number of credits used for the generation')
|
||||||
data: Optional[list[RecraftReturnedObject]] = Field(None, description='Array of generated image information')
|
data: list[RecraftReturnedObject] | None = Field(None, description='Array of generated image information')
|
||||||
image: Optional[RecraftReturnedObject] = Field(None, description='Single generated image')
|
image: RecraftReturnedObject | None = Field(None, description='Single generated image')
|
||||||
|
|
||||||
|
|
||||||
|
class RecraftCreateStyleRequest(BaseModel):
|
||||||
|
style: str = Field(..., description="realistic_image, digital_illustration, vector_illustration, or icon")
|
||||||
|
|
||||||
|
|
||||||
|
class RecraftCreateStyleResponse(BaseModel):
|
||||||
|
id: str = Field(..., description="UUID of the created style")
|
||||||
|
|||||||
@ -12,6 +12,8 @@ from comfy_api_nodes.apis.recraft import (
|
|||||||
RecraftColor,
|
RecraftColor,
|
||||||
RecraftColorChain,
|
RecraftColorChain,
|
||||||
RecraftControls,
|
RecraftControls,
|
||||||
|
RecraftCreateStyleRequest,
|
||||||
|
RecraftCreateStyleResponse,
|
||||||
RecraftImageGenerationRequest,
|
RecraftImageGenerationRequest,
|
||||||
RecraftImageGenerationResponse,
|
RecraftImageGenerationResponse,
|
||||||
RecraftImageSize,
|
RecraftImageSize,
|
||||||
@ -323,6 +325,75 @@ class RecraftStyleInfiniteStyleLibrary(IO.ComfyNode):
|
|||||||
return IO.NodeOutput(RecraftStyle(style_id=style_id))
|
return IO.NodeOutput(RecraftStyle(style_id=style_id))
|
||||||
|
|
||||||
|
|
||||||
|
class RecraftCreateStyleNode(IO.ComfyNode):
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="RecraftCreateStyleNode",
|
||||||
|
display_name="Recraft Create Style",
|
||||||
|
category="api node/image/Recraft",
|
||||||
|
description="Create a custom style from reference images. "
|
||||||
|
"Upload 1-5 images to use as style references. "
|
||||||
|
"Total size of all images is limited to 5 MB.",
|
||||||
|
inputs=[
|
||||||
|
IO.Combo.Input(
|
||||||
|
"style",
|
||||||
|
options=["realistic_image", "digital_illustration"],
|
||||||
|
tooltip="The base style of the generated images.",
|
||||||
|
),
|
||||||
|
IO.Autogrow.Input(
|
||||||
|
"images",
|
||||||
|
template=IO.Autogrow.TemplatePrefix(
|
||||||
|
IO.Image.Input("image"),
|
||||||
|
prefix="image",
|
||||||
|
min=1,
|
||||||
|
max=5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
IO.String.Output(display_name="style_id"),
|
||||||
|
],
|
||||||
|
hidden=[
|
||||||
|
IO.Hidden.auth_token_comfy_org,
|
||||||
|
IO.Hidden.api_key_comfy_org,
|
||||||
|
IO.Hidden.unique_id,
|
||||||
|
],
|
||||||
|
is_api_node=True,
|
||||||
|
price_badge=IO.PriceBadge(
|
||||||
|
expr="""{"type":"usd","usd": 0.04}""",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(
|
||||||
|
cls,
|
||||||
|
style: str,
|
||||||
|
images: IO.Autogrow.Type,
|
||||||
|
) -> IO.NodeOutput:
|
||||||
|
files = []
|
||||||
|
total_size = 0
|
||||||
|
max_total_size = 5 * 1024 * 1024 # 5 MB limit
|
||||||
|
for i, img in enumerate(list(images.values())):
|
||||||
|
file_bytes = tensor_to_bytesio(img, total_pixels=2048 * 2048, mime_type="image/webp").read()
|
||||||
|
total_size += len(file_bytes)
|
||||||
|
if total_size > max_total_size:
|
||||||
|
raise Exception("Total size of all images exceeds 5 MB limit.")
|
||||||
|
files.append((f"file{i + 1}", file_bytes))
|
||||||
|
|
||||||
|
response = await sync_op(
|
||||||
|
cls,
|
||||||
|
endpoint=ApiEndpoint(path="/proxy/recraft/styles", method="POST"),
|
||||||
|
response_model=RecraftCreateStyleResponse,
|
||||||
|
files=files,
|
||||||
|
data=RecraftCreateStyleRequest(style=style),
|
||||||
|
content_type="multipart/form-data",
|
||||||
|
max_retries=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
return IO.NodeOutput(response.id)
|
||||||
|
|
||||||
|
|
||||||
class RecraftTextToImageNode(IO.ComfyNode):
|
class RecraftTextToImageNode(IO.ComfyNode):
|
||||||
@classmethod
|
@classmethod
|
||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
@ -395,7 +466,7 @@ class RecraftTextToImageNode(IO.ComfyNode):
|
|||||||
negative_prompt: str = None,
|
negative_prompt: str = None,
|
||||||
recraft_controls: RecraftControls = None,
|
recraft_controls: RecraftControls = None,
|
||||||
) -> IO.NodeOutput:
|
) -> IO.NodeOutput:
|
||||||
validate_string(prompt, strip_whitespace=False, max_length=1000)
|
validate_string(prompt, strip_whitespace=False, min_length=1, max_length=1000)
|
||||||
default_style = RecraftStyle(RecraftStyleV3.realistic_image)
|
default_style = RecraftStyle(RecraftStyleV3.realistic_image)
|
||||||
if recraft_style is None:
|
if recraft_style is None:
|
||||||
recraft_style = default_style
|
recraft_style = default_style
|
||||||
@ -1024,6 +1095,7 @@ class RecraftExtension(ComfyExtension):
|
|||||||
RecraftStyleV3DigitalIllustrationNode,
|
RecraftStyleV3DigitalIllustrationNode,
|
||||||
RecraftStyleV3LogoRasterNode,
|
RecraftStyleV3LogoRasterNode,
|
||||||
RecraftStyleInfiniteStyleLibrary,
|
RecraftStyleInfiniteStyleLibrary,
|
||||||
|
RecraftCreateStyleNode,
|
||||||
RecraftColorRGBNode,
|
RecraftColorRGBNode,
|
||||||
RecraftControlsNode,
|
RecraftControlsNode,
|
||||||
]
|
]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user