1- from inspect import cleandoc
2-
31import torch
42from pydantic import BaseModel
53from typing_extensions import override
64
7- from comfy_api .latest import IO , ComfyExtension
5+ from comfy_api .latest import IO , ComfyExtension , Input
86from comfy_api_nodes .apis .bfl_api import (
97 BFLFluxExpandImageRequest ,
108 BFLFluxFillImageRequest ,
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
4038class 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
157152class 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
273265class 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
284273class 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
420406class 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
526509class 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+
635628class 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