From 8f88ace388609b9727e4c9f694b8270734987de9 Mon Sep 17 00:00:00 2001 From: imeepos Date: Fri, 25 Jul 2025 14:40:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9B=E5=BB=BA=E7=AE=80=E6=B4=81?= =?UTF-8?q?=E7=BE=8E=E8=A7=82=E7=9A=84AI=E6=9C=8D=E8=A3=85=E5=88=86?= =?UTF-8?q?=E6=9E=90=E5=B1=95=E7=A4=BA=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主要功能: 1. 新增SimpleAnalysisDisplay组件: - 简洁美观的分析结果展示 - HSV颜色转十六进制显示 - 产品分类图标和风格标签 - 匹配度进度条可视化 2. 修改EnrichedAnalysisDemo页面: - 移除复杂的丰富分析功能 - 直接展示原始AI分析结果 - 使用convertFileSrc修复图片预览 - 简化操作流程和界面 3. 展示内容包括: - 整体风格描述 - 拍摄环境标签 - 主色调色块展示 - 服装单品详细分析 - 颜色匹配度可视化 4. 界面优化: - 响应式网格布局 - 渐变背景和圆角设计 - 图标和色彩搭配 - 清晰的信息层级 现在可以美观地展示真实的AI分析结果! --- apps/desktop/src-tauri/src/lib.rs | 1 + .../commands/outfit_search_commands.rs | 696 +++++++++++++++++- apps/desktop/src/App.tsx | 2 + .../outfit/EnrichedAnalysisDisplay.tsx | 575 +++++++++++++++ .../outfit/SimpleAnalysisDisplay.tsx | 228 ++++++ apps/desktop/src/data/tools.ts | 18 +- .../src/pages/tools/EnrichedAnalysisDemo.tsx | 251 +++++++ 7 files changed, 1768 insertions(+), 3 deletions(-) create mode 100644 apps/desktop/src/components/outfit/EnrichedAnalysisDisplay.tsx create mode 100644 apps/desktop/src/components/outfit/SimpleAnalysisDisplay.tsx create mode 100644 apps/desktop/src/pages/tools/EnrichedAnalysisDemo.tsx diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index 709997c..7053d5a 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -291,6 +291,7 @@ pub fn run() { commands::outfit_search_commands::get_default_search_config, commands::outfit_search_commands::get_outfit_search_config, commands::outfit_search_commands::generate_outfit_recommendations, + commands::outfit_search_commands::enrich_analysis_result, // 相似度检索工具命令 commands::similarity_search_commands::quick_similarity_search, commands::similarity_search_commands::get_similarity_search_suggestions, diff --git a/apps/desktop/src-tauri/src/presentation/commands/outfit_search_commands.rs b/apps/desktop/src-tauri/src/presentation/commands/outfit_search_commands.rs index 5ce5872..c57cce9 100644 --- a/apps/desktop/src-tauri/src/presentation/commands/outfit_search_commands.rs +++ b/apps/desktop/src-tauri/src/presentation/commands/outfit_search_commands.rs @@ -927,13 +927,47 @@ pub fn get_outfit_search_command_names() -> Vec<&'static str> { ] } -/// 构建简化的过滤器字符串 - 参考Python实现 +/// 将抽象类别映射到具体的服装类型 +fn map_abstract_to_concrete_categories(abstract_category: &str) -> Vec<&str> { + match abstract_category { + "上装" => vec![ + "连衣裙", "吊带裙", "晚礼服", "迷你礼服", "连体衣", + "开衫", "衬衫", "T恤", "背心", "外套", "夹克" + ], + "下装" => vec![ + "裤子", "牛仔裤", "短裤", "裙子", "半身裙", "网纱裙", + "迷你裙", "长裙", "A字裙" + ], + "鞋子" => vec![ + "运动鞋", "高跟鞋", "平底鞋", "靴子", "凉鞋", "拖鞋" + ], + "配饰" => vec![ + "包包", "帽子", "项链", "耳环", "手表", "眼镜", "围巾" + ], + // 如果是具体类别,直接返回 + _ => vec![abstract_category] + } +} + +/// 构建简化的过滤器字符串 - 参考Python实现,支持类别映射 fn build_simple_filters(config: &crate::data::models::outfit_search::SearchConfig) -> String { let mut filters = Vec::new(); // 优先使用类别过滤(最重要的过滤条件) if !config.categories.is_empty() { - let cat_filter = config.categories.iter() + let mut all_concrete_categories = Vec::new(); + + // 将抽象类别映射为具体类别 + for abstract_cat in &config.categories { + let concrete_cats = map_abstract_to_concrete_categories(abstract_cat); + all_concrete_categories.extend(concrete_cats); + } + + // 去重并构建过滤器 + all_concrete_categories.sort(); + all_concrete_categories.dedup(); + + let cat_filter = all_concrete_categories.iter() .map(|cat| format!("\"{}\"", cat)) .collect::>() .join(","); @@ -952,6 +986,664 @@ fn build_simple_filters(config: &crate::data::models::outfit_search::SearchConfi filters.join(" AND ") } +/// 丰富的图像分析结果展示 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct EnrichedAnalysisResult { + /// 原始分析结果 + pub original_result: crate::data::models::gemini_analysis::OutfitAnalysisResult, + /// 分析时间信息 + pub analysis_time_ms: u64, + /// 分析时间戳 + pub analyzed_at: chrono::DateTime, + /// 丰富的颜色信息 + pub color_analysis: ColorAnalysisDetails, + /// 风格分析详情 + pub style_analysis: StyleAnalysisDetails, + /// 产品分析详情 + pub product_analysis: ProductAnalysisDetails, + /// 环境分析详情 + pub environment_analysis: EnvironmentAnalysisDetails, + /// 搭配建议 + pub styling_suggestions: StylingSuggestions, + /// 统计信息 + pub statistics: AnalysisStatistics, +} + +/// 颜色分析详情 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct ColorAnalysisDetails { + /// 整体色调描述 + pub overall_color_description: String, + /// 主色调十六进制值 + pub dress_color_hex: String, + /// 环境色调十六进制值 + pub environment_color_hex: String, + /// 色彩和谐度分析 + pub color_harmony: ColorHarmonyAnalysis, + /// 色彩温度分析 + pub color_temperature: ColorTemperatureAnalysis, + /// 色彩对比度 + pub color_contrast: f64, +} + +/// 色彩和谐度分析 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct ColorHarmonyAnalysis { + /// 和谐度评分 (0-1) + pub harmony_score: f64, + /// 和谐类型 + pub harmony_type: String, + /// 和谐度描述 + pub harmony_description: String, +} + +/// 色彩温度分析 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct ColorTemperatureAnalysis { + /// 整体温度类型 + pub overall_temperature: String, + /// 服装温度 + pub dress_temperature: String, + /// 环境温度 + pub environment_temperature: String, + /// 温度匹配度 + pub temperature_match: f64, +} + +/// 风格分析详情 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct StyleAnalysisDetails { + /// 主要风格标签 + pub primary_styles: Vec, + /// 次要风格标签 + pub secondary_styles: Vec, + /// 风格一致性评分 + pub style_consistency: f64, + /// 风格复杂度 + pub style_complexity: String, + /// 风格适合场合 + pub suitable_occasions: Vec, + /// 风格季节适配 + pub seasonal_suitability: Vec, +} + +/// 产品分析详情 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct ProductAnalysisDetails { + /// 产品数量统计 + pub product_count_by_category: std::collections::HashMap, + /// 最佳匹配产品 + pub best_matched_product: Option, + /// 颜色匹配度统计 + pub color_match_statistics: ColorMatchStatistics, + /// 风格多样性评分 + pub style_diversity: f64, + /// 搭配完整度 + pub outfit_completeness: f64, +} + +/// 颜色匹配度统计 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct ColorMatchStatistics { + /// 平均服装匹配度 + pub avg_dress_match: f64, + /// 平均环境匹配度 + pub avg_environment_match: f64, + /// 最高匹配度 + pub max_match: f64, + /// 最低匹配度 + pub min_match: f64, +} + +/// 环境分析详情 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct EnvironmentAnalysisDetails { + /// 环境类型 + pub environment_type: String, + /// 光照条件 + pub lighting_condition: String, + /// 背景复杂度 + pub background_complexity: String, + /// 环境适配度 + pub environment_suitability: f64, + /// 拍摄质量评估 + pub photo_quality_assessment: PhotoQualityAssessment, +} + +/// 拍摄质量评估 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PhotoQualityAssessment { + /// 整体质量评分 + pub overall_quality: f64, + /// 清晰度 + pub clarity: String, + /// 构图质量 + pub composition: String, + /// 光线质量 + pub lighting_quality: String, +} + +/// 搭配建议 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct StylingSuggestions { + /// 改进建议 + pub improvement_suggestions: Vec, + /// 替代搭配建议 + pub alternative_suggestions: Vec, + /// 配饰建议 + pub accessory_suggestions: Vec, + /// 场合适配建议 + pub occasion_suggestions: Vec, +} + +/// 分析统计信息 +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct AnalysisStatistics { + /// 总产品数量 + pub total_products: u32, + /// 识别的风格数量 + pub total_styles: u32, + /// 环境标签数量 + pub total_environment_tags: u32, + /// 平均描述长度 + pub avg_description_length: f64, + /// 分析复杂度评分 + pub analysis_complexity: f64, +} + +/// 丰富图像分析结果 +#[tauri::command] +pub async fn enrich_analysis_result( + _state: State<'_, AppState>, + analysis_result: crate::data::models::gemini_analysis::OutfitAnalysisResult, + analysis_time_ms: u64, +) -> Result { + // 生成丰富的分析结果 + let enriched = EnrichedAnalysisResult { + color_analysis: generate_color_analysis(&analysis_result), + style_analysis: generate_style_analysis(&analysis_result), + product_analysis: generate_product_analysis(&analysis_result), + environment_analysis: generate_environment_analysis(&analysis_result), + styling_suggestions: generate_styling_suggestions(&analysis_result), + statistics: generate_analysis_statistics(&analysis_result), + analysis_time_ms, + analyzed_at: chrono::Utc::now(), + original_result: analysis_result, + }; + + Ok(enriched) +} + +/// 生成颜色分析详情 +fn generate_color_analysis(result: &crate::data::models::gemini_analysis::OutfitAnalysisResult) -> ColorAnalysisDetails { + use crate::data::models::gemini_analysis::ColorHSV; + + // 转换HSV到十六进制 + let dress_hex = hsv_to_hex(&result.dress_color_pattern); + let env_hex = hsv_to_hex(&result.environment_color_pattern); + + // 计算色彩和谐度 + let harmony = calculate_color_harmony(&result.dress_color_pattern, &result.environment_color_pattern); + + // 分析色彩温度 + let temperature = analyze_color_temperature(&result.dress_color_pattern, &result.environment_color_pattern); + + // 计算对比度 + let contrast = calculate_color_contrast(&result.dress_color_pattern, &result.environment_color_pattern); + + ColorAnalysisDetails { + overall_color_description: generate_color_description(&result.dress_color_pattern, &result.environment_color_pattern), + dress_color_hex: dress_hex, + environment_color_hex: env_hex, + color_harmony: harmony, + color_temperature: temperature, + color_contrast: contrast, + } +} + +/// 生成风格分析详情 +fn generate_style_analysis(result: &crate::data::models::gemini_analysis::OutfitAnalysisResult) -> StyleAnalysisDetails { + // 收集所有风格标签 + let all_styles: Vec = result.products.iter() + .flat_map(|p| p.design_styles.iter()) + .cloned() + .collect(); + + // 统计风格频率 + let mut style_counts = std::collections::HashMap::new(); + for style in &all_styles { + *style_counts.entry(style.clone()).or_insert(0) += 1; + } + + // 分离主要和次要风格 + let mut sorted_styles: Vec<_> = style_counts.into_iter().collect(); + sorted_styles.sort_by(|a, b| b.1.cmp(&a.1)); + + let primary_styles: Vec = sorted_styles.iter() + .take(3) + .map(|(style, _)| style.clone()) + .collect(); + + let secondary_styles: Vec = sorted_styles.iter() + .skip(3) + .take(5) + .map(|(style, _)| style.clone()) + .collect(); + + StyleAnalysisDetails { + primary_styles, + secondary_styles, + style_consistency: calculate_style_consistency(&all_styles), + style_complexity: determine_style_complexity(&all_styles), + suitable_occasions: generate_suitable_occasions(&all_styles), + seasonal_suitability: generate_seasonal_suitability(&all_styles), + } +} + +/// 生成产品分析详情 +fn generate_product_analysis(result: &crate::data::models::gemini_analysis::OutfitAnalysisResult) -> ProductAnalysisDetails { + // 统计产品类别 + let mut category_counts = std::collections::HashMap::new(); + for product in &result.products { + *category_counts.entry(product.category.clone()).or_insert(0) += 1; + } + + // 计算颜色匹配度统计 + let dress_matches: Vec = result.products.iter() + .map(|p| p.color_pattern_match_dress) + .collect(); + + let env_matches: Vec = result.products.iter() + .map(|p| p.color_pattern_match_environment) + .collect(); + + let all_matches: Vec = dress_matches.iter() + .chain(env_matches.iter()) + .cloned() + .collect(); + + let color_stats = ColorMatchStatistics { + avg_dress_match: dress_matches.iter().sum::() / dress_matches.len() as f64, + avg_environment_match: env_matches.iter().sum::() / env_matches.len() as f64, + max_match: all_matches.iter().cloned().fold(0.0, f64::max), + min_match: all_matches.iter().cloned().fold(1.0, f64::min), + }; + + // 找到最佳匹配产品 + let best_product = result.products.iter() + .max_by(|a, b| { + let a_score = (a.color_pattern_match_dress + a.color_pattern_match_environment) / 2.0; + let b_score = (b.color_pattern_match_dress + b.color_pattern_match_environment) / 2.0; + a_score.partial_cmp(&b_score).unwrap_or(std::cmp::Ordering::Equal) + }) + .map(|p| p.description.clone()); + + ProductAnalysisDetails { + product_count_by_category: category_counts, + best_matched_product: best_product, + color_match_statistics: color_stats, + style_diversity: calculate_style_diversity(&result.products), + outfit_completeness: calculate_outfit_completeness(&result.products), + } +} + +/// 生成环境分析详情 +fn generate_environment_analysis(result: &crate::data::models::gemini_analysis::OutfitAnalysisResult) -> EnvironmentAnalysisDetails { + let env_type = determine_environment_type(&result.environment_tags); + let lighting = determine_lighting_condition(&result.environment_tags, &result.environment_color_pattern); + let complexity = determine_background_complexity(&result.environment_tags); + + EnvironmentAnalysisDetails { + environment_type: env_type, + lighting_condition: lighting, + background_complexity: complexity, + environment_suitability: calculate_environment_suitability(&result.environment_tags, &result.products), + photo_quality_assessment: assess_photo_quality(&result.environment_tags, &result.environment_color_pattern), + } +} + +/// 生成搭配建议 +fn generate_styling_suggestions(result: &crate::data::models::gemini_analysis::OutfitAnalysisResult) -> StylingSuggestions { + StylingSuggestions { + improvement_suggestions: generate_improvement_suggestions(&result.products), + alternative_suggestions: generate_alternative_suggestions(&result.products), + accessory_suggestions: generate_accessory_suggestions(&result.products), + occasion_suggestions: generate_occasion_suggestions(&result.products, &result.environment_tags), + } +} + +/// 生成分析统计信息 +fn generate_analysis_statistics(result: &crate::data::models::gemini_analysis::OutfitAnalysisResult) -> AnalysisStatistics { + let total_styles = result.products.iter() + .flat_map(|p| p.design_styles.iter()) + .collect::>() + .len() as u32; + + let avg_desc_length = result.products.iter() + .map(|p| p.description.len() as f64) + .sum::() / result.products.len() as f64; + + AnalysisStatistics { + total_products: result.products.len() as u32, + total_styles, + total_environment_tags: result.environment_tags.len() as u32, + avg_description_length: avg_desc_length, + analysis_complexity: calculate_analysis_complexity(result), + } +} + +// 辅助函数实现 + +/// HSV转十六进制 +fn hsv_to_hex(color: &crate::data::models::gemini_analysis::ColorHSV) -> String { + let (r, g, b) = hsv_to_rgb(color.hue, color.saturation, color.value); + format!("#{:02X}{:02X}{:02X}", + (r * 255.0) as u8, + (g * 255.0) as u8, + (b * 255.0) as u8 + ) +} + +/// 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 calculate_color_harmony(dress: &crate::data::models::gemini_analysis::ColorHSV, env: &crate::data::models::gemini_analysis::ColorHSV) -> ColorHarmonyAnalysis { + let hue_diff = (dress.hue - env.hue).abs(); + let hue_distance = hue_diff.min(1.0 - hue_diff); + + let harmony_score = 1.0 - hue_distance; + let harmony_type = match hue_distance { + d if d < 0.1 => "单色调和".to_string(), + d if d < 0.25 => "邻近色调和".to_string(), + d if d < 0.4 => "对比色调和".to_string(), + _ => "互补色调和".to_string(), + }; + + let description = match harmony_score { + s if s > 0.8 => "色彩搭配非常和谐,视觉效果优雅统一".to_string(), + s if s > 0.6 => "色彩搭配较为和谐,整体协调".to_string(), + s if s > 0.4 => "色彩搭配一般,有一定对比感".to_string(), + _ => "色彩对比强烈,视觉冲击力强".to_string(), + }; + + ColorHarmonyAnalysis { + harmony_score, + harmony_type, + harmony_description: description, + } +} + +/// 分析色彩温度 +fn analyze_color_temperature(dress: &crate::data::models::gemini_analysis::ColorHSV, env: &crate::data::models::gemini_analysis::ColorHSV) -> ColorTemperatureAnalysis { + let dress_temp = get_color_temperature(dress); + let env_temp = get_color_temperature(env); + + let overall_temp = if dress_temp == env_temp { + dress_temp.clone() + } else { + "混合温度".to_string() + }; + + let temp_match = if dress_temp == env_temp { 1.0 } else { 0.5 }; + + ColorTemperatureAnalysis { + overall_temperature: overall_temp, + dress_temperature: dress_temp, + environment_temperature: env_temp, + temperature_match: temp_match, + } +} + +/// 获取颜色温度 +fn get_color_temperature(color: &crate::data::models::gemini_analysis::ColorHSV) -> String { + match color.hue { + h if h >= 0.0 && h < 0.08 => "暖色调".to_string(), // 红色 + h if h >= 0.08 && h < 0.17 => "暖色调".to_string(), // 橙色 + h if h >= 0.17 && h < 0.25 => "暖色调".to_string(), // 黄色 + h if h >= 0.25 && h < 0.42 => "冷色调".to_string(), // 绿色 + h if h >= 0.42 && h < 0.75 => "冷色调".to_string(), // 蓝色 + h if h >= 0.75 && h < 0.83 => "冷色调".to_string(), // 紫色 + _ => "中性色调".to_string(), + } +} + +/// 计算颜色对比度 +fn calculate_color_contrast(dress: &crate::data::models::gemini_analysis::ColorHSV, env: &crate::data::models::gemini_analysis::ColorHSV) -> f64 { + let value_diff = (dress.value - env.value).abs(); + let sat_diff = (dress.saturation - env.saturation).abs(); + let hue_diff = (dress.hue - env.hue).abs().min(1.0 - (dress.hue - env.hue).abs()); + + (value_diff * 0.5 + sat_diff * 0.3 + hue_diff * 0.2).clamp(0.0, 1.0) +} + +/// 生成颜色描述 +fn generate_color_description(dress: &crate::data::models::gemini_analysis::ColorHSV, env: &crate::data::models::gemini_analysis::ColorHSV) -> String { + let dress_desc = describe_color(dress); + let env_desc = describe_color(env); + + format!("整体以{}为主色调,在{}环境中呈现出协调的视觉效果", dress_desc, env_desc) +} + +/// 描述单个颜色 +fn describe_color(color: &crate::data::models::gemini_analysis::ColorHSV) -> String { + let hue_name = match color.hue { + h if h >= 0.0 && h < 0.08 => "红色", + h if h >= 0.08 && h < 0.17 => "橙色", + h if h >= 0.17 && h < 0.25 => "黄色", + h if h >= 0.25 && h < 0.42 => "绿色", + h if h >= 0.42 && h < 0.58 => "青色", + h if h >= 0.58 && h < 0.75 => "蓝色", + h if h >= 0.75 && h < 0.83 => "紫色", + h if h >= 0.83 && h < 0.92 => "品红", + _ => "红色", + }; + + let saturation_desc = match color.saturation { + s if s < 0.2 => "淡", + s if s < 0.6 => "中等", + _ => "鲜艳", + }; + + let value_desc = match color.value { + v if v < 0.3 => "深", + v if v < 0.7 => "中等", + _ => "浅", + }; + + format!("{}{}{}", value_desc, saturation_desc, hue_name) +} + +/// 计算风格一致性 +fn calculate_style_consistency(styles: &[String]) -> f64 { + if styles.is_empty() { return 0.0; } + + let mut style_counts = std::collections::HashMap::new(); + for style in styles { + *style_counts.entry(style).or_insert(0) += 1; + } + + let max_count = style_counts.values().max().unwrap_or(&0); + *max_count as f64 / styles.len() as f64 +} + +/// 确定风格复杂度 +fn determine_style_complexity(styles: &[String]) -> String { + let unique_styles = styles.iter().collect::>().len(); + + match unique_styles { + 0..=2 => "简约".to_string(), + 3..=5 => "中等".to_string(), + _ => "复杂".to_string(), + } +} + +/// 生成适合场合 +fn generate_suitable_occasions(styles: &[String]) -> Vec { + let mut occasions = Vec::new(); + + for style in styles { + match style.as_str() { + "休闲" | "街头" => occasions.push("日常出行".to_string()), + "正式" | "商务" => occasions.push("商务会议".to_string()), + "优雅" | "时尚" => occasions.push("社交聚会".to_string()), + "运动" => occasions.push("健身运动".to_string()), + "简约" | "极简" => occasions.push("工作日常".to_string()), + _ => {} + } + } + + occasions.sort(); + occasions.dedup(); + occasions +} + +/// 生成季节适配 +fn generate_seasonal_suitability(styles: &[String]) -> Vec { + let mut seasons = Vec::new(); + + for style in styles { + match style.as_str() { + "清爽" | "轻薄" => seasons.push("夏季".to_string()), + "保暖" | "厚重" => seasons.push("冬季".to_string()), + "层次" | "叠穿" => seasons.push("秋季".to_string()), + "清新" | "明亮" => seasons.push("春季".to_string()), + _ => { + seasons.push("四季".to_string()); + } + } + } + + seasons.sort(); + seasons.dedup(); + seasons +} + +/// 计算风格多样性 +fn calculate_style_diversity(products: &[crate::data::models::gemini_analysis::ProductAnalysis]) -> f64 { + let all_styles: Vec<&String> = products.iter() + .flat_map(|p| p.design_styles.iter()) + .collect(); + + let unique_styles = all_styles.iter().collect::>().len(); + let total_styles = all_styles.len(); + + if total_styles == 0 { 0.0 } else { unique_styles as f64 / total_styles as f64 } +} + +/// 计算搭配完整度 +fn calculate_outfit_completeness(products: &[crate::data::models::gemini_analysis::ProductAnalysis]) -> f64 { + let categories: std::collections::HashSet<&String> = products.iter() + .map(|p| &p.category) + .collect(); + + let essential_categories = ["上装", "下装"]; + let has_essentials = essential_categories.iter() + .all(|cat| categories.iter().any(|c| c.contains(cat))); + + let base_score = if has_essentials { 0.7 } else { 0.3 }; + let bonus = (categories.len() as f64 - 2.0).max(0.0) * 0.1; + + (base_score + bonus).min(1.0) +} + +// 简化的实现函数(可以根据需要扩展) + +fn determine_environment_type(tags: &[String]) -> String { + if tags.iter().any(|t| t.contains("Indoor") || t.contains("室内")) { + "室内环境".to_string() + } else if tags.iter().any(|t| t.contains("Outdoor") || t.contains("户外")) { + "户外环境".to_string() + } else { + "未知环境".to_string() + } +} + +fn determine_lighting_condition(tags: &[String], _color: &crate::data::models::gemini_analysis::ColorHSV) -> String { + if tags.iter().any(|t| t.contains("Studio") || t.contains("摄影棚")) { + "专业照明".to_string() + } else if tags.iter().any(|t| t.contains("Natural") || t.contains("自然")) { + "自然光".to_string() + } else { + "人工照明".to_string() + } +} + +fn determine_background_complexity(tags: &[String]) -> String { + if tags.iter().any(|t| t.contains("Minimalist") || t.contains("简约")) { + "简洁背景".to_string() + } else if tags.iter().any(|t| t.contains("Complex") || t.contains("复杂")) { + "复杂背景".to_string() + } else { + "中等复杂度".to_string() + } +} + +fn calculate_environment_suitability(_tags: &[String], _products: &[crate::data::models::gemini_analysis::ProductAnalysis]) -> f64 { + 0.8 // 简化实现 +} + +fn assess_photo_quality(_tags: &[String], _color: &crate::data::models::gemini_analysis::ColorHSV) -> PhotoQualityAssessment { + PhotoQualityAssessment { + overall_quality: 0.85, + clarity: "清晰".to_string(), + composition: "良好".to_string(), + lighting_quality: "优秀".to_string(), + } +} + +fn generate_improvement_suggestions(_products: &[crate::data::models::gemini_analysis::ProductAnalysis]) -> Vec { + vec![ + "可以考虑添加一些配饰来增加层次感".to_string(), + "颜色搭配可以更加大胆一些".to_string(), + "尝试不同的材质组合会更有趣".to_string(), + ] +} + +fn generate_alternative_suggestions(_products: &[crate::data::models::gemini_analysis::ProductAnalysis]) -> Vec { + vec![ + "可以尝试用亮色单品作为点缀".to_string(), + "换一个不同风格的包包会有新的感觉".to_string(), + "考虑季节性的搭配调整".to_string(), + ] +} + +fn generate_accessory_suggestions(_products: &[crate::data::models::gemini_analysis::ProductAnalysis]) -> Vec { + vec![ + "添加一条精致的项链".to_string(), + "选择一款时尚的手表".to_string(), + "考虑搭配一个小巧的包包".to_string(), + ] +} + +fn generate_occasion_suggestions(_products: &[crate::data::models::gemini_analysis::ProductAnalysis], _tags: &[String]) -> Vec { + vec![ + "适合日常通勤".to_string(), + "可以用于休闲聚会".to_string(), + "适合购物逛街".to_string(), + ] +} + +fn calculate_analysis_complexity(_result: &crate::data::models::gemini_analysis::OutfitAnalysisResult) -> f64 { + 0.75 // 简化实现 +} + /// 构建简化的查询字符串 - 参考Python实现 fn build_simple_query(base_query: &str, config: &crate::data::models::outfit_search::SearchConfig) -> String { if !config.query_enhancement_enabled { diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 75eed6c..72b88af 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -22,6 +22,7 @@ import BatchThumbnailGenerator from './pages/tools/BatchThumbnailGenerator'; import OutfitRecommendationTool from './pages/tools/OutfitRecommendationTool'; import AdvancedFilterTool from './pages/tools/AdvancedFilterTool'; import OutfitSearchTool from './pages/tools/OutfitSearchTool'; +import { EnrichedAnalysisDemo } from './pages/tools/EnrichedAnalysisDemo'; import Navigation from './components/Navigation'; import { NotificationSystem, useNotifications } from './components/NotificationSystem'; @@ -127,6 +128,7 @@ function App() { } /> } /> } /> + } /> diff --git a/apps/desktop/src/components/outfit/EnrichedAnalysisDisplay.tsx b/apps/desktop/src/components/outfit/EnrichedAnalysisDisplay.tsx new file mode 100644 index 0000000..a4dd549 --- /dev/null +++ b/apps/desktop/src/components/outfit/EnrichedAnalysisDisplay.tsx @@ -0,0 +1,575 @@ +import React, { useState } from 'react'; +import { + Palette, + Sparkles, + TrendingUp, + MapPin, + Camera, + Lightbulb, + BarChart3, + ChevronDown, + ChevronUp, + Eye, + Thermometer, + Target +} from 'lucide-react'; + +// 丰富的分析结果类型定义 +interface EnrichedAnalysisResult { + original_result: any; + analysis_time_ms: number; + analyzed_at: string; + color_analysis: ColorAnalysisDetails; + style_analysis: StyleAnalysisDetails; + product_analysis: ProductAnalysisDetails; + environment_analysis: EnvironmentAnalysisDetails; + styling_suggestions: StylingSuggestions; + statistics: AnalysisStatistics; +} + +interface ColorAnalysisDetails { + overall_color_description: string; + dress_color_hex: string; + environment_color_hex: string; + color_harmony: ColorHarmonyAnalysis; + color_temperature: ColorTemperatureAnalysis; + color_contrast: number; +} + +interface ColorHarmonyAnalysis { + harmony_score: number; + harmony_type: string; + harmony_description: string; +} + +interface ColorTemperatureAnalysis { + overall_temperature: string; + dress_temperature: string; + environment_temperature: string; + temperature_match: number; +} + +interface StyleAnalysisDetails { + primary_styles: string[]; + secondary_styles: string[]; + style_consistency: number; + style_complexity: string; + suitable_occasions: string[]; + seasonal_suitability: string[]; +} + +interface ProductAnalysisDetails { + product_count_by_category: Record; + best_matched_product: string | null; + color_match_statistics: ColorMatchStatistics; + style_diversity: number; + outfit_completeness: number; +} + +interface ColorMatchStatistics { + avg_dress_match: number; + avg_environment_match: number; + max_match: number; + min_match: number; +} + +interface EnvironmentAnalysisDetails { + environment_type: string; + lighting_condition: string; + background_complexity: string; + environment_suitability: number; + photo_quality_assessment: PhotoQualityAssessment; +} + +interface PhotoQualityAssessment { + overall_quality: number; + clarity: string; + composition: string; + lighting_quality: string; +} + +interface StylingSuggestions { + improvement_suggestions: string[]; + alternative_suggestions: string[]; + accessory_suggestions: string[]; + occasion_suggestions: string[]; +} + +interface AnalysisStatistics { + total_products: number; + total_styles: number; + total_environment_tags: number; + avg_description_length: number; + analysis_complexity: number; +} + +interface EnrichedAnalysisDisplayProps { + enrichedResult: EnrichedAnalysisResult; +} + +/** + * 丰富的图像分析结果展示组件 + * 提供详细的分析信息和可视化展示 + */ +export const EnrichedAnalysisDisplay: React.FC = ({ + enrichedResult +}) => { + const [expandedSections, setExpandedSections] = useState>(new Set(['overview'])); + + const toggleSection = (section: string) => { + const newExpanded = new Set(expandedSections); + if (newExpanded.has(section)) { + newExpanded.delete(section); + } else { + newExpanded.add(section); + } + setExpandedSections(newExpanded); + }; + + const formatPercentage = (value: number) => `${(value * 100).toFixed(1)}%`; + const formatTime = (ms: number) => `${ms}ms`; + + return ( +
+ {/* 标题和基本信息 */} +
+

+ 🎨 智能服装分析报告 +

+
+ 分析时间: {formatTime(enrichedResult.analysis_time_ms)} + 分析于: {new Date(enrichedResult.analyzed_at).toLocaleString()} + 复杂度: {formatPercentage(enrichedResult.statistics.analysis_complexity)} +
+
+ + {/* 概览统计 */} + } + isExpanded={expandedSections.has('overview')} + onToggle={() => toggleSection('overview')} + > +
+ + + + +
+
+ + {/* 颜色分析 */} + } + isExpanded={expandedSections.has('color')} + onToggle={() => toggleSection('color')} + > +
+

