Skip to content

Commit 5b4d066

Browse files
authored
add Flux2MaxImage API Node (#11420)
1 parent 894802b commit 5b4d066

File tree

1 file changed

+31
-37
lines changed

1 file changed

+31
-37
lines changed

comfy_api_nodes/nodes_bfl.py

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
from inspect import cleandoc
2-
31
import torch
42
from pydantic import BaseModel
53
from typing_extensions import override
64

7-
from comfy_api.latest import IO, ComfyExtension
5+
from comfy_api.latest import IO, ComfyExtension, Input
86
from comfy_api_nodes.apis.bfl_api import (
97
BFLFluxExpandImageRequest,
108
BFLFluxFillImageRequest,
@@ -28,7 +26,7 @@
2826
)
2927

3028

31-
def convert_mask_to_image(mask: torch.Tensor):
29+
def convert_mask_to_image(mask: Input.Image):
3230
"""
3331
Make mask have the expected amount of dims (4) and channels (3) to be recognized as an image.
3432
"""
@@ -38,17 +36,14 @@ def convert_mask_to_image(mask: torch.Tensor):
3836

3937

4038
class FluxProUltraImageNode(IO.ComfyNode):
41-
"""
42-
Generates images using Flux Pro 1.1 Ultra via api based on prompt and resolution.
43-
"""
4439

4540
@classmethod
4641
def define_schema(cls) -> IO.Schema:
4742
return IO.Schema(
4843
node_id="FluxProUltraImageNode",
4944
display_name="Flux 1.1 [pro] Ultra Image",
5045
category="api node/image/BFL",
51-
description=cleandoc(cls.__doc__ or ""),
46+
description="Generates images using Flux Pro 1.1 Ultra via api based on prompt and resolution.",
5247
inputs=[
5348
IO.String.Input(
5449
"prompt",
@@ -117,7 +112,7 @@ async def execute(
117112
prompt_upsampling: bool = False,
118113
raw: bool = False,
119114
seed: int = 0,
120-
image_prompt: torch.Tensor | None = None,
115+
image_prompt: Input.Image | None = None,
121116
image_prompt_strength: float = 0.1,
122117
) -> IO.NodeOutput:
123118
if image_prompt is None:
@@ -155,17 +150,14 @@ async def execute(
155150

156151

157152
class FluxKontextProImageNode(IO.ComfyNode):
158-
"""
159-
Edits images using Flux.1 Kontext [pro] via api based on prompt and aspect ratio.
160-
"""
161153

162154
@classmethod
163155
def define_schema(cls) -> IO.Schema:
164156
return IO.Schema(
165157
node_id=cls.NODE_ID,
166158
display_name=cls.DISPLAY_NAME,
167159
category="api node/image/BFL",
168-
description=cleandoc(cls.__doc__ or ""),
160+
description="Edits images using Flux.1 Kontext [pro] via api based on prompt and aspect ratio.",
169161
inputs=[
170162
IO.String.Input(
171163
"prompt",
@@ -231,7 +223,7 @@ async def execute(
231223
aspect_ratio: str,
232224
guidance: float,
233225
steps: int,
234-
input_image: torch.Tensor | None = None,
226+
input_image: Input.Image | None = None,
235227
seed=0,
236228
prompt_upsampling=False,
237229
) -> IO.NodeOutput:
@@ -271,28 +263,22 @@ async def execute(
271263

272264

273265
class FluxKontextMaxImageNode(FluxKontextProImageNode):
274-
"""
275-
Edits images using Flux.1 Kontext [max] via api based on prompt and aspect ratio.
276-
"""
277266

278-
DESCRIPTION = cleandoc(__doc__ or "")
267+
DESCRIPTION = "Edits images using Flux.1 Kontext [max] via api based on prompt and aspect ratio."
279268
BFL_PATH = "/proxy/bfl/flux-kontext-max/generate"
280269
NODE_ID = "FluxKontextMaxImageNode"
281270
DISPLAY_NAME = "Flux.1 Kontext [max] Image"
282271

283272

284273
class FluxProExpandNode(IO.ComfyNode):
285-
"""
286-
Outpaints image based on prompt.
287-
"""
288274

289275
@classmethod
290276
def define_schema(cls) -> IO.Schema:
291277
return IO.Schema(
292278
node_id="FluxProExpandNode",
293279
display_name="Flux.1 Expand Image",
294280
category="api node/image/BFL",
295-
description=cleandoc(cls.__doc__ or ""),
281+
description="Outpaints image based on prompt.",
296282
inputs=[
297283
IO.Image.Input("image"),
298284
IO.String.Input(
@@ -371,7 +357,7 @@ def define_schema(cls) -> IO.Schema:
371357
@classmethod
372358
async def execute(
373359
cls,
374-
image: torch.Tensor,
360+
image: Input.Image,
375361
prompt: str,
376362
prompt_upsampling: bool,
377363
top: int,
@@ -418,17 +404,14 @@ async def execute(
418404

419405

420406
class FluxProFillNode(IO.ComfyNode):
421-
"""
422-
Inpaints image based on mask and prompt.
423-
"""
424407

425408
@classmethod
426409
def define_schema(cls) -> IO.Schema:
427410
return IO.Schema(
428411
node_id="FluxProFillNode",
429412
display_name="Flux.1 Fill Image",
430413
category="api node/image/BFL",
431-
description=cleandoc(cls.__doc__ or ""),
414+
description="Inpaints image based on mask and prompt.",
432415
inputs=[
433416
IO.Image.Input("image"),
434417
IO.Mask.Input("mask"),
@@ -480,8 +463,8 @@ def define_schema(cls) -> IO.Schema:
480463
@classmethod
481464
async def execute(
482465
cls,
483-
image: torch.Tensor,
484-
mask: torch.Tensor,
466+
image: Input.Image,
467+
mask: Input.Image,
485468
prompt: str,
486469
prompt_upsampling: bool,
487470
steps: int,
@@ -525,11 +508,15 @@ async def execute(
525508

526509
class Flux2ProImageNode(IO.ComfyNode):
527510

511+
NODE_ID = "Flux2ProImageNode"
512+
DISPLAY_NAME = "Flux.2 [pro] Image"
513+
API_ENDPOINT = "/proxy/bfl/flux-2-pro/generate"
514+
528515
@classmethod
529516
def define_schema(cls) -> IO.Schema:
530517
return IO.Schema(
531-
node_id="Flux2ProImageNode",
532-
display_name="Flux.2 [pro] Image",
518+
node_id=cls.NODE_ID,
519+
display_name=cls.DISPLAY_NAME,
533520
category="api node/image/BFL",
534521
description="Generates images synchronously based on prompt and resolution.",
535522
inputs=[
@@ -563,12 +550,11 @@ def define_schema(cls) -> IO.Schema:
563550
),
564551
IO.Boolean.Input(
565552
"prompt_upsampling",
566-
default=False,
553+
default=True,
567554
tooltip="Whether to perform upsampling on the prompt. "
568-
"If active, automatically modifies the prompt for more creative generation, "
569-
"but results are nondeterministic (same seed will not produce exactly the same result).",
555+
"If active, automatically modifies the prompt for more creative generation.",
570556
),
571-
IO.Image.Input("images", optional=True, tooltip="Up to 4 images to be used as references."),
557+
IO.Image.Input("images", optional=True, tooltip="Up to 9 images to be used as references."),
572558
],
573559
outputs=[IO.Image.Output()],
574560
hidden=[
@@ -587,7 +573,7 @@ async def execute(
587573
height: int,
588574
seed: int,
589575
prompt_upsampling: bool,
590-
images: torch.Tensor | None = None,
576+
images: Input.Image | None = None,
591577
) -> IO.NodeOutput:
592578
reference_images = {}
593579
if images is not None:
@@ -598,7 +584,7 @@ async def execute(
598584
reference_images[key_name] = tensor_to_base64_string(images[image_index], total_pixels=2048 * 2048)
599585
initial_response = await sync_op(
600586
cls,
601-
ApiEndpoint(path="/proxy/bfl/flux-2-pro/generate", method="POST"),
587+
ApiEndpoint(path=cls.API_ENDPOINT, method="POST"),
602588
response_model=BFLFluxProGenerateResponse,
603589
data=Flux2ProGenerateRequest(
604590
prompt=prompt,
@@ -632,6 +618,13 @@ def price_extractor(_r: BaseModel) -> float | None:
632618
return IO.NodeOutput(await download_url_to_image_tensor(response.result["sample"]))
633619

634620

621+
class Flux2MaxImageNode(Flux2ProImageNode):
622+
623+
NODE_ID = "Flux2MaxImageNode"
624+
DISPLAY_NAME = "Flux.2 [max] Image"
625+
API_ENDPOINT = "/proxy/bfl/flux-2-max/generate"
626+
627+
635628
class BFLExtension(ComfyExtension):
636629
@override
637630
async def get_node_list(self) -> list[type[IO.ComfyNode]]:
@@ -642,6 +635,7 @@ async def get_node_list(self) -> list[type[IO.ComfyNode]]:
642635
FluxProExpandNode,
643636
FluxProFillNode,
644637
Flux2ProImageNode,
638+
Flux2MaxImageNode,
645639
]
646640

647641

0 commit comments

Comments
 (0)