49
49
unpack ,
50
50
)
51
51
from invokeai .backend .flux .text_conditioning import FluxReduxConditioning , FluxTextConditioning
52
- from invokeai .backend .model_manager .config import ModelFormat
52
+ from invokeai .backend .model_manager .config import ModelFormat , ModelVariantType
53
53
from invokeai .backend .patches .layer_patcher import LayerPatcher
54
54
from invokeai .backend .patches .lora_conversions .flux_lora_constants import FLUX_LORA_TRANSFORMER_PREFIX
55
55
from invokeai .backend .patches .model_patch_raw import ModelPatchRaw
@@ -267,22 +267,19 @@ def _run_diffusion(
267
267
if is_schnell and self .control_lora :
268
268
raise ValueError ("Control LoRAs cannot be used with FLUX Schnell" )
269
269
270
- # TODO(ryand): It's a bit confusing that we support inpainting via both FLUX Fill and masked image-to-image.
271
- # Think about ways to tidy this interface, or at least add clear error messages when incompatible inputs are
272
- # provided.
273
-
274
- # Prepare the extra image conditioning tensor if either of the following are provided:
275
- # - FLUX structural control image
276
- # - FLUX Fill conditioning
270
+ # Prepare the extra image conditioning tensor (img_cond) for either FLUX structural control or FLUX Fill.
277
271
img_cond : torch .Tensor | None = None
278
- if self .control_lora is not None and self .fill_conditioning is not None :
279
- raise ValueError ("Control LoRA and Fill conditioning cannot be used together." )
280
- elif self .control_lora is not None :
281
- img_cond = self ._prep_structural_control_img_cond (context )
282
- elif self .fill_conditioning is not None :
272
+ is_flux_fill = transformer_config .variant == ModelVariantType .Inpaint # type: ignore
273
+ if is_flux_fill :
283
274
img_cond = self ._prep_flux_fill_img_cond (
284
275
context , device = TorchDevice .choose_torch_device (), dtype = inference_dtype
285
276
)
277
+ else :
278
+ if self .fill_conditioning is not None :
279
+ raise ValueError ("fill_conditioning was provided, but the model is not a FLUX Fill model." )
280
+
281
+ if self .control_lora is not None :
282
+ img_cond = self ._prep_structural_control_img_cond (context )
286
283
287
284
inpaint_mask = self ._prep_inpaint_mask (context , x )
288
285
@@ -662,12 +659,13 @@ def _prep_controlnet_extensions(
662
659
663
660
return controlnet_extensions
664
661
665
- def _prep_structural_control_img_cond (self , context : InvocationContext ) -> torch .Tensor :
662
+ def _prep_structural_control_img_cond (self , context : InvocationContext ) -> torch .Tensor | None :
663
+ if self .control_lora is None :
664
+ return None
665
+
666
666
if not self .controlnet_vae :
667
667
raise ValueError ("controlnet_vae must be set when using a FLUX Control LoRA." )
668
668
669
- assert self .control_lora is not None
670
-
671
669
# Load the conditioning image and resize it to the target image size.
672
670
cond_img = context .images .get_pil (self .control_lora .img .image_name )
673
671
cond_img = cond_img .convert ("RGB" )
@@ -689,16 +687,29 @@ def _prep_structural_control_img_cond(self, context: InvocationContext) -> torch
689
687
def _prep_flux_fill_img_cond (
690
688
self , context : InvocationContext , device : torch .device , dtype : torch .dtype
691
689
) -> torch .Tensor :
692
- """Prepare the FLUX Fill conditioning.
690
+ """Prepare the FLUX Fill conditioning. This method should be called iff the model is a FLUX Fill model.
693
691
694
692
This logic is based on:
695
693
https://github.com/black-forest-labs/flux/blob/716724eb276d94397be99710a0a54d352664e23b/src/flux/sampling.py#L107-L157
696
694
"""
695
+ # Validate inputs.
696
+ if self .fill_conditioning is None :
697
+ raise ValueError ("A FLUX Fill model is being used without fill_conditioning." )
697
698
# TODO(ryand): We should probable rename controlnet_vae. It's used for more than just ControlNets.
698
- if not self .controlnet_vae :
699
- raise ValueError ("controlnet_vae must be set when using a FLUX Fill conditioning." )
699
+ if self .controlnet_vae is None :
700
+ raise ValueError ("A FLUX Fill model is being used without controlnet_vae." )
701
+ if self .control_lora is not None :
702
+ raise ValueError (
703
+ "A FLUX Fill model is being used, but a control_lora was provided. Control LoRAs are not compatible with FLUX Fill models."
704
+ )
700
705
701
- assert self .fill_conditioning is not None
706
+ # Log input warnings related to FLUX Fill usage.
707
+ if self .denoise_mask is not None :
708
+ context .logger .warning (
709
+ "Both fill_conditioning and a denoise_mask were provided. You probably meant to use one or the other."
710
+ )
711
+ if self .guidance < 25.0 :
712
+ context .logger .warning ("A guidance value of ~30.0 is recommended for FLUX Fill models." )
702
713
703
714
# Load the conditioning image and resize it to the target image size.
704
715
cond_img = context .images .get_pil (self .fill_conditioning .image .image_name , mode = "RGB" )
0 commit comments