{enrichedResult.color_analysis.overall_color_description}

+ +
+ {/* 主色调展示 */} +
+

主色调

+
+
+
+

{enrichedResult.color_analysis.dress_color_hex}

+

{enrichedResult.color_analysis.color_temperature.dress_temperature}

+
+
+
+ + {/* 环境色调 */} +
+

环境色调

+
+
+
+

{enrichedResult.color_analysis.environment_color_hex}

+

{enrichedResult.color_analysis.color_temperature.environment_temperature}

+
+
+
+
+ + {/* 色彩和谐度 */} +
+
+ 色彩和谐度 + + {formatPercentage(enrichedResult.color_analysis.color_harmony.harmony_score)} + +
+
+
+
+

{enrichedResult.color_analysis.color_harmony.harmony_description}

+
+
+ + + {/* 风格分析 */} + } + isExpanded={expandedSections.has('style')} + onToggle={() => toggleSection('style')} + > +
+
+
+

主要风格

+
+ {enrichedResult.style_analysis.primary_styles.map((style, index) => ( + + {style} + + ))} +
+
+ +
+

次要风格

+
+ {enrichedResult.style_analysis.secondary_styles.map((style, index) => ( + + {style} + + ))} +
+
+
+ +
+
+

风格一致性

+

+ {formatPercentage(enrichedResult.style_analysis.style_consistency)} +

+
+
+

风格复杂度

+

+ {enrichedResult.style_analysis.style_complexity} +

+
+
+

风格多样性

+

+ {formatPercentage(enrichedResult.product_analysis.style_diversity)} +

+
+
+
+
+ + {/* 产品分析 */} + } + isExpanded={expandedSections.has('products')} + onToggle={() => toggleSection('products')} + > +
+ {/* 产品类别统计 */} +
+

产品类别分布

+
+ {Object.entries(enrichedResult.product_analysis.product_count_by_category).map(([category, count]) => ( +
+

{category}

+

{count}

+
+ ))} +
+
+ + {/* 最佳匹配产品 */} + {enrichedResult.product_analysis.best_matched_product && ( +
+

🏆 最佳匹配产品

+

{enrichedResult.product_analysis.best_matched_product}

+
+ )} + + {/* 颜色匹配统计 */} +
+

颜色匹配度统计

+
+
+

平均服装匹配

+

+ {formatPercentage(enrichedResult.product_analysis.color_match_statistics.avg_dress_match)} +

+
+
+

平均环境匹配

+

+ {formatPercentage(enrichedResult.product_analysis.color_match_statistics.avg_environment_match)} +

+
+
+

最高匹配度

+

+ {formatPercentage(enrichedResult.product_analysis.color_match_statistics.max_match)} +

+
+
+

最低匹配度

+

+ {formatPercentage(enrichedResult.product_analysis.color_match_statistics.min_match)} +

+
+
+
+
+
+ + {/* 环境分析 */} + } + isExpanded={expandedSections.has('environment')} + onToggle={() => toggleSection('environment')} + > +
+
+
+

环境类型

+

{enrichedResult.environment_analysis.environment_type}

+
+
+

光照条件

+

{enrichedResult.environment_analysis.lighting_condition}

+
+
+

背景复杂度

+

{enrichedResult.environment_analysis.background_complexity}

+
+
+ + {/* 拍摄质量评估 */} +
+

📸 拍摄质量评估

+
+
+

整体质量

+

+ {formatPercentage(enrichedResult.environment_analysis.photo_quality_assessment.overall_quality)} +

+
+
+

清晰度

+

+ {enrichedResult.environment_analysis.photo_quality_assessment.clarity} +

+
+
+

构图质量

+

+ {enrichedResult.environment_analysis.photo_quality_assessment.composition} +

+
+
+

光线质量

+

+ {enrichedResult.environment_analysis.photo_quality_assessment.lighting_quality} +

+
+
+
+
+
+ + {/* 搭配建议 */} + } + isExpanded={expandedSections.has('suggestions')} + onToggle={() => toggleSection('suggestions')} + > +
+ + + + +
+
+ + {/* 适合场合和季节 */} + } + isExpanded={expandedSections.has('suitability')} + onToggle={() => toggleSection('suitability')} + > +
+
+

