Hairstyle Changer
Try any haircut or hair color before you commit. Upload a selfie and use the hairstyle changer workflow to a variety of hair options.
概要
Hairstyle Changer is a ComfyUI workflow that lets you preview different haircuts and hair colors on a selfie before you commit. It starts with LoadImage to bring in your photo, then routes your style choices through ComfySwitchNode and preset strings defined in PrimitiveStringMultiline. Those choices are combined with StringConcatenate and, when needed, pulled from a structured presets block via JsonExtractString. The edited result is displayed in PreviewAny and saved through SaveImage.
At the core is a custom processing node (id: d4c06663-cb1a-4a41-a36b-f09c93e55e7e) that applies the hairstyle/color change using the inputs prepared upstream. CustomCombo is used to package the image and text parameters into a clean input for that node. This parameterized design makes it easy to A/B test looks simply by flipping the ComfySwitchNode or tweaking the preset strings—keeping your original photo intact while focusing changes on hair appearance.
入力するもの
- ワークフローを読み込み中
ComfyUI で実行できます。 このワークフローはこのページでは実行できません。すべてが読み込まれた状態でComfy Cloudで開くか、ご自身のComfyUI用にダウンロードしてください。
Cloudで試すワークフローの内部
ノードグラフの読み取り専用プレビューです。ノードを編集するには、Comfy Cloudで開くかダウンロードしてください。
Loading the graph
Open full-size workflow preview- 作成者
- Rob
カスタムノードが必要です
- ワークフローを読み込み中
コードからこのワークフローを使用する
可能な場合はワークフローグラフと入力から生成されます。それ以外の場合は保存された例が表示されます。料金が発生する場合があるため、コードを実行する前に認証情報とエンドポイントを確認してください。
What you need
- Runs on
- Comfy Cloud
- キー
- COMFY_API_KEY
有料の Cloud プランとクレジットが必要です。
# Python 3.10+: pip install comfy-sdk==0.4.0
import os
from comfy_sdk import Comfy
api_key = os.environ.get("COMFY_API_KEY", "").strip()
if not api_key: raise RuntimeError("Set COMFY_API_KEY")
os.environ.setdefault("COMFY_BASE_URL", "https://cloud.comfy.org")
client = Comfy(api_key=api_key)
workflow = client.workflows.from_json({
"132": {
"class_type": "LoadImage",
"inputs": {
"image": "e6bc10130ce0e9dbd3573751650d9f01c2687728383958094ab49d0b35ccfeae.png"
},
"_meta": {
"title": "Load Image"
}
},
"197": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "Qwen_Edit_2511",
"images": [
"196:175",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"234": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": " ",
"string_a": "Keep the exact same facial identity, facial features, expression, pose, clothing, background, lighting, and composition as the original photo. Only change the subject's hair.",
"string_b": [
"258",
0
]
},
"_meta": {
"title": "Assemble Prompt"
}
},
"235": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"234",
0
]
},
"_meta": {
"title": "Preview as Text"
}
},
"252": {
"class_type": "CustomCombo",
"inputs": {
"choice": "Long Waves"
},
"_meta": {
"title": "Hairstyle"
}
},
"253": {
"class_type": "JsonExtractString",
"inputs": {
"json_string": "{\n \"Buzz Cut\": \"Change the subject's hairstyle to a very short, even buzz cut with a clean hairline.\",\n \"Slicked Back\": \"Change the subject's hairstyle to medium-length hair combed straight back with a polished sheen.\",\n \"Side Part\": \"Change the subject's hairstyle to a classic neatly combed side part with a crisp parting line.\",\n \"Textured Quiff\": \"Change the subject's hairstyle to a voluminous textured quiff with short faded sides.\",\n \"Curly Top\": \"Change the subject's hairstyle to tight natural curls on top with tapered short sides.\",\n \"Afro\": \"Change the subject's hairstyle to a full, rounded natural afro with soft, even volume.\",\n \"Long Waves\": \"Change the subject's hairstyle to shoulder-length loose, flowing waves with natural body.\",\n \"Long Straight\": \"Change the subject's hairstyle to long, sleek, straight hair falling past the shoulders.\",\n \"Bob Cut\": \"Change the subject's hairstyle to a chin-length blunt bob with a smooth, even edge.\",\n \"Pixie Cut\": \"Change the subject's hairstyle to a short, cropped pixie cut with soft feathered layers.\",\n \"Box Braids\": \"Change the subject's hairstyle to neat medium-width box braids falling to the shoulders.\",\n \"High Ponytail\": \"Change the subject's hairstyle to hair pulled up into a sleek high ponytail.\",\n \"Top Knot Bun\": \"Change the subject's hairstyle to hair gathered into a neat top-knot bun.\",\n \"Mohawk\": \"Change the subject's hairstyle to a bold upright mohawk with closely shaved sides.\",\n \"Bald\": \"Remove the subject's hair entirely, giving them a cleanly shaved bald head with natural scalp texture.\"\n}",
"key": [
"252",
0
]
},
"_meta": {
"title": "Hairstyle Prompt (JSON)"
}
},
"256": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": " ",
"string_a": [
"253",
0
],
"string_b": [
"263",
0
]
},
"_meta": {
"title": "Hairstyle + Color"
}
},
"257": {
"class_type": "PrimitiveStringMultiline",
"inputs": {
"value": "Change the subject's hairstyle to shoulder-length loose waves colored copper red. Keep everything else exactly the same."
},
"_meta": {
"title": "Custom Prompt Text"
}
},
"258": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"256",
0
],
"on_true": [
"257",
0
],
"switch": False
},
"_meta": {
"title": "Custom Prompt?"
}
},
"262": {
"class_type": "CustomCombo",
"inputs": {
"choice": "Platinum White"
},
"_meta": {
"title": "Hair Color"
}
},
"263": {
"class_type": "JsonExtractString",
"inputs": {
"json_string": "{\n \"Keep Original Color\": \"Keep the subject's original hair color.\",\n \"Blonde\": \"The hair is colored blonde.\",\n \"Dark Brown\": \"The hair is colored dark brown.\",\n \"Black\": \"The hair is colored black.\",\n \"Auburn Red\": \"The hair is colored auburn red.\",\n \"Platinum White\": \"The hair is colored platinum white.\",\n \"Silver Gray\": \"The hair is colored silver gray.\"\n}",
"key": [
"262",
0
]
},
"_meta": {
"title": "Hair Color Prompt (JSON)"
}
},
"196:152": {
"class_type": "CFGNorm",
"inputs": {
"model": [
"196:155",
0
],
"pre_cfg": False,
"strength": 1
},
"_meta": {
"title": "CFGNorm"
}
},
"196:155": {
"class_type": "ModelSamplingAuraFlow",
"inputs": {
"model": [
"196:166",
0
],
"sampling": "flow",
"shift": 3.1
},
"_meta": {
"title": "ModelSamplingAuraFlow"
}
},
"196:156": {
"class_type": "VAELoader",
"inputs": {
"vae_name": "qwen_image_vae.safetensors"
},
"_meta": {
"title": "Load VAE"
}
},
"196:161": {
"class_type": "TextEncodeQwenImageEditPlus",
"inputs": {
"clip": [
"196:167",
0
],
"image1": [
"196:176",
0
],
"prompt": [
"235",
0
],
"vae": [
"196:156",
0
]
},
"_meta": {
"title": "TextEncodeQwenImageEditPlus (Positive)"
}
},
"196:162": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "Qwen-Image-Edit-2511-Lightning-4steps-V1.0-bf16.safetensors",
"model": [
"196:152",
0
],
"strength_model": 1
},
"_meta": {
"title": "Load LoRA"
}
},
"196:163": {
"class_type": "PrimitiveFloat",
"inputs": {
"value": 4
},
"_meta": {
"title": "CFG"
}
},
"196:164": {
"class_type": "PrimitiveFloat",
"inputs": {
"value": 1
},
"_meta": {
"title": "CFG"
}
},
"196:165": {
"class_type": "VAEEncode",
"inputs": {
"pixels": [
"196:176",
0
],
"vae": [
"196:156",
0
]
},
"_meta": {
"title": "VAE Encode"
}
},
"196:166": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "qwen_image_edit_2511_bf16.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"196:167": {
"class_type": "CLIPLoader",
"inputs": {
"clip_name": "qwen_2.5_vl_7b_fp8_scaled.safetensors",
"device": "default",
"type": "qwen_image"
},
"_meta": {
"title": "Load CLIP"
}
},
"196:168": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"196:152",
0
],
"on_true": [
"196:162",
0
],
"switch": [
"196:171",
0
]
},
"_meta": {
"title": "Switch (Model)"
}
},
"196:169": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 6
},
"_meta": {
"title": "Steps"
}
},
"196:170": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 30
},
"_meta": {
"title": "Steps"
}
},
"196:171": {
"class_type": "PrimitiveBoolean",
"inputs": {
"value": True
},
"_meta": {
"title": "Enable 4steps LoRA?"
}
},
"196:172": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"196:163",
0
],
"on_true": [
"196:164",
0
],
"switch": [
"196:171",
0
]
},
"_meta": {
"title": "Switch (CFG)"
}
},
"196:173": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"196:170",
0
],
"on_true": [
"196:169",
0
],
"switch": [
"196:171",
0
]
},
"_meta": {
"title": "Switch (Steps)"
}
},
"196:174": {
"class_type": "KSampler",
"inputs": {
"cfg": [
"196:172",
0
],
"denoise": 1,
"latent_image": [
"196:165",
0
],
"model": [
"196:168",
0
],
"negative": [
"196:229",
0
],
"positive": [
"196:161",
0
],
"sampler_name": "euler",
"scheduler": "simple",
"seed": 935848232837487,
"steps": [
"196:173",
0
]
},
"_meta": {
"title": "KSampler"
}
},
"196:175": {
"class_type": "VAEDecode",
"inputs": {
"samples": [
"196:174",
0
],
"vae": [
"196:156",
0
]
},
"_meta": {
"title": "VAE Decode"
}
},
"196:176": {
"class_type": "FluxKontextImageScale",
"inputs": {
"image": [
"132",
0
]
},
"_meta": {
"title": "FluxKontextImageScale"
}
},
"196:229": {
"class_type": "TextEncodeQwenImageEditPlus",
"inputs": {
"clip": [
"196:167",
0
],
"image1": [
"196:176",
0
],
"prompt": "",
"vae": [
"196:156",
0
]
},
"_meta": {
"title": "Text Encode Qwen Image Edit Plus"
}
}
})
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)よくある質問
A front-facing photo with even lighting, minimal shadows, and hair clearly visible. Avoid hats, heavy hair accessories, or obstructions. A neutral background helps the processor focus on hair.
It is configured to target hair appearance via the custom processor (node id d4c06663-cb1a-4a41-a36b-f09c93e55e7e) and its text parameters. Minor spill to nearby regions can occur; if you see drift, try a tighter crop around the head, reduce extreme style changes in the preset text, and rerun.
Edit PrimitiveStringMultiline to include new preset entries (e.g., keys like "copper_lob" or "icy_blonde"). Use JsonExtractString to pull those entries, and ensure your ComfySwitchNode points to the correct keys. StringConcatenate will assemble the final parameter string for the processor.
Install the extension that provides the custom node with id d4c06663-cb1a-4a41-a36b-f09c93e55e7e and restart ComfyUI. Check the ComfyUI console/log for the exact repository or package name if it’s indicated by your setup.