356 lines
10 KiB
Markdown
356 lines
10 KiB
Markdown
# 服装搭配智能搜索系统设计文档
|
||
|
||
## 概述
|
||
|
||
基于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 (优化功能)
|
||
- [ ] 搜索历史和偏好
|
||
- [ ] 性能优化和缓存
|
||
- [ ] 用户体验改进
|