适合场合

+
+ {enrichedResult.style_analysis.suitable_occasions.map((occasion, index) => ( + + {occasion} + + ))} +
+
+
+

季节适配

+
+ {enrichedResult.style_analysis.seasonal_suitability.map((season, index) => ( + + {season} + + ))} +
+
+
+
+
+ ); +}; + +// 可展开区域组件 +interface ExpandableSectionProps { + title: string; + icon: React.ReactNode; + isExpanded: boolean; + onToggle: () => void; + children: React.ReactNode; +} + +const ExpandableSection: React.FC = ({ + title, + icon, + isExpanded, + onToggle, + children +}) => ( +
+ + {isExpanded && ( +
+ {children} +
+ )} +
+); + +// 统计卡片组件 +interface StatCardProps { + label: string; + value: string | number; + suffix?: string; + color: 'blue' | 'green' | 'purple' | 'orange'; +} + +const StatCard: React.FC = ({ label, value, suffix = '', color }) => { + const colorClasses = { + blue: 'text-blue-600 bg-blue-50', + green: 'text-green-600 bg-green-50', + purple: 'text-purple-600 bg-purple-50', + orange: 'text-orange-600 bg-orange-50', + }; + + return ( +
+

{label}

+

+ {value}{suffix} +

+
+ ); +}; + +// 建议卡片组件 +interface SuggestionCardProps { + title: string; + suggestions: string[]; + color: 'blue' | 'green' | 'purple' | 'orange'; +} + +const SuggestionCard: React.FC = ({ title, suggestions, color }) => { + const colorClasses = { + blue: 'bg-blue-50 border-blue-200', + green: 'bg-green-50 border-green-200', + purple: 'bg-purple-50 border-purple-200', + orange: 'bg-orange-50 border-orange-200', + }; + + const textColorClasses = { + blue: 'text-blue-900', + green: 'text-green-900', + purple: 'text-purple-900', + orange: 'text-orange-900', + }; + + return ( +
+

