feat: 实现AI穿搭方案智能分组功能

- 修改提示词让AI直接返回分组结构
- 添加GroupingStrategy和OutfitQualityScore数据结构
- 支持按风格、场合、季节等维度智能分组
- 为每个方案添加质量评分系统
- 前端支持分组展示和获取更多同类方案
- 保持向后兼容性

主要变更:
- 后端: 更新提示词和解析逻辑支持分组JSON结构
- 前端: OutfitRecommendationList支持分组显示
- 类型: 新增分组相关TypeScript接口
- 功能: 每个分组支持'获取更多'按钮扩展方案
This commit is contained in:
imeepos
2025-07-28 11:26:13 +08:00
parent 9a764d60dc
commit d33f7fbc7f
5 changed files with 526 additions and 78 deletions

View File

@@ -10,7 +10,14 @@ import {
Info
} from 'lucide-react';
import OutfitRecommendationService from '../../services/outfitRecommendationService';
import { OutfitRecommendation, STYLE_OPTIONS, OCCASION_OPTIONS, SEASON_OPTIONS } from '../../types/outfitRecommendation';
import {
OutfitRecommendation,
OutfitRecommendationGroup,
GroupingStrategy,
STYLE_OPTIONS,
OCCASION_OPTIONS,
SEASON_OPTIONS
} from '../../types/outfitRecommendation';
import OutfitRecommendationList from '../../components/outfit/OutfitRecommendationList';
import { CustomSelect } from '../../components/CustomSelect';
import { MaterialSearchPanel, MaterialDetailModal } from '../../components/material';
@@ -28,6 +35,9 @@ const OutfitRecommendationTool: React.FC = () => {
const [colorPreferences, setColorPreferences] = useState<string[]>([]);
const [count, setCount] = useState(3);
// 分组相关状态
const [groups, setGroups] = useState<OutfitRecommendationGroup[]>([]);
const [groupingStrategy, setGroupingStrategy] = useState<GroupingStrategy | null>(null);
const [recommendations, setRecommendations] = useState<OutfitRecommendation[]>([]);
const [isGenerating, setIsGenerating] = useState(false);
const [error, setError] = useState<string | null>(null);
@@ -61,7 +71,18 @@ const OutfitRecommendationTool: React.FC = () => {
count,
});
setRecommendations(response.recommendations);
// 更新分组和方案数据
if (response.groups && response.groups.length > 0) {
setGroups(response.groups);
setGroupingStrategy(response.grouping_strategy);
// 为向后兼容也设置recommendations
setRecommendations(response.recommendations || []);
} else {
// 向后兼容模式
setGroups([]);
setGroupingStrategy(null);
setRecommendations(response.recommendations || []);
}
} catch (err) {
console.error('穿搭方案生成失败:', err);
setError(err instanceof Error ? err.message : '穿搭方案生成失败');
@@ -75,6 +96,65 @@ const OutfitRecommendationTool: React.FC = () => {
handleGenerate();
}, [handleGenerate]);
// 获取更多同类方案
const handleLoadMoreForGroup = useCallback(async (groupId: string, styleKeywords: string[]) => {
try {
console.log(`🎨 获取分组 ${groupId} 的更多方案,关键词:`, styleKeywords);
// 构建增强的查询
const enhancedQuery = `${query} ${styleKeywords.join(' ')}`;
const response = await OutfitRecommendationService.generateRecommendations({
query: enhancedQuery,
target_style: targetStyle || undefined,
occasions: occasions.length > 0 ? occasions : undefined,
season: season || undefined,
color_preferences: colorPreferences.length > 0 ? colorPreferences : undefined,
count: 3, // 每次获取3个新方案
});
// 找到对应的分组并添加新方案
if (response.groups && response.groups.length > 0) {
// 如果返回了分组,合并到现有分组中
setGroups(prevGroups => {
return prevGroups.map(group => {
if (group.group_id === groupId) {
// 找到匹配的新分组并合并方案
const newGroup = response.groups.find(g =>
g.style_keywords.some(keyword =>
styleKeywords.includes(keyword)
)
);
if (newGroup) {
return {
...group,
children: [...group.children, ...newGroup.children]
};
}
}
return group;
});
});
} else if (response.recommendations) {
// 向后兼容:直接添加到对应分组
setGroups(prevGroups => {
return prevGroups.map(group => {
if (group.group_id === groupId) {
return {
...group,
children: [...group.children, ...response.recommendations]
};
}
return group;
});
});
}
} catch (err) {
console.error('获取更多方案失败:', err);
setError(err instanceof Error ? err.message : '获取更多方案失败');
}
}, [query, targetStyle, occasions, season, colorPreferences]);
// 清空表单
const handleClear = useCallback(() => {
setQuery('');
@@ -83,6 +163,8 @@ const OutfitRecommendationTool: React.FC = () => {
setSeason('');
setColorPreferences([]);
setCount(3);
setGroups([]);
setGroupingStrategy(null);
setRecommendations([]);
setError(null);
}, []);
@@ -362,11 +444,14 @@ const OutfitRecommendationTool: React.FC = () => {
{/* 右侧结果区域 */}
<div className="lg:col-span-3">
<OutfitRecommendationList
groups={groups}
groupingStrategy={groupingStrategy || undefined}
recommendations={recommendations}
isLoading={isGenerating}
error={error || undefined}
onRegenerate={handleRegenerate}
onMaterialSearch={handleMaterialSearch}
onLoadMoreForGroup={handleLoadMoreForGroup}
className="min-h-[600px]"
/>
</div>