File size: 11,531 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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/env python3
"""v3 matrix: depth-only, handwritten prompts + generic negative, portrait singles. -> outputs_v3."""
import json, os, shutil, sys, time, urllib.request
from run_sweeps import post, HOST, W, H, HW, HH, SEED

OUT_ROOT = "/workspace/outputs_v3"
COMFY_OUT = "/workspace/ComfyUI/output"
R = ["r1.jpg", "r2.jpg", "r3.jpg", "r4.jpg"]
T = ["t1.jpg", "t2.jpg", "t3.jpg", "t4.jpg", "t5.jpg", "t6.jpg"]

POS = ("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.")
NEG = ("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")
SCENE = ("A candid photograph of a woman walking through a rain-soaked city street at night, "
         "neon signs reflecting in the wet pavement, cinematic atmosphere, shallow depth of field, "
         "subtle film grain.")

def core2(p, style_img, comp_img, guidance, redux=0.5):
    p["u"] = {"class_type": "UNETLoader", "inputs": {"unet_name": "flux1-dev.safetensors", "weight_dtype": "default"}}
    p["c"] = {"class_type": "DualCLIPLoader", "inputs": {"clip_name1": "t5xxl_fp16.safetensors",
        "clip_name2": "clip_l.safetensors", "type": "flux", "device": "default"}}
    p["v"] = {"class_type": "VAELoader", "inputs": {"vae_name": "ae.safetensors"}}
    p["txt"] = {"class_type": "CLIPTextEncode", "inputs": {"clip": ["c", 0], "text": POS}}
    p["guid"] = {"class_type": "FluxGuidance", "inputs": {"conditioning": ["txt", 0], "guidance": guidance}}
    p["neg"] = {"class_type": "CLIPTextEncode", "inputs": {"clip": ["c", 0], "text": NEG}}
    p["si"] = {"class_type": "LoadImage", "inputs": {"image": style_img}}
    p["cvl"] = {"class_type": "CLIPVisionLoader", "inputs": {"clip_name": "sigclip_vision_patch14_384.safetensors"}}
    p["cve"] = {"class_type": "CLIPVisionEncode", "inputs": {"clip_vision": ["cvl", 0], "image": ["si", 0], "crop": "center"}}
    p["sml"] = {"class_type": "StyleModelLoader", "inputs": {"style_model_name": "flux1-redux-dev.safetensors"}}
    p["sma"] = {"class_type": "StyleModelApply", "inputs": {"conditioning": ["guid", 0],
        "style_model": ["sml", 0], "clip_vision_output": ["cve", 0], "strength": redux, "strength_type": "attn_bias"}}
    p["ci"] = {"class_type": "LoadImage", "inputs": {"image": comp_img}}
    p["rs"] = {"class_type": "ImageResize+", "inputs": {"image": ["ci", 0], "width": W, "height": H,
        "interpolation": "lanczos", "method": "fill / crop", "condition": "always", "multiple_of": 0}}
    p["depth"] = {"class_type": "DepthAnythingV2Preprocessor", "inputs": {
        "image": ["rs", 0], "ckpt_name": "depth_anything_v2_vitl.pth", "resolution": W}}

