File size: 11,104 Bytes
478cb8f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | #!/usr/bin/env python3
"""Generate flux-v2 workflow JSONs: portrait pre-pass, saved crops, hires group, bfl guidance fix."""
import build_workflows as B
from build_workflows import G, DEFS, CORE, BYPASS, flux_loaders, redux_branch
ESSENTIALS = {"cnr_id": "comfyui_essentials"}
DEFS["ImageResize+"] = ([("image", "IMAGE")],
[("IMAGE", "IMAGE"), ("width", "INT"), ("height", "INT")],
ESSENTIALS, [310, 170])
DEFS["LatentUpscaleBy"] = ([("samples", "LATENT")], [("LATENT", "LATENT")], CORE, [290, 82])
W, H = 896, 1152 # portrait bucket, both /64
HW, HH = 1344, 1728 # hires 1.5x
INPUT_SPEC = """
**Optimal inputs** (both refs): 3:4 portrait, 1152x1536, sRGB 8-bit JPEG q90+/PNG, no
watermarks/text/borders, EXIF baked. Style ref: keep the style-defining content in the vertical
middle (sigclip center-crops to a square β top/bottom ~12% are discarded). Composition ref:
clear fg/bg depth separation. Any other input still works β the pre-pass normalizes to 896x1152
(fill/crop) and the exact crop + depth map are saved next to the outputs for auditing."""
def comp_prepass(g, x, y, save_prefix):
"""LoadImage -> ImageResize+ 896x1152 fill/crop -> depth; saves crop + depth map."""
ci = g.add("LoadImage", ["composition_ref.png", "image"], pos=(x, y),
title="Composition reference (Image B)")
rs = g.add("ImageResize+", [W, H, "lanczos", "fill / crop", "always", 0],
inputs={"image": (ci, 0)}, pos=(x + 420, y + 30), title="Normalize to 896x1152")
g.add("SaveImage", [f"{save_prefix}/inputs/comp-crop"], inputs={"images": (rs, 0)},
pos=(x + 420, y + 240), size=[260, 270], title="Save crop (audit)")
depth = g.add("DepthAnythingV2Preprocessor", ["depth_anything_v2_vitl.pth", W],
inputs={"image": (rs, 0)}, pos=(x + 840, y + 30))
g.add("SaveImage", [f"{save_prefix}/inputs/depth"], inputs={"images": (depth, 0)},
pos=(x + 840, y + 240), size=[260, 270], title="Save depth map (audit)")
return ci, rs, depth
def build_v2_style_composition():
g = G()
g.add("MarkdownNote", [f"""## FLUX Redux + ControlNet β style + composition (v2)
v2 changes vs v1: portrait pre-pass (any input β exact **896x1152** fill/crop, so depth map ==
latent, zero padding), saved input crops + depth maps for auditing, steps 32, and a bypassed
**HIRES** group (1.5x latent upscale β second pass at denoise 0.30 with Redux conditioning
carried, ControlNet released β enable for ~1344x1728 finals; keeps aesthetic, adds detail).
Models & knobs: unchanged from v1 (see `flux-redux-style-composition.json` notes). Redux **multiply 0.35** β NEVER attn_bias with a ControlNet: its attention mask never reaches
the CN branch (code-verified), so base and CN fight and bodies deform. Union-Pro-2.0 depth
0.7 / end 0.8 (drop end to 0.6 for more freedom), FluxGuidance **3.0** (sweep-validated; 2.5 softer/filmic, 3.5 punchier), euler/simple/32/CFG 1.
Bypassed groups: CANNY stack (0.35), ReduxAdvanced alt, turbo fast-preview, HIRES.
{INPUT_SPEC}"""], pos=(-1340, -180), size=[580, 620])
unet, clip, vae = flux_loaders(g)
s_img, cv_loader, cv_enc, sm_loader = redux_branch(g, -720, 420)
txt = g.add("CLIPTextEncode", ['A photograph of a beautiful woman posing naturally. Her body is anatomically correct, with well-proportioned limbs, natural relaxed hands, and a balanced, graceful posture. The image is sharp and coherent, with realistic skin texture and lighting that matches the scene.'], inputs={"clip": (clip, 0)}, pos=(-300, 60),
title="Prompt (generic anatomy default β edit or clear)")
guid = g.add("FluxGuidance", [3.0], inputs={"conditioning": (txt, 0)}, pos=(140, 60))
neg = g.add("CLIPTextEncode", ['deformed anatomy, extra limbs, missing limbs, fused or extra fingers, malformed hands, twisted joints, distorted face, mutated body, disfigured, blurry, lowres, jpeg artifacts, watermark, text, logo, oversaturated, plastic skin'], inputs={"clip": (clip, 0)}, pos=(-300, 250),
title="Negative (INERT at CFG 1.0 β activates only if CFG > 1)")
apply_style = g.add("StyleModelApply", [0.35, "multiply"],
inputs={"conditioning": (guid, 0), "style_model": (sm_loader, 0),
"clip_vision_output": (cv_enc, 0)}, pos=(140, 300))
radv = g.add("ReduxAdvanced", [3, "area", "center crop (square)", 1.0, 0.1],
inputs={"conditioning": (guid, 0), "style_model": (sm_loader, 0),
"clip_vision": (cv_loader, 0), "image": (s_img, 0)},
pos=(140, 520), mode=BYPASS, title="ALT: ReduxAdvanced (rewire to use)")
ci, rs, depth = comp_prepass(g, -720, 1000, "flux-v2/style-comp")
canny = g.add("Canny", [0.2, 0.5], inputs={"image": (rs, 0)}, pos=(-300, 1560),
mode=BYPASS, title="OPTIONAL: canny edges")
cn_loader = g.add("ControlNetLoader", ["FLUX.1-dev-ControlNet-Union-Pro-2.0.safetensors"],
pos=(300, 950))
cn_depth = g.add("ControlNetApplySD3", [0.7, 0.0, 0.8],
inputs={"positive": (apply_style, 0), "negative": (neg, 0),
"control_net": (cn_loader, 0), "vae": (vae, 0), "image": (depth, 0)},
pos=(700, 300), title="Apply ControlNet β DEPTH")
cn_canny = g.add("ControlNetApplySD3", [0.35, 0.0, 0.6],
inputs={"positive": (cn_depth, 0), "negative": (cn_depth, 1),
"control_net": (cn_loader, 0), "vae": (vae, 0), "image": (canny, 0)},
pos=(700, 560), mode=BYPASS, title="OPTIONAL: Apply ControlNet β CANNY (stack)")
turbo = g.add("LoraLoaderModelOnly", ["flux1-turbo-alpha.safetensors", 1.0],
inputs={"model": (unet, 0)}, pos=(-300, -160), mode=BYPASS,
title="FAST PREVIEW: turbo LoRA (set steps 8)")
msf = g.add("ModelSamplingFlux", [1.15, 0.5, W, H], inputs={"model": (turbo, 0)}, pos=(140, -160))
latent = g.add("EmptySD3LatentImage", [W, H, 1], pos=(700, 950))
ks = g.add("KSampler", [0, "randomize", 32, 1.0, "euler", "simple", 1.0],
inputs={"model": (msf, 0), "positive": (cn_canny, 0), "negative": (cn_canny, 1),
"latent_image": (latent, 0)}, pos=(1120, 300))
dec = g.add("VAEDecode", inputs={"samples": (ks, 0), "vae": (vae, 0)}, pos=(1460, 300))
g.add("SaveImage", ["flux-v2/style-comp"], inputs={"images": (dec, 0)}, pos=(1460, 420))
# HIRES group (all bypassed): 1.5x latent -> refine at denoise 0.30, Redux kept, CN released
up = g.add("LatentUpscaleBy", ["bislerp", 1.5], inputs={"samples": (ks, 0)},
pos=(1120, 660), mode=BYPASS, title="HIRES: 1.5x latent")
msf2 = g.add("ModelSamplingFlux", [1.15, 0.5, HW, HH], inputs={"model": (turbo, 0)},
pos=(1120, 800), mode=BYPASS, title="HIRES: shift @1344x1728")
ks2 = g.add("KSampler", [0, "randomize", 32, 1.0, "euler", "simple", 0.30],
inputs={"model": (msf2, 0), "positive": (apply_style, 0), "negative": (neg, 0),
"latent_image": (up, 0)}, pos=(1460, 660), mode=BYPASS,
title="HIRES: refine pass (denoise 0.30)")
dec2 = g.add("VAEDecode", inputs={"samples": (ks2, 0), "vae": (vae, 0)},
pos=(1800, 660), mode=BYPASS)
g.add("SaveImage", ["flux-v2/style-comp-hires"], inputs={"images": (dec2, 0)},
pos=(1800, 780), mode=BYPASS, title="HIRES: save")
g.group("STYLE REFERENCE β Redux", -740, 340, 1220, 700, "#3f789e")
g.group("COMPOSITION REFERENCE β 896x1152 pre-pass", -740, 900, 1500, 840, "#8f5b34")
g.group("SAMPLING", 1080, 200, 800, 380, "#444")
g.group("HIRES (bypassed β enable all 5)", 1080, 600, 1100, 520, "#4a6b4a")
g.dump(f"{B.OUT}/flux-v2-redux-style-composition.json")
def build_v2_bfl_lora():
g = G()
g.add("MarkdownNote", [f"""## FLUX Redux + official BFL Depth LoRA (v2 β A/B variant)
v2 changes vs v1: portrait pre-pass (896x1152 fill/crop β critical here: with latent-concat
conditioning any padding becomes image content), saved crop + depth map, steps 32, and
**FluxGuidance 10.0 + LoRA 0.85** (BFL spec β the LoRA is distilled at guidance 10; earlier
lower-guidance results were an artifact of the attn_bias bug). Redux multiply 0.35, never
attn_bias (see style-composition notes). No canny stacking possible in this method.
{INPUT_SPEC}"""], pos=(-1340, -180), size=[580, 560])
unet, clip, vae = flux_loaders(g)
s_img, cv_loader, cv_enc, sm_loader = redux_branch(g, -720, 420)
txt = g.add("CLIPTextEncode", ['A photograph of a beautiful woman posing naturally. Her body is anatomically correct, with well-proportioned limbs, natural relaxed hands, and a balanced, graceful posture. The image is sharp and coherent, with realistic skin texture and lighting that matches the scene.'], inputs={"clip": (clip, 0)}, pos=(-300, 60),
title="Prompt (generic anatomy default β edit or clear)")
guid = g.add("FluxGuidance", [10.0], inputs={"conditioning": (txt, 0)}, pos=(140, 60))
neg = g.add("CLIPTextEncode", ['deformed anatomy, extra limbs, missing limbs, fused or extra fingers, malformed hands, twisted joints, distorted face, mutated body, disfigured, blurry, lowres, jpeg artifacts, watermark, text, logo, oversaturated, plastic skin'], inputs={"clip": (clip, 0)}, pos=(-300, 250),
title="Negative (INERT at CFG 1.0 β activates only if CFG > 1)")
apply_style = g.add("StyleModelApply", [0.35, "multiply"],
inputs={"conditioning": (guid, 0), "style_model": (sm_loader, 0),
"clip_vision_output": (cv_enc, 0)}, pos=(140, 300))
ci, rs, depth = comp_prepass(g, -720, 1000, "flux-v2/style-comp-bfl")
ip2p = g.add("InstructPixToPixConditioning",
inputs={"positive": (apply_style, 0), "negative": (neg, 0), "vae": (vae, 0),
"pixels": (depth, 0)}, pos=(700, 300))
dlora = g.add("LoraLoaderModelOnly", ["flux1-depth-dev-lora.safetensors", 0.85],
inputs={"model": (unet, 0)}, pos=(-300, -160), title="BFL Depth LoRA")
msf = g.add("ModelSamplingFlux", [1.15, 0.5, W, H], inputs={"model": (dlora, 0)}, pos=(140, -160))
ks = g.add("KSampler", [0, "randomize", 32, 1.0, "euler", "simple", 1.0],
inputs={"model": (msf, 0), "positive": (ip2p, 0), "negative": (ip2p, 1),
"latent_image": (ip2p, 2)}, pos=(1120, 300))
dec = g.add("VAEDecode", inputs={"samples": (ks, 0), "vae": (vae, 0)}, pos=(1460, 300))
g.add("SaveImage", ["flux-v2/style-comp-bfl"], inputs={"images": (dec, 0)}, pos=(1460, 420))
g.group("STYLE REFERENCE β Redux", -740, 340, 1220, 700, "#3f789e")
g.group("COMPOSITION β 896x1152 pre-pass + BFL Depth LoRA", -740, 900, 1500, 620, "#8f5b34")
g.dump(f"{B.OUT}/flux-v2-redux-style-composition-bfl-lora.json")
build_v2_style_composition()
build_v2_bfl_lora()
|