Commit 000fbec3 authored by wuxk1's avatar wuxk1
Browse files

optim for test1,2,5

parent 57b0ad8e
{
"last_node_id": 64,
"last_link_id": 132,
"nodes": [
{
"id": 25,
"type": "RandomNoise",
"pos": {
"0": 6,
"1": -135
},
"size": {
"0": 315,
"1": 82
},
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "NOISE",
"type": "NOISE",
"links": [
84
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "RandomNoise"
},
"widgets_values": [
186462208016243,
"fixed"
],
"color": "#2a363b",
"bgcolor": "#3f5159"
},
{
"id": 26,
"type": "FluxGuidance",
"pos": {
"0": 372,
"1": -171
},
"size": {
"0": 317.4000244140625,
"1": 58
},
"flags": {
"collapsed": false
},
"order": 13,
"mode": 0,
"inputs": [
{
"name": "conditioning",
"type": "CONDITIONING",
"link": 41
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
107
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "FluxGuidance"
},
"widgets_values": [
3.5
],
"color": "#233",
"bgcolor": "#355"
},
{
"id": 6,
"type": "CLIPTextEncode",
"pos": {
"0": 372,
"1": -55
},
"size": {
"0": 422.84503173828125,
"1": 164.31304931640625
},
"flags": {},
"order": 12,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 132
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
41
],
"slot_index": 0
}
],
"title": "CLIP Text Encode (Positive Prompt)",
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"Half body portrait of 60 years old guy, with an surprised expression, he is lost in vectors of AI models, sourounded by PC monitors and many cables, on his tshirt is a text with words printed in Arial font:\"PuLID Flux\", detailed, glowy background, photorealistic style with skin inperfections, looks like shot with an smartphone, skin details without plastic look, ASUS Keyboard."
],
"color": "#232",
"bgcolor": "#353"
},
{
"id": 27,
"type": "EmptySD3LatentImage",
"pos": {
"0": 383,
"1": 155
},
"size": {
"0": 315,
"1": 106
},
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
86
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "EmptySD3LatentImage"
},
"widgets_values": [
768,
1024,
1
],
"color": "#323",
"bgcolor": "#535"
},
{
"id": 16,
"type": "KSamplerSelect",
"pos": {
"0": 384,
"1": 313
},
"size": {
"0": 315,
"1": 58
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "SAMPLER",
"type": "SAMPLER",
"links": [
85
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "KSamplerSelect"
},
"widgets_values": [
"euler"
]
},
{
"id": 17,
"type": "BasicScheduler",
"pos": {
"0": 392,
"1": 424
},
"size": {
"0": 315,
"1": 106
},
"flags": {
"collapsed": false
},
"order": 11,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 131,
"slot_index": 0
}
],
"outputs": [
{
"name": "SIGMAS",
"type": "SIGMAS",
"links": [
93
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "BasicScheduler"
},
"widgets_values": [
"simple",
10,
1
]
},
{
"id": 54,
"type": "LoadImage",
"pos": {
"0": 729,
"1": -490
},
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 3,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
126
],
"slot_index": 0,
"shape": 3
},
{
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"einstein.jpg",
"image"
]
},
{
"id": 53,
"type": "PulidFluxInsightFaceLoader",
"pos": {
"0": 822,
"1": -80
},
"size": {
"0": 365.4000244140625,
"1": 58
},
"flags": {},
"order": 4,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "FACEANALYSIS",
"type": "FACEANALYSIS",
"links": [
124
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "PulidFluxInsightFaceLoader"
},
"widgets_values": [
"CPU"
]
},
{
"id": 51,
"type": "PulidFluxEvaClipLoader",
"pos": {
"0": 845,
"1": 52
},
"size": {
"0": 327.5999755859375,
"1": 26
},
"flags": {},
"order": 5,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "EVA_CLIP",
"type": "EVA_CLIP",
"links": [
123
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "PulidFluxEvaClipLoader"
}
},
{
"id": 45,
"type": "PulidFluxModelLoader",
"pos": {
"0": 846,
"1": 137
},
"size": {
"0": 315,
"1": 58
},
"flags": {},
"order": 6,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "PULIDFLUX",
"type": "PULIDFLUX",
"links": [
125
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "PulidFluxModelLoader"
},
"widgets_values": [
"pulid_flux_v0.9.0.safetensors"
]
},
{
"id": 62,
"type": "ApplyPulidFlux",
"pos": {
"0": 842,
"1": 258
},
"size": {
"0": 315,
"1": 206
},
"flags": {},
"order": 10,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 130
},
{
"name": "pulid_flux",
"type": "PULIDFLUX",
"link": 125
},
{
"name": "eva_clip",
"type": "EVA_CLIP",
"link": 123
},
{
"name": "face_analysis",
"type": "FACEANALYSIS",
"link": 124
},
{
"name": "image",
"type": "IMAGE",
"link": 126
},
{
"name": "attn_mask",
"type": "MASK",
"link": null
}
],
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
122
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "ApplyPulidFlux"
},
"widgets_values": [
1,
0,
1
]
},
{
"id": 47,
"type": "BasicGuider",
"pos": {
"0": 1217,
"1": 401
},
"size": {
"0": 241.79998779296875,
"1": 46
},
"flags": {},
"order": 14,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 122
},
{
"name": "conditioning",
"type": "CONDITIONING",
"link": 107
}
],
"outputs": [
{
"name": "GUIDER",
"type": "GUIDER",
"links": [
83
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "BasicGuider"
}
},
{
"id": 48,
"type": "SamplerCustomAdvanced",
"pos": {
"0": 1205,
"1": -39
},
"size": {
"0": 355.20001220703125,
"1": 326
},
"flags": {},
"order": 15,
"mode": 0,
"inputs": [
{
"name": "noise",
"type": "NOISE",
"link": 84
},
{
"name": "guider",
"type": "GUIDER",
"link": 83
},
{
"name": "sampler",
"type": "SAMPLER",
"link": 85
},
{
"name": "sigmas",
"type": "SIGMAS",
"link": 93
},
{
"name": "latent_image",
"type": "LATENT",
"link": 86
}
],
"outputs": [
{
"name": "output",
"type": "LATENT",
"links": [
87
],
"slot_index": 0,
"shape": 3
},
{
"name": "denoised_output",
"type": "LATENT",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "SamplerCustomAdvanced"
}
},
{
"id": 49,
"type": "VAEDecode",
"pos": {
"0": 1263,
"1": -137
},
"size": {
"0": 210,
"1": 46
},
"flags": {},
"order": 16,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 87
},
{
"name": "vae",
"type": "VAE",
"link": 88
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
89
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "VAEDecode"
}
},
{
"id": 50,
"type": "PreviewImage",
"pos": {
"0": 1587,
"1": -169
},
"size": {
"0": 841.524169921875,
"1": 698.3060302734375
},
"flags": {},
"order": 17,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 89
}
],
"outputs": [],
"properties": {
"Node name for S&R": "PreviewImage"
}
},
{
"id": 63,
"type": "UNETLoader",
"pos": {
"0": 6,
"1": -7
},
"size": {
"0": 315,
"1": 82
},
"flags": {},
"order": 7,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
130,
131
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "UNETLoader"
},
"widgets_values": [
"flux1-dev.safetensors",
"default"
]
},
{
"id": 10,
"type": "VAELoader",
"pos": {
"0": 12,
"1": 285
},
"size": {
"0": 311.81634521484375,
"1": 60.429901123046875
},
"flags": {},
"order": 8,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "VAE",
"type": "VAE",
"links": [
88
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "VAELoader"
},
"widgets_values": [
"flux1_vae.safetensors"
]
},
{
"id": 64,
"type": "DualCLIPLoader",
"pos": {
"0": 8,
"1": 124
},
"size": {
"0": 315,
"1": 106
},
"flags": {},
"order": 9,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "CLIP",
"type": "CLIP",
"links": [
132
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "DualCLIPLoader"
},
"widgets_values": [
"t5xxl_fp16.safetensors",
"clip_l.safetensors",
"flux"
]
}
],
"links": [
[
41,
6,
0,
26,
0,
"CONDITIONING"
],
[
83,
47,
0,
48,
1,
"GUIDER"
],
[
84,
25,
0,
48,
0,
"NOISE"
],
[
85,
16,
0,
48,
2,
"SAMPLER"
],
[
86,
27,
0,
48,
4,
"LATENT"
],
[
87,
48,
0,
49,
0,
"LATENT"
],
[
88,
10,
0,
49,
1,
"VAE"
],
[
89,
49,
0,
50,
0,
"IMAGE"
],
[
93,
17,
0,
48,
3,
"SIGMAS"
],
[
107,
26,
0,
47,
1,
"CONDITIONING"
],
[
122,
62,
0,
47,
0,
"MODEL"
],
[
123,
51,
0,
62,
2,
"EVA_CLIP"
],
[
124,
53,
0,
62,
3,
"FACEANALYSIS"
],
[
125,
45,
0,
62,
1,
"PULIDFLUX"
],
[
126,
54,
0,
62,
4,
"IMAGE"
],
[
130,
63,
0,
62,
0,
"MODEL"
],
[
131,
63,
0,
17,
0,
"MODEL"
],
[
132,
64,
0,
6,
0,
"CLIP"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 0.9090909090909091,
"offset": [
113.84966682267732,
547.8597243753773
]
}
},
"version": 0.4
}
\ No newline at end of file
{
"last_node_id": 62,
"last_link_id": 129,
"nodes": [
{
"id": 25,
"type": "RandomNoise",
"pos": {
"0": 6,
"1": -135
},
"size": [
315,
82
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "NOISE",
"type": "NOISE",
"links": [
84
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "RandomNoise"
},
"widgets_values": [
186462208016243,
"fixed"
],
"color": "#2a363b",
"bgcolor": "#3f5159"
},
{
"id": 31,
"type": "UnetLoaderGGUF",
"pos": {
"0": 14,
"1": 5
},
"size": {
"0": 315,
"1": 58
},
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
127,
129
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "UnetLoaderGGUF"
},
"widgets_values": [
"flux1-dev-Q8_0.gguf"
]
},
{
"id": 41,
"type": "DualCLIPLoaderGGUF",
"pos": {
"0": 18,
"1": 114
},
"size": {
"0": 315,
"1": 106
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "CLIP",
"type": "CLIP",
"links": [
128
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "DualCLIPLoaderGGUF"
},
"widgets_values": [
"t5-v1_1-xxl-encoder-Q8_0.gguf",
"clip_l.safetensors",
"flux"
]
},
{
"id": 10,
"type": "VAELoader",
"pos": {
"0": 23,
"1": 275
},
"size": {
"0": 311.81634521484375,
"1": 60.429901123046875
},
"flags": {},
"order": 3,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "VAE",
"type": "VAE",
"links": [
88
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "VAELoader"
},
"widgets_values": [
"flux1_vae.safetensors"
]
},
{
"id": 26,
"type": "FluxGuidance",
"pos": {
"0": 372,
"1": -171
},
"size": {
"0": 317.4000244140625,
"1": 58
},
"flags": {
"collapsed": false
},
"order": 13,
"mode": 0,
"inputs": [
{
"name": "conditioning",
"type": "CONDITIONING",
"link": 41
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
107
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "FluxGuidance"
},
"widgets_values": [
3.5
],
"color": "#233",
"bgcolor": "#355"
},
{
"id": 6,
"type": "CLIPTextEncode",
"pos": {
"0": 372,
"1": -55
},
"size": {
"0": 422.84503173828125,
"1": 164.31304931640625
},
"flags": {},
"order": 11,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 128
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
41
],
"slot_index": 0
}
],
"title": "CLIP Text Encode (Positive Prompt)",
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"Half body portrait of 60 years old guy, with an surprised expression, he is lost in vectors of AI models, sourounded by PC monitors and many cables, on his tshirt is a text with words printed in Arial font:\"PuLID Flux\", detailed, glowy background, photorealistic style with skin inperfections, looks like shot with an smartphone, skin details without plastic look, ASUS Keyboard."
],
"color": "#232",
"bgcolor": "#353"
},
{
"id": 27,
"type": "EmptySD3LatentImage",
"pos": {
"0": 383,
"1": 155
},
"size": {
"0": 315,
"1": 106
},
"flags": {},
"order": 4,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
86
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "EmptySD3LatentImage"
},
"widgets_values": [
768,
1024,
1
],
"color": "#323",
"bgcolor": "#535"
},
{
"id": 16,
"type": "KSamplerSelect",
"pos": {
"0": 384,
"1": 313
},
"size": {
"0": 315,
"1": 58
},
"flags": {},
"order": 5,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "SAMPLER",
"type": "SAMPLER",
"links": [
85
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "KSamplerSelect"
},
"widgets_values": [
"euler"
]
},
{
"id": 17,
"type": "BasicScheduler",
"pos": {
"0": 392,
"1": 424
},
"size": {
"0": 315,
"1": 106
},
"flags": {
"collapsed": false
},
"order": 10,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 129,
"slot_index": 0
}
],
"outputs": [
{
"name": "SIGMAS",
"type": "SIGMAS",
"links": [
93
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "BasicScheduler"
},
"widgets_values": [
"simple",
10,
1
]
},
{
"id": 54,
"type": "LoadImage",
"pos": {
"0": 729,
"1": -490
},
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 6,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
126
],
"slot_index": 0,
"shape": 3
},
{
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"einstein.jpg",
"image"
]
},
{
"id": 53,
"type": "PulidFluxInsightFaceLoader",
"pos": {
"0": 822,
"1": -80
},
"size": {
"0": 365.4000244140625,
"1": 58
},
"flags": {},
"order": 7,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "FACEANALYSIS",
"type": "FACEANALYSIS",
"links": [
124
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "PulidFluxInsightFaceLoader"
},
"widgets_values": [
"CPU"
]
},
{
"id": 51,
"type": "PulidFluxEvaClipLoader",
"pos": {
"0": 845,
"1": 52
},
"size": {
"0": 327.5999755859375,
"1": 26
},
"flags": {},
"order": 8,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "EVA_CLIP",
"type": "EVA_CLIP",
"links": [
123
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "PulidFluxEvaClipLoader"
}
},
{
"id": 45,
"type": "PulidFluxModelLoader",
"pos": {
"0": 846,
"1": 137
},
"size": {
"0": 315,
"1": 58
},
"flags": {},
"order": 9,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "PULIDFLUX",
"type": "PULIDFLUX",
"links": [
125
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "PulidFluxModelLoader"
},
"widgets_values": [
"pulid_flux_v0.9.0.safetensors"
]
},
{
"id": 62,
"type": "ApplyPulidFlux",
"pos": {
"0": 842,
"1": 258
},
"size": {
"0": 315,
"1": 206
},
"flags": {},
"order": 12,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 127
},
{
"name": "pulid_flux",
"type": "PULIDFLUX",
"link": 125
},
{
"name": "eva_clip",
"type": "EVA_CLIP",
"link": 123
},
{
"name": "face_analysis",
"type": "FACEANALYSIS",
"link": 124
},
{
"name": "image",
"type": "IMAGE",
"link": 126
},
{
"name": "attn_mask",
"type": "MASK",
"link": null
}
],
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
122
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "ApplyPulidFlux"
},
"widgets_values": [
1,
0,
1
]
},
{
"id": 47,
"type": "BasicGuider",
"pos": {
"0": 1217,
"1": 401
},
"size": {
"0": 241.79998779296875,
"1": 46
},
"flags": {},
"order": 14,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 122
},
{
"name": "conditioning",
"type": "CONDITIONING",
"link": 107
}
],
"outputs": [
{
"name": "GUIDER",
"type": "GUIDER",
"links": [
83
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "BasicGuider"
}
},
{
"id": 48,
"type": "SamplerCustomAdvanced",
"pos": {
"0": 1205,
"1": -39
},
"size": {
"0": 355.20001220703125,
"1": 326
},
"flags": {},
"order": 15,
"mode": 0,
"inputs": [
{
"name": "noise",
"type": "NOISE",
"link": 84
},
{
"name": "guider",
"type": "GUIDER",
"link": 83
},
{
"name": "sampler",
"type": "SAMPLER",
"link": 85
},
{
"name": "sigmas",
"type": "SIGMAS",
"link": 93
},
{
"name": "latent_image",
"type": "LATENT",
"link": 86
}
],
"outputs": [
{
"name": "output",
"type": "LATENT",
"links": [
87
],
"slot_index": 0,
"shape": 3
},
{
"name": "denoised_output",
"type": "LATENT",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "SamplerCustomAdvanced"
}
},
{
"id": 49,
"type": "VAEDecode",
"pos": {
"0": 1263,
"1": -137
},
"size": {
"0": 210,
"1": 46
},
"flags": {},
"order": 16,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 87
},
{
"name": "vae",
"type": "VAE",
"link": 88
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
89
],
"slot_index": 0,
"shape": 3
}
],
"properties": {
"Node name for S&R": "VAEDecode"
}
},
{
"id": 50,
"type": "PreviewImage",
"pos": {
"0": 1587,
"1": -169
},
"size": {
"0": 841.524169921875,
"1": 698.3060302734375
},
"flags": {},
"order": 17,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 89
}
],
"outputs": [],
"properties": {
"Node name for S&R": "PreviewImage"
}
}
],
"links": [
[
41,
6,
0,
26,
0,
"CONDITIONING"
],
[
83,
47,
0,
48,
1,
"GUIDER"
],
[
84,
25,
0,
48,
0,
"NOISE"
],
[
85,
16,
0,
48,
2,
"SAMPLER"
],
[
86,
27,
0,
48,
4,
"LATENT"
],
[
87,
48,
0,
49,
0,
"LATENT"
],
[
88,
10,
0,
49,
1,
"VAE"
],
[
89,
49,
0,
50,
0,
"IMAGE"
],
[
93,
17,
0,
48,
3,
"SIGMAS"
],
[
107,
26,
0,
47,
1,
"CONDITIONING"
],
[
122,
62,
0,
47,
0,
"MODEL"
],
[
123,
51,
0,
62,
2,
"EVA_CLIP"
],
[
124,
53,
0,
62,
3,
"FACEANALYSIS"
],
[
125,
45,
0,
62,
1,
"PULIDFLUX"
],
[
126,
54,
0,
62,
4,
"IMAGE"
],
[
127,
31,
0,
62,
0,
"MODEL"
],
[
128,
41,
0,
6,
0,
"CLIP"
],
[
129,
31,
0,
17,
0,
"MODEL"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 0.7513148009015777,
"offset": [
124.42912136813258,
743.5079061935592
]
}
},
"version": 0.4
}
\ No newline at end of file
# supervised by a global average embedding, which is a biased estimation of the true embedding
# use projection to enable a complex decoding
# makes no big difference than mean so far, the decoding may not work 🤦‍
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torch
from tqdm import tqdm
import random
class Transform(nn.Module):
def __init__(self, n=2, token_size=32, input_dim=2048):
super().__init__()
self.n=n
self.dim= input_dim*token_size
self.token_size=token_size
self.input_dim=input_dim
self.weight = nn.Parameter(torch.ones(self.n,1),requires_grad=True)
self.projections = nn.ModuleList([nn.Sequential(
nn.Linear(self.dim, 512),
nn.ReLU(),
nn.Linear(512, self.dim)
) for _ in range(self.n)])
def encode(self, x):
x = x.view(-1, self.dim)
x = self.weight*x
return x
def decode(self, x):
out=[]
for i in range(self.n):
t = self.projections[i](x[i])
out.append(t)
x = torch.stack(out, dim=0)
x=x.view(self.n,self.token_size,self.input_dim)
x=torch.mean(x,dim=0)
return x
def forward(self, x):
x = self.encode(x)
x = self.decode(x)
return x
def online_train(cond, device="cuda:1",step=1000):
old_device=cond.device
dtype=cond.dtype
cond = cond.clone().to(device,torch.float32)
cond.requires_grad=False
torch.set_grad_enabled(True)
print("online training, initializing model...")
n=cond.shape[0]
model=Transform(n=n)
optimizer = optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.0001)
criterion = nn.MSELoss()
model.to(device)
model.train()
y=torch.mean(cond,dim=0)
random.seed(42)
bar=tqdm(range(step))
for s in bar:
optimizer.zero_grad()
attack_weight=[random.uniform(0.5,1.5) for _ in range(n)]
attack_weight=torch.tensor(attack_weight)[:,None,None].to(device)
x=attack_weight*cond
output = model(x)
loss = criterion(output, y)
loss.backward()
optimizer.step()
bar.set_postfix(loss=loss.item())
weight=model.weight
cond=weight[:,:,None]*cond
print(weight)
print("online training, ending...")
del model
del optimizer
cond=torch.mean(cond,dim=0).unsqueeze(0)
return cond.to(old_device,dtype=dtype)
\ No newline at end of file
# self-supervised learning, one of the embedding acts as the target, the other as the support
# works nicely
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torch
from tqdm import tqdm
import random
class Transform(nn.Module):
def __init__(self, n=2, token_size=32, input_dim=2048):
super().__init__()
self.n=n
self.token_size=token_size
self.weight = nn.Parameter(torch.ones(self.n,self.token_size),requires_grad=True)
def encode(self, x):
x = torch.einsum('bij,bi->ij', x, self.weight)
return x
def forward(self, x):
x = self.encode(x)
return x
def criterion(output, target, token_sample_rate=0.25):
t=target-output
t=torch.norm(t,dim=1)
s=random.sample(range(t.shape[0]),int(token_sample_rate*t.shape[0]))
return torch.mean(t[s])
def online_train(cond, device="cuda:1",step=1000):
old_device=cond.device
dtype=cond.dtype
cond = cond.clone().to(device,torch.float32)
# cond.requires_grad=False
# torch.set_grad_enabled(True)
y=cond[0,:,:]
cond=cond[1:,:,:]
print("online training, initializing model...")
n=cond.shape[0]
model=Transform(n=n)
optimizer = optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.0001)
model.to(device)
model.train()
random.seed(42)
bar=tqdm(range(step))
for s in bar:
optimizer.zero_grad()
x=cond
output = model(x)
loss = criterion(output, y)
loss.backward()
optimizer.step()
bar.set_postfix(loss=loss.item())
weight=model.weight
print(weight)
cond=weight[:,:,None]*cond+y[None,:,:]*(1.0/n)
print("online training, ending...")
del model
del optimizer
cond=torch.mean(cond,dim=0).unsqueeze(0)
return cond.to(old_device,dtype=dtype)
\ No newline at end of file
import torch
from torch import nn, Tensor
from torchvision import transforms
from torchvision.transforms import functional
import os
import logging
import folder_paths
import comfy.utils
from comfy.ldm.flux.layers import timestep_embedding
import comfy.model_management
from insightface.app import FaceAnalysis
from facexlib.parsing import init_parsing_model
from facexlib.utils.face_restoration_helper import FaceRestoreHelper
import torch.nn.functional as F
from .eva_clip.constants import OPENAI_DATASET_MEAN, OPENAI_DATASET_STD
from .encoders_flux import IDFormer, PerceiverAttentionCA
INSIGHTFACE_DIR = os.path.join(folder_paths.models_dir, "insightface")
MODELS_DIR = os.path.join(folder_paths.models_dir, "pulid")
if "pulid" not in folder_paths.folder_names_and_paths:
current_paths = [MODELS_DIR]
else:
current_paths, _ = folder_paths.folder_names_and_paths["pulid"]
folder_paths.folder_names_and_paths["pulid"] = (current_paths, folder_paths.supported_pt_extensions)
from .online_train2 import online_train
class PulidFluxModel(nn.Module):
def __init__(self):
super().__init__()
self.double_interval = 2
self.single_interval = 4
# Init encoder
self.pulid_encoder = IDFormer()
# Init attention
num_ca = 19 // self.double_interval + 38 // self.single_interval
if 19 % self.double_interval != 0:
num_ca += 1
if 38 % self.single_interval != 0:
num_ca += 1
self.pulid_ca = nn.ModuleList([
PerceiverAttentionCA() for _ in range(num_ca)
])
def from_pretrained(self, path: str):
state_dict = comfy.utils.load_torch_file(path, safe_load=True)
state_dict_dict = {}
for k, v in state_dict.items():
module = k.split('.')[0]
state_dict_dict.setdefault(module, {})
new_k = k[len(module) + 1:]
state_dict_dict[module][new_k] = v
for module in state_dict_dict:
getattr(self, module).load_state_dict(state_dict_dict[module], strict=True)
del state_dict
del state_dict_dict
def get_embeds(self, face_embed, clip_embeds):
return self.pulid_encoder(face_embed, clip_embeds)
def forward_orig(
self,
img: Tensor,
img_ids: Tensor,
txt: Tensor,
txt_ids: Tensor,
timesteps: Tensor,
y: Tensor,
guidance: Tensor = None,
control=None,
transformer_options={},
attn_mask: Tensor = None,
**kwargs # so it won't break if we add more stuff in the future
) -> Tensor:
device = comfy.model_management.get_torch_device()
patches_replace = transformer_options.get("patches_replace", {})
if img.ndim != 3 or txt.ndim != 3:
raise ValueError("Input img and txt tensors must have 3 dimensions.")
# running on sequences img
img = self.img_in(img)
vec = self.time_in(timestep_embedding(timesteps, 256).to(img.dtype))
if self.params.guidance_embed:
if guidance is None:
raise ValueError("Didn't get guidance strength for guidance distilled model.")
vec = vec + self.guidance_in(timestep_embedding(guidance, 256).to(img.dtype))
vec = vec + self.vector_in(y)
txt = self.txt_in(txt)
ids = torch.cat((txt_ids, img_ids), dim=1)
pe = self.pe_embedder(ids)
ca_idx = 0
blocks_replace = patches_replace.get("dit", {})
for i, block in enumerate(self.double_blocks):
if ("double_block", i) in blocks_replace:
def block_wrap(args):
out = {}
out["img"], out["txt"] = block(img=args["img"],
txt=args["txt"],
vec=args["vec"],
pe=args["pe"],
attn_mask=args.get("attn_mask"))
return out
out = blocks_replace[("double_block", i)]({"img": img,
"txt": txt,
"vec": vec,
"pe": pe,
"attn_mask": attn_mask},
{"original_block": block_wrap})
txt = out["txt"]
img = out["img"]
else:
img, txt = block(img=img,
txt=txt,
vec=vec,
pe=pe,
attn_mask=attn_mask)
if control is not None: # Controlnet
control_i = control.get("input")
if i < len(control_i):
add = control_i[i]
if add is not None:
img += add
# PuLID attention
if self.pulid_data:
if i % self.pulid_double_interval == 0:
# Will calculate influence of all pulid nodes at once
for _, node_data in self.pulid_data.items():
condition_start = node_data['sigma_start'] >= timesteps
condition_end = timesteps >= node_data['sigma_end']
condition = torch.logical_and(
condition_start, condition_end).all()
if condition:
img = img + node_data['weight'] * self.pulid_ca[ca_idx].to(device)(node_data['embedding'], img)
ca_idx += 1
img = torch.cat((txt, img), 1)
for i, block in enumerate(self.single_blocks):
if ("single_block", i) in blocks_replace:
def block_wrap(args):
out = {}
out["img"] = block(args["img"],
vec=args["vec"],
pe=args["pe"],
attn_mask=args.get("attn_mask"))
return out
out = blocks_replace[("single_block", i)]({"img": img,
"vec": vec,
"pe": pe,
"attn_mask": attn_mask},
{"original_block": block_wrap})
img = out["img"]
else:
img = block(img, vec=vec, pe=pe, attn_mask=attn_mask)
if control is not None: # Controlnet
control_o = control.get("output")
if i < len(control_o):
add = control_o[i]
if add is not None:
img[:, txt.shape[1] :, ...] += add
# PuLID attention
if self.pulid_data:
real_img, txt = img[:, txt.shape[1]:, ...], img[:, :txt.shape[1], ...]
if i % self.pulid_single_interval == 0:
# Will calculate influence of all nodes at once
for _, node_data in self.pulid_data.items():
condition_start = node_data['sigma_start'] >= timesteps
condition_end = timesteps >= node_data['sigma_end']
# Combine conditions and reduce to a single boolean
condition = torch.logical_and(condition_start, condition_end).all()
if condition:
real_img = real_img + node_data['weight'] * self.pulid_ca[ca_idx].to(device)(node_data['embedding'], real_img)
ca_idx += 1
img = torch.cat((txt, real_img), 1)
img = img[:, txt.shape[1] :, ...]
img = self.final_layer(img, vec) # (N, T, patch_size ** 2 * out_channels)
return img
def tensor_to_image(tensor):
image = tensor.mul(255).clamp(0, 255).byte().cpu()
image = image[..., [2, 1, 0]].numpy()
return image
def image_to_tensor(image):
tensor = torch.clamp(torch.from_numpy(image).float() / 255., 0, 1)
tensor = tensor[..., [2, 1, 0]]
return tensor
def resize_with_pad(img, target_size): # image: 1, h, w, 3
img = img.permute(0, 3, 1, 2)
H, W = target_size
h, w = img.shape[2], img.shape[3]
scale_h = H / h
scale_w = W / w
scale = min(scale_h, scale_w)
new_h = int(min(h * scale,H))
new_w = int(min(w * scale,W))
new_size = (new_h, new_w)
img = F.interpolate(img, size=new_size, mode='bicubic', align_corners=False)
pad_top = (H - new_h) // 2
pad_bottom = (H - new_h) - pad_top
pad_left = (W - new_w) // 2
pad_right = (W - new_w) - pad_left
img = F.pad(img, pad=(pad_left, pad_right, pad_top, pad_bottom), mode='constant', value=0)
return img.permute(0, 2, 3, 1)
def to_gray(img):
x = 0.299 * img[:, 0:1] + 0.587 * img[:, 1:2] + 0.114 * img[:, 2:3]
x = x.repeat(1, 3, 1, 1)
return x
"""
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Nodes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
class PulidFluxModelLoader:
@classmethod
def INPUT_TYPES(s):
return {"required": {"pulid_file": (folder_paths.get_filename_list("pulid"), )}}
RETURN_TYPES = ("PULIDFLUX",)
FUNCTION = "load_model"
CATEGORY = "pulid"
def load_model(self, pulid_file):
model_path = folder_paths.get_full_path("pulid", pulid_file)
# Also initialize the model, takes longer to load but then it doesn't have to be done every time you change parameters in the apply node
model = PulidFluxModel()
logging.info("Loading PuLID-Flux model.")
model.from_pretrained(path=model_path)
return (model,)
class PulidFluxInsightFaceLoader:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"provider": (["CPU", "CUDA", "ROCM"], ),
},
}
RETURN_TYPES = ("FACEANALYSIS",)
FUNCTION = "load_insightface"
CATEGORY = "pulid"
def load_insightface(self, provider):
model = FaceAnalysis(name="antelopev2", root=INSIGHTFACE_DIR, providers=[provider + 'ExecutionProvider',]) # alternative to buffalo_l
model.prepare(ctx_id=0, det_size=(640, 640))
return (model,)
class PulidFluxEvaClipLoader:
@classmethod
def INPUT_TYPES(s):
return {
"required": {},
}
RETURN_TYPES = ("EVA_CLIP",)
FUNCTION = "load_eva_clip"
CATEGORY = "pulid"
def load_eva_clip(self):
from .eva_clip.factory import create_model_and_transforms
model, _, _ = create_model_and_transforms('EVA02-CLIP-L-14-336', 'eva_clip', force_custom_clip=True)
model = model.visual
eva_transform_mean = getattr(model, 'image_mean', OPENAI_DATASET_MEAN)
eva_transform_std = getattr(model, 'image_std', OPENAI_DATASET_STD)
if not isinstance(eva_transform_mean, (list, tuple)):
model["image_mean"] = (eva_transform_mean,) * 3
if not isinstance(eva_transform_std, (list, tuple)):
model["image_std"] = (eva_transform_std,) * 3
return (model,)
class ApplyPulidFlux:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"model": ("MODEL", ),
"pulid_flux": ("PULIDFLUX", ),
"eva_clip": ("EVA_CLIP", ),
"face_analysis": ("FACEANALYSIS", ),
"image": ("IMAGE", ),
"weight": ("FLOAT", {"default": 1.0, "min": -1.0, "max": 5.0, "step": 0.05 }),
"start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001 }),
"end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001 }),
"fusion": (["mean","concat","max","norm_id","max_token","auto_weight","train_weight"],),
"fusion_weight_max": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 20.0, "step": 0.1 }),
"fusion_weight_min": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 20.0, "step": 0.1 }),
"train_step": ("INT", {"default": 1000, "min": 0, "max": 20000, "step": 1 }),
"use_gray": ("BOOLEAN", {"default": True, "label_on": "enabled", "label_off": "disabled"}),
},
"optional": {
"attn_mask": ("MASK", ),
"prior_image": ("IMAGE",), # for train weight, as the target
},
"hidden": {
"unique_id": "UNIQUE_ID"
},
}
RETURN_TYPES = ("MODEL",)
FUNCTION = "apply_pulid_flux"
CATEGORY = "pulid"
def __init__(self):
self.pulid_data_dict = None
device = comfy.model_management.get_torch_device()
self.face_helper = FaceRestoreHelper(
upscale_factor=1,
face_size=512,
crop_ratio=(1, 1),
det_model='retinaface_resnet50',
save_ext='png',
device=device,
)
self.face_helper.face_parse = None
self.face_helper.face_parse = init_parsing_model(model_name='bisenet', device=device)
def apply_pulid_flux(self, model, pulid_flux, eva_clip, face_analysis, image, weight, start_at, end_at, prior_image=None,fusion="mean", fusion_weight_max=1.0, fusion_weight_min=0.0, train_step=1000, use_gray=True, attn_mask=None, unique_id=None):
device = comfy.model_management.get_torch_device()
# Why should I care what args say, when the unet model has a different dtype?!
# Am I missing something?!
#dtype = comfy.model_management.unet_dtype()
dtype = model.model.diffusion_model.dtype
# For 8bit use bfloat16 (because ufunc_add_CUDA is not implemented)
if dtype in [torch.float8_e4m3fn, torch.float8_e5m2]:
dtype = torch.bfloat16
eva_clip.to(device, dtype=dtype)
pulid_flux.to(device, dtype=dtype)
# TODO: Add masking support!
if attn_mask is not None:
if attn_mask.dim() > 3:
attn_mask = attn_mask.squeeze(-1)
elif attn_mask.dim() < 3:
attn_mask = attn_mask.unsqueeze(0)
attn_mask = attn_mask.to(device, dtype=dtype)
if prior_image is not None:
prior_image = resize_with_pad(prior_image.to(image.device, dtype=image.dtype), target_size=(image.shape[1], image.shape[2]))
image=torch.cat((prior_image,image),dim=0)
image = tensor_to_image(image)
"""
face_helper = FaceRestoreHelper(
upscale_factor=1,
face_size=512,
crop_ratio=(1, 1),
det_model='retinaface_resnet50',
save_ext='png',
device=device,
)
face_helper.face_parse = None
face_helper.face_parse = init_parsing_model(model_name='bisenet', device=device)
"""
face_helper=self.face_helper
bg_label = [0, 16, 18, 7, 8, 9, 14, 15]
cond = []
# Analyse multiple images at multiple sizes and combine largest area embeddings
for i in range(image.shape[0]):
# get insightface embeddings
iface_embeds = None
for size in [(size, size) for size in range(640, 256, -64)]:
face_analysis.det_model.input_size = size
face_info = face_analysis.get(image[i])
if face_info:
# Only use the maximum face
# Removed the reverse=True from original code because we need the largest area not the smallest one!
# Sorts the list in ascending order (smallest to largest),
# then selects the last element, which is the largest face
face_info = sorted(face_info, key=lambda x: (x.bbox[2] - x.bbox[0]) * (x.bbox[3] - x.bbox[1]))[-1]
iface_embeds = torch.from_numpy(face_info.embedding).unsqueeze(0).to(device, dtype=dtype)
break
else:
# No face detected, skip this image
logging.warning(f'Warning: No face detected in image {str(i)}')
continue
# get eva_clip embeddings
face_helper.clean_all()
face_helper.read_image(image[i])
face_helper.get_face_landmarks_5(only_center_face=True)
face_helper.align_warp_face()
if len(face_helper.cropped_faces) == 0:
# No face detected, skip this image
continue
# Get aligned face image
align_face = face_helper.cropped_faces[0]
# Convert bgr face image to tensor
align_face = image_to_tensor(align_face).unsqueeze(0).permute(0, 3, 1, 2).to(device)
parsing_out = face_helper.face_parse(functional.normalize(align_face, [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]))[0]
parsing_out = parsing_out.argmax(dim=1, keepdim=True)
bg = sum(parsing_out == i for i in bg_label).bool()
white_image = torch.ones_like(align_face)
# Only keep the face features
if use_gray:
_align_face = to_gray(align_face)
else:
_align_face = align_face
face_features_image = torch.where(bg, white_image, _align_face)
# Transform img before sending to eva_clip
# Apparently MPS only supports NEAREST interpolation?
face_features_image = functional.resize(face_features_image, eva_clip.image_size, transforms.InterpolationMode.BICUBIC if 'cuda' in device.type else transforms.InterpolationMode.NEAREST).to(device, dtype=dtype)
face_features_image = functional.normalize(face_features_image, eva_clip.image_mean, eva_clip.image_std)
# eva_clip
id_cond_vit, id_vit_hidden = eva_clip(face_features_image, return_all_features=False, return_hidden=True, shuffle=False)
id_cond_vit = id_cond_vit.to(device, dtype=dtype)
for idx in range(len(id_vit_hidden)):
id_vit_hidden[idx] = id_vit_hidden[idx].to(device, dtype=dtype)
id_cond_vit = torch.div(id_cond_vit, torch.norm(id_cond_vit, 2, 1, True))
# Combine embeddings
id_cond = torch.cat([iface_embeds, id_cond_vit], dim=-1)
# Pulid_encoder
cond.append(pulid_flux.get_embeds(id_cond, id_vit_hidden))
if not cond:
# No faces detected, return the original model
logging.warning("PuLID warning: No faces detected in any of the given images, returning unmodified model.")
return (model,)
# fusion embeddings
if fusion == "mean":
cond = torch.cat(cond).to(device, dtype=dtype) # N,32,2048
if cond.shape[0] > 1:
cond = torch.mean(cond, dim=0, keepdim=True)
elif fusion == "concat":
cond = torch.cat(cond, dim=1).to(device, dtype=dtype)
elif fusion == "max":
cond = torch.cat(cond).to(device, dtype=dtype)
if cond.shape[0] > 1:
cond = torch.max(cond, dim=0, keepdim=True)[0]
elif fusion == "norm_id":
cond = torch.cat(cond).to(device, dtype=dtype)
if cond.shape[0] > 1:
norm=torch.norm(cond,dim=(1,2))
norm=norm/torch.sum(norm)
cond=torch.einsum("wij,w->ij",cond,norm).unsqueeze(0)
elif fusion == "max_token":
cond = torch.cat(cond).to(device, dtype=dtype)
if cond.shape[0] > 1:
norm=torch.norm(cond,dim=2)
_,idx=torch.max(norm,dim=0)
cond=torch.stack([cond[j,i] for i,j in enumerate(idx)]).unsqueeze(0)
elif fusion == "auto_weight": # 🤔
cond = torch.cat(cond).to(device, dtype=dtype)
if cond.shape[0] > 1:
norm=torch.norm(cond,dim=2)
order=torch.argsort(norm,descending=False,dim=0)
regular_weight=torch.linspace(fusion_weight_min,fusion_weight_max,norm.shape[0]).to(device, dtype=dtype)
_cond=[]
for i in range(cond.shape[1]):
o=order[:,i]
_cond.append(torch.einsum('ij,i->j',cond[:,i,:],regular_weight[o]))
cond=torch.stack(_cond,dim=0).unsqueeze(0)
elif fusion == "train_weight":
cond = torch.cat(cond).to(device, dtype=dtype)
if cond.shape[0] > 1:
if train_step > 0:
with torch.inference_mode(False):
cond = online_train(cond, device=cond.device, step=train_step)
else:
cond = torch.mean(cond, dim=0, keepdim=True)
sigma_start = model.get_model_object("model_sampling").percent_to_sigma(start_at)
sigma_end = model.get_model_object("model_sampling").percent_to_sigma(end_at)
# Patch the Flux model (original diffusion_model)
# Nah, I don't care for the official ModelPatcher because it's undocumented!
# I want the end result now, and I don’t mind if I break other custom nodes in the process. 😄
flux_model = model.model.diffusion_model
# Let's see if we already patched the underlying flux model, if not apply patch
if not hasattr(flux_model, "pulid_ca"):
# Add perceiver attention, variables and current node data (weight, embedding, sigma_start, sigma_end)
# The pulid_data is stored in Dict by unique node index,
# so we can chain multiple ApplyPulidFlux nodes!
flux_model.pulid_ca = pulid_flux.pulid_ca
flux_model.pulid_double_interval = pulid_flux.double_interval
flux_model.pulid_single_interval = pulid_flux.single_interval
flux_model.pulid_data = {}
# Replace model forward_orig with our own
new_method = forward_orig.__get__(flux_model, flux_model.__class__)
setattr(flux_model, 'forward_orig', new_method)
# Patch is already in place, add data (weight, embedding, sigma_start, sigma_end) under unique node index
flux_model.pulid_data[unique_id] = {
'weight': weight,
'embedding': cond,
'sigma_start': sigma_start,
'sigma_end': sigma_end,
}
# Keep a reference for destructor (if node is deleted the data will be deleted as well)
self.pulid_data_dict = {'data': flux_model.pulid_data, 'unique_id': unique_id}
return (model,)
def __del__(self):
# Destroy the data for this node
if self.pulid_data_dict:
del self.pulid_data_dict['data'][self.pulid_data_dict['unique_id']]
del self.pulid_data_dict
NODE_CLASS_MAPPINGS = {
"PulidFluxModelLoader": PulidFluxModelLoader,
"PulidFluxInsightFaceLoader": PulidFluxInsightFaceLoader,
"PulidFluxEvaClipLoader": PulidFluxEvaClipLoader,
"ApplyPulidFlux": ApplyPulidFlux,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"PulidFluxModelLoader": "Load PuLID Flux Model",
"PulidFluxInsightFaceLoader": "Load InsightFace (PuLID Flux)",
"PulidFluxEvaClipLoader": "Load Eva Clip (PuLID Flux)",
"ApplyPulidFlux": "Apply PuLID Flux",
}
facexlib
insightface
#onnxruntime
#onnxruntime-gpu
ftfy
timm
# Adapted from https://github.com/sgl-project/sglang/blob/main/.pre-commit-config.yaml
default_stages: [pre-commit, pre-push, manual]
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-symlinks
- id: destroyed-symlinks
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
args: [--allow-multiple-documents]
- id: check-json
- id: check-toml
- id: check-ast
- id: check-added-large-files
- id: check-merge-conflict
# - id: check-shebang-scripts-are-executable
- id: detect-private-key
# - id: debug-statements
# - id: no-commit-to-branch
- repo: https://github.com/PyCQA/isort
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.2
hooks:
- id: ruff
args: [--fixable=F401]
exclude: \.ipynb$
- repo: https://github.com/psf/black
rev: 24.10.0
hooks:
- id: black-jupyter
- id: black
args: [-l, "120"]
files: ^(nunchaku/|scripts/|tests/)
- repo: https://github.com/kynan/nbstripout
rev: 0.8.1
hooks:
- id: nbstripout
args:
- '--keep-output'
- '--extra-keys=metadata.kernelspec metadata.language_info.version'
- repo: https://github.com/google/yamlfmt
rev: v0.17.0
hooks:
- id: yamlfmt
- repo: https://github.com/hukkin/mdformat
rev: 0.7.22
hooks:
- id: mdformat
name: (Markdown) Format docs with mdformat
additional_dependencies:
- mdformat-gfm
- mdformat-black
- mdformat-myst
- repo: https://github.com/PyCQA/doc8
rev: v2.0.0
hooks:
- id: doc8
additional_dependencies: []
- repo: https://github.com/rstcheck/rstcheck
rev: main # should be replaced with the current verison
hooks:
- id: rstcheck
additional_dependencies: ['rstcheck[sphinx,toml]']
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2024] [MIT HAN Lab]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
<div align="center" id="nunchaku_logo">
<img src="https://raw.githubusercontent.com/nunchaku-tech/nunchaku/96615bd93a1f0d2cf98039fddecfec43ce34cc96/assets/nunchaku.svg" alt="logo" width="220"></img>
</div>
<h3 align="center">
<a href="http://arxiv.org/abs/2411.05007"><b>Paper</b></a> | <a href="https://nunchaku.tech/docs/ComfyUI-nunchaku/"><b>Docs</b></a> | <a href="https://hanlab.mit.edu/projects/svdquant"><b>Website</b></a> | <a href="https://hanlab.mit.edu/blog/svdquant"><b>Blog</b></a> | <a href="https://svdquant.mit.edu"><b>Demo</b></a> | <a href="https://huggingface.co/nunchaku-tech"><b>Hugging Face</b></a> | <a href="https://modelscope.cn/organization/nunchaku-tech"><b>ModelScope</b></a>
</h3>
<h3 align="center">
<a href="README.md"><b>English</b></a> | <a href="README_ZH.md"><b>中文</b></a>
</h3>
This repository provides the ComfyUI plugin for [**Nunchaku**](https://github.com/nunchaku-tech/nunchaku), an efficient inference engine for 4-bit neural networks quantized with [SVDQuant](http://arxiv.org/abs/2411.05007). For the quantization library, check out [DeepCompressor](https://github.com/nunchaku-tech/deepcompressor).
Join our user groups on [**Discord**](https://discord.gg/Wk6PnwX9Sm) and [**WeChat**](https://huggingface.co/datasets/nunchaku-tech/cdn/resolve/main/nunchaku/assets/wechat.jpg) for discussions—details [here](https://github.com/nunchaku-tech/nunchaku/issues/149). If you have any questions, run into issues, or are interested in contributing, feel free to share your thoughts with us!
# Nunchaku ComfyUI Plugin
![comfyui](https://huggingface.co/datasets/nunchaku-tech/cdn/resolve/main/ComfyUI-nunchaku/comfyui.jpg)
## News
- **[2025-09-09]** 🔥 Released **4-bit Qwen-Image-Edit** together with the [4/8-step Lightning](https://huggingface.co/lightx2v/Qwen-Image-Lightning) variants! Models are available on [Hugging Face](https://huggingface.co/nunchaku-tech/nunchaku-qwen-image). Try them out with this [workflow](./example_workflows/nunchaku-qwen-image-edit.json)!
- **[2025-09-04]** 🚀 Official release of **Nunchaku v1.0.0**! Qwen-Image now supports **asynchronous offloading**, cutting Transformer VRAM usage to as little as **3 GiB** with no performance loss. You can also try our pre-quantized [4/8-step Qwen-Image-Lightning](https://huggingface.co/lightx2v/Qwen-Image-Lightning) models on [Hugging Face](https://huggingface.co/nunchaku-tech/nunchaku-qwen-image) or [ModelScope](https://modelscope.cn/models/nunchaku-tech/nunchaku-qwen-image).
- **[2025-08-23]** 🚀 **v1.0.0** adds support for [Qwen-Image](https://huggingface.co/Qwen/Qwen-Image)! Check [this workflow](example_workflows/nunchaku-qwen-image.json) to get started. LoRA support is coming soon.
- **[2025-07-17]** 📘 The official [**ComfyUI-nunchaku documentation**](https://nunchaku.tech/docs/ComfyUI-nunchaku/) is now live! Explore comprehensive guides and resources to help you get started.
- **[2025-06-29]** 🔥 **v0.3.3** now supports [FLUX.1-Kontext-dev](https://huggingface.co/black-forest-labs/FLUX.1-Kontext-dev)! Download the quantized model from [Hugging Face](https://huggingface.co/nunchaku-tech/nunchaku-flux.1-kontext-dev) or [ModelScope](https://modelscope.cn/models/nunchaku-tech/nunchaku-flux.1-kontext-dev) and use this [workflow](./example_workflows/nunchaku-flux.1-kontext-dev.json) to get started.
<details>
<summary>More</summary>
- **[2025-06-11]** Starting from **v0.3.2**, you can now **easily install or update the [Nunchaku](https://github.com/nunchaku-tech/nunchaku) wheel** using this [workflow](https://github.com/nunchaku-tech/ComfyUI-nunchaku/blob/main/example_workflows/install_wheel.json)!
- **[2025-06-07]** 🚀 **Release Patch v0.3.1!** We bring back **FB Cache** support and fix **4-bit text encoder loading**. PuLID nodes are now optional and won’t interfere with other nodes. We've also added a **NunchakuWheelInstaller** node to help you install the correct [Nunchaku](https://github.com/nunchaku-tech/nunchaku) wheel.
- **[2025-06-01]** 🚀 **Release v0.3.0!** This update adds support for multiple-batch inference, [**ControlNet-Union-Pro 2.0**](https://huggingface.co/Shakker-Labs/FLUX.1-dev-ControlNet-Union-Pro-2.0) and initial integration of [**PuLID**](https://github.com/ToTheBeginning/PuLID). You can now load Nunchaku FLUX models as a single file, and our upgraded [**4-bit T5 encoder**](https://huggingface.co/nunchaku-tech/nunchaku-t5) now matches **FP8 T5** in quality!
- **[2025-04-16]** 🎥 Released tutorial videos in both [**English**](https://youtu.be/YHAVe-oM7U8?si=cM9zaby_aEHiFXk0) and [**Chinese**](https://www.bilibili.com/video/BV1BTocYjEk5/?share_source=copy_web&vd_source=8926212fef622f25cc95380515ac74ee) to assist installation and usage.
- **[2025-04-09]** 📢 Published the [April roadmap](https://github.com/nunchaku-tech/nunchaku/issues/266) and an [FAQ](https://github.com/nunchaku-tech/nunchaku/discussions/262) to help the community get started and stay up to date with Nunchaku’s development.
- **[2025-04-05]** 🚀 **Release v0.2.0!** This release introduces [**multi-LoRA**](example_workflows/nunchaku-flux.1-dev.json) and [**ControlNet**](example_workflows/nunchaku-flux.1-dev-controlnet-union-pro.json) support, with enhanced performance using FP16 attention and First-Block Cache. We've also added [**20-series GPU**](examples/flux.1-dev-turing.py) compatibility and official workflows for [FLUX.1-redux](example_workflows/nunchaku-flux.1-redux-dev.json)!
</details>
## Getting Started
- [Installation Guide](https://nunchaku.tech/docs/ComfyUI-nunchaku/get_started/installation.html)
- [Usage Tutorial](https://nunchaku.tech/docs/ComfyUI-nunchaku/get_started/usage.html)
- [Example Workflows](https://nunchaku.tech/docs/ComfyUI-nunchaku/workflows/toc.html)
- [Node Reference](https://nunchaku.tech/docs/ComfyUI-nunchaku/nodes/toc.html)
- [API Reference](https://nunchaku.tech/docs/ComfyUI-nunchaku/api/toc.html)
- [Custom Model Quantization: DeepCompressor](https://github.com/mit-han-lab/deepcompressor)
- [Contribution Guide](https://nunchaku.tech/docs/ComfyUI-nunchaku/developer/contribution_guide.html)
- [Frequently Asked Questions](https://nunchaku.tech/docs/nunchaku/faq/faq.html)
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=nunchaku-tech/ComfyUI-nunchaku&type=Date)](https://www.star-history.com/#nunchaku-tech/ComfyUI-nunchaku&Date)
<div align="center" id="nunchaku_logo">
<img src="https://raw.githubusercontent.com/nunchaku-tech/nunchaku/96615bd93a1f0d2cf98039fddecfec43ce34cc96/assets/nunchaku.svg" alt="logo" width="220"></img>
</div>
<h3 align="center">
<a href="http://arxiv.org/abs/2411.05007"><b>论文</b></a> | <a href="https://nunchaku.tech/docs/ComfyUI-nunchaku/"><b>文档</b></a> | <a href="https://hanlab.mit.edu/projects/svdquant"><b>官网</b></a> | <a href="https://hanlab.mit.edu/blog/svdquant"><b>博客</b></a> | <a href="https://svdquant.mit.edu"><b>演示</b></a> | <a href="https://huggingface.co/nunchaku-tech"><b>Hugging Face</b></a> | <a href="https://modelscope.cn/organization/nunchaku-tech"><b>魔搭社区</b></a>
</h3>
<h3 align="center">
<a href="README.md"><b>English</b></a> | <a href="README_ZH.md"><b>中文</b></a>
</h3>
本仓库为 [**Nunchaku**](https://github.com/nunchaku-tech/nunchaku) 提供了 ComfyUI 插件,Nunchaku 是一个高效的 4-bit 神经网络推理引擎,采用 [SVDQuant](http://arxiv.org/abs/2411.05007) 量化方法。量化库请参考 [DeepCompressor](https://github.com/nunchaku-tech/deepcompressor)
欢迎加入我们的用户群:[**Slack**](https://join.slack.com/t/nunchaku/shared_invite/zt-3170agzoz-NgZzWaTrEj~n2KEV3Hpl5Q)[**Discord**](https://discord.gg/Wk6PnwX9Sm)[**微信**](https://huggingface.co/datasets/nunchaku-tech/cdn/resolve/main/nunchaku/assets/wechat.jpg)(详情见[这里](https://github.com/nunchaku-tech/nunchaku/issues/149))。如有任何问题、遇到 bug 或有意贡献代码,欢迎随时与我们交流!
# Nunchaku ComfyUI 插件
![comfyui](https://huggingface.co/datasets/nunchaku-tech/cdn/resolve/main/ComfyUI-nunchaku/comfyui.jpg)
## 最新动态
- **[2025-08-22]** 🚀 **v1.0.0** 新增对[Qwen-Image](https://huggingface.co/Qwen/Qwen-Image)的支持!查看[示例工作流](example_workflows/nunchaku-qwen-image.json)即可快速上手。LoRA支持即将推出。
- **[2025-07-17]** 🚀 [**ComfyUI-nunchaku 官方文档**](https://nunchaku.tech/docs/ComfyUI-nunchaku/)上线!提供详细的入门指南和资源。
- **[2025-06-29]** 📘 **v0.3.3** 现已支持 [FLUX.1-Kontext-dev](https://huggingface.co/black-forest-labs/FLUX.1-Kontext-dev)!可从 [Hugging Face](https://huggingface.co/nunchaku-tech/nunchaku-flux.1-kontext-dev)[魔搭社区](https://modelscope.cn/models/nunchaku-tech/nunchaku-flux.1-kontext-dev) 下载量化模型,并参考此 [工作流](./example_workflows/nunchaku-flux.1-kontext-dev.json) 快速上手。
- **[2025-06-11]****v0.3.2** 起,您可以通过此 [工作流](https://github.com/nunchaku-tech/ComfyUI-nunchaku/blob/main/example_workflows/install_wheel.json) **轻松安装或升级 [Nunchaku](https://github.com/nunchaku-tech/nunchaku) wheel 包**
- **[2025-06-07]** 🚀 **v0.3.1 补丁发布!** 恢复了 **FB Cache** 支持,修复了 **4-bit 文本编码器加载**问题。PuLID 节点现为可选,不会影响其他节点。新增 **NunchakuWheelInstaller** 节点,帮助您安装正确的 [Nunchaku](https://github.com/nunchaku-tech/nunchaku) wheel。
<details>
<summary>更多动态</summary>
- **[2025-06-01]** 🚀 **v0.3.0 发布!** 新增多 batch 推理、[**ControlNet-Union-Pro 2.0**](https://huggingface.co/Shakker-Labs/FLUX.1-dev-ControlNet-Union-Pro-2.0) 支持,以及初步集成 [**PuLID**](https://github.com/ToTheBeginning/PuLID)。现可将 Nunchaku FLUX 模型作为单文件加载,升级后的 [**4-bit T5 编码器**](https://huggingface.co/nunchaku-tech/nunchaku-t5) 质量媲美 **FP8 T5**
- **[2025-04-16]** 🎥 发布了 [**英文**](https://youtu.be/YHAVe-oM7U8?si=cM9zaby_aEHiFXk0)[**中文**](https://www.bilibili.com/video/BV1BTocYjEk5/?share_source=copy_web&vd_source=8926212fef622f25cc95380515ac74ee) 教学视频,助力安装与使用。
- **[2025-04-09]** 📢 发布了 [四月路线图](https://github.com/nunchaku-tech/nunchaku/issues/266)[FAQ](https://github.com/nunchaku-tech/nunchaku/discussions/262),帮助社区用户快速上手并了解最新进展。
- **[2025-04-05]** 🚀 **v0.2.0 发布!** 支持 [**多 LoRA**](example_workflows/nunchaku-flux.1-dev.json)[**ControlNet**](example_workflows/nunchaku-flux.1-dev-controlnet-union-pro.json),FP16 attention 与 First-Block Cache 性能增强。新增 [**20 系显卡**](examples/flux.1-dev-turing.py) 兼容性,并提供 [FLUX.1-redux](example_workflows/nunchaku-flux.1-redux-dev.json) 官方工作流!
</details>
## 快速上手
- [安装指南](https://nunchaku.tech/docs/ComfyUI-nunchaku/get_started/installation.html)
- [使用教程](https://nunchaku.tech/docs/ComfyUI-nunchaku/get_started/usage.html)
- [示例工作流](https://nunchaku.tech/docs/ComfyUI-nunchaku/workflows/toc.html)
- [节点参考](https://nunchaku.tech/docs/ComfyUI-nunchaku/nodes/toc.html)
- [API 参考](https://nunchaku.tech/docs/ComfyUI-nunchaku/api/toc.html)
- [自定义模型量化:DeepCompressor](https://github.com/nunchaku-tech/deepcompressor)
- [贡献指南](https://nunchaku.tech/docs/ComfyUI-nunchaku/developer/contribution_guide.html)
- [常见问题 FAQ](https://nunchaku.tech/docs/nunchaku/faq/faq.html)
import logging
import os
# Get log level from environment variable (default to INFO)
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
# Configure logging
logging.basicConfig(level=getattr(logging, log_level, logging.INFO), format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
logger.info("=" * 40 + " ComfyUI-nunchaku Initialization " + "=" * 40)
from .utils import get_package_version, get_plugin_version, supported_versions
nunchaku_full_version = get_package_version("nunchaku").split("+")[0].strip()
logger.info(f"Nunchaku version: {nunchaku_full_version}")
logger.info(f"ComfyUI-nunchaku version: {get_plugin_version()}")
nunchaku_version = nunchaku_full_version.split("+")[0].strip()
nunchaku_major_minor_patch_version = ".".join(nunchaku_version.split(".")[:3])
if f"v{nunchaku_major_minor_patch_version}" not in supported_versions:
logger.warning(
f"ComfyUI-nunchaku {get_plugin_version()} is not compatible with nunchaku {nunchaku_full_version}. "
f"Please update nunchaku to a supported version in {supported_versions}."
f"v1.0.0 currently is a nightly version. You can find the wheels at https://github.com/nunchaku-tech/nunchaku/releases/."
)
NODE_CLASS_MAPPINGS = {}
try:
from .nodes.models.flux import NunchakuFluxDiTLoader
NODE_CLASS_MAPPINGS["NunchakuFluxDiTLoader"] = NunchakuFluxDiTLoader
except ImportError:
logger.exception("Node `NunchakuFluxDiTLoader` import failed:")
try:
from .nodes.models.qwenimage import NunchakuQwenImageDiTLoader
NODE_CLASS_MAPPINGS["NunchakuQwenImageDiTLoader"] = NunchakuQwenImageDiTLoader
except ImportError:
logger.exception("Node `NunchakuQwenImageDiTLoader` import failed:")
try:
from .nodes.lora.flux import NunchakuFluxLoraLoader, NunchakuFluxLoraStack
NODE_CLASS_MAPPINGS["NunchakuFluxLoraLoader"] = NunchakuFluxLoraLoader
NODE_CLASS_MAPPINGS["NunchakuFluxLoraStack"] = NunchakuFluxLoraStack
except ImportError:
logger.exception("Nodes `NunchakuFluxLoraLoader` and `NunchakuFluxLoraStack` import failed:")
try:
from .nodes.models.text_encoder import NunchakuTextEncoderLoader, NunchakuTextEncoderLoaderV2
NODE_CLASS_MAPPINGS["NunchakuTextEncoderLoader"] = NunchakuTextEncoderLoader
NODE_CLASS_MAPPINGS["NunchakuTextEncoderLoaderV2"] = NunchakuTextEncoderLoaderV2
except ImportError:
logger.exception("Nodes `NunchakuTextEncoderLoader` and `NunchakuTextEncoderLoaderV2` import failed:")
try:
from .nodes.preprocessors.depth import FluxDepthPreprocessor
NODE_CLASS_MAPPINGS["NunchakuDepthPreprocessor"] = FluxDepthPreprocessor
except ImportError:
logger.exception("Node `NunchakuDepthPreprocessor` import failed:")
try:
from .nodes.models.pulid import (
NunchakuFluxPuLIDApplyV2,
NunchakuPulidApply,
NunchakuPulidLoader,
NunchakuPuLIDLoaderV2,
)
NODE_CLASS_MAPPINGS["NunchakuPulidApply"] = NunchakuPulidApply
NODE_CLASS_MAPPINGS["NunchakuPulidLoader"] = NunchakuPulidLoader
NODE_CLASS_MAPPINGS["NunchakuPuLIDLoaderV2"] = NunchakuPuLIDLoaderV2
NODE_CLASS_MAPPINGS["NunchakuFluxPuLIDApplyV2"] = NunchakuFluxPuLIDApplyV2
except ImportError:
logger.exception(
"Nodes `NunchakuPulidApply`,`NunchakuPulidLoader`, "
"`NunchakuPuLIDLoaderV2` and `NunchakuFluxPuLIDApplyV2` import failed:"
)
try:
from .nodes.models.ipadapter import NunchakuFluxIPAdapterApply, NunchakuIPAdapterLoader
NODE_CLASS_MAPPINGS["NunchakuFluxIPAdapterApply"] = NunchakuFluxIPAdapterApply
NODE_CLASS_MAPPINGS["NunchakuIPAdapterLoader"] = NunchakuIPAdapterLoader
except ImportError:
logger.exception("Nodes `NunchakuFluxIPAdapterApply` and `NunchakuIPAdapterLoader` import failed:")
try:
from .nodes.tools.merge_safetensors import NunchakuModelMerger
NODE_CLASS_MAPPINGS["NunchakuModelMerger"] = NunchakuModelMerger
except ImportError:
logger.exception("Node `NunchakuModelMerger` import failed:")
try:
from .nodes.tools.installers import NunchakuWheelInstaller
NODE_CLASS_MAPPINGS["NunchakuWheelInstaller"] = NunchakuWheelInstaller
except ImportError:
logger.exception("Node `NunchakuWheelInstaller` import failed:")
NODE_DISPLAY_NAME_MAPPINGS = {k: v.TITLE for k, v in NODE_CLASS_MAPPINGS.items()}
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
logger.info("=" * (80 + len(" ComfyUI-nunchaku Initialization ")))
{
"id": "e33d94b5-334c-4607-8ef0-6ca542730844",
"revision": 0,
"last_node_id": 3,
"last_link_id": 1,
"nodes": [
{
"id": 2,
"type": "PreviewAny",
"pos": [
659.4140625,
253.45053100585938
],
"size": [
418.6068115234375,
88
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "source",
"type": "*",
"link": 1
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.39",
"Node name for S&R": "PreviewAny"
},
"widgets_values": []
},
{
"id": 1,
"type": "NunchakuWheelInstaller",
"pos": [
299.934814453125,
255.38197326660156
],
"size": [
270,
82
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "status",
"type": "STRING",
"links": [
1
]
}
],
"properties": {
"Node name for S&R": "NunchakuWheelInstaller"
},
"widgets_values": [
"ModelScope",
"v0.3.0"
]
},
{
"id": 3,
"type": "Note",
"pos": [
310.68572998046875,
429.6354064941406
],
"size": [
250.13458251953125,
121.31512451171875
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"This workflow will automatically install the compatible Nunchaku wheels from GitHub Releases, Hugging Face, or ModelScope. Once installation is complete, please restart ComfyUI."
],
"color": "#432",
"bgcolor": "#653"
}
],
"links": [
[
1,
1,
0,
2,
0,
"*"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1,
"offset": [
286.0416564941406,
72.68229675292969
]
},
"frontendVersion": "1.20.7"
},
"version": 0.4
}
{
"id": "d1f50cbf-9a19-4468-87f2-51635bceee09",
"revision": 0,
"last_node_id": 7,
"last_link_id": 3,
"nodes": [
{
"id": 4,
"type": "PreviewAny",
"pos": [
730.3975830078125,
118.38714599609375
],
"size": [
531.5799560546875,
88
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "source",
"type": "*",
"link": 3
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.34",
"Node name for S&R": "PreviewAny"
},
"widgets_values": []
},
{
"id": 6,
"type": "Note",
"pos": [
327.0765380859375,
289.9415588378906
],
"size": [
435.1649169921875,
124.8914794921875
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"Follow this simple workflow to merge a previously saved SVDQuant model folder into a single `.safetensors` file:\n1. Place your existing SVDQuant model folders inside the `models/diffusion_models/` directory.\n2. Set the `model_folder` variable to the name of the folder you want to merge.\n3. The merged model file will be saved to `models/diffusion_models/` with the filename specified by `save_name`."
],
"color": "#432",
"bgcolor": "#653"
},
{
"id": 7,
"type": "NunchakuModelMerger",
"pos": [
322.8587951660156,
118.55458068847656
],
"size": [
328.3153076171875,
82
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "status",
"type": "STRING",
"links": [
3
]
}
],
"properties": {
"Node name for S&R": "NunchakuModelMerger"
},
"widgets_values": [
"svdq-fp4-flux.1-dev",
"svdq-fp4_r32-flux.1-dev"
]
}
],
"links": [
[
3,
7,
0,
4,
0,
"*"
]
],
"groups": [],
"config": {},
"extra": {
"frontendVersion": "1.18.10"
},
"version": 0.4
}
{
"id": "b2ac78a1-9f70-4787-baf7-9703dc66e15e",
"revision": 0,
"last_node_id": 43,
"last_link_id": 84,
"nodes": [
{
"id": 38,
"type": "ImageScale",
"pos": [
379.69903564453125,
565.2651977539062
],
"size": [
315,
130
],
"flags": {},
"order": 6,
"mode": 0,
"inputs": [
{
"localized_name": "image",
"name": "image",
"type": "IMAGE",
"link": 75
}
],
"outputs": [
{
"localized_name": "IMAGE",
"name": "IMAGE",
"type": "IMAGE",
"slot_index": 0,
"links": [
76
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "ImageScale"
},
"widgets_values": [
"nearest-exact",
1024,
1024,
"center"
]
},
{
"id": 35,
"type": "InstructPixToPixConditioning",
"pos": [
1031.3619384765625,
153.57142639160156
],
"size": [
235.1999969482422,
86
],
"flags": {},
"order": 11,
"mode": 0,
"inputs": [
{
"label": "positive",
"localized_name": "positive",
"name": "positive",
"type": "CONDITIONING",
"link": 67
},
{
"label": "negative",
"localized_name": "negative",
"name": "negative",
"type": "CONDITIONING",
"link": 68
},
{
"label": "vae",
"localized_name": "vae",
"name": "vae",
"type": "VAE",
"link": 69
},
{
"label": "pixels",
"localized_name": "pixels",
"name": "pixels",
"type": "IMAGE",
"link": 70
}
],
"outputs": [
{
"label": "positive",
"localized_name": "positive",
"name": "positive",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
64
]
},
{
"label": "negative",
"localized_name": "negative",
"name": "negative",
"type": "CONDITIONING",
"slot_index": 1,
"links": [
65
]
},
{
"label": "latent",
"localized_name": "latent",
"name": "latent",
"type": "LATENT",
"slot_index": 2,
"links": [
66
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "InstructPixToPixConditioning"
},
"widgets_values": []
},
{
"id": 18,
"type": "Canny",
"pos": [
744.2684936523438,
566.853515625
],
"size": [
315,
82
],
"flags": {},
"order": 9,
"mode": 0,
"inputs": [
{
"label": "image",
"localized_name": "image",
"name": "image",
"type": "IMAGE",
"link": 76
}
],
"outputs": [
{
"label": "IMAGE",
"localized_name": "IMAGE",
"name": "IMAGE",
"shape": 3,
"type": "IMAGE",
"slot_index": 0,
"links": [
26,
70
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "Canny"
},
"widgets_values": [
0.15,
0.3
]
},
{
"id": 32,
"type": "VAELoader",
"pos": [
1071.1641845703125,
376.27001953125
],
"size": [
315,
58
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"label": "VAE",
"localized_name": "VAE",
"name": "VAE",
"type": "VAE",
"slot_index": 0,
"links": [
60,
69
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "VAELoader"
},
"widgets_values": [
"ae.safetensors"
]
},
{
"id": 8,
"type": "VAEDecode",
"pos": [
1498.102294921875,
368.63604736328125
],
"size": [
210,
46
],
"flags": {},
"order": 13,
"mode": 0,
"inputs": [
{
"label": "samples",
"localized_name": "samples",
"name": "samples",
"type": "LATENT",
"link": 7
},
{
"label": "vae",
"localized_name": "vae",
"name": "vae",
"type": "VAE",
"link": 60
}
],
"outputs": [
{
"label": "IMAGE",
"localized_name": "IMAGE",
"name": "IMAGE",
"type": "IMAGE",
"slot_index": 0,
"links": [
9
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "VAEDecode"
},
"widgets_values": []
},
{
"id": 9,
"type": "SaveImage",
"pos": [
1738.742919921875,
57.38672637939453
],
"size": [
828.9535522460938,
893.8475341796875
],
"flags": {},
"order": 14,
"mode": 0,
"inputs": [
{
"label": "images",
"localized_name": "images",
"name": "images",
"type": "IMAGE",
"link": 9
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24"
},
"widgets_values": [
"ComfyUI",
""
]
},
{
"id": 26,
"type": "FluxGuidance",
"pos": [
899.2306518554688,
8.470590591430664
],
"size": [
317.4000244140625,
58
],
"flags": {},
"order": 8,
"mode": 0,
"inputs": [
{
"label": "conditioning",
"localized_name": "conditioning",
"name": "conditioning",
"type": "CONDITIONING",
"link": 41
}
],
"outputs": [
{
"label": "CONDITIONING",
"localized_name": "CONDITIONING",
"name": "CONDITIONING",
"shape": 3,
"type": "CONDITIONING",
"slot_index": 0,
"links": [
67
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "FluxGuidance"
},
"widgets_values": [
30
]
},
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
531.693359375,
458.5068054199219
],
"size": [
425.27801513671875,
180.6060791015625
],
"flags": {
"collapsed": true
},
"order": 5,
"mode": 0,
"inputs": [
{
"label": "clip",
"localized_name": "clip",
"name": "clip",
"type": "CLIP",
"link": 63
}
],
"outputs": [
{
"label": "CONDITIONING",
"localized_name": "CONDITIONING",
"name": "CONDITIONING",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
68
]
}
],
"title": "CLIP Text Encode (Negative Prompt)",
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
""
],
"color": "#322",
"bgcolor": "#533"
},
{
"id": 34,
"type": "DualCLIPLoader",
"pos": [
490.4931640625,
251.2148895263672
],
"size": [
315,
122
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [
{
"label": "CLIP",
"localized_name": "CLIP",
"name": "CLIP",
"type": "CLIP",
"links": [
62,
63
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "DualCLIPLoader"
},
"widgets_values": [
"clip_l.safetensors",
"t5xxl_fp16.safetensors",
"flux",
"default"
]
},
{
"id": 3,
"type": "KSampler",
"pos": [
1340.538818359375,
-73.13742065429688
],
"size": [
315,
262
],
"flags": {},
"order": 12,
"mode": 0,
"inputs": [
{
"label": "model",
"localized_name": "model",
"name": "model",
"type": "MODEL",
"link": 84
},
{
"label": "positive",
"localized_name": "positive",
"name": "positive",
"type": "CONDITIONING",
"link": 64
},
{
"label": "negative",
"localized_name": "negative",
"name": "negative",
"type": "CONDITIONING",
"link": 65
},
{
"label": "latent_image",
"localized_name": "latent_image",
"name": "latent_image",
"type": "LATENT",
"link": 66
}
],
"outputs": [
{
"label": "LATENT",
"localized_name": "LATENT",
"name": "LATENT",
"type": "LATENT",
"slot_index": 0,
"links": [
7
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "KSampler"
},
"widgets_values": [
107906103108925,
"randomize",
20,
1,
"euler",
"normal",
1
]
},
{
"id": 17,
"type": "LoadImage",
"pos": [
6.694743633270264,
562.3865966796875
],
"size": [
315,
314.0000305175781
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [],
"outputs": [
{
"label": "IMAGE",
"localized_name": "IMAGE",
"name": "IMAGE",
"shape": 3,
"type": "IMAGE",
"slot_index": 0,
"links": [
75
]
},
{
"label": "MASK",
"localized_name": "MASK",
"name": "MASK",
"shape": 3,
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"robot.png",
"image",
""
]
},
{
"id": 19,
"type": "PreviewImage",
"pos": [
1149.2786865234375,
565.11669921875
],
"size": [
439.3782653808594,
481.0416259765625
],
"flags": {},
"order": 10,
"mode": 0,
"inputs": [
{
"label": "images",
"localized_name": "images",
"name": "images",
"type": "IMAGE",
"link": 26
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "PreviewImage"
},
"widgets_values": [
""
]
},
{
"id": 23,
"type": "CLIPTextEncode",
"pos": [
442.4932861328125,
14.832307815551758
],
"size": [
422.84503173828125,
164.31304931640625
],
"flags": {},
"order": 4,
"mode": 0,
"inputs": [
{
"label": "clip",
"localized_name": "clip",
"name": "clip",
"type": "CLIP",
"link": 62
}
],
"outputs": [
{
"label": "CONDITIONING",
"localized_name": "CONDITIONING",
"name": "CONDITIONING",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
41
]
}
],
"title": "CLIP Text Encode (Positive Prompt)",
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"A robot made of exotic candies and chocolates of different kinds. The background is filled with confetti and celebratory gifts, yarn art style"
],
"color": "#232",
"bgcolor": "#353"
},
{
"id": 42,
"type": "NunchakuFluxDiTLoader",
"pos": [
78.86559295654297,
-122.51927185058594
],
"size": [
315,
202
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [],
"outputs": [
{
"localized_name": "MODEL",
"name": "MODEL",
"type": "MODEL",
"links": [
83
]
}
],
"properties": {
"Node name for S&R": "NunchakuFluxDiTLoader"
},
"widgets_values": [
"svdq-int4-flux.1-dev",
0,
"nunchaku-fp16",
"auto",
0,
"bfloat16",
"enabled"
]
},
{
"id": 43,
"type": "NunchakuFluxLoraLoader",
"pos": [
538.5196533203125,
-115.99840545654297
],
"size": [
340.20001220703125,
82
],
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"localized_name": "model",
"name": "model",
"type": "MODEL",
"link": 83
}
],
"outputs": [
{
"localized_name": "MODEL",
"name": "MODEL",
"type": "MODEL",
"links": [
84
]
}
],
"properties": {
"Node name for S&R": "NunchakuFluxLoraLoader"
},
"widgets_values": [
"canny.safetensors",
0.8500000000000002
]
}
],
"links": [
[
7,
3,
0,
8,
0,
"LATENT"
],
[
9,
8,
0,
9,
0,
"IMAGE"
],
[
26,
18,
0,
19,
0,
"IMAGE"
],
[
41,
23,
0,
26,
0,
"CONDITIONING"
],
[
60,
32,
0,
8,
1,
"VAE"
],
[
62,
34,
0,
23,
0,
"CLIP"
],
[
63,
34,
0,
7,
0,
"CLIP"
],
[
64,
35,
0,
3,
1,
"CONDITIONING"
],
[
65,
35,
1,
3,
2,
"CONDITIONING"
],
[
66,
35,
2,
3,
3,
"LATENT"
],
[
67,
26,
0,
35,
0,
"CONDITIONING"
],
[
68,
7,
0,
35,
1,
"CONDITIONING"
],
[
69,
32,
0,
35,
2,
"VAE"
],
[
70,
18,
0,
35,
3,
"IMAGE"
],
[
75,
17,
0,
38,
0,
"IMAGE"
],
[
76,
38,
0,
18,
0,
"IMAGE"
],
[
78,
36,
0,
40,
0,
"MODEL"
],
[
83,
42,
0,
43,
0,
"MODEL"
],
[
84,
43,
0,
3,
0,
"MODEL"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 0.8140274938684117,
"offset": [
633.2890855809035,
313.51162384315967
]
},
"node_versions": {
"comfy-core": "0.3.24"
}
},
"version": 0.4
}
{
"id": "b2ac78a1-9f70-4787-baf7-9703dc66e15e",
"revision": 0,
"last_node_id": 39,
"last_link_id": 77,
"nodes": [
{
"id": 9,
"type": "SaveImage",
"pos": [
1850,
40
],
"size": [
828.9535522460938,
893.8475341796875
],
"flags": {},
"order": 13,
"mode": 0,
"inputs": [
{
"label": "images",
"localized_name": "images",
"name": "images",
"type": "IMAGE",
"link": 9
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24"
},
"widgets_values": [
"ComfyUI",
""
]
},
{
"id": 32,
"type": "VAELoader",
"pos": [
1290,
350
],
"size": [
315,
58
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"label": "VAE",
"localized_name": "VAE",
"name": "VAE",
"type": "VAE",
"slot_index": 0,
"links": [
60,
69
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "VAELoader"
},
"widgets_values": [
"ae.safetensors"
]
},
{
"id": 18,
"type": "Canny",
"pos": [
744.2684936523438,
566.853515625
],
"size": [
315,
82
],
"flags": {},
"order": 8,
"mode": 0,
"inputs": [
{
"label": "image",
"localized_name": "image",
"name": "image",
"type": "IMAGE",
"link": 76
}
],
"outputs": [
{
"label": "IMAGE",
"localized_name": "IMAGE",
"name": "IMAGE",
"shape": 3,
"type": "IMAGE",
"slot_index": 0,
"links": [
26,
70
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "Canny"
},
"widgets_values": [
0.15,
0.3
]
},
{
"id": 38,
"type": "ImageScale",
"pos": [
379.69903564453125,
565.2651977539062
],
"size": [
315,
130
],
"flags": {},
"order": 6,
"mode": 0,
"inputs": [
{
"localized_name": "image",
"name": "image",
"type": "IMAGE",
"link": 75
}
],
"outputs": [
{
"localized_name": "IMAGE",
"name": "IMAGE",
"type": "IMAGE",
"slot_index": 0,
"links": [
76
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "ImageScale"
},
"widgets_values": [
"nearest-exact",
1024,
1024,
"center"
]
},
{
"id": 26,
"type": "FluxGuidance",
"pos": [
680.8111572265625,
112.23383331298828
],
"size": [
317.4000244140625,
58
],
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"label": "conditioning",
"localized_name": "conditioning",
"name": "conditioning",
"type": "CONDITIONING",
"link": 41
}
],
"outputs": [
{
"label": "CONDITIONING",
"localized_name": "CONDITIONING",
"name": "CONDITIONING",
"shape": 3,
"type": "CONDITIONING",
"slot_index": 0,
"links": [
67
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "FluxGuidance"
},
"widgets_values": [
30
]
},
{
"id": 23,
"type": "CLIPTextEncode",
"pos": [
244.5854949951172,
81.77906036376953
],
"size": [
422.84503173828125,
164.31304931640625
],
"flags": {},
"order": 4,
"mode": 0,
"inputs": [
{
"label": "clip",
"localized_name": "clip",
"name": "clip",
"type": "CLIP",
"link": 62
}
],
"outputs": [
{
"label": "CONDITIONING",
"localized_name": "CONDITIONING",
"name": "CONDITIONING",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
41
]
}
],
"title": "CLIP Text Encode (Positive Prompt)",
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"A robot made of exotic candies and chocolates of different kinds. The background is filled with confetti and celebratory gifts."
],
"color": "#232",
"bgcolor": "#353"
},
{
"id": 34,
"type": "DualCLIPLoader",
"pos": [
-220.53102111816406,
97.30029296875
],
"size": [
315,
122
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [
{
"label": "CLIP",
"localized_name": "CLIP",
"name": "CLIP",
"type": "CLIP",
"links": [
62,
63
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "DualCLIPLoader"
},
"widgets_values": [
"clip_l.safetensors",
"t5xxl_fp16.safetensors",
"flux",
"default"
]
},
{
"id": 8,
"type": "VAEDecode",
"pos": [
1699.7835693359375,
-60.63755416870117
],
"size": [
210,
46
],
"flags": {},
"order": 12,
"mode": 0,
"inputs": [
{
"label": "samples",
"localized_name": "samples",
"name": "samples",
"type": "LATENT",
"link": 7
},
{
"label": "vae",
"localized_name": "vae",
"name": "vae",
"type": "VAE",
"link": 60
}
],
"outputs": [
{
"label": "IMAGE",
"localized_name": "IMAGE",
"name": "IMAGE",
"type": "IMAGE",
"slot_index": 0,
"links": [
9
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "VAEDecode"
},
"widgets_values": []
},
{
"id": 3,
"type": "KSampler",
"pos": [
1320.5775146484375,
-80.12444305419922
],
"size": [
315,
262
],
"flags": {},
"order": 11,
"mode": 0,
"inputs": [
{
"label": "model",
"localized_name": "model",
"name": "model",
"type": "MODEL",
"link": 77
},
{
"label": "positive",
"localized_name": "positive",
"name": "positive",
"type": "CONDITIONING",
"link": 64
},
{
"label": "negative",
"localized_name": "negative",
"name": "negative",
"type": "CONDITIONING",
"link": 65
},
{
"label": "latent_image",
"localized_name": "latent_image",
"name": "latent_image",
"type": "LATENT",
"link": 66
}
],
"outputs": [
{
"label": "LATENT",
"localized_name": "LATENT",
"name": "LATENT",
"type": "LATENT",
"slot_index": 0,
"links": [
7
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "KSampler"
},
"widgets_values": [
39783659540192,
"randomize",
20,
1,
"euler",
"normal",
1
]
},
{
"id": 19,
"type": "PreviewImage",
"pos": [
1127.9403076171875,
554.3356323242188
],
"size": [
571.5869140625,
625.5296020507812
],
"flags": {},
"order": 9,
"mode": 0,
"inputs": [
{
"label": "images",
"localized_name": "images",
"name": "images",
"type": "IMAGE",
"link": 26
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "PreviewImage"
},
"widgets_values": [
""
]
},
{
"id": 35,
"type": "InstructPixToPixConditioning",
"pos": [
1031.3619384765625,
153.57142639160156
],
"size": [
235.1999969482422,
86
],
"flags": {},
"order": 10,
"mode": 0,
"inputs": [
{
"label": "positive",
"localized_name": "positive",
"name": "positive",
"type": "CONDITIONING",
"link": 67
},
{
"label": "negative",
"localized_name": "negative",
"name": "negative",
"type": "CONDITIONING",
"link": 68
},
{
"label": "vae",
"localized_name": "vae",
"name": "vae",
"type": "VAE",
"link": 69
},
{
"label": "pixels",
"localized_name": "pixels",
"name": "pixels",
"type": "IMAGE",
"link": 70
}
],
"outputs": [
{
"label": "positive",
"localized_name": "positive",
"name": "positive",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
64
]
},
{
"label": "negative",
"localized_name": "negative",
"name": "negative",
"type": "CONDITIONING",
"slot_index": 1,
"links": [
65
]
},
{
"label": "latent",
"localized_name": "latent",
"name": "latent",
"type": "LATENT",
"slot_index": 2,
"links": [
66
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "InstructPixToPixConditioning"
},
"widgets_values": []
},
{
"id": 17,
"type": "LoadImage",
"pos": [
6.694743633270264,
562.3865966796875
],
"size": [
315,
314.0000305175781
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [],
"outputs": [
{
"label": "IMAGE",
"localized_name": "IMAGE",
"name": "IMAGE",
"shape": 3,
"type": "IMAGE",
"slot_index": 0,
"links": [
75
]
},
{
"label": "MASK",
"localized_name": "MASK",
"name": "MASK",
"shape": 3,
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"robot.png",
"image",
""
]
},
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
287.2383728027344,
446.1422424316406
],
"size": [
425.27801513671875,
180.6060791015625
],
"flags": {
"collapsed": true,
"pinned": true
},
"order": 5,
"mode": 0,
"inputs": [
{
"label": "clip",
"localized_name": "clip",
"name": "clip",
"type": "CLIP",
"link": 63
}
],
"outputs": [
{
"label": "CONDITIONING",
"localized_name": "CONDITIONING",
"name": "CONDITIONING",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
68
]
}
],
"title": "CLIP Text Encode (Negative Prompt)",
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.24",
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
""
],
"color": "#322",
"bgcolor": "#533"
},
{
"id": 39,
"type": "NunchakuFluxDiTLoader",
"pos": [
793.3363647460938,
-164.9036102294922
],
"size": [
315,
202
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [],
"outputs": [
{
"localized_name": "MODEL",
"name": "MODEL",
"type": "MODEL",
"links": [
77
]
}
],
"properties": {
"Node name for S&R": "NunchakuFluxDiTLoader"
},
"widgets_values": [
"svdq-int4-flux.1-canny-dev",
0,
"nunchaku-fp16",
"auto",
0,
"bfloat16",
"enabled"
]
}
],
"links": [
[
7,
3,
0,
8,
0,
"LATENT"
],
[
9,
8,
0,
9,
0,
"IMAGE"
],
[
26,
18,
0,
19,
0,
"IMAGE"
],
[
41,
23,
0,
26,
0,
"CONDITIONING"
],
[
60,
32,
0,
8,
1,
"VAE"
],
[
62,
34,
0,
23,
0,
"CLIP"
],
[
63,
34,
0,
7,
0,
"CLIP"
],
[
64,
35,
0,
3,
1,
"CONDITIONING"
],
[
65,
35,
1,
3,
2,
"CONDITIONING"
],
[
66,
35,
2,
3,
3,
"LATENT"
],
[
67,
26,
0,
35,
0,
"CONDITIONING"
],
[
68,
7,
0,
35,
1,
"CONDITIONING"
],
[
69,
32,
0,
35,
2,
"VAE"
],
[
70,
18,
0,
35,
3,
"IMAGE"
],
[
75,
17,
0,
38,
0,
"IMAGE"
],
[
76,
38,
0,
18,
0,
"IMAGE"
],
[
77,
39,
0,
3,
0,
"MODEL"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 0.9849732675807723,
"offset": [
350.6069209843413,
371.94271826301787
]
},
"node_versions": {
"comfy-core": "0.3.24"
}
},
"version": 0.4
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment