# 服装搭配智能搜索系统设计文档

## 概述

基于promptx/outfit-match的Python实现，设计一个集成到Tauri桌面应用的服装搭配智能搜索系统。该系统的核心功能是：用户上传服装图片 → AI分析提取特征 → 在数据库中搜索相似商品 → 提供LLM驱动的情景搭配建议。

## 核心功能流程

### 1. 图像分析流程
```
用户上传图片 → Gemini API分析 → 提取颜色/风格/类别 → 生成搜索条件 → 显示解析结果
```

### 2. 智能搜索流程  
```
解析结果 → 构建搜索过滤器 → Vertex AI Search → 返回相似商品 → 分页展示结果
```

### 3. LLM问答流程
```
用户输入情景 → RAG检索相关数据 → LLM生成搭配建议 → 展示推荐结果
```

## 系统架构设计

### 前端架构 (React + TypeScript)
```
src/pages/OutfitSearch.tsx           # 主搜索页面
src/components/outfit/
├── ImageUploader.tsx               # 图片上传组件
├── AnalysisResult.tsx              # AI分析结果展示
├── SearchPanel.tsx                 # 搜索配置面板
├── SearchResults.tsx               # 搜索结果展示
├── ColorPicker.tsx                 # 颜色选择器
├── FilterPanel.tsx                 # 筛选条件面板
└── LLMChat.tsx                     # LLM问答组件
```

### 后端架构 (Rust)
```
src/data/models/
├── outfit_search.rs                # 搜索相关数据模型
└── gemini_analysis.rs              # Gemini分析结果模型

src/business/services/
├── gemini_service.rs               # Gemini API集成服务
├── outfit_search_service.rs        # 搜索引擎服务
└── vertex_ai_service.rs            # Vertex AI Search集成

src/presentation/commands/
└── outfit_search_commands.rs       # Tauri命令接口
```

## 核心数据模型

### Gemini分析结果模型
```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutfitAnalysisResult {
    pub environment_tags: Vec<String>,
    pub environment_color_pattern: ColorHSV,
    pub dress_color_pattern: ColorHSV,
    pub style_description: String,
    pub products: Vec<ProductAnalysis>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProductAnalysis {
    pub category: String,
    pub description: String,
    pub color_pattern: ColorHSV,
    pub design_styles: Vec<String>,
    pub color_pattern_match_dress: f64,
    pub color_pattern_match_environment: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColorHSV {
    pub hue: f64,        // 色相 (0-1)
    pub saturation: f64, // 饱和度 (0-1)
    pub value: f64,      // 明度 (0-1)
}
```

### 搜索配置模型
```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchConfig {
    pub relevance_threshold: RelevanceThreshold,
    pub environments: Vec<String>,
    pub categories: Vec<String>,
    pub color_filters: HashMap<String, ColorFilter>,
    pub design_styles: HashMap<String, Vec<String>>,
    pub max_keywords: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColorFilter {
    pub enabled: bool,
    pub color: ColorHSV,
    pub hue_threshold: f64,
    pub saturation_threshold: f64,
    pub value_threshold: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RelevanceThreshold {
    LOWEST,
    LOW,
    MEDIUM,
    HIGH,
}
```

### 搜索结果模型
```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchResponse {
    pub results: Vec<SearchResult>,
    pub total_size: usize,
    pub next_page_token: Option<String>,
    pub search_time_ms: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchResult {
    pub id: String,
    pub image_url: String,
    pub style_description: String,
    pub environment_tags: Vec<String>,
    pub products: Vec<ProductInfo>,
    pub relevance_score: f64,
}
```

## API接口设计

### Tauri命令接口
```rust
// 图像分析
#[tauri::command]
pub async fn analyze_outfit_image(
    state: State<'_, AppState>,
    image_path: String,
) -> Result<OutfitAnalysisResult, String>;

// 智能搜索
#[tauri::command]
pub async fn search_similar_outfits(
    state: State<'_, AppState>,
    config: SearchConfig,
) -> Result<SearchResponse, String>;

// LLM问答
#[tauri::command]
pub async fn ask_llm_outfit_advice(
    state: State<'_, AppState>,
    user_input: String,
) -> Result<String, String>;

// 获取搜索建议
#[tauri::command]
pub async fn get_search_suggestions(
    state: State<'_, AppState>,
    query: String,
) -> Result<Vec<String>, String>;
```

## 核心算法实现

### HSV颜色匹配算法
```rust
impl ColorHSV {
    pub fn from_rgb_hex(hex: &str) -> Result<Self> {
        // RGB转HSV实现
    }
    
    pub fn to_rgb_hex(&self) -> String {
        // HSV转RGB实现
    }
    
    pub fn is_in_range(&self, other: &ColorHSV, thresholds: &ColorThresholds) -> bool {
        let hue_diff = (self.hue - other.hue).abs();
        let sat_diff = (self.saturation - other.saturation).abs();
        let val_diff = (self.value - other.value).abs();
        
        hue_diff <= thresholds.hue &&
        sat_diff <= thresholds.saturation &&
        val_diff <= thresholds.value
    }
}
```

