Files
mixvideo-v2/cargos/comfyui-sdk/template_hub/ai_model_face_hair_fix.rs
root 84081284f7 fix: 修复ComfyUI V2模板创建参数解析问题并重构工作流创建
主要修改:

1. **扩展ComfyUI SDK参数类型支持**
   - 在ParameterType枚举中添加Integer、Float、Image、Audio、Video类型
   - 在ParameterSchema中添加节点映射和媒体文件相关字段
   - 添加step、accept、maxSize、width、height、duration、node_mapping字段
   - 为新字段添加serde默认值支持

2. **修复参数解析问题**
   - 解决comfyui_v2_create_template命令缺少type字段的错误
   - 确保前端传递的参数类型与后端ParameterType枚举匹配
   - 修复r#enum字段的正确使用(用于JSON Schema兼容性)

3. **重构工作流模板创建方式**
   - 将ai_model_face_hair_fix.rs中的create_workflow函数重构为create_workflow_from_json
   - 改为从JSON字符串解析ComfyUIWorkflow,而非手动构建HashMap
   - 提高可维护性和与实际使用场景的一致性

4. **更新相关测试和验证代码**
   - 修复validation.rs中的测试用例,添加新字段的默认值
   - 确保所有ParameterSchema创建都包含完整字段

5. **添加测试数据**
   - 创建test_template_creation.json用于测试参数格式

这些修改解决了前端传递的参数格式与后端期望格式不匹配的问题,
使工作流模板创建功能能够正常工作。
2025-08-08 23:10:38 +08:00

390 lines
9.7 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
};
/// 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")
}