fix: 移除无用代码
This commit is contained in:
@@ -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<void>;
|
||||
createAnalysis: (request: CreateOutfitAnalysisRequest) => Promise<OutfitAnalysis>;
|
||||
startAnalysis: (analysisId: string) => Promise<void>;
|
||||
deleteAnalysis: (id: string) => Promise<void>;
|
||||
setCurrentAnalysis: (analysis: OutfitAnalysis | null) => void;
|
||||
|
||||
// 单品相关操作
|
||||
fetchItems: (options?: OutfitItemQueryOptions) => Promise<void>;
|
||||
createItem: (request: CreateOutfitItemRequest) => Promise<OutfitItem>;
|
||||
createItemsFromAnalysis: (projectId: string, analysisId: string) => Promise<OutfitItem[]>;
|
||||
updateItem: (id: string, request: any) => Promise<void>;
|
||||
deleteItem: (id: string) => Promise<void>;
|
||||
setCurrentItem: (item: OutfitItem | null) => void;
|
||||
setSelectedItems: (itemIds: string[]) => void;
|
||||
toggleItemSelection: (itemId: string) => void;
|
||||
|
||||
// 搭配相关操作
|
||||
fetchMatchings: (options?: OutfitMatchingQueryOptions) => Promise<void>;
|
||||
createMatching: (request: CreateOutfitMatchingRequest) => Promise<OutfitMatching>;
|
||||
updateMatching: (id: string, request: any) => Promise<void>;
|
||||
deleteMatching: (id: string) => Promise<void>;
|
||||
toggleFavorite: (id: string) => Promise<void>;
|
||||
incrementWearCount: (id: string) => Promise<void>;
|
||||
smartMatching: (request: any) => Promise<any>;
|
||||
setCurrentMatching: (matching: OutfitMatching | null) => void;
|
||||
|
||||
// 搜索和过滤
|
||||
setSearchFilters: (filters: any) => void;
|
||||
clearFilters: () => void;
|
||||
|
||||
// 通用操作
|
||||
clearError: () => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
}
|
||||
|
||||
export const useOutfitStore = create<OutfitStore>((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<OutfitAnalysis[]>('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<OutfitAnalysis>('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<OutfitItem[]>('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<OutfitItem>('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<OutfitItem[]>('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<OutfitMatching[]>('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<OutfitMatching>('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 });
|
||||
},
|
||||
}));
|
||||
@@ -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. 提交前进行代码审查
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目遵循与主项目相同的许可证。
|
||||
Reference in New Issue
Block a user