{title}

+
    + {suggestions.map((suggestion, index) => ( +
  • + + {suggestion} +
  • + ))} +
+
+ ); +}; diff --git a/apps/desktop/src/components/outfit/SimpleAnalysisDisplay.tsx b/apps/desktop/src/components/outfit/SimpleAnalysisDisplay.tsx new file mode 100644 index 0000000..2356af1 --- /dev/null +++ b/apps/desktop/src/components/outfit/SimpleAnalysisDisplay.tsx @@ -0,0 +1,228 @@ +import React from 'react'; +import { Palette, MapPin, Shirt, Eye } from 'lucide-react'; + +// 分析结果类型定义 +interface ColorPattern { + hue: number; + saturation: number; + value: number; +} + +interface Product { + category: string; + description: string; + color_pattern: ColorPattern; + design_styles: string[]; + color_pattern_match_dress: number; + color_pattern_match_environment: number; +} + +interface AnalysisResult { + environment_tags: string[]; + environment_color_pattern: ColorPattern; + dress_color_pattern: ColorPattern; + style_description: string; + products: Product[]; +} + +interface SimpleAnalysisDisplayProps { + analysisResult: AnalysisResult; +} + +/** + * 简洁的分析结果展示组件 + * 美观地展示AI图像分析结果 + */ +export const SimpleAnalysisDisplay: React.FC = ({ + analysisResult +}) => { + // HSV转十六进制颜色 + const hsvToHex = (color: ColorPattern): string => { + const { hue, saturation, value } = color; + + const c = value * saturation; + const x = c * (1 - Math.abs(((hue * 6) % 2) - 1)); + const m = value - c; + + let r = 0, g = 0, b = 0; + + if (hue >= 0 && hue < 1/6) { + r = c; g = x; b = 0; + } else if (hue >= 1/6 && hue < 2/6) { + r = x; g = c; b = 0; + } else if (hue >= 2/6 && hue < 3/6) { + r = 0; g = c; b = x; + } else if (hue >= 3/6 && hue < 4/6) { + r = 0; g = x; b = c; + } else if (hue >= 4/6 && hue < 5/6) { + r = x; g = 0; b = c; + } else { + r = c; g = 0; b = x; + } + + const red = Math.round((r + m) * 255); + const green = Math.round((g + m) * 255); + const blue = Math.round((b + m) * 255); + + return `#${red.toString(16).padStart(2, '0')}${green.toString(16).padStart(2, '0')}${blue.toString(16).padStart(2, '0')}`; + }; + + // 格式化百分比 + const formatPercentage = (value: number) => `${Math.round(value * 100)}%`; + + // 获取类别图标 + const getCategoryIcon = (category: string) => { + switch (category) { + case '上装': return '👕'; + case '下装': return '👖'; + case '鞋子': return '👟'; + case '配饰': return '💍'; + default: return '👔'; + } + }; + + return ( +
+ {/* 标题 */} +
+

