From 75946c7c1e33139e2f37800515c445f00d411af6 Mon Sep 17 00:00:00 2001 From: imeepos Date: Thu, 17 Jul 2025 21:15:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/desktop/src/stores/outfitStore.ts | 471 ------------------------- docs/outfit-matching-feature.md | 289 --------------- 2 files changed, 760 deletions(-) delete mode 100644 apps/desktop/src/stores/outfitStore.ts delete mode 100644 docs/outfit-matching-feature.md diff --git a/apps/desktop/src/stores/outfitStore.ts b/apps/desktop/src/stores/outfitStore.ts deleted file mode 100644 index 6b65b10..0000000 --- a/apps/desktop/src/stores/outfitStore.ts +++ /dev/null @@ -1,471 +0,0 @@ -import { create } from 'zustand'; -import { invoke } from '@tauri-apps/api/core'; - -// 基础数据类型 -interface ColorHSV { - hue: number; - saturation: number; - value: number; -} - -interface OutfitAnalysis { - id: string; - project_id: string; - image_path: string; - image_name: string; - analysis_status: 'Pending' | 'Processing' | 'Completed' | 'Failed'; - analysis_result?: { - environment_tags: string[]; - environment_color_pattern: ColorHSV; - dress_color_pattern: ColorHSV; - style_description: string; - products: Array<{ - category: string; - description: string; - color_pattern: ColorHSV; - design_styles: string[]; - color_pattern_match_dress: number; - color_pattern_match_environment: number; - }>; - }; - error_message?: string; - created_at: string; - updated_at: string; - analyzed_at?: string; -} - -interface OutfitItem { - id: string; - project_id: string; - analysis_id?: string; - name: string; - category: string; - brand?: string; - color_primary: ColorHSV; - styles: string[]; - image_urls: string[]; - tags: string[]; - notes?: string; - created_at: string; - updated_at: string; -} - -interface OutfitMatching { - id: string; - project_id: string; - matching_name: string; - matching_type: string; - items: Array<{ - item_id: string; - item_name: string; - category: string; - color_primary: ColorHSV; - styles: string[]; - role_in_outfit: string; - image_url?: string; - }>; - score_details: { - color_harmony_score: number; - style_consistency_score: number; - proportion_score: number; - occasion_appropriateness: number; - trend_factor: number; - overall_score: number; - }; - suggestions: Array<{ - suggestion_type: string; - description: string; - priority: number; - }>; - occasion_tags: string[]; - season_tags: string[]; - style_description: string; - color_palette: ColorHSV[]; - is_favorite: boolean; - wear_count: number; - last_worn_date?: string; - created_at: string; - updated_at: string; -} - -// 查询参数接口 -interface OutfitAnalysisQueryOptions { - project_id?: string; - status?: string; - limit?: number; - offset?: number; -} - -interface OutfitItemQueryOptions { - project_id?: string; - category?: string; - styles?: string[]; - brand?: string; - tags?: string[]; - limit?: number; - offset?: number; -} - -interface OutfitMatchingQueryOptions { - project_id?: string; - filters?: any; - sort_by?: string; - sort_order?: string; - limit?: number; - offset?: number; -} - -// 创建请求接口 -interface CreateOutfitAnalysisRequest { - project_id: string; - image_path: string; - image_name: string; -} - -interface CreateOutfitItemRequest { - project_id: string; - analysis_id?: string; - name: string; - category: string; - brand?: string; - color_primary: ColorHSV; - styles: string[]; - image_urls: string[]; - tags: string[]; - notes?: string; -} - -interface CreateOutfitMatchingRequest { - project_id: string; - matching_name: string; - matching_type: string; - item_ids: string[]; - occasion_tags: string[]; - season_tags: string[]; - style_description?: string; -} - -// Store 接口 -interface OutfitStore { - // 状态 - analyses: OutfitAnalysis[]; - items: OutfitItem[]; - matchings: OutfitMatching[]; - currentAnalysis: OutfitAnalysis | null; - currentItem: OutfitItem | null; - currentMatching: OutfitMatching | null; - selectedItems: string[]; - searchFilters: any; - isLoading: boolean; - error: string | null; - - // 分析相关操作 - fetchAnalyses: (options?: OutfitAnalysisQueryOptions) => Promise; - createAnalysis: (request: CreateOutfitAnalysisRequest) => Promise; - startAnalysis: (analysisId: string) => Promise; - deleteAnalysis: (id: string) => Promise; - setCurrentAnalysis: (analysis: OutfitAnalysis | null) => void; - - // 单品相关操作 - fetchItems: (options?: OutfitItemQueryOptions) => Promise; - createItem: (request: CreateOutfitItemRequest) => Promise; - createItemsFromAnalysis: (projectId: string, analysisId: string) => Promise; - updateItem: (id: string, request: any) => Promise; - deleteItem: (id: string) => Promise; - setCurrentItem: (item: OutfitItem | null) => void; - setSelectedItems: (itemIds: string[]) => void; - toggleItemSelection: (itemId: string) => void; - - // 搭配相关操作 - fetchMatchings: (options?: OutfitMatchingQueryOptions) => Promise; - createMatching: (request: CreateOutfitMatchingRequest) => Promise; - updateMatching: (id: string, request: any) => Promise; - deleteMatching: (id: string) => Promise; - toggleFavorite: (id: string) => Promise; - incrementWearCount: (id: string) => Promise; - smartMatching: (request: any) => Promise; - setCurrentMatching: (matching: OutfitMatching | null) => void; - - // 搜索和过滤 - setSearchFilters: (filters: any) => void; - clearFilters: () => void; - - // 通用操作 - clearError: () => void; - setLoading: (loading: boolean) => void; -} - -export const useOutfitStore = create((set, get) => ({ - // 初始状态 - analyses: [], - items: [], - matchings: [], - currentAnalysis: null, - currentItem: null, - currentMatching: null, - selectedItems: [], - searchFilters: {}, - isLoading: false, - error: null, - - // 分析相关操作 - fetchAnalyses: async (options = {}) => { - set({ isLoading: true, error: null }); - try { - const analyses = await invoke('list_outfit_analyses', { options }); - set({ analyses, isLoading: false }); - } catch (error) { - set({ error: String(error), isLoading: false }); - } - }, - - createAnalysis: async (request) => { - set({ isLoading: true, error: null }); - try { - const analysis = await invoke('create_outfit_analysis', { request }); - set(state => ({ - analyses: [analysis, ...state.analyses], - isLoading: false - })); - return analysis; - } catch (error) { - set({ error: String(error), isLoading: false }); - throw error; - } - }, - - startAnalysis: async (analysisId) => { - try { - await invoke('start_outfit_analysis', { analysisId }); - // 更新分析状态为处理中 - set(state => ({ - analyses: state.analyses.map(a => - a.id === analysisId - ? { ...a, analysis_status: 'Processing' as const } - : a - ) - })); - } catch (error) { - set({ error: String(error) }); - throw error; - } - }, - - deleteAnalysis: async (id) => { - try { - await invoke('delete_outfit_analysis', { id }); - set(state => ({ - analyses: state.analyses.filter(a => a.id !== id) - })); - } catch (error) { - set({ error: String(error) }); - throw error; - } - }, - - setCurrentAnalysis: (analysis) => { - set({ currentAnalysis: analysis }); - }, - - // 单品相关操作 - fetchItems: async (options = {}) => { - set({ isLoading: true, error: null }); - try { - const items = await invoke('list_outfit_items', { options }); - set({ items, isLoading: false }); - } catch (error) { - set({ error: String(error), isLoading: false }); - } - }, - - createItem: async (request) => { - set({ isLoading: true, error: null }); - try { - const item = await invoke('create_outfit_item', { request }); - set(state => ({ - items: [item, ...state.items], - isLoading: false - })); - return item; - } catch (error) { - set({ error: String(error), isLoading: false }); - throw error; - } - }, - - createItemsFromAnalysis: async (projectId, analysisId) => { - set({ isLoading: true, error: null }); - try { - const items = await invoke('create_outfit_items_from_analysis', { - projectId, - analysisId - }); - set(state => ({ - items: [...items, ...state.items], - isLoading: false - })); - return items; - } catch (error) { - set({ error: String(error), isLoading: false }); - throw error; - } - }, - - updateItem: async (id, request) => { - try { - await invoke('update_outfit_item', { id, request }); - // 重新获取单品列表 - const { fetchItems } = get(); - await fetchItems(); - } catch (error) { - set({ error: String(error) }); - throw error; - } - }, - - deleteItem: async (id) => { - try { - await invoke('delete_outfit_item', { id }); - set(state => ({ - items: state.items.filter(i => i.id !== id), - selectedItems: state.selectedItems.filter(itemId => itemId !== id) - })); - } catch (error) { - set({ error: String(error) }); - throw error; - } - }, - - setCurrentItem: (item) => { - set({ currentItem: item }); - }, - - setSelectedItems: (itemIds) => { - set({ selectedItems: itemIds }); - }, - - toggleItemSelection: (itemId) => { - set(state => ({ - selectedItems: state.selectedItems.includes(itemId) - ? state.selectedItems.filter(id => id !== itemId) - : [...state.selectedItems, itemId] - })); - }, - - // 搭配相关操作 - fetchMatchings: async (options = {}) => { - set({ isLoading: true, error: null }); - try { - const matchings = await invoke('list_outfit_matchings', { options }); - set({ matchings, isLoading: false }); - } catch (error) { - set({ error: String(error), isLoading: false }); - } - }, - - createMatching: async (request) => { - set({ isLoading: true, error: null }); - try { - const matching = await invoke('create_outfit_matching', { request }); - set(state => ({ - matchings: [matching, ...state.matchings], - isLoading: false, - selectedItems: [] // 清空选择 - })); - return matching; - } catch (error) { - set({ error: String(error), isLoading: false }); - throw error; - } - }, - - updateMatching: async (id, request) => { - try { - await invoke('update_outfit_matching', { id, request }); - // 重新获取搭配列表 - const { fetchMatchings } = get(); - await fetchMatchings(); - } catch (error) { - set({ error: String(error) }); - throw error; - } - }, - - deleteMatching: async (id) => { - try { - await invoke('delete_outfit_matching', { id }); - set(state => ({ - matchings: state.matchings.filter(m => m.id !== id) - })); - } catch (error) { - set({ error: String(error) }); - throw error; - } - }, - - toggleFavorite: async (id) => { - try { - const matching = get().matchings.find(m => m.id === id); - if (matching) { - await invoke('update_outfit_matching', { - id, - request: { is_favorite: !matching.is_favorite } - }); - set(state => ({ - matchings: state.matchings.map(m => - m.id === id ? { ...m, is_favorite: !m.is_favorite } : m - ) - })); - } - } catch (error) { - set({ error: String(error) }); - throw error; - } - }, - - incrementWearCount: async (id) => { - try { - await invoke('increment_outfit_matching_wear_count', { id }); - // 重新获取搭配列表 - const { fetchMatchings } = get(); - await fetchMatchings(); - } catch (error) { - set({ error: String(error) }); - throw error; - } - }, - - smartMatching: async (request) => { - set({ isLoading: true, error: null }); - try { - const result = await invoke('smart_outfit_matching', { request }); - set({ isLoading: false }); - return result; - } catch (error) { - set({ error: String(error), isLoading: false }); - throw error; - } - }, - - setCurrentMatching: (matching) => { - set({ currentMatching: matching }); - }, - - // 搜索和过滤 - setSearchFilters: (filters) => { - set({ searchFilters: filters }); - }, - - clearFilters: () => { - set({ searchFilters: {} }); - }, - - // 通用操作 - clearError: () => { - set({ error: null }); - }, - - setLoading: (loading) => { - set({ isLoading: loading }); - }, -})); diff --git a/docs/outfit-matching-feature.md b/docs/outfit-matching-feature.md deleted file mode 100644 index a40b650..0000000 --- a/docs/outfit-matching-feature.md +++ /dev/null @@ -1,289 +0,0 @@ -# 服装搭配功能文档 - -## 概述 - -服装搭配功能是一个基于AI的智能服装分析和搭配推荐系统,集成到现有的Tauri桌面应用中。该功能提供图像分析、服装单品管理和智能搭配推荐等核心能力。 - -## 功能特性 - -### 1. 图像分析 -- **AI图像识别**: 使用Google Gemini API分析服装图像 -- **自动分类**: 识别服装类别(上装、下装、连衣裙、外套等) -- **颜色分析**: 提取HSV颜色模型,支持精确的颜色匹配 -- **风格识别**: 识别服装风格(休闲、正式、运动、时尚等) -- **环境分析**: 分析图像环境和场景 - -### 2. 服装单品管理 -- **单品档案**: 创建详细的服装单品信息 -- **属性管理**: 管理颜色、风格、品牌、尺寸等属性 -- **标签系统**: 支持自定义标签分类 -- **图片管理**: 支持多张图片展示 -- **搜索过滤**: 按类别、颜色、风格等条件搜索 - -### 3. 智能搭配推荐 -- **算法匹配**: 基于颜色和谐度、风格一致性等算法 -- **评分系统**: 提供详细的搭配评分和建议 -- **场合推荐**: 根据不同场合推荐合适搭配 -- **季节搭配**: 考虑季节因素的搭配建议 -- **收藏管理**: 支持收藏喜欢的搭配方案 - -## 技术架构 - -### 后端架构 (Rust) - -#### 数据模型层 -``` -src/data/models/ -├── outfit_analysis.rs # 分析记录模型 -├── outfit_item.rs # 服装单品模型 -└── outfit_matching.rs # 搭配匹配模型 -``` - -#### 数据访问层 -``` -src/data/repositories/ -├── outfit_analysis_repository.rs -├── outfit_item_repository.rs -└── outfit_matching_repository.rs -``` - -#### 业务逻辑层 -``` -src/business/services/ -├── outfit_analysis_service.rs -├── outfit_item_service.rs -└── outfit_matching_service.rs -``` - -#### API接口层 -``` -src/presentation/commands/ -└── outfit_commands.rs # Tauri命令接口 -``` - -### 前端架构 (React + TypeScript) - -#### 页面组件 -``` -src/pages/ -└── OutfitMatch.tsx # 主页面组件 -``` - -#### 功能组件 -``` -src/components/outfit/ -├── ImageUploader.tsx # 图像上传组件 -├── OutfitAnalysisResult.tsx # 分析结果展示 -├── OutfitSearchPanel.tsx # 搜索面板 -├── OutfitCard.tsx # 搭配卡片 -└── OutfitItemCard.tsx # 单品卡片 -``` - -#### 状态管理 -``` -src/stores/ -└── outfitStore.ts # Zustand状态管理 -``` - -## 数据库设计 - -### 表结构 - -#### outfit_analyses (分析记录表) -```sql -CREATE TABLE 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 -); -``` - -#### outfit_items (服装单品表) -```sql -CREATE TABLE 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 -); -``` - -#### outfit_matchings (搭配记录表) -```sql -CREATE TABLE 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 -); -``` - -## API接口 - -### Tauri命令接口 - -#### 分析相关 -- `create_outfit_analysis` - 创建分析记录 -- `start_outfit_analysis` - 开始分析 -- `list_outfit_analyses` - 获取分析列表 -- `get_outfit_analysis_by_id` - 获取分析详情 -- `delete_outfit_analysis` - 删除分析记录 - -#### 单品相关 -- `create_outfit_item` - 创建服装单品 -- `create_outfit_items_from_analysis` - 从分析结果创建单品 -- `list_outfit_items` - 获取单品列表 -- `get_outfit_item_by_id` - 获取单品详情 -- `update_outfit_item` - 更新单品信息 -- `delete_outfit_item` - 删除单品 - -#### 搭配相关 -- `create_outfit_matching` - 创建搭配 -- `list_outfit_matchings` - 获取搭配列表 -- `get_outfit_matching_by_id` - 获取搭配详情 -- `update_outfit_matching` - 更新搭配信息 -- `delete_outfit_matching` - 删除搭配 -- `smart_outfit_matching` - 智能搭配推荐 -- `increment_outfit_matching_wear_count` - 增加穿着次数 - -## 算法设计 - -### 颜色匹配算法 -使用HSV颜色空间进行颜色相似度计算: -```rust -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) -} -``` - -### 搭配评分算法 -综合考虑多个维度: -- **颜色和谐度** (权重: 30%): 基于颜色理论的和谐度计算 -- **风格一致性** (权重: 25%): 风格标签的匹配度 -- **比例协调度** (权重: 20%): 服装比例的协调性 -- **场合适宜度** (权重: 15%): 适合特定场合的程度 -- **时尚度** (权重: 10%): 当前流行趋势的符合度 - -## 使用指南 - -### 1. 图像分析流程 -1. 在项目详情页面切换到"服装搭配"标签 -2. 上传服装图像文件 -3. 系统自动进行AI分析 -4. 查看分析结果和识别的服装单品 -5. 可选择创建服装单品档案 - -### 2. 搭配创建流程 -1. 在服装单品页面选择要搭配的单品 -2. 点击"创建搭配"按钮 -3. 系统自动计算搭配评分 -4. 查看搭配建议和优化提示 -5. 保存搭配方案 - -### 3. 智能推荐流程 -1. 点击"智能搭配"按钮 -2. 系统基于现有单品生成推荐搭配 -3. 查看推荐结果和评分 -4. 选择喜欢的搭配保存 - -## 测试 - -### 单元测试 -- 颜色相似度计算测试 -- 搭配评分算法测试 -- 数据模型验证测试 - -### 集成测试 -- 完整分析流程测试 -- 搭配推荐功能测试 -- 数据库操作测试 - -### 运行测试 -```bash -cd apps/desktop/src-tauri -cargo test outfit -``` - -## 部署和配置 - -### 环境要求 -- Rust 1.70+ -- Node.js 18+ -- Google Cloud API密钥 -- SQLite数据库 - -### 配置步骤 -1. 配置Google Cloud API密钥 -2. 设置Gemini服务参数 -3. 初始化数据库表结构 -4. 编译和运行应用 - -## 未来规划 - -### 短期目标 -- [ ] 完善图像上传和分析功能 -- [ ] 实现完整的搭配推荐算法 -- [ ] 添加更多服装类别支持 -- [ ] 优化用户界面和交互 - -### 长期目标 -- [ ] 支持视频分析 -- [ ] 集成更多AI模型 -- [ ] 社交分享功能 -- [ ] 个性化推荐系统 -- [ ] 移动端适配 - -## 贡献指南 - -1. 遵循现有的代码规范和架构模式 -2. 添加适当的单元测试和集成测试 -3. 更新相关文档 -4. 提交前进行代码审查 - -## 许可证 - -本项目遵循与主项目相同的许可证。