def v3_style_comp(style_img, comp_img, tag):
    p = {}
    core2(p, style_img, comp_img, guidance=3.0)
    p["savedepth"] = {"class_type": "SaveImage", "inputs": {"images": ["depth", 0],
        "filename_prefix": f"v3/flux-v2-redux-style-composition/inputs/{tag}-depth"}}
    p["cnl"] = {"class_type": "ControlNetLoader", "inputs": {"control_net_name": "FLUX.1-dev-ControlNet-Union-Pro-2.0.safetensors"}}
    p["cn"] = {"class_type": "ControlNetApplySD3", "inputs": {"positive": ["sma", 0], "negative": ["neg", 0],
        "control_net": ["cnl", 0], "vae": ["v", 0], "image": ["depth", 0],
        "strength": 0.7, "start_percent": 0.0, "end_percent": 0.8}}
    p["msf"] = {"class_type": "ModelSamplingFlux", "inputs": {"model": ["u", 0],
        "max_shift": 1.15, "base_shift": 0.5, "width": W, "height": H}}
    p["lat"] = {"class_type": "EmptySD3LatentImage", "inputs": {"width": W, "height": H, "batch_size": 1}}
    p["ks"] = {"class_type": "KSampler", "inputs": {"model": ["msf", 0], "positive": ["cn", 0],
        "negative": ["cn", 1], "latent_image": ["lat", 0], "seed": SEED, "steps": 32, "cfg": 1.0,
        "sampler_name": "euler", "scheduler": "simple", "denoise": 1.0}}
    p["dec"] = {"class_type": "VAEDecode", "inputs": {"samples": ["ks", 0], "vae": ["v", 0]}}
    p["save"] = {"class_type": "SaveImage", "inputs": {"images": ["dec", 0],
        "filename_prefix": f"v3/flux-v2-redux-style-composition/{tag}"}}
    p["up"] = {"class_type": "LatentUpscaleBy", "inputs": {"samples": ["ks", 0], "upscale_method": "bislerp", "scale_by": 1.5}}
    p["msf2"] = {"class_type": "ModelSamplingFlux", "inputs": {"model": ["u", 0],
        "max_shift": 1.15, "base_shift": 0.5, "width": HW, "height": HH}}
    p["ks2"] = {"class_type": "KSampler", "inputs": {"model": ["msf2", 0], "positive": ["sma", 0],
        "negative": ["neg", 0], "latent_image": ["up", 0], "seed": SEED, "steps": 32, "cfg": 1.0,
        "sampler_name": "euler", "scheduler": "simple", "denoise": 0.30}}
    p["dec2"] = {"class_type": "VAEDecode", "inputs": {"samples": ["ks2", 0], "vae": ["v", 0]}}
    p["save2"] = {"class_type": "SaveImage", "inputs": {"images": ["dec2", 0],
        "filename_prefix": f"v3/flux-v2-redux-style-composition/hires/{tag}"}}
    return p

def v3_bfl(style_img, comp_img, tag):
    p = {}
    core2(p, style_img, comp_img, guidance=4.0)
    p["lora"] = {"class_type": "LoraLoaderModelOnly", "inputs": {"model": ["u", 0],
        "lora_name": "flux1-depth-dev-lora.safetensors", "strength_model": 1.0}}
    p["ip2p"] = {"class_type": "InstructPixToPixConditioning", "inputs": {"positive": ["sma", 0],
        "negative": ["neg", 0], "vae": ["v", 0], "pixels": ["depth", 0]}}
    p["msf"] = {"class_type": "ModelSamplingFlux", "inputs": {"model": ["lora", 0],
        "max_shift": 1.15, "base_shift": 0.5, "width": W, "height": H}}
    p["ks"] = {"class_type": "KSampler", "inputs": {"model": ["msf", 0], "positive": ["ip2p", 0],
        "negative": ["ip2p", 1], "latent_image": ["ip2p", 2], "seed": SEED, "steps": 32, "cfg": 1.0,
        "sampler_name": "euler", "scheduler": "simple", "denoise": 1.0}}
    p["dec"] = {"class_type": "VAEDecode", "inputs": {"samples": ["ks", 0], "vae": ["v", 0]}}
    p["save"] = {"class_type": "SaveImage", "inputs": {"images": ["dec", 0],
        "filename_prefix": f"v3/flux-v2-redux-style-composition-bfl-lora/{tag}"}}
    return p