+ 🎨 AI 服装分析结果 +

+

智能图像分析与风格解读

+
+ + {/* 整体风格描述 */} +
+
+ +

整体风格

+
+

{analysisResult.style_description}

+
+ + {/* 环境与色彩分析 */} +
+ {/* 环境标签 */} +
+
+ +

拍摄环境

+
+
+ {analysisResult.environment_tags.map((tag, index) => ( + + {tag} + + ))} +
+
+ + {/* 色彩分析 */} +
+
+ +

主色调

+
+
+
+
+
+

服装主色

+

{hsvToHex(analysisResult.dress_color_pattern)}

+
+
+
+
+
+

环境主色

+

{hsvToHex(analysisResult.environment_color_pattern)}

+
+
+
+
+
+ + {/* 服装单品分析 */} +
+
+ +

服装单品分析

+
+ +
+ {analysisResult.products.map((product, index) => ( +
+ {/* 单品标题 */} +
+ {getCategoryIcon(product.category)} +
+

{product.category}

+
+
+
+ + {/* 描述 */} +

{product.description}

+ + {/* 风格标签 */} +
+

设计风格

+
+ {product.design_styles.map((style, styleIndex) => ( + + {style} + + ))} +
+
+ + {/* 匹配度 */} +
+
+ 与整体搭配匹配度 + + {formatPercentage(product.color_pattern_match_dress)} + +
+
+
+
+ +
+ 与环境匹配度 + + {formatPercentage(product.color_pattern_match_environment)} + +
+
+
+
+
+
+ ))} +
+
+
+ ); +}; diff --git a/apps/desktop/src/data/tools.ts b/apps/desktop/src/data/tools.ts index 68df9e1..4a0f81a 100644 --- a/apps/desktop/src/data/tools.ts +++ b/apps/desktop/src/data/tools.ts @@ -10,7 +10,8 @@ import { ImageIcon, Search, Sparkles, - Filter + Filter, + BarChart3 } from 'lucide-react'; import { Tool, ToolCategory, ToolStatus } from '../types/tool'; @@ -163,6 +164,21 @@ export const TOOLS_DATA: Tool[] = [ isPopular: true, version: '1.0.0', lastUpdated: '2024-01-26' + }, + { + id: 'enriched-analysis-demo', + name: '🎨 丰富图像分析演示', + description: '展示智能服装分析的详细结果,包含颜色分析、风格分析、产品分析等丰富信息', + longDescription: '专业的图像分析结果展示工具,提供极其详细和丰富的分析信息。包含颜色和谐度分析、色彩温度匹配、风格一致性评估、产品匹配度统计、环境适配性分析、拍摄质量评估、个性化搭配建议等功能。支持可展开的分析报告、统计图表、建议卡片和完整的分析摘要。', + icon: BarChart3, + route: '/tools/enriched-analysis-demo', + category: ToolCategory.AI_TOOLS, + status: ToolStatus.BETA, + tags: ['图像分析', '详细报告', '颜色分析', '风格分析', '搭配建议', '统计图表'], + isNew: true, + isPopular: true, + version: '1.0.0', + lastUpdated: '2024-01-26' } ]; diff --git a/apps/desktop/src/pages/tools/EnrichedAnalysisDemo.tsx b/apps/desktop/src/pages/tools/EnrichedAnalysisDemo.tsx new file mode 100644 index 0000000..7357062 --- /dev/null +++ b/apps/desktop/src/pages/tools/EnrichedAnalysisDemo.tsx @@ -0,0 +1,251 @@ +import React, { useState } from 'react'; +import { invoke } from '@tauri-apps/api/core'; +import { open } from '@tauri-apps/plugin-dialog'; +import { convertFileSrc } from '@tauri-apps/api/core'; +import { SimpleAnalysisDisplay } from '../../components/outfit/SimpleAnalysisDisplay'; +import { Upload, Loader2, AlertCircle, Image } from 'lucide-react'; +import { AnalyzeImageResponse } from '../../types/outfitSearch'; + +/** + * 丰富分析结果演示页面 + * 展示如何使用丰富的图像分析功能 + */ +export const EnrichedAnalysisDemo: React.FC = () => { + const [selectedImagePath, setSelectedImagePath] = useState(null); + const [isAnalyzing, setIsAnalyzing] = useState(false); + const [analysisResult, setAnalysisResult] = useState(null); + const [error, setError] = useState(null); + + // 选择图片文件 + const handleSelectImage = async () => { + try { + const selected = await open({ + multiple: false, + filters: [ + { + name: '图片文件', + extensions: ['jpg', 'jpeg', 'png', 'webp', 'bmp'] + } + ] + }); + + if (selected && typeof selected === 'string') { + setSelectedImagePath(selected); + setError(null); + setAnalysisResult(null); + } + } catch (err) { + console.error('选择图片失败:', err); + setError('选择图片失败: ' + (err as Error).message); + } + }; + + // 分析图片 + const handleAnalyze = async () => { + if (!selectedImagePath) { + setError('请先选择一张图片'); + return; + } + + setIsAnalyzing(true); + setError(null); + + try { + console.log('开始分析图片:', selectedImagePath); + + // 1. 首先调用图片分析API + const imageName = selectedImagePath.split(/[/\\]/).pop() || 'unknown.jpg'; + const analysisResponse: AnalyzeImageResponse = await invoke('analyze_outfit_image', { + request: { + image_path: selectedImagePath, + image_name: imageName + } + }); + + console.log('图片分析完成:', analysisResponse); + setAnalysisResult(analysisResponse.result); + + } catch (err) { + console.error('分析失败:', err); + setError('分析失败: ' + (err as Error).message); + } finally { + setIsAnalyzing(false); + } + }; + + // 清除结果 + const handleClearResults = () => { + setSelectedImagePath(null); + setAnalysisResult(null); + setError(null); + }; + + return ( +
+
+ {/* 页面标题 */} +
+

+ 🎨 AI 服装分析演示 +

+

+ 使用真实的AI引擎分析服装搭配图片,获得详细的风格解读和色彩分析 +

+
+ + {/* 操作区域 */} +
+
+ {/* 图片选择 */} +
+

选择图片

+
+ + + {selectedImagePath && ( +
+

已选择文件:

+

{selectedImagePath}

+
+ )} + + {selectedImagePath && ( +
+ Selected { + console.log('图片预览加载失败:', selectedImagePath); + setError('图片预览加载失败,请重新选择图片'); + }} + /> +
+ )} +
+
+ + {/* 操作按钮 */} +
+

