feat(enhance): LoRA switches per template (#218)
A template can offer optional LoRAs the app turns on or off.
- enhance.toml: [[template.lora]] { id, label, default } per template.
Each id drives every workflow node titled `imageapi:lora:<id>`, so
Wan's high- and low-noise pair share one switch.
- POST /enhance takes `loras: {id: bool}`; a missing id uses its default,
an id the template doesn't offer is a 400. Off sets strength_model
(and strength_clip when present) to 0, so the graph is never rewired.
- The resolved switches are stored on the job (new enhance_jobs.loras
JSON column) and returned in the job view, so a retry or adjust can
repeat them; GET /enhance/templates lists each template's switches.
- A lora-titled node without a declaration keeps its exported strength,
and a declaration without nodes isn't offered; both are startup
warnings. A lora-titled node without a numeric strength_model fails
the template.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e317bfee98
commit
31da21e061
12 files changed
+910
-33
No files matched your search
+348
@@ -0,0 +1,348 @@
|
||||
{
|
||||
"1": {
|
||||
"class_type": "ImageApiLoadImageFromPath",
|
||||
"_meta": {
|
||||
"title": "imageapi:source"
|
||||
},
|
||||
"inputs": {
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"class_type": "ImageApiTargetSize",
|
||||
"_meta": {
|
||||
"title": "Target Size (~0.92 MP, keeps aspect)"
|
||||
},
|
||||
"inputs": {
|
||||
"image": [
|
||||
"1",
|
||||
0
|
||||
],
|
||||
"max_megapixels": 0.92,
|
||||
"min_megapixels": 0.92,
|
||||
"multiple_of": 16
|
||||
}
|
||||
},
|
||||
"10": {
|
||||
"class_type": "UNETLoader",
|
||||
"_meta": {
|
||||
"title": "Wan 2.2 i2v high noise"
|
||||
},
|
||||
"inputs": {
|
||||
"unet_name": "wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors",
|
||||
"weight_dtype": "default"
|
||||
}
|
||||
},
|
||||
"11": {
|
||||
"class_type": "UNETLoader",
|
||||
"_meta": {
|
||||
"title": "Wan 2.2 i2v low noise"
|
||||
},
|
||||
"inputs": {
|
||||
"unet_name": "wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors",
|
||||
"weight_dtype": "default"
|
||||
}
|
||||
},
|
||||
"12": {
|
||||
"class_type": "LoraLoaderModelOnly",
|
||||
"_meta": {
|
||||
"title": "lightx2v 4-step (high)"
|
||||
},
|
||||
"inputs": {
|
||||
"model": [
|
||||
"10",
|
||||
0
|
||||
],
|
||||
"lora_name": "wan2.2_i2v_lightx2v_4steps_lora_v1_high_noise.safetensors",
|
||||
"strength_model": 1.0
|
||||
}
|
||||
},
|
||||
"13": {
|
||||
"class_type": "LoraLoaderModelOnly",
|
||||
"_meta": {
|
||||
"title": "lightx2v 4-step (low)"
|
||||
},
|
||||
"inputs": {
|
||||
"model": [
|
||||
"11",
|
||||
0
|
||||
],
|
||||
"lora_name": "wan2.2_i2v_lightx2v_4steps_lora_v1_low_noise.safetensors",
|
||||
"strength_model": 1.0
|
||||
}
|
||||
},
|
||||
"14": {
|
||||
"class_type": "ModelSamplingSD3",
|
||||
"_meta": {
|
||||
"title": "Shift (high)"
|
||||
},
|
||||
"inputs": {
|
||||
"model": [
|
||||
"50",
|
||||
0
|
||||
],
|
||||
"shift": 5.0
|
||||
}
|
||||
},
|
||||
"15": {
|
||||
"class_type": "ModelSamplingSD3",
|
||||
"_meta": {
|
||||
"title": "Shift (low)"
|
||||
},
|
||||
"inputs": {
|
||||
"model": [
|
||||
"51",
|
||||
0
|
||||
],
|
||||
"shift": 5.0
|
||||
}
|
||||
},
|
||||
"40": {
|
||||
"class_type": "PathchSageAttentionKJ",
|
||||
"_meta": {
|
||||
"title": "Sage attention (high)"
|
||||
},
|
||||
"inputs": {
|
||||
"model": [
|
||||
"14",
|
||||
0
|
||||
],
|
||||
"sage_attention": "auto"
|
||||
}
|
||||
},
|
||||
"41": {
|
||||
"class_type": "PathchSageAttentionKJ",
|
||||
"_meta": {
|
||||
"title": "Sage attention (low)"
|
||||
},
|
||||
"inputs": {
|
||||
"model": [
|
||||
"15",
|
||||
0
|
||||
],
|
||||
"sage_attention": "auto"
|
||||
}
|
||||
},
|
||||
"16": {
|
||||
"class_type": "CLIPLoader",
|
||||
"_meta": {
|
||||
"title": "Load CLIP"
|
||||
},
|
||||
"inputs": {
|
||||
"clip_name": "umt5_xxl_fp8_e4m3fn_scaled.safetensors",
|
||||
"type": "wan",
|
||||
"device": "default"
|
||||
}
|
||||
},
|
||||
"17": {
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "imageapi:prompt"
|
||||
},
|
||||
"inputs": {
|
||||
"clip": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"text": "natural, lifelike motion with a slow, gentle camera movement, realistic, cinematic"
|
||||
}
|
||||
},
|
||||
"18": {
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "Negative"
|
||||
},
|
||||
"inputs": {
|
||||
"clip": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"text": "static, frozen, blurry, low quality, distorted, warped faces, morphing, flicker, watermark, text"
|
||||
}
|
||||
},
|
||||
"19": {
|
||||
"class_type": "VAELoader",
|
||||
"_meta": {
|
||||
"title": "Load VAE"
|
||||
},
|
||||
"inputs": {
|
||||
"vae_name": "wan_2.1_vae.safetensors"
|
||||
}
|
||||
},
|
||||
"21": {
|
||||
"class_type": "WanImageToVideo",
|
||||
"_meta": {
|
||||
"title": "Wan Image To Video (81 frames)"
|
||||
},
|
||||
"inputs": {
|
||||
"positive": [
|
||||
"17",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"18",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"19",
|
||||
0
|
||||
],
|
||||
"start_image": [
|
||||
"1",
|
||||
0
|
||||
],
|
||||
"width": [
|
||||
"2",
|
||||
0
|
||||
],
|
||||
"height": [
|
||||
"2",
|
||||
1
|
||||
],
|
||||
"length": 81,
|
||||
"batch_size": 1
|
||||
}
|
||||
},
|
||||
"22": {
|
||||
"class_type": "KSamplerAdvanced",
|
||||
"_meta": {
|
||||
"title": "Sampler (high, steps 0-2)"
|
||||
},
|
||||
"inputs": {
|
||||
"model": [
|
||||
"40",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"21",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"21",
|
||||
1
|
||||
],
|
||||
"latent_image": [
|
||||
"21",
|
||||
2
|
||||
],
|
||||
"add_noise": "enable",
|
||||
"noise_seed": 1,
|
||||
"steps": 4,
|
||||
"cfg": 1.0,
|
||||
"sampler_name": "euler",
|
||||
"scheduler": "simple",
|
||||
"start_at_step": 0,
|
||||
"end_at_step": 2,
|
||||
"return_with_leftover_noise": "enable"
|
||||
}
|
||||
},
|
||||
"23": {
|
||||
"class_type": "KSamplerAdvanced",
|
||||
"_meta": {
|
||||
"title": "Sampler (low, steps 2-4)"
|
||||
},
|
||||
"inputs": {
|
||||
"model": [
|
||||
"41",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"21",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"21",
|
||||
1
|
||||
],
|
||||
"latent_image": [
|
||||
"22",
|
||||
0
|
||||
],
|
||||
"add_noise": "disable",
|
||||
"noise_seed": 0,
|
||||
"steps": 4,
|
||||
"cfg": 1.0,
|
||||
"sampler_name": "euler",
|
||||
"scheduler": "simple",
|
||||
"start_at_step": 2,
|
||||
"end_at_step": 10000,
|
||||
"return_with_leftover_noise": "disable"
|
||||
}
|
||||
},
|
||||
"24": {
|
||||
"class_type": "VAEDecode",
|
||||
"_meta": {
|
||||
"title": "VAE Decode"
|
||||
},
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"23",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"19",
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"25": {
|
||||
"class_type": "CreateVideo",
|
||||
"_meta": {
|
||||
"title": "Create Video (16 fps)"
|
||||
},
|
||||
"inputs": {
|
||||
"images": [
|
||||
"24",
|
||||
0
|
||||
],
|
||||
"fps": 16.0
|
||||
}
|
||||
},
|
||||
"36": {
|
||||
"class_type": "ImageApiSaveVideoVersion",
|
||||
"_meta": {
|
||||
"title": "imageapi:save"
|
||||
},
|
||||
"inputs": {
|
||||
"video": [
|
||||
"25",
|
||||
0
|
||||
],
|
||||
"source": [
|
||||
"1",
|
||||
1
|
||||
],
|
||||
"kind": "animated",
|
||||
"subfolder": "aiedits",
|
||||
"require_approval": true
|
||||
}
|
||||
},
|
||||
"50": {
|
||||
"inputs": {
|
||||
"lora_name": "example_style_high.safetensors",
|
||||
"strength_model": 1.0,
|
||||
"model": [
|
||||
"12",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LoraLoaderModelOnly",
|
||||
"_meta": {
|
||||
"title": "imageapi:lora:style"
|
||||
}
|
||||
},
|
||||
"51": {
|
||||
"inputs": {
|
||||
"lora_name": "example_style_low.safetensors",
|
||||
"strength_model": 1.0,
|
||||
"model": [
|
||||
"13",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LoraLoaderModelOnly",
|
||||
"_meta": {
|
||||
"title": "imageapi:lora:style"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user