Skip to content

Commit 50333f1

Browse files
authored
api nodes(Ideogram): add Ideogram Character (#9616)
* api nodes(Ideogram): add Ideogram Character * rename renderingSpeed default value from 'balanced' to 'default'
1 parent 26d5b86 commit 50333f1

File tree

2 files changed

+91
-8
lines changed

2 files changed

+91
-8
lines changed

comfy_api_nodes/apis/__init__.py

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

comfy_api_nodes/nodes_ideogram.py

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ def define_schema(cls):
255255
display_name="Ideogram V1",
256256
category="api node/image/Ideogram",
257257
description="Generates images using the Ideogram V1 model.",
258+
is_api_node=True,
258259
inputs=[
259260
comfy_io.String.Input(
260261
"prompt",
@@ -383,6 +384,7 @@ def define_schema(cls):
383384
display_name="Ideogram V2",
384385
category="api node/image/Ideogram",
385386
description="Generates images using the Ideogram V2 model.",
387+
is_api_node=True,
386388
inputs=[
387389
comfy_io.String.Input(
388390
"prompt",
@@ -552,6 +554,7 @@ def define_schema(cls):
552554
category="api node/image/Ideogram",
553555
description="Generates images using the Ideogram V3 model. "
554556
"Supports both regular image generation from text prompts and image editing with mask.",
557+
is_api_node=True,
555558
inputs=[
556559
comfy_io.String.Input(
557560
"prompt",
@@ -612,11 +615,21 @@ def define_schema(cls):
612615
),
613616
comfy_io.Combo.Input(
614617
"rendering_speed",
615-
options=["BALANCED", "TURBO", "QUALITY"],
616-
default="BALANCED",
618+
options=["DEFAULT", "TURBO", "QUALITY"],
619+
default="DEFAULT",
617620
tooltip="Controls the trade-off between generation speed and quality",
618621
optional=True,
619622
),
623+
comfy_io.Image.Input(
624+
"character_image",
625+
tooltip="Image to use as character reference.",
626+
optional=True,
627+
),
628+
comfy_io.Mask.Input(
629+
"character_mask",
630+
tooltip="Optional mask for character reference image.",
631+
optional=True,
632+
),
620633
],
621634
outputs=[
622635
comfy_io.Image.Output(),
@@ -639,12 +652,46 @@ async def execute(
639652
magic_prompt_option="AUTO",
640653
seed=0,
641654
num_images=1,
642-
rendering_speed="BALANCED",
655+
rendering_speed="DEFAULT",
656+
character_image=None,
657+
character_mask=None,
643658
):
644659
auth = {
645660
"auth_token": cls.hidden.auth_token_comfy_org,
646661
"comfy_api_key": cls.hidden.api_key_comfy_org,
647662
}
663+
if rendering_speed == "BALANCED": # for backward compatibility
664+
rendering_speed = "DEFAULT"
665+
666+
character_img_binary = None
667+
character_mask_binary = None
668+
669+
if character_image is not None:
670+
input_tensor = character_image.squeeze().cpu()
671+
if character_mask is not None:
672+
character_mask = resize_mask_to_image(character_mask, character_image, allow_gradient=False)
673+
character_mask = 1.0 - character_mask
674+
if character_mask.shape[1:] != character_image.shape[1:-1]:
675+
raise Exception("Character mask and image must be the same size")
676+
677+
mask_np = (character_mask.squeeze().cpu().numpy() * 255).astype(np.uint8)
678+
mask_img = Image.fromarray(mask_np)
679+
mask_byte_arr = BytesIO()
680+
mask_img.save(mask_byte_arr, format="PNG")
681+
mask_byte_arr.seek(0)
682+
character_mask_binary = mask_byte_arr
683+
character_mask_binary.name = "mask.png"
684+
685+
img_np = (input_tensor.numpy() * 255).astype(np.uint8)
686+
img = Image.fromarray(img_np)
687+
img_byte_arr = BytesIO()
688+
img.save(img_byte_arr, format="PNG")
689+
img_byte_arr.seek(0)
690+
character_img_binary = img_byte_arr
691+
character_img_binary.name = "image.png"
692+
elif character_mask is not None:
693+
raise Exception("Character mask requires character image to be present")
694+
648695
# Check if both image and mask are provided for editing mode
649696
if image is not None and mask is not None:
650697
# Edit mode
@@ -693,6 +740,15 @@ async def execute(
693740
if num_images > 1:
694741
edit_request.num_images = num_images
695742

743+
files = {
744+
"image": img_binary,
745+
"mask": mask_binary,
746+
}
747+
if character_img_binary:
748+
files["character_reference_images"] = character_img_binary
749+
if character_mask_binary:
750+
files["character_mask_binary"] = character_mask_binary
751+
696752
# Execute the operation for edit mode
697753
operation = SynchronousOperation(
698754
endpoint=ApiEndpoint(
@@ -702,10 +758,7 @@ async def execute(
702758
response_model=IdeogramGenerateResponse,
703759
),
704760
request=edit_request,
705-
files={
706-
"image": img_binary,
707-
"mask": mask_binary,
708-
},
761+
files=files,
709762
content_type="multipart/form-data",
710763
auth_kwargs=auth,
711764
)
@@ -739,6 +792,14 @@ async def execute(
739792
if num_images > 1:
740793
gen_request.num_images = num_images
741794

795+
files = {}
796+
if character_img_binary:
797+
files["character_reference_images"] = character_img_binary
798+
if character_mask_binary:
799+
files["character_mask_binary"] = character_mask_binary
800+
if files:
801+
gen_request.style_type = "AUTO"
802+
742803
# Execute the operation for generation mode
743804
operation = SynchronousOperation(
744805
endpoint=ApiEndpoint(
@@ -748,6 +809,8 @@ async def execute(
748809
response_model=IdeogramGenerateResponse,
749810
),
750811
request=gen_request,
812+
files=files if files else None,
813+
content_type="multipart/form-data",
751814
auth_kwargs=auth,
752815
)
753816

0 commit comments

Comments
 (0)