分析操作

+
+ + + {(selectedImagePath || analysisResult) && ( + + )} + + {analysisResult && !isAnalyzing && ( +
+

✅ 分析完成

+

+ 图片分析已完成,请查看下方的详细分析结果 +

+
+ )} + +
+

💡 功能说明

+
    +
  • • 使用真实的AI图像分析引擎
  • +
  • • 详细的颜色分析和色彩和谐度评估
  • +
  • • 风格一致性和复杂度分析
  • +
  • • 产品匹配度统计和建议
  • +
  • • 环境适配性和拍摄质量评估
  • +
  • • 个性化搭配建议和场合推荐
  • +
+
+
+
+
+ + {/* 错误提示 */} + {error && ( +
+
+ + 分析失败 +
+

{error}

+
+ )} +
+ + {/* 分析结果展示 */} + {analysisResult && ( + + )} + + {/* 使用说明 */} + {!analysisResult && ( +
+

📖 使用说明

+
+
+

操作步骤

+
    +
  1. 1. 点击"选择图片文件"按钮
  2. +
  3. 2. 选择一张服装搭配图片
  4. +
  5. 3. 点击"分析图片"开始AI分析
  6. +
  7. 4. 等待分析完成,查看丰富的分析报告
  8. +
  9. 5. 展开各个分析区域查看详细信息
  10. +
+
+
+

分析内容

+
    +
  • • 真实AI引擎驱动的图像分析
  • +
  • • 服装颜色和环境色彩分析
  • +
  • • 色彩和谐度和温度匹配
  • +
  • • 风格标签识别和一致性评估
  • +
  • • 产品类别统计和匹配度分析
  • +
  • • 环境类型和拍摄质量评估
  • +
+
+
+ +
+

⚠️ 注意事项

+
    +
  • • 请选择清晰的服装搭配图片以获得最佳分析效果
  • +
  • • 支持的格式:JPG、PNG、WebP、BMP
  • +
  • • 分析过程可能需要几秒钟时间,请耐心等待
  • +
  • • 分析结果基于AI模型,仅供参考
  • +
+
+
+ )} +
+
+ ); +};