Skip to content

Commit 05a258e

Browse files
authored
add WanImageToImageApi node (#10094)
1 parent c8276f8 commit 05a258e

File tree

1 file changed

+148
-1
lines changed

1 file changed

+148
-1
lines changed

comfy_api_nodes/nodes_wan.py

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ class Text2ImageInputField(BaseModel):
2828
negative_prompt: Optional[str] = Field(None)
2929

3030

31+
class Image2ImageInputField(BaseModel):
32+
prompt: str = Field(...)
33+
negative_prompt: Optional[str] = Field(None)
34+
images: list[str] = Field(..., min_length=1, max_length=2)
35+
36+
3137
class Text2VideoInputField(BaseModel):
3238
prompt: str = Field(...)
3339
negative_prompt: Optional[str] = Field(None)
@@ -49,6 +55,13 @@ class Txt2ImageParametersField(BaseModel):
4955
watermark: bool = Field(True)
5056

5157

58+
class Image2ImageParametersField(BaseModel):
59+
size: Optional[str] = Field(None)
60+
n: int = Field(1, description="Number of images to generate.") # we support only value=1
61+
seed: int = Field(..., ge=0, le=2147483647)
62+
watermark: bool = Field(True)
63+
64+
5265
class Text2VideoParametersField(BaseModel):
5366
size: str = Field(...)
5467
seed: int = Field(..., ge=0, le=2147483647)
@@ -73,6 +86,12 @@ class Text2ImageTaskCreationRequest(BaseModel):
7386
parameters: Txt2ImageParametersField = Field(...)
7487

7588

89+
class Image2ImageTaskCreationRequest(BaseModel):
90+
model: str = Field(...)
91+
input: Image2ImageInputField = Field(...)
92+
parameters: Image2ImageParametersField = Field(...)
93+
94+
7695
class Text2VideoTaskCreationRequest(BaseModel):
7796
model: str = Field(...)
7897
input: Text2VideoInputField = Field(...)
@@ -135,7 +154,12 @@ async def process_task(
135154
url: str,
136155
request_model: Type[T],
137156
response_model: Type[R],
138-
payload: Union[Text2ImageTaskCreationRequest, Text2VideoTaskCreationRequest, Image2VideoTaskCreationRequest],
157+
payload: Union[
158+
Text2ImageTaskCreationRequest,
159+
Image2ImageTaskCreationRequest,
160+
Text2VideoTaskCreationRequest,
161+
Image2VideoTaskCreationRequest,
162+
],
139163
node_id: str,
140164
estimated_duration: int,
141165
poll_interval: int,
@@ -288,6 +312,128 @@ async def execute(
288312
return comfy_io.NodeOutput(await download_url_to_image_tensor(str(response.output.results[0].url)))
289313

290314

315+
class WanImageToImageApi(comfy_io.ComfyNode):
316+
@classmethod
317+
def define_schema(cls):
318+
return comfy_io.Schema(
319+
node_id="WanImageToImageApi",
320+
display_name="Wan Image to Image",
321+
category="api node/image/Wan",
322+
description="Generates an image from one or two input images and a text prompt. "
323+
"The output image is currently fixed at 1.6 MP; its aspect ratio matches the input image(s).",
324+
inputs=[
325+
comfy_io.Combo.Input(
326+
"model",
327+
options=["wan2.5-i2i-preview"],
328+
default="wan2.5-i2i-preview",
329+
tooltip="Model to use.",
330+
),
331+
comfy_io.Image.Input(
332+
"image",
333+
tooltip="Single-image editing or multi-image fusion, maximum 2 images.",
334+
),
335+
comfy_io.String.Input(
336+
"prompt",
337+
multiline=True,
338+
default="",
339+
tooltip="Prompt used to describe the elements and visual features, supports English/Chinese.",
340+
),
341+
comfy_io.String.Input(
342+
"negative_prompt",
343+
multiline=True,
344+
default="",
345+
tooltip="Negative text prompt to guide what to avoid.",
346+
optional=True,
347+
),
348+
# redo this later as an optional combo of recommended resolutions
349+
# comfy_io.Int.Input(
350+
# "width",
351+
# default=1280,
352+
# min=384,
353+
# max=1440,
354+
# step=16,
355+
# optional=True,
356+
# ),
357+
# comfy_io.Int.Input(
358+
# "height",
359+
# default=1280,
360+
# min=384,
361+
# max=1440,
362+
# step=16,
363+
# optional=True,
364+
# ),
365+
comfy_io.Int.Input(
366+
"seed",
367+
default=0,
368+
min=0,
369+
max=2147483647,
370+
step=1,
371+
display_mode=comfy_io.NumberDisplay.number,
372+
control_after_generate=True,
373+
tooltip="Seed to use for generation.",
374+
optional=True,
375+
),
376+
comfy_io.Boolean.Input(
377+
"watermark",
378+
default=True,
379+
tooltip="Whether to add an \"AI generated\" watermark to the result.",
380+
optional=True,
381+
),
382+
],
383+
outputs=[
384+
comfy_io.Image.Output(),
385+
],
386+
hidden=[
387+
comfy_io.Hidden.auth_token_comfy_org,
388+
comfy_io.Hidden.api_key_comfy_org,
389+
comfy_io.Hidden.unique_id,
390+
],
391+
is_api_node=True,
392+
)
393+
394+
@classmethod
395+
async def execute(
396+
cls,
397+
model: str,
398+
image: torch.Tensor,
399+
prompt: str,
400+
negative_prompt: str = "",
401+
# width: int = 1024,
402+
# height: int = 1024,
403+
seed: int = 0,
404+
watermark: bool = True,
405+
):
406+
n_images = get_number_of_images(image)
407+
if n_images not in (1, 2):
408+
raise ValueError(f"Expected 1 or 2 input images, got {n_images}.")
409+
images = []
410+
for i in image:
411+
images.append("data:image/png;base64," + tensor_to_base64_string(i, total_pixels=4096*4096))
412+
payload = Image2ImageTaskCreationRequest(
413+
model=model,
414+
input=Image2ImageInputField(prompt=prompt, negative_prompt=negative_prompt, images=images),
415+
parameters=Image2ImageParametersField(
416+
# size=f"{width}*{height}",
417+
seed=seed,
418+
watermark=watermark,
419+
),
420+
)
421+
response = await process_task(
422+
{
423+
"auth_token": cls.hidden.auth_token_comfy_org,
424+
"comfy_api_key": cls.hidden.api_key_comfy_org,
425+
},
426+
"/proxy/wan/api/v1/services/aigc/image2image/image-synthesis",
427+
request_model=Image2ImageTaskCreationRequest,
428+
response_model=ImageTaskStatusResponse,
429+
payload=payload,
430+
node_id=cls.hidden.unique_id,
431+
estimated_duration=42,
432+
poll_interval=3,
433+
)
434+
return comfy_io.NodeOutput(await download_url_to_image_tensor(str(response.output.results[0].url)))
435+
436+
291437
class WanTextToVideoApi(comfy_io.ComfyNode):
292438
@classmethod
293439
def define_schema(cls):
@@ -593,6 +739,7 @@ class WanApiExtension(ComfyExtension):
593739
async def get_node_list(self) -> list[type[comfy_io.ComfyNode]]:
594740
return [
595741
WanTextToImageApi,
742+
WanImageToImageApi,
596743
WanTextToVideoApi,
597744
WanImageToVideoApi,
598745
]

0 commit comments

Comments
 (0)