mixvideo-v2/cargos/comfyui-sdk/template_hub/ai_model_face_hair_fix.rs

436 lines
18 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 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, ComfyUINode, NodeMeta
};
/// 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,
pattern: None,
items: None,
properties: 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,
pattern: None,
items: None,
properties: 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,
pattern: None,
items: None,
properties: None,
});
let workflow = create_workflow();
WorkflowTemplateData {
metadata,
workflow,
parameters,
}
}
fn create_workflow() -> ComfyUIWorkflow {
let mut workflow = HashMap::new();
// Node 6: 遮罩边缘滑条快速模糊
workflow.insert("6".to_string(), ComfyUINode {
class_type: "EG_ZZ_MHHT".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("模糊强度".to_string(), json!(3));
inputs.insert("mask".to_string(), json!(["53", 1]));
inputs
},
_meta: Some(NodeMeta {
title: Some("2🐕遮罩边缘滑条快速模糊".to_string()),
}),
});
// Node 8: Checkpoint加载器
workflow.insert("8".to_string(), ComfyUINode {
class_type: "CheckpointLoaderSimple".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("ckpt_name".to_string(), json!("juggernaut_reborn_sd1,5.safetensors"));
inputs
},
_meta: Some(NodeMeta {
title: Some("Checkpoint加载器简易".to_string()),
}),
});
// Node 9: CLIP文本编码 (头发)
workflow.insert("9".to_string(), ComfyUINode {
class_type: "CLIPTextEncode".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("text".to_string(), json!("Smooth long hair,Hair details, quality hair,Smooth hair"));
inputs.insert("clip".to_string(), json!(["8", 1]));
inputs
},
_meta: Some(NodeMeta {
title: Some("CLIP文本编码".to_string()),
}),
});
// Node 10: CLIP文本编码 (负面头发)
workflow.insert("10".to_string(), ComfyUINode {
class_type: "CLIPTextEncode".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("text".to_string(), json!("Frizzy hair, dry hair, split ends,bad quality, poor quality, doll, disfigured, jpg, toy, bad anatomy, missing limbs, missing fingers, 3d, cgi"));
inputs.insert("clip".to_string(), json!(["8", 1]));
inputs
},
_meta: Some(NodeMeta {
title: Some("CLIP文本编码".to_string()),
}),
});
// Node 13: CLIP文本编码 (脸部)
workflow.insert("13".to_string(), ComfyUINode {
class_type: "CLIPTextEncode".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("text".to_string(), json!(["59", 0]));
inputs.insert("clip".to_string(), json!(["8", 1]));
inputs
},
_meta: Some(NodeMeta {
title: Some("CLIP文本编码".to_string()),
}),
});
// Node 14: CLIP文本编码 (负面脸部)
workflow.insert("14".to_string(), ComfyUINode {
class_type: "CLIPTextEncode".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("text".to_string(), json!("(NSFW:1.2),(worst quality:1.2),(low quality:1.2),(normal quality:1.2),low resolution,watermark,"));
inputs.insert("clip".to_string(), json!(["8", 1]));
inputs
},
_meta: Some(NodeMeta {
title: Some("CLIP文本编码".to_string()),
}),
});
// Node 22: Segformer Ultra V2 (头发)
workflow.insert("22".to_string(), ComfyUINode {
class_type: "LayerMask: SegformerUltraV2".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("detail_method".to_string(), json!("VITMatte(local)"));
inputs.insert("detail_erode".to_string(), json!(44));
inputs.insert("detail_dilate".to_string(), json!(6));
inputs.insert("black_point".to_string(), json!(0.030000000000000006));
inputs.insert("white_point".to_string(), json!(0.99));
inputs.insert("process_detail".to_string(), json!(true));
inputs.insert("device".to_string(), json!("cuda"));
inputs.insert("max_megapixels".to_string(), json!(2));
inputs.insert("image".to_string(), json!(["30", 0]));
inputs.insert("segformer_pipeline".to_string(), json!(["28", 0]));
inputs
},
_meta: Some(NodeMeta {
title: Some("LayerMask: Segformer Ultra V2".to_string()),
}),
});
// Node 25: 局部重绘采样器 (头发)
workflow.insert("25".to_string(), ComfyUINode {
class_type: "EG_CYQ_JB".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("seed".to_string(), json!(646617836820462i64));
inputs.insert("steps".to_string(), json!(30));
inputs.insert("cfg".to_string(), json!(4.5200000000000005));
inputs.insert("sampler_name".to_string(), json!("dpmpp_2s_ancestral"));
inputs.insert("scheduler".to_string(), json!("karras"));
inputs.insert("denoise".to_string(), json!(0.4));
inputs.insert("重绘模式".to_string(), json!("原图"));
inputs.insert("遮罩延展".to_string(), json!(10));
inputs.insert("仅局部重绘".to_string(), json!(true));
inputs.insert("局部重绘大小".to_string(), json!(768));
inputs.insert("重绘区域扩展".to_string(), json!(50));
inputs.insert("遮罩羽化".to_string(), json!(5));
inputs.insert("TEXT".to_string(), json!("2🐕出品必出精品"));
inputs.insert("model".to_string(), json!(["8", 0]));
inputs.insert("image".to_string(), json!(["30", 0]));
inputs.insert("vae".to_string(), json!(["8", 2]));
inputs.insert("mask".to_string(), json!(["47", 0]));
inputs.insert("positive".to_string(), json!(["9", 0]));
inputs.insert("negative".to_string(), json!(["10", 0]));
inputs
},
_meta: Some(NodeMeta {
title: Some("2🐕局部重绘采样器".to_string()),
}),
});
// Node 26: 局部重绘采样器 (脸部)
workflow.insert("26".to_string(), ComfyUINode {
class_type: "EG_CYQ_JB".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("seed".to_string(), json!(969968724502727i64));
inputs.insert("steps".to_string(), json!(30));
inputs.insert("cfg".to_string(), json!(4.5200000000000005));
inputs.insert("sampler_name".to_string(), json!("dpmpp_2s_ancestral"));
inputs.insert("scheduler".to_string(), json!("karras"));
inputs.insert("denoise".to_string(), json!(["71", 0]));
inputs.insert("重绘模式".to_string(), json!("原图"));
inputs.insert("遮罩延展".to_string(), json!(10));
inputs.insert("仅局部重绘".to_string(), json!(true));
inputs.insert("局部重绘大小".to_string(), json!(768));
inputs.insert("重绘区域扩展".to_string(), json!(50));
inputs.insert("遮罩羽化".to_string(), json!(5));
inputs.insert("TEXT".to_string(), json!("2🐕出品必出精品"));
inputs.insert("model".to_string(), json!(["8", 0]));
inputs.insert("image".to_string(), json!(["25", 1]));
inputs.insert("vae".to_string(), json!(["8", 2]));
inputs.insert("mask".to_string(), json!(["6", 0]));
inputs.insert("positive".to_string(), json!(["13", 0]));
inputs.insert("negative".to_string(), json!(["14", 0]));
inputs
},
_meta: Some(NodeMeta {
title: Some("2🐕局部重绘采样器".to_string()),
}),
});
// Node 28: Segformer Clothes Pipeline (头发)
workflow.insert("28".to_string(), ComfyUINode {
class_type: "LayerMask: SegformerClothesPipelineLoader".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("model".to_string(), json!("segformer_b3_clothes"));
inputs.insert("face".to_string(), json!(false));
inputs.insert("hair".to_string(), json!(true));
inputs.insert("hat".to_string(), json!(false));
inputs.insert("sunglass".to_string(), json!(false));
inputs.insert("left_arm".to_string(), json!(false));
inputs.insert("right_arm".to_string(), json!(false));
inputs.insert("left_leg".to_string(), json!(false));
inputs.insert("right_leg".to_string(), json!(false));
inputs.insert("left_shoe".to_string(), json!(false));
inputs.insert("right_shoe".to_string(), json!(false));
inputs.insert("upper_clothes".to_string(), json!(false));
inputs.insert("skirt".to_string(), json!(false));
inputs.insert("pants".to_string(), json!(false));
inputs.insert("dress".to_string(), json!(false));
inputs.insert("belt".to_string(), json!(false));
inputs.insert("bag".to_string(), json!(false));
inputs.insert("scarf".to_string(), json!(false));
inputs
},
_meta: Some(NodeMeta {
title: Some("LayerMask: Segformer Clothes Pipeline".to_string()),
}),
});
// Node 30: 加载图像
workflow.insert("30".to_string(), ComfyUINode {
class_type: "LoadImage".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("image".to_string(), json!("{{input_image}}"));
inputs
},
_meta: Some(NodeMeta {
title: Some("加载图像".to_string()),
}),
});
// Node 44: Mask Fill Holes
workflow.insert("44".to_string(), ComfyUINode {
class_type: "Mask Fill Holes".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("masks".to_string(), json!(["22", 1]));
inputs
},
_meta: Some(NodeMeta {
title: Some("Mask Fill Holes".to_string()),
}),
});
// Node 47: Grow Mask With Blur
workflow.insert("47".to_string(), ComfyUINode {
class_type: "GrowMaskWithBlur".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("expand".to_string(), json!(5));
inputs.insert("incremental_expandrate".to_string(), json!(5));
inputs.insert("tapered_corners".to_string(), json!(true));
inputs.insert("flip_input".to_string(), json!(false));
inputs.insert("blur_radius".to_string(), json!(9.4));
inputs.insert("lerp_alpha".to_string(), json!(0.9900000000000002));
inputs.insert("decay_factor".to_string(), json!(1));
inputs.insert("fill_holes".to_string(), json!(false));
inputs.insert("mask".to_string(), json!(["44", 0]));
inputs
},
_meta: Some(NodeMeta {
title: Some("Grow Mask With Blur".to_string()),
}),
});
// Node 52: Segformer Clothes Pipeline (脸部)
workflow.insert("52".to_string(), ComfyUINode {
class_type: "LayerMask: SegformerClothesPipelineLoader".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("model".to_string(), json!("segformer_b3_clothes"));
inputs.insert("face".to_string(), json!(true));
inputs.insert("hair".to_string(), json!(false));
inputs.insert("hat".to_string(), json!(false));
inputs.insert("sunglass".to_string(), json!(true));
inputs.insert("left_arm".to_string(), json!(false));
inputs.insert("right_arm".to_string(), json!(false));
inputs.insert("left_leg".to_string(), json!(false));
inputs.insert("right_leg".to_string(), json!(false));
inputs.insert("left_shoe".to_string(), json!(false));
inputs.insert("right_shoe".to_string(), json!(false));
inputs.insert("upper_clothes".to_string(), json!(false));
inputs.insert("skirt".to_string(), json!(false));
inputs.insert("pants".to_string(), json!(false));
inputs.insert("dress".to_string(), json!(false));
inputs.insert("belt".to_string(), json!(false));
inputs.insert("bag".to_string(), json!(false));
inputs.insert("scarf".to_string(), json!(false));
inputs
},
_meta: Some(NodeMeta {
title: Some("LayerMask: Segformer Clothes Pipeline".to_string()),
}),
});
// Node 53: Segformer Ultra V2 (脸部)
workflow.insert("53".to_string(), ComfyUINode {
class_type: "LayerMask: SegformerUltraV2".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("detail_method".to_string(), json!("VITMatte(local)"));
inputs.insert("detail_erode".to_string(), json!(6));
inputs.insert("detail_dilate".to_string(), json!(4));
inputs.insert("black_point".to_string(), json!(0.01));
inputs.insert("white_point".to_string(), json!(0.99));
inputs.insert("process_detail".to_string(), json!(false));
inputs.insert("device".to_string(), json!("cuda"));
inputs.insert("max_megapixels".to_string(), json!(2));
inputs.insert("image".to_string(), json!(["30", 0]));
inputs.insert("segformer_pipeline".to_string(), json!(["52", 0]));
inputs
},
_meta: Some(NodeMeta {
title: Some("LayerMask: Segformer Ultra V2".to_string()),
}),
});
// Node 58: 保存图像
workflow.insert("58".to_string(), ComfyUINode {
class_type: "SaveImage".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("filename_prefix".to_string(), json!("ComfyUI"));
inputs.insert("images".to_string(), json!(["26", 1]));
inputs
},
_meta: Some(NodeMeta {
title: Some("保存图像".to_string()),
}),
});
// Node 59: String (脸部提示词)
workflow.insert("59".to_string(), ComfyUINode {
class_type: "String".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("String".to_string(), json!("A girl, slim figure, oval face, beauty, Pink and greasy lips{{face_prompt}}"));
inputs
},
_meta: Some(NodeMeta {
title: Some("String".to_string()),
}),
});
// Node 71: Float (脸部去噪强度)
workflow.insert("71".to_string(), ComfyUINode {
class_type: "Float".to_string(),
inputs: {
let mut inputs = HashMap::new();
inputs.insert("Number".to_string(), json!("{{face_denoise}}"));
inputs
},
_meta: Some(NodeMeta {
title: Some("Float".to_string()),
}),
});
workflow
}