fix: 移除无用代码
This commit is contained in:
parent
121f2ebc5d
commit
0883674877
|
|
@ -10,6 +10,3 @@ pub mod project_template_binding;
|
|||
pub mod template_matching_result;
|
||||
pub mod export_record;
|
||||
pub mod video_generation;
|
||||
pub mod outfit_analysis;
|
||||
pub mod outfit_item;
|
||||
pub mod outfit_matching;
|
||||
|
|
|
|||
|
|
@ -1,206 +0,0 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
/// HSV颜色模型
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct ColorHSV {
|
||||
pub hue: f64, // 色相 (0.0-1.0)
|
||||
pub saturation: f64, // 饱和度 (0.0-1.0)
|
||||
pub value: f64, // 明度 (0.0-1.0)
|
||||
}
|
||||
|
||||
impl ColorHSV {
|
||||
pub fn new(hue: f64, saturation: f64, value: f64) -> Self {
|
||||
Self {
|
||||
hue: hue.clamp(0.0, 1.0),
|
||||
saturation: saturation.clamp(0.0, 1.0),
|
||||
value: value.clamp(0.0, 1.0),
|
||||
}
|
||||
}
|
||||
|
||||
/// 转换为RGB十六进制字符串
|
||||
pub fn to_rgb_hex(&self) -> String {
|
||||
let (r, g, b) = hsv_to_rgb(self.hue, self.saturation, self.value);
|
||||
format!("#{:02x}{:02x}{:02x}",
|
||||
(r * 255.0) as u8,
|
||||
(g * 255.0) as u8,
|
||||
(b * 255.0) as u8)
|
||||
}
|
||||
|
||||
/// 从RGB十六进制字符串创建
|
||||
pub fn from_rgb_hex(hex: &str) -> Result<Self, String> {
|
||||
let hex = hex.trim_start_matches('#');
|
||||
if hex.len() != 6 {
|
||||
return Err("Invalid hex color format".to_string());
|
||||
}
|
||||
|
||||
let r = u8::from_str_radix(&hex[0..2], 16).map_err(|_| "Invalid red component")?;
|
||||
let g = u8::from_str_radix(&hex[2..4], 16).map_err(|_| "Invalid green component")?;
|
||||
let b = u8::from_str_radix(&hex[4..6], 16).map_err(|_| "Invalid blue component")?;
|
||||
|
||||
let (h, s, v) = rgb_to_hsv(r as f64 / 255.0, g as f64 / 255.0, b as f64 / 255.0);
|
||||
Ok(Self::new(h, s, v))
|
||||
}
|
||||
|
||||
/// 计算与另一个颜色的相似度 (0.0-1.0)
|
||||
pub fn similarity(&self, other: &ColorHSV) -> f64 {
|
||||
let hue_diff = (self.hue - other.hue).abs().min(1.0 - (self.hue - other.hue).abs());
|
||||
let sat_diff = (self.saturation - other.saturation).abs();
|
||||
let val_diff = (self.value - other.value).abs();
|
||||
|
||||
// 加权计算相似度,色相权重最高
|
||||
let similarity = 1.0 - (hue_diff * 0.5 + sat_diff * 0.3 + val_diff * 0.2);
|
||||
similarity.clamp(0.0, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// 分析状态枚举
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum AnalysisStatus {
|
||||
Pending, // 待分析
|
||||
Processing, // 分析中
|
||||
Completed, // 已完成
|
||||
Failed, // 分析失败
|
||||
}
|
||||
|
||||
impl Default for AnalysisStatus {
|
||||
fn default() -> Self {
|
||||
Self::Pending
|
||||
}
|
||||
}
|
||||
|
||||
/// 服装项目信息
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitProduct {
|
||||
pub category: String, // 服装类别 (如: "牛仔裤", "T恤")
|
||||
pub description: String, // 描述
|
||||
pub color_pattern: ColorHSV, // 主色调
|
||||
pub design_styles: Vec<String>, // 设计风格标签
|
||||
pub color_pattern_match_dress: f64, // 与整体搭配的颜色匹配度 (0.0-1.0)
|
||||
pub color_pattern_match_environment: f64, // 与环境的颜色匹配度 (0.0-1.0)
|
||||
}
|
||||
|
||||
/// 图像分析结果
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ImageAnalysisResult {
|
||||
pub environment_tags: Vec<String>, // 环境标签
|
||||
pub environment_color_pattern: ColorHSV, // 环境色调
|
||||
pub dress_color_pattern: ColorHSV, // 整体搭配色调
|
||||
pub style_description: String, // 风格描述
|
||||
pub products: Vec<OutfitProduct>, // 识别到的服装项目
|
||||
}
|
||||
|
||||
/// 服装分析记录
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitAnalysis {
|
||||
pub id: String,
|
||||
pub project_id: String,
|
||||
pub image_path: String, // 原始图像路径
|
||||
pub image_name: String, // 图像名称
|
||||
pub analysis_status: AnalysisStatus, // 分析状态
|
||||
pub analysis_result: Option<ImageAnalysisResult>, // 分析结果
|
||||
pub error_message: Option<String>, // 错误信息
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub analyzed_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
/// 创建分析请求
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CreateOutfitAnalysisRequest {
|
||||
pub project_id: String,
|
||||
pub image_path: String,
|
||||
pub image_name: String,
|
||||
}
|
||||
|
||||
/// 更新分析请求
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UpdateOutfitAnalysisRequest {
|
||||
pub analysis_status: Option<AnalysisStatus>,
|
||||
pub analysis_result: Option<ImageAnalysisResult>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
/// 分析查询选项
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitAnalysisQueryOptions {
|
||||
pub project_id: Option<String>,
|
||||
pub status: Option<AnalysisStatus>,
|
||||
pub limit: Option<u32>,
|
||||
pub offset: Option<u32>,
|
||||
}
|
||||
|
||||
/// 分析统计信息
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitAnalysisStats {
|
||||
pub total_count: u32,
|
||||
pub pending_count: u32,
|
||||
pub processing_count: u32,
|
||||
pub completed_count: u32,
|
||||
pub failed_count: u32,
|
||||
}
|
||||
|
||||
// HSV和RGB转换函数
|
||||
fn hsv_to_rgb(h: f64, s: f64, v: f64) -> (f64, f64, f64) {
|
||||
let c = v * s;
|
||||
let x = c * (1.0 - ((h * 6.0) % 2.0 - 1.0).abs());
|
||||
let m = v - c;
|
||||
|
||||
let (r_prime, g_prime, b_prime) = match (h * 6.0) as i32 {
|
||||
0 => (c, x, 0.0),
|
||||
1 => (x, c, 0.0),
|
||||
2 => (0.0, c, x),
|
||||
3 => (0.0, x, c),
|
||||
4 => (x, 0.0, c),
|
||||
5 => (c, 0.0, x),
|
||||
_ => (0.0, 0.0, 0.0),
|
||||
};
|
||||
|
||||
(r_prime + m, g_prime + m, b_prime + m)
|
||||
}
|
||||
|
||||
fn rgb_to_hsv(r: f64, g: f64, b: f64) -> (f64, f64, f64) {
|
||||
let max = r.max(g).max(b);
|
||||
let min = r.min(g).min(b);
|
||||
let delta = max - min;
|
||||
|
||||
let h = if delta == 0.0 {
|
||||
0.0
|
||||
} else if max == r {
|
||||
((g - b) / delta) % 6.0
|
||||
} else if max == g {
|
||||
(b - r) / delta + 2.0
|
||||
} else {
|
||||
(r - g) / delta + 4.0
|
||||
} / 6.0;
|
||||
|
||||
let s = if max == 0.0 { 0.0 } else { delta / max };
|
||||
let v = max;
|
||||
|
||||
(h.abs(), s, v)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_color_hsv_conversion() {
|
||||
let color = ColorHSV::new(0.5, 0.8, 0.9);
|
||||
let hex = color.to_rgb_hex();
|
||||
let converted = ColorHSV::from_rgb_hex(&hex).unwrap();
|
||||
|
||||
assert!((color.hue - converted.hue).abs() < 0.01);
|
||||
assert!((color.saturation - converted.saturation).abs() < 0.01);
|
||||
assert!((color.value - converted.value).abs() < 0.01);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_color_similarity() {
|
||||
let color1 = ColorHSV::new(0.5, 0.8, 0.9);
|
||||
let color2 = ColorHSV::new(0.52, 0.82, 0.88);
|
||||
let similarity = color1.similarity(&color2);
|
||||
|
||||
assert!(similarity > 0.8); // 应该很相似
|
||||
}
|
||||
}
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{DateTime, Utc};
|
||||
use super::outfit_analysis::ColorHSV;
|
||||
|
||||
/// 服装类别枚举
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub enum OutfitCategory {
|
||||
Top, // 上装 (T恤、衬衫、毛衣等)
|
||||
Bottom, // 下装 (裤子、裙子等)
|
||||
Dress, // 连衣裙
|
||||
Outerwear, // 外套
|
||||
Footwear, // 鞋类
|
||||
Accessory, // 配饰
|
||||
Other, // 其他
|
||||
}
|
||||
|
||||
impl OutfitCategory {
|
||||
pub fn from_string(category: &str) -> Self {
|
||||
match category.to_lowercase().as_str() {
|
||||
"上装" | "t恤" | "衬衫" | "毛衣" | "背心" | "top" => Self::Top,
|
||||
"下装" | "裤子" | "牛仔裤" | "短裤" | "裙子" | "bottom" => Self::Bottom,
|
||||
"连衣裙" | "长裙" | "dress" => Self::Dress,
|
||||
"外套" | "夹克" | "大衣" | "outerwear" => Self::Outerwear,
|
||||
"鞋子" | "运动鞋" | "高跟鞋" | "footwear" => Self::Footwear,
|
||||
"配饰" | "帽子" | "包包" | "首饰" | "accessory" => Self::Accessory,
|
||||
_ => Self::Other,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_chinese(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Top => "上装",
|
||||
Self::Bottom => "下装",
|
||||
Self::Dress => "连衣裙",
|
||||
Self::Outerwear => "外套",
|
||||
Self::Footwear => "鞋类",
|
||||
Self::Accessory => "配饰",
|
||||
Self::Other => "其他",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 服装风格枚举
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub enum OutfitStyle {
|
||||
Casual, // 休闲
|
||||
Formal, // 正式
|
||||
Business, // 商务
|
||||
Sporty, // 运动
|
||||
Vintage, // 复古
|
||||
Bohemian, // 波西米亚
|
||||
Minimalist, // 极简
|
||||
Streetwear, // 街头
|
||||
Elegant, // 优雅
|
||||
Trendy, // 时尚
|
||||
Other(String), // 其他自定义风格
|
||||
}
|
||||
|
||||
impl OutfitStyle {
|
||||
pub fn from_string(style: &str) -> Self {
|
||||
match style.to_lowercase().as_str() {
|
||||
"casual" | "休闲" => Self::Casual,
|
||||
"formal" | "正式" => Self::Formal,
|
||||
"business" | "商务" => Self::Business,
|
||||
"sporty" | "运动" => Self::Sporty,
|
||||
"vintage" | "复古" => Self::Vintage,
|
||||
"bohemian" | "波西米亚" => Self::Bohemian,
|
||||
"minimalist" | "极简" => Self::Minimalist,
|
||||
"streetwear" | "街头" => Self::Streetwear,
|
||||
"elegant" | "优雅" => Self::Elegant,
|
||||
"trendy" | "时尚" => Self::Trendy,
|
||||
_ => Self::Other(style.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::Casual => "休闲".to_string(),
|
||||
Self::Formal => "正式".to_string(),
|
||||
Self::Business => "商务".to_string(),
|
||||
Self::Sporty => "运动".to_string(),
|
||||
Self::Vintage => "复古".to_string(),
|
||||
Self::Bohemian => "波西米亚".to_string(),
|
||||
Self::Minimalist => "极简".to_string(),
|
||||
Self::Streetwear => "街头".to_string(),
|
||||
Self::Elegant => "优雅".to_string(),
|
||||
Self::Trendy => "时尚".to_string(),
|
||||
Self::Other(s) => s.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 服装尺寸信息
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitSize {
|
||||
pub size_label: String, // 尺码标签 (如: "M", "L", "XL")
|
||||
pub measurements: Option<SizeMeasurements>, // 具体尺寸
|
||||
}
|
||||
|
||||
/// 具体尺寸测量
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SizeMeasurements {
|
||||
pub chest: Option<f64>, // 胸围 (cm)
|
||||
pub waist: Option<f64>, // 腰围 (cm)
|
||||
pub hip: Option<f64>, // 臀围 (cm)
|
||||
pub length: Option<f64>, // 长度 (cm)
|
||||
pub sleeve: Option<f64>, // 袖长 (cm)
|
||||
}
|
||||
|
||||
/// 服装材质信息
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitMaterial {
|
||||
pub fabric_type: String, // 面料类型 (如: "棉", "聚酯纤维")
|
||||
pub fabric_composition: Vec<FabricComponent>, // 面料成分
|
||||
pub care_instructions: Vec<String>, // 护理说明
|
||||
}
|
||||
|
||||
/// 面料成分
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FabricComponent {
|
||||
pub material: String, // 材料名称
|
||||
pub percentage: f64, // 百分比
|
||||
}
|
||||
|
||||
/// 服装单品实体
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitItem {
|
||||
pub id: String,
|
||||
pub project_id: String,
|
||||
pub analysis_id: Option<String>, // 关联的分析记录ID
|
||||
pub name: String, // 服装名称
|
||||
pub category: OutfitCategory, // 服装类别
|
||||
pub brand: Option<String>, // 品牌
|
||||
pub model: Option<String>, // 型号
|
||||
pub color_primary: ColorHSV, // 主色调
|
||||
pub color_secondary: Option<ColorHSV>, // 次要色调
|
||||
pub styles: Vec<OutfitStyle>, // 风格标签
|
||||
pub design_elements: Vec<String>, // 设计元素 (如: "条纹", "印花", "刺绣")
|
||||
pub size: Option<OutfitSize>, // 尺寸信息
|
||||
pub material: Option<OutfitMaterial>, // 材质信息
|
||||
pub price: Option<f64>, // 价格
|
||||
pub purchase_date: Option<DateTime<Utc>>, // 购买日期
|
||||
pub image_urls: Vec<String>, // 图片URL列表
|
||||
pub tags: Vec<String>, // 自定义标签
|
||||
pub notes: Option<String>, // 备注
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
/// 创建服装单品请求
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CreateOutfitItemRequest {
|
||||
pub project_id: String,
|
||||
pub analysis_id: Option<String>,
|
||||
pub name: String,
|
||||
pub category: OutfitCategory,
|
||||
pub brand: Option<String>,
|
||||
pub model: Option<String>,
|
||||
pub color_primary: ColorHSV,
|
||||
pub color_secondary: Option<ColorHSV>,
|
||||
pub styles: Vec<OutfitStyle>,
|
||||
pub design_elements: Vec<String>,
|
||||
pub size: Option<OutfitSize>,
|
||||
pub material: Option<OutfitMaterial>,
|
||||
pub price: Option<f64>,
|
||||
pub purchase_date: Option<DateTime<Utc>>,
|
||||
pub image_urls: Vec<String>,
|
||||
pub tags: Vec<String>,
|
||||
pub notes: Option<String>,
|
||||
}
|
||||
|
||||
/// 更新服装单品请求
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UpdateOutfitItemRequest {
|
||||
pub name: Option<String>,
|
||||
pub category: Option<OutfitCategory>,
|
||||
pub brand: Option<String>,
|
||||
pub model: Option<String>,
|
||||
pub color_primary: Option<ColorHSV>,
|
||||
pub color_secondary: Option<ColorHSV>,
|
||||
pub styles: Option<Vec<OutfitStyle>>,
|
||||
pub design_elements: Option<Vec<String>>,
|
||||
pub size: Option<OutfitSize>,
|
||||
pub material: Option<OutfitMaterial>,
|
||||
pub price: Option<f64>,
|
||||
pub purchase_date: Option<DateTime<Utc>>,
|
||||
pub image_urls: Option<Vec<String>>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
pub notes: Option<String>,
|
||||
}
|
||||
|
||||
/// 服装单品查询选项
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitItemQueryOptions {
|
||||
pub project_id: Option<String>,
|
||||
pub category: Option<OutfitCategory>,
|
||||
pub styles: Option<Vec<OutfitStyle>>,
|
||||
pub color_similarity_threshold: Option<f64>, // 颜色相似度阈值
|
||||
pub target_color: Option<ColorHSV>, // 目标颜色
|
||||
pub brand: Option<String>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
pub limit: Option<u32>,
|
||||
pub offset: Option<u32>,
|
||||
}
|
||||
|
||||
/// 服装单品统计信息
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitItemStats {
|
||||
pub total_count: u32,
|
||||
pub category_counts: std::collections::HashMap<String, u32>,
|
||||
pub style_counts: std::collections::HashMap<String, u32>,
|
||||
pub brand_counts: std::collections::HashMap<String, u32>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_outfit_category_conversion() {
|
||||
assert_eq!(OutfitCategory::from_string("T恤"), OutfitCategory::Top);
|
||||
assert_eq!(OutfitCategory::from_string("牛仔裤"), OutfitCategory::Bottom);
|
||||
assert_eq!(OutfitCategory::from_string("连衣裙"), OutfitCategory::Dress);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_outfit_style_conversion() {
|
||||
assert_eq!(OutfitStyle::from_string("休闲"), OutfitStyle::Casual);
|
||||
assert_eq!(OutfitStyle::from_string("正式"), OutfitStyle::Formal);
|
||||
|
||||
let custom_style = OutfitStyle::from_string("自定义风格");
|
||||
match custom_style {
|
||||
OutfitStyle::Other(s) => assert_eq!(s, "自定义风格"),
|
||||
_ => panic!("Expected Other variant"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{DateTime, Utc};
|
||||
use super::outfit_analysis::ColorHSV;
|
||||
use super::outfit_item::{OutfitCategory, OutfitStyle};
|
||||
|
||||
/// 匹配类型枚举
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum MatchingType {
|
||||
ColorHarmony, // 颜色和谐搭配
|
||||
StyleConsistent, // 风格一致搭配
|
||||
Complementary, // 互补搭配
|
||||
Seasonal, // 季节性搭配
|
||||
Occasion, // 场合搭配
|
||||
Trendy, // 时尚搭配
|
||||
}
|
||||
|
||||
impl MatchingType {
|
||||
pub fn to_chinese(&self) -> &'static str {
|
||||
match self {
|
||||
Self::ColorHarmony => "颜色和谐",
|
||||
Self::StyleConsistent => "风格一致",
|
||||
Self::Complementary => "互补搭配",
|
||||
Self::Seasonal => "季节搭配",
|
||||
Self::Occasion => "场合搭配",
|
||||
Self::Trendy => "时尚搭配",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 匹配置信度等级
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum ConfidenceLevel {
|
||||
Low, // 低 (0.0-0.4)
|
||||
Medium, // 中 (0.4-0.7)
|
||||
High, // 高 (0.7-0.9)
|
||||
Excellent, // 极佳 (0.9-1.0)
|
||||
}
|
||||
|
||||
impl ConfidenceLevel {
|
||||
pub fn from_score(score: f64) -> Self {
|
||||
match score {
|
||||
s if s >= 0.9 => Self::Excellent,
|
||||
s if s >= 0.7 => Self::High,
|
||||
s if s >= 0.4 => Self::Medium,
|
||||
_ => Self::Low,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_chinese(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Low => "低",
|
||||
Self::Medium => "中",
|
||||
Self::High => "高",
|
||||
Self::Excellent => "极佳",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 搭配评分详情
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MatchingScoreDetails {
|
||||
pub color_harmony_score: f64, // 颜色和谐度评分 (0.0-1.0)
|
||||
pub style_consistency_score: f64, // 风格一致性评分 (0.0-1.0)
|
||||
pub proportion_score: f64, // 比例协调度评分 (0.0-1.0)
|
||||
pub occasion_appropriateness: f64, // 场合适宜度评分 (0.0-1.0)
|
||||
pub trend_factor: f64, // 时尚度评分 (0.0-1.0)
|
||||
pub overall_score: f64, // 综合评分 (0.0-1.0)
|
||||
}
|
||||
|
||||
impl MatchingScoreDetails {
|
||||
pub fn calculate_overall_score(&mut self) {
|
||||
// 加权计算综合评分
|
||||
self.overall_score = (
|
||||
self.color_harmony_score * 0.3 +
|
||||
self.style_consistency_score * 0.25 +
|
||||
self.proportion_score * 0.2 +
|
||||
self.occasion_appropriateness * 0.15 +
|
||||
self.trend_factor * 0.1
|
||||
).clamp(0.0, 1.0);
|
||||
}
|
||||
|
||||
pub fn get_confidence_level(&self) -> ConfidenceLevel {
|
||||
ConfidenceLevel::from_score(self.overall_score)
|
||||
}
|
||||
}
|
||||
|
||||
/// 搭配建议
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MatchingSuggestion {
|
||||
pub suggestion_type: String, // 建议类型 (如: "颜色调整", "风格优化")
|
||||
pub description: String, // 建议描述
|
||||
pub priority: u8, // 优先级 (1-5, 5最高)
|
||||
}
|
||||
|
||||
/// 搭配组合中的单品
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MatchingOutfitItem {
|
||||
pub item_id: String, // 服装单品ID
|
||||
pub item_name: String, // 服装名称
|
||||
pub category: OutfitCategory, // 类别
|
||||
pub color_primary: ColorHSV, // 主色调
|
||||
pub styles: Vec<OutfitStyle>, // 风格
|
||||
pub role_in_outfit: String, // 在搭配中的角色 (如: "主角", "配角", "点缀")
|
||||
pub image_url: Option<String>, // 图片URL
|
||||
}
|
||||
|
||||
/// 搭配匹配结果
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitMatching {
|
||||
pub id: String,
|
||||
pub project_id: String,
|
||||
pub matching_name: String, // 搭配名称
|
||||
pub matching_type: MatchingType, // 匹配类型
|
||||
pub items: Vec<MatchingOutfitItem>, // 搭配的服装单品
|
||||
pub score_details: MatchingScoreDetails, // 评分详情
|
||||
pub suggestions: Vec<MatchingSuggestion>, // 搭配建议
|
||||
pub occasion_tags: Vec<String>, // 适用场合标签
|
||||
pub season_tags: Vec<String>, // 适用季节标签
|
||||
pub style_description: String, // 风格描述
|
||||
pub color_palette: Vec<ColorHSV>, // 色彩搭配方案
|
||||
pub is_favorite: bool, // 是否收藏
|
||||
pub wear_count: u32, // 穿着次数
|
||||
pub last_worn_date: Option<DateTime<Utc>>, // 最后穿着日期
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
/// 创建搭配匹配请求
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CreateOutfitMatchingRequest {
|
||||
pub project_id: String,
|
||||
pub matching_name: String,
|
||||
pub matching_type: MatchingType,
|
||||
pub item_ids: Vec<String>, // 服装单品ID列表
|
||||
pub occasion_tags: Vec<String>,
|
||||
pub season_tags: Vec<String>,
|
||||
pub style_description: Option<String>,
|
||||
}
|
||||
|
||||
/// 更新搭配匹配请求
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UpdateOutfitMatchingRequest {
|
||||
pub matching_name: Option<String>,
|
||||
pub matching_type: Option<MatchingType>,
|
||||
pub item_ids: Option<Vec<String>>,
|
||||
pub occasion_tags: Option<Vec<String>>,
|
||||
pub season_tags: Option<Vec<String>>,
|
||||
pub style_description: Option<String>,
|
||||
pub is_favorite: Option<bool>,
|
||||
}
|
||||
|
||||
/// 搭配搜索过滤条件
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitMatchingSearchFilters {
|
||||
pub categories: Option<Vec<OutfitCategory>>, // 包含的服装类别
|
||||
pub styles: Option<Vec<OutfitStyle>>, // 风格过滤
|
||||
pub colors: Option<Vec<ColorHSV>>, // 颜色过滤
|
||||
pub color_similarity_threshold: Option<f64>, // 颜色相似度阈值
|
||||
pub occasions: Option<Vec<String>>, // 场合过滤
|
||||
pub seasons: Option<Vec<String>>, // 季节过滤
|
||||
pub min_score: Option<f64>, // 最低评分
|
||||
pub confidence_level: Option<ConfidenceLevel>, // 置信度等级
|
||||
pub matching_types: Option<Vec<MatchingType>>, // 匹配类型
|
||||
}
|
||||
|
||||
/// 搭配匹配查询选项
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitMatchingQueryOptions {
|
||||
pub project_id: Option<String>,
|
||||
pub filters: Option<OutfitMatchingSearchFilters>,
|
||||
pub sort_by: Option<String>, // 排序字段 ("score", "created_at", "wear_count")
|
||||
pub sort_order: Option<String>, // 排序方向 ("asc", "desc")
|
||||
pub limit: Option<u32>,
|
||||
pub offset: Option<u32>,
|
||||
}
|
||||
|
||||
/// 智能搭配推荐请求
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SmartMatchingRequest {
|
||||
pub project_id: String,
|
||||
pub base_item_id: Option<String>, // 基础单品ID (可选)
|
||||
pub target_occasion: Option<String>, // 目标场合
|
||||
pub target_season: Option<String>, // 目标季节
|
||||
pub preferred_styles: Option<Vec<OutfitStyle>>, // 偏好风格
|
||||
pub color_preferences: Option<Vec<ColorHSV>>, // 颜色偏好
|
||||
pub exclude_item_ids: Option<Vec<String>>, // 排除的单品ID
|
||||
pub max_results: Option<u32>, // 最大结果数
|
||||
}
|
||||
|
||||
/// 智能搭配推荐结果
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SmartMatchingResult {
|
||||
pub recommended_matchings: Vec<OutfitMatching>, // 推荐的搭配
|
||||
pub reasoning: String, // 推荐理由
|
||||
pub confidence_score: f64, // 推荐置信度
|
||||
}
|
||||
|
||||
/// 搭配匹配统计信息
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutfitMatchingStats {
|
||||
pub total_matchings: u32,
|
||||
pub favorite_count: u32,
|
||||
pub average_score: f64,
|
||||
pub most_worn_matching_id: Option<String>,
|
||||
pub style_distribution: std::collections::HashMap<String, u32>,
|
||||
pub occasion_distribution: std::collections::HashMap<String, u32>,
|
||||
pub season_distribution: std::collections::HashMap<String, u32>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_confidence_level_from_score() {
|
||||
assert_eq!(ConfidenceLevel::from_score(0.95), ConfidenceLevel::Excellent);
|
||||
assert_eq!(ConfidenceLevel::from_score(0.8), ConfidenceLevel::High);
|
||||
assert_eq!(ConfidenceLevel::from_score(0.5), ConfidenceLevel::Medium);
|
||||
assert_eq!(ConfidenceLevel::from_score(0.2), ConfidenceLevel::Low);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matching_score_calculation() {
|
||||
let mut score_details = MatchingScoreDetails {
|
||||
color_harmony_score: 0.8,
|
||||
style_consistency_score: 0.9,
|
||||
proportion_score: 0.7,
|
||||
occasion_appropriateness: 0.8,
|
||||
trend_factor: 0.6,
|
||||
overall_score: 0.0,
|
||||
};
|
||||
|
||||
score_details.calculate_overall_score();
|
||||
assert!(score_details.overall_score > 0.7);
|
||||
assert!(score_details.overall_score < 0.9);
|
||||
}
|
||||
}
|
||||
|
|
@ -808,77 +808,6 @@ impl Database {
|
|||
[],
|
||||
)?;
|
||||
|
||||
// 创建服装分析表
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS outfit_analyses (
|
||||
id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
image_path TEXT NOT NULL,
|
||||
image_name TEXT NOT NULL,
|
||||
analysis_status TEXT NOT NULL DEFAULT 'Pending',
|
||||
analysis_result TEXT,
|
||||
error_message TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
analyzed_at DATETIME,
|
||||
FOREIGN KEY (project_id) REFERENCES projects (id) ON DELETE CASCADE
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 创建服装单品表
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS outfit_items (
|
||||
id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
analysis_id TEXT,
|
||||
name TEXT NOT NULL,
|
||||
category TEXT NOT NULL,
|
||||
brand TEXT,
|
||||
model TEXT,
|
||||
color_primary TEXT NOT NULL,
|
||||
color_secondary TEXT,
|
||||
styles TEXT NOT NULL,
|
||||
design_elements TEXT,
|
||||
size_info TEXT,
|
||||
material_info TEXT,
|
||||
price REAL,
|
||||
purchase_date DATETIME,
|
||||
image_urls TEXT,
|
||||
tags TEXT,
|
||||
notes TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (project_id) REFERENCES projects (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (analysis_id) REFERENCES outfit_analyses (id) ON DELETE SET NULL
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 创建服装搭配表
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS outfit_matchings (
|
||||
id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
matching_name TEXT NOT NULL,
|
||||
matching_type TEXT NOT NULL,
|
||||
items TEXT NOT NULL,
|
||||
score_details TEXT NOT NULL,
|
||||
suggestions TEXT,
|
||||
occasion_tags TEXT,
|
||||
season_tags TEXT,
|
||||
style_description TEXT NOT NULL,
|
||||
color_palette TEXT,
|
||||
is_favorite BOOLEAN DEFAULT 0,
|
||||
wear_count INTEGER DEFAULT 0,
|
||||
last_worn_date DATETIME,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (project_id) REFERENCES projects (id) ON DELETE CASCADE
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 创建索引
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_projects_name ON projects (name)",
|
||||
|
|
@ -1021,65 +950,6 @@ impl Database {
|
|||
"CREATE INDEX IF NOT EXISTS idx_export_records_created_at ON export_records (created_at)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 创建服装分析表索引
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_analyses_project_id ON outfit_analyses (project_id)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_analyses_status ON outfit_analyses (analysis_status)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_analyses_created_at ON outfit_analyses (created_at)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 创建服装单品表索引
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_items_project_id ON outfit_items (project_id)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_items_analysis_id ON outfit_items (analysis_id)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_items_category ON outfit_items (category)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_items_brand ON outfit_items (brand)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 创建服装搭配表索引
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_matchings_project_id ON outfit_matchings (project_id)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_matchings_type ON outfit_matchings (matching_type)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_matchings_favorite ON outfit_matchings (is_favorite)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outfit_matchings_created_at ON outfit_matchings (created_at)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 添加新字段(如果不存在)- 数据库迁移
|
||||
let _ = conn.execute(
|
||||
"ALTER TABLE template_materials ADD COLUMN file_exists BOOLEAN DEFAULT FALSE",
|
||||
|
|
|
|||
Loading…
Reference in New Issue