### 搜索过滤器构建
```rust
impl SearchFilterBuilder {
    pub fn build_filters(config: &SearchConfig) -> String {
        let mut filters = Vec::new();
        
        // 类别过滤
        if !config.categories.is_empty() {
            for category in &config.categories {
                let mut inner_filters = vec![
                    format!("products.category: ANY(\"{}\")", category)
                ];
                
                // 颜色过滤
                if let Some(color_filter) = config.color_filters.get(category) {
                    if color_filter.enabled {
                        inner_filters.extend(Self::build_color_filters(color_filter));
                    }
                }
                
                // 设计风格过滤
                if let Some(styles) = config.design_styles.get(category) {
                    if !styles.is_empty() {
                        let styles_str = styles.iter()
                            .map(|s| format!("\"{}\"", s))
                            .collect::<Vec<_>>()
                            .join(",");
                        inner_filters.push(format!("products.design_styles: ANY({})", styles_str));
                    }
                }
                
                filters.push(format!("({})", inner_filters.join(" AND ")));
            }
        }
        
        // 环境标签过滤
        if !config.environments.is_empty() {
            let env_str = config.environments.iter()
                .map(|e| format!("\"{}\"", e))
                .collect::<Vec<_>>()
                .join(",");
            filters.push(format!("environment_tags: ANY({})", env_str));
        }
        
        filters.join(" AND ")
    }
}
```

## 用户界面设计

### 主搜索页面布局
```typescript
export const OutfitSearch: React.FC = () => {
  return (
    <div className="outfit-search-container">
      <div className="search-panel">
        <ImageUploader onAnalysisComplete={handleAnalysis} />
        <SearchPanel config={searchConfig} onConfigChange={updateConfig} />
        <LLMChat onAskLLM={handleLLMQuery} />
      </div>
      
      <div className="results-panel">
        <SearchResults 
          results={searchResults} 
          onPageChange={handlePageChange}
        />
      </div>
    </div>
  );
};
```

### 搜索配置面板
```typescript
export const SearchPanel: React.FC<SearchPanelProps> = ({ config, onConfigChange }) => {
  return (
    <div className="search-config">
      <div className="relevance-threshold">
        <label>匹配严格程度</label>
        <select value={config.relevance_threshold} onChange={handleThresholdChange}>
          <option value="LOWEST">最低</option>
          <option value="LOW">低</option>
          <option value="MEDIUM">中等</option>
          <option value="HIGH">高</option>
        </select>
      </div>
      
      <div className="category-filters">
        {config.categories.map(category => (
          <CategoryFilter 
            key={category}
            category={category}
            colorFilter={config.color_filters[category]}
            designStyles={config.design_styles[category]}
            onFilterChange={handleFilterChange}
          />
        ))}
      </div>
      
      <button onClick={handleSearch}>搜索</button>
    </div>
  );
};
```

## 集成方案

### 与现有系统集成
1. **导航系统集成**: 搜索功能作为顶部导航栏的独立页面，类似现有的"模特管理"、"AI分类设置"等
2. **AI分类系统复用**: 复用现有的Gemini API集成和提示词生成逻辑
3. **配置管理**: project_id等配置作为全局环境变量或应用配置，不依赖具体项目
4. **状态管理**: 使用现有的Zustand状态管理模式

### 配置管理
```rust
// 全局配置结构
#[derive(Debug, Clone)]
pub struct OutfitSearchConfig {
    pub google_project_id: String,        // "gen-lang-client-0413414134"
    pub vertex_ai_app_id: String,         // "jeans-search_1751353769585"
    pub storage_bucket_name: String,      // "fashion_image_block"
    pub data_store_id: String,            // "jeans_pattern_data_store"
    pub cloudflare_project_id: String,    // "67720b647ff2b55cf37ba3ef9e677083"
    pub cloudflare_gateway_id: String,    // "bowong-dev"
}

impl Default for OutfitSearchConfig {
    fn default() -> Self {
        Self {
            google_project_id: "gen-lang-client-0413414134".to_string(),
            vertex_ai_app_id: "jeans-search_1751353769585".to_string(),
            storage_bucket_name: "fashion_image_block".to_string(),
            data_store_id: "jeans_pattern_data_store".to_string(),
            cloudflare_project_id: "67720b647ff2b55cf37ba3ef9e677083".to_string(),
            cloudflare_gateway_id: "bowong-dev".to_string(),
        }
    }
}
```

### 部署配置
1. **环境变量**: 配置Google Cloud访问令牌、Cloudflare网关等
2. **依赖管理**: 添加必要的Rust crates和npm包
3. **构建配置**: 更新Tauri配置以支持网络访问权限

## 开发优先级

### P0 (核心功能)
- [ ] Gemini API集成和图像分析
- [ ] 基础搜索界面和结果展示
- [ ] HSV颜色匹配算法

### P1 (完整功能)
- [ ] Vertex AI Search集成
- [ ] 高级搜索过滤器
- [ ] LLM问答功能

### P2 (优化功能)
- [ ] 搜索历史和偏好
- [ ] 性能优化和缓存
- [ ] 用户体验改进