def single(style_img, tag, kind):
    p = {}
    unet = "flux1-schnell.safetensors" if kind == "schnell" else "flux1-dev.safetensors"
    p["u"] = {"class_type": "UNETLoader", "inputs": {"unet_name": unet, "weight_dtype": "default"}}
    p["c"] = {"class_type": "DualCLIPLoader", "inputs": {"clip_name1": "t5xxl_fp16.safetensors",
        "clip_name2": "clip_l.safetensors", "type": "flux", "device": "default"}}
    p["v"] = {"class_type": "VAELoader", "inputs": {"vae_name": "ae.safetensors"}}
    text = {"fal": POS, "prompt": SCENE, "schnell": ""}[kind]
    p["txt"] = {"class_type": "CLIPTextEncode", "inputs": {"clip": ["c", 0], "text": text}}
    p["si"] = {"class_type": "LoadImage", "inputs": {"image": style_img}}
    p["cvl"] = {"class_type": "CLIPVisionLoader", "inputs": {"clip_name": "sigclip_vision_patch14_384.safetensors"}}
    p["cve"] = {"class_type": "CLIPVisionEncode", "inputs": {"clip_vision": ["cvl", 0], "image": ["si", 0], "crop": "center"}}
    p["sml"] = {"class_type": "StyleModelLoader", "inputs": {"style_model_name": "flux1-redux-dev.safetensors"}}
    cond = ["txt", 0]
    if kind != "schnell":
        p["guid"] = {"class_type": "FluxGuidance", "inputs": {"conditioning": ["txt", 0], "guidance": 3.5}}
        cond = ["guid", 0]
    strength, stype = (0.5, "attn_bias") if kind == "prompt" else (1.0, "multiply")
    if kind == "fal":
        strength, stype = 0.6, "attn_bias"  # prompt must coexist with style
    p["sma"] = {"class_type": "StyleModelApply", "inputs": {"conditioning": cond,
        "style_model": ["sml", 0], "clip_vision_output": ["cve", 0], "strength": strength, "strength_type": stype}}
    w, h = (768, 1024) if kind == "fal" else (W, H)
    if kind != "schnell":
        p["msf"] = {"class_type": "ModelSamplingFlux", "inputs": {"model": ["u", 0],
            "max_shift": 1.15, "base_shift": 0.5, "width": w, "height": h}}
        model = ["msf", 0]
    else:
        model = ["u", 0]
    p["noise"] = {"class_type": "RandomNoise", "inputs": {"noise_seed": SEED}}
    p["guider"] = {"class_type": "BasicGuider", "inputs": {"model": model, "conditioning": ["sma", 0]}}
    p["samp"] = {"class_type": "KSamplerSelect", "inputs": {"sampler_name": "euler"}}
    p["sched"] = {"class_type": "BasicScheduler", "inputs": {"model": model, "scheduler": "simple",
        "steps": 4 if kind == "schnell" else 28, "denoise": 1.0}}
    p["lat"] = {"class_type": "EmptySD3LatentImage", "inputs": {"width": w, "height": h, "batch_size": 1}}
    p["sca"] = {"class_type": "SamplerCustomAdvanced", "inputs": {"noise": ["noise", 0], "guider": ["guider", 0],
        "sampler": ["samp", 0], "sigmas": ["sched", 0], "latent_image": ["lat", 0]}}
    p["dec"] = {"class_type": "VAEDecode", "inputs": {"samples": ["sca", 0], "vae": ["v", 0]}}
    wfname = {"fal": "flux-redux-fal-dev", "prompt": "flux-redux-prompt", "schnell": "flux-redux-schnell"}[kind]
    p["save"] = {"class_type": "SaveImage", "inputs": {"images": ["dec", 0], "filename_prefix": f"v3/{wfname}/{tag}"}}
    return p

def main():
    combos = [(r, t) for r in R for t in T] + [(a, b) for a in R for b in R if a != b]
    q = []
    for r, t in combos:
        q.append(v3_style_comp(r, t, f"{r.split('.')[0]}x{t.split('.')[0]}"))
    for r, t in combos:
        q.append(v3_bfl(r, t, f"{r.split('.')[0]}x{t.split('.')[0]}"))
    for r in R:
        for kind in ["fal", "prompt", "schnell"]:
            q.append(single(r, r.split(".")[0], kind))
    ids = {}
    for i, prompt in enumerate(q):
        ids[post(prompt)] = i
    print(f"queued {len(q)}", flush=True)
    pending, errors = set(ids), []
    while pending:
        time.sleep(15)
        for pid in list(pending):
            try:
                with urllib.request.urlopen(f"{HOST}/history/{pid}") as r:
                    h = json.loads(r.read())
            except Exception:
                continue
            if pid not in h: continue
            st = h[pid].get("status", {})
            if st.get("completed"):
                pending.discard(pid)
                if (len(ids) - len(pending)) % 10 == 0:
                    print(f"progress {len(ids)-len(pending)}/{len(ids)}", flush=True)
            elif st.get("status_str") == "error":
                pending.discard(pid); errors.append(pid)
                msgs = [m for m in st.get("messages", []) if m[0] == "execution_error"]
                print(f"ERROR: {(msgs[-1][1].get('exception_message','?') if msgs else '?')[:300]}", flush=True)
    src = os.path.join(COMFY_OUT, "v3")
    for root, _, files in os.walk(src):
        rel = os.path.relpath(root, src)
        dst = os.path.join(OUT_ROOT, rel)
        os.makedirs(dst, exist_ok=True)
        for f in files:
            shutil.copy(os.path.join(root, f), os.path.join(dst, f.split("_")[0] + ".png"))
    print("COLLECTED", flush=True)
    for root, dirs, files in os.walk(OUT_ROOT):
        if files:
            print(f"  {os.path.relpath(root, OUT_ROOT)}: {len(files)}", flush=True)
    if errors:
        print("ERRORS:", len(errors)); sys.exit(1)
    print("V3 MATRIX COMPLETE", flush=True)

if __name__ == "__main__":
    main()