Skip to content

Commit 9fdc06b

Browse files
RyanJDickpsychedelicious
authored andcommitted
Add FLUX Fill input validation and error/warning reporting.
1 parent 5ea3ec5 commit 9fdc06b

File tree

1 file changed

+31
-20
lines changed

1 file changed

+31
-20
lines changed

invokeai/app/invocations/flux_denoise.py

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
unpack,
5050
)
5151
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
5353
from invokeai.backend.patches.layer_patcher import LayerPatcher
5454
from invokeai.backend.patches.lora_conversions.flux_lora_constants import FLUX_LORA_TRANSFORMER_PREFIX
5555
from invokeai.backend.patches.model_patch_raw import ModelPatchRaw
@@ -267,22 +267,19 @@ def _run_diffusion(
267267
if is_schnell and self.control_lora:
268268
raise ValueError("Control LoRAs cannot be used with FLUX Schnell")
269269

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.
277271
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:
283274
img_cond = self._prep_flux_fill_img_cond(
284275
context, device=TorchDevice.choose_torch_device(), dtype=inference_dtype
285276
)
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)
286283

287284
inpaint_mask = self._prep_inpaint_mask(context, x)
288285

@@ -662,12 +659,13 @@ def _prep_controlnet_extensions(
662659

663660
return controlnet_extensions
664661

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+
666666
if not self.controlnet_vae:
667667
raise ValueError("controlnet_vae must be set when using a FLUX Control LoRA.")
668668

669-
assert self.control_lora is not None
670-
671669
# Load the conditioning image and resize it to the target image size.
672670
cond_img = context.images.get_pil(self.control_lora.img.image_name)
673671
cond_img = cond_img.convert("RGB")
@@ -689,16 +687,29 @@ def _prep_structural_control_img_cond(self, context: InvocationContext) -> torch
689687
def _prep_flux_fill_img_cond(
690688
self, context: InvocationContext, device: torch.device, dtype: torch.dtype
691689
) -> 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.
693691
694692
This logic is based on:
695693
https://github.com/black-forest-labs/flux/blob/716724eb276d94397be99710a0a54d352664e23b/src/flux/sampling.py#L107-L157
696694
"""
695+
# Validate inputs.
696+
if self.fill_conditioning is None:
697+
raise ValueError("A FLUX Fill model is being used without fill_conditioning.")
697698
# 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+
)
700705

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.")
702713

703714
# Load the conditioning image and resize it to the target image size.
704715
cond_img = context.images.get_pil(self.fill_conditioning.image.image_name, mode="RGB")

0 commit comments

Comments
 (0)