390 lines
9.7 KiB
Rust
390 lines
9.7 KiB
Rust
//! AI Model Face & Hair Detail Fix Template
|
||
//!
|
||
//! This template performs detailed face and hair enhancement for AI model photos.
|
||
//! It uses segmentation masks and local inpainting to improve facial features and hair quality.
|
||
//!
|
||
//! Features:
|
||
//! - Automatic face and hair segmentation
|
||
//! - Two-stage local inpainting (hair first, then face)
|
||
//! - Configurable denoising strength
|
||
//! - High-quality detail enhancement
|
||
|
||
use std::collections::HashMap;
|
||
use serde_json::json;
|
||
use crate::types::{
|
||
WorkflowTemplateData, TemplateMetadata, ParameterSchema, ParameterType,
|
||
ComfyUIWorkflow
|
||
};
|
||
|
||
/// AI Model Face & Hair Detail Fix Template
|
||
pub static AI_MODEL_FACE_HAIR_FIX_TEMPLATE: once_cell::sync::Lazy<WorkflowTemplateData> =
|
||
once_cell::sync::Lazy::new(|| {
|
||
create_ai_model_face_hair_fix_template()
|
||
});
|
||
|
||
fn create_ai_model_face_hair_fix_template() -> WorkflowTemplateData {
|
||
let metadata = TemplateMetadata {
|
||
id: "ai-model-face-hair-fix".to_string(),
|
||
name: "AI Model Face & Hair Detail Fix".to_string(),
|
||
description: Some("Professional face and hair detail enhancement for AI model photos using segmentation and local inpainting".to_string()),
|
||
category: Some("enhancement".to_string()),
|
||
tags: Some(vec![
|
||
"face-enhancement".to_string(),
|
||
"hair-enhancement".to_string(),
|
||
"portrait".to_string(),
|
||
"ai-model".to_string(),
|
||
"detail-fix".to_string(),
|
||
"inpainting".to_string(),
|
||
]),
|
||
version: Some("1.0.0".to_string()),
|
||
author: Some("ComfyUI SDK".to_string()),
|
||
created_at: None,
|
||
updated_at: None,
|
||
};
|
||
|
||
let mut parameters = HashMap::new();
|
||
|
||
parameters.insert("input_image".to_string(), ParameterSchema {
|
||
param_type: ParameterType::String,
|
||
required: Some(true),
|
||
default: Some(json!("20250806-190606.jpg")),
|
||
description: Some("Input image filename to enhance".to_string()),
|
||
r#enum: None,
|
||
min: None,
|
||
max: None,
|
||
step: None,
|
||
pattern: None,
|
||
items: None,
|
||
properties: None,
|
||
accept: None,
|
||
max_size: None,
|
||
width: None,
|
||
height: None,
|
||
duration: None,
|
||
node_mapping: None,
|
||
});
|
||
|
||
parameters.insert("face_prompt".to_string(), ParameterSchema {
|
||
param_type: ParameterType::String,
|
||
required: Some(true),
|
||
default: Some(json!("A girl, slim figure, oval face, beauty, Pink and greasy lips,")),
|
||
description: Some("Positive prompt for face enhancement".to_string()),
|
||
r#enum: None,
|
||
min: None,
|
||
max: None,
|
||
step: None,
|
||
pattern: None,
|
||
items: None,
|
||
properties: None,
|
||
accept: None,
|
||
max_size: None,
|
||
width: None,
|
||
height: None,
|
||
duration: None,
|
||
node_mapping: None,
|
||
});
|
||
|
||
parameters.insert("face_denoise".to_string(), ParameterSchema {
|
||
param_type: ParameterType::String,
|
||
required: Some(true),
|
||
default: Some(json!("0.30")),
|
||
description: Some("Denoising strength for face enhancement".to_string()),
|
||
r#enum: None,
|
||
min: None,
|
||
max: None,
|
||
step: None,
|
||
pattern: None,
|
||
items: None,
|
||
properties: None,
|
||
accept: None,
|
||
max_size: None,
|
||
width: None,
|
||
height: None,
|
||
duration: None,
|
||
node_mapping: None,
|
||
});
|
||
|
||
let workflow = create_workflow_from_json();
|
||
|
||
WorkflowTemplateData {
|
||
metadata,
|
||
workflow,
|
||
parameters,
|
||
}
|
||
}
|
||
|
||
fn create_workflow_from_json() -> ComfyUIWorkflow {
|
||
let workflow_json = r#"
|
||
{
|
||
"6": {
|
||
"inputs": {
|
||
"模糊强度": 3,
|
||
"mask": ["53", 1]
|
||
},
|
||
"class_type": "EG_ZZ_MHHT",
|
||
"_meta": {
|
||
"title": "2🐕遮罩边缘滑条快速模糊"
|
||
}
|
||
},
|
||
"8": {
|
||
"inputs": {
|
||
"ckpt_name": "juggernaut_reborn_sd1,5.safetensors"
|
||
},
|
||
"class_type": "CheckpointLoaderSimple",
|
||
"_meta": {
|
||
"title": "Checkpoint加载器(简易)"
|
||
}
|
||
},
|
||
"9": {
|
||
"inputs": {
|
||
"text": "Smooth long hair,Hair details, quality hair,Smooth hair",
|
||
"clip": ["8", 1]
|
||
},
|
||
"class_type": "CLIPTextEncode",
|
||
"_meta": {
|
||
"title": "CLIP文本编码"
|
||
}
|
||
},
|
||
"10": {
|
||
"inputs": {
|
||
"text": "Frizzy hair, dry hair, split ends,bad quality, poor quality, doll, disfigured, jpg, toy, bad anatomy, missing limbs, missing fingers, 3d, cgi",
|
||
"clip": ["8", 1]
|
||
},
|
||
"class_type": "CLIPTextEncode",
|
||
"_meta": {
|
||
"title": "CLIP文本编码"
|
||
}
|
||
},
|
||
"13": {
|
||
"inputs": {
|
||
"text": ["59", 0],
|
||
"clip": ["8", 1]
|
||
},
|
||
"class_type": "CLIPTextEncode",
|
||
"_meta": {
|
||
"title": "CLIP文本编码"
|
||
}
|
||
},
|
||
"14": {
|
||
"inputs": {
|
||
"text": "(NSFW:1.2),(worst quality:1.2),(low quality:1.2),(normal quality:1.2),low resolution,watermark,",
|
||
"clip": ["8", 1]
|
||
},
|
||
"class_type": "CLIPTextEncode",
|
||
"_meta": {
|
||
"title": "CLIP文本编码"
|
||
}
|
||
},
|
||
"22": {
|
||
"inputs": {
|
||
"detail_method": "VITMatte(local)",
|
||
"detail_erode": 44,
|
||
"detail_dilate": 6,
|
||
"black_point": 0.030000000000000006,
|
||
"white_point": 0.99,
|
||
"process_detail": true,
|
||
"device": "cuda",
|
||
"max_megapixels": 2,
|
||
"image": ["30", 0],
|
||
"segformer_pipeline": ["28", 0]
|
||
},
|
||
"class_type": "LayerMask: SegformerUltraV2",
|
||
"_meta": {
|
||
"title": "LayerMask: Segformer Ultra V2"
|
||
}
|
||
},
|
||
"25": {
|
||
"inputs": {
|
||
"seed": 646617836820462,
|
||
"steps": 30,
|
||
"cfg": 4.5200000000000005,
|
||
"sampler_name": "dpmpp_2s_ancestral",
|
||
"scheduler": "karras",
|
||
"denoise": 0.4,
|
||
"重绘模式": "原图",
|
||
"遮罩延展": 10,
|
||
"仅局部重绘": true,
|
||
"局部重绘大小": 768,
|
||
"重绘区域扩展": 50,
|
||
"遮罩羽化": 5,
|
||
"TEXT": "2🐕出品,必出精品",
|
||
"model": ["8", 0],
|
||
"image": ["30", 0],
|
||
"vae": ["8", 2],
|
||
"mask": ["47", 0],
|
||
"positive": ["9", 0],
|
||
"negative": ["10", 0]
|
||
},
|
||
"class_type": "EG_CYQ_JB",
|
||
"_meta": {
|
||
"title": "2🐕局部重绘采样器"
|
||
}
|
||
},
|
||
"26": {
|
||
"inputs": {
|
||
"seed": 969968724502727,
|
||
"steps": 30,
|
||
"cfg": 4.5200000000000005,
|
||
"sampler_name": "dpmpp_2s_ancestral",
|
||
"scheduler": "karras",
|
||
"denoise": ["71", 0],
|
||
"重绘模式": "原图",
|
||
"遮罩延展": 10,
|
||
"仅局部重绘": true,
|
||
"局部重绘大小": 768,
|
||
"重绘区域扩展": 50,
|
||
"遮罩羽化": 5,
|
||
"TEXT": "2🐕出品,必出精品",
|
||
"model": ["8", 0],
|
||
"image": ["25", 1],
|
||
"vae": ["8", 2],
|
||
"mask": ["6", 0],
|
||
"positive": ["13", 0],
|
||
"negative": ["14", 0]
|
||
},
|
||
"class_type": "EG_CYQ_JB",
|
||
"_meta": {
|
||
"title": "2🐕局部重绘采样器"
|
||
}
|
||
},
|
||
"28": {
|
||
"inputs": {
|
||
"model": "segformer_b3_clothes",
|
||
"face": false,
|
||
"hair": true,
|
||
"hat": false,
|
||
"sunglass": false,
|
||
"left_arm": false,
|
||
"right_arm": false,
|
||
"left_leg": false,
|
||
"right_leg": false,
|
||
"left_shoe": false,
|
||
"right_shoe": false,
|
||
"upper_clothes": false,
|
||
"skirt": false,
|
||
"pants": false,
|
||
"dress": false,
|
||
"belt": false,
|
||
"bag": false,
|
||
"scarf": false
|
||
},
|
||
"class_type": "LayerMask: SegformerClothesPipelineLoader",
|
||
"_meta": {
|
||
"title": "LayerMask: Segformer Clothes Pipeline"
|
||
}
|
||
},
|
||
"30": {
|
||
"inputs": {
|
||
"image": "{{input_image}}"
|
||
},
|
||
"class_type": "LoadImage",
|
||
"_meta": {
|
||
"title": "加载图像"
|
||
}
|
||
},
|
||
"44": {
|
||
"inputs": {
|
||
"masks": ["22", 1]
|
||
},
|
||
"class_type": "Mask Fill Holes",
|
||
"_meta": {
|
||
"title": "Mask Fill Holes"
|
||
}
|
||
},
|
||
"47": {
|
||
"inputs": {
|
||
"expand": 5,
|
||
"incremental_expandrate": 5,
|
||
"tapered_corners": true,
|
||
"flip_input": false,
|
||
"blur_radius": 9.4,
|
||
"lerp_alpha": 0.9900000000000002,
|
||
"decay_factor": 1,
|
||
"fill_holes": false,
|
||
"mask": ["44", 0]
|
||
},
|
||
"class_type": "GrowMaskWithBlur",
|
||
"_meta": {
|
||
"title": "Grow Mask With Blur"
|
||
}
|
||
},
|
||
"52": {
|
||
"inputs": {
|
||
"model": "segformer_b3_clothes",
|
||
"face": true,
|
||
"hair": false,
|
||
"hat": false,
|
||
"sunglass": true,
|
||
"left_arm": false,
|
||
"right_arm": false,
|
||
"left_leg": false,
|
||
"right_leg": false,
|
||
"left_shoe": false,
|
||
"right_shoe": false,
|
||
"upper_clothes": false,
|
||
"skirt": false,
|
||
"pants": false,
|
||
"dress": false,
|
||
"belt": false,
|
||
"bag": false,
|
||
"scarf": false
|
||
},
|
||
"class_type": "LayerMask: SegformerClothesPipelineLoader",
|
||
"_meta": {
|
||
"title": "LayerMask: Segformer Clothes Pipeline"
|
||
}
|
||
},
|
||
"53": {
|
||
"inputs": {
|
||
"detail_method": "VITMatte(local)",
|
||
"detail_erode": 6,
|
||
"detail_dilate": 4,
|
||
"black_point": 0.01,
|
||
"white_point": 0.99,
|
||
"process_detail": false,
|
||
"device": "cuda",
|
||
"max_megapixels": 2,
|
||
"image": ["30", 0],
|
||
"segformer_pipeline": ["52", 0]
|
||
},
|
||
"class_type": "LayerMask: SegformerUltraV2",
|
||
"_meta": {
|
||
"title": "LayerMask: Segformer Ultra V2"
|
||
}
|
||
},
|
||
"58": {
|
||
"inputs": {
|
||
"filename_prefix": "ComfyUI",
|
||
"images": ["26", 1]
|
||
},
|
||
"class_type": "SaveImage",
|
||
"_meta": {
|
||
"title": "保存图像"
|
||
}
|
||
},
|
||
"59": {
|
||
"inputs": {
|
||
"String": "{{face_prompt}}"
|
||
},
|
||
"class_type": "String",
|
||
"_meta": {
|
||
"title": "String"
|
||
}
|
||
},
|
||
"71": {
|
||
"inputs": {
|
||
"Number": "{{face_denoise}}"
|
||
},
|
||
"class_type": "Float",
|
||
"_meta": {
|
||
"title": "Float"
|
||
}
|
||
}
|
||
}
|
||
"#;
|
||
|
||
// 解析 JSON 字符串为 ComfyUIWorkflow
|
||
serde_json::from_str(workflow_json)
|
||
.expect("Failed to parse workflow JSON")
|
||
}
|