feat: 新增食物识别API,调整字段名,扩展识别功能与提示逻辑
This commit is contained in:
@@ -44,12 +44,14 @@ export interface FoodConfirmationOption {
|
||||
}
|
||||
|
||||
/**
|
||||
* 食物识别确认结果接口
|
||||
* 食物识别确认结果接口 - 现在总是返回数组结构
|
||||
*/
|
||||
export interface FoodRecognitionResult {
|
||||
recognizedItems: FoodConfirmationOption[];
|
||||
items: FoodConfirmationOption[]; // 修改:统一使用items作为数组字段名
|
||||
analysisText: string;
|
||||
confidence: number;
|
||||
isFoodDetected: boolean; // 是否识别到食物
|
||||
nonFoodMessage?: string; // 非食物提示信息
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,9 +115,11 @@ export class DietAnalysisService {
|
||||
} catch (error) {
|
||||
this.logger.error(`食物识别失败: ${error instanceof Error ? error.message : String(error)}`);
|
||||
return {
|
||||
recognizedItems: [],
|
||||
items: [],
|
||||
analysisText: '食物识别失败,请稍后重试',
|
||||
confidence: 0
|
||||
confidence: 0,
|
||||
isFoodDetected: false,
|
||||
nonFoodMessage: '服务暂时不可用,请稍后重试'
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -369,15 +373,21 @@ export class DietAnalysisService {
|
||||
* @returns 提示文本
|
||||
*/
|
||||
private buildFoodRecognitionPrompt(suggestedMealType: MealType): string {
|
||||
return `作为专业营养分析师,请分析这张食物图片并生成用户确认选项。
|
||||
return `作为专业营养分析师,请分析这张图片并判断是否包含食物。
|
||||
|
||||
当前时间建议餐次:${suggestedMealType}
|
||||
|
||||
请识别图片中的食物,并为每种食物生成确认选项。返回以下格式的JSON:
|
||||
**首先判断图片内容:**
|
||||
- 如果图片中包含食物,请识别并生成确认选项
|
||||
- 如果图片中不包含食物(如风景、人物、物品、文字等),请明确标识
|
||||
|
||||
返回以下格式的JSON:
|
||||
{
|
||||
"confidence": number, // 整体识别置信度 0-100
|
||||
"analysisText": string, // 简短的识别说明文字
|
||||
"recognizedItems": [ // 识别的食物列表
|
||||
"confidence": number, // 整体识别置信度 0-100
|
||||
"analysisText": string, // 简短的识别说明文字
|
||||
"isFoodDetected": boolean, // 是否检测到食物
|
||||
"nonFoodMessage": string, // 当isFoodDetected为false时的提示信息
|
||||
"recognizedItems": [ // 识别的食物列表(如果是食物才有内容)
|
||||
{
|
||||
"id": string, // 唯一标识符
|
||||
"foodName": string, // 食物名称
|
||||
@@ -395,12 +405,26 @@ export class DietAnalysisService {
|
||||
]
|
||||
}
|
||||
|
||||
要求:
|
||||
1. 如果图片中有多种食物,为每种主要食物生成一个选项
|
||||
2. label字段要简洁易懂,格式如"一条鱼 200卡"、"一碗米饭 150卡"
|
||||
3. 营养数据要合理估算
|
||||
4. 如果图片模糊或无法识别,返回空的recognizedItems数组
|
||||
5. 最多生成5个选项,优先选择主要食物`;
|
||||
**识别规则:**
|
||||
1. **非食物情况:**
|
||||
- 如果图片中没有食物,设置 isFoodDetected: false
|
||||
- recognizedItems 返回空数组
|
||||
- nonFoodMessage 提供友好的提示,如"图片中未检测到食物,请上传包含食物的图片"
|
||||
- confidence 设置为对判断的置信度
|
||||
|
||||
2. **食物识别情况:**
|
||||
- 设置 isFoodDetected: true
|
||||
- nonFoodMessage 可以为空或不设置
|
||||
- 如果图片中有多种食物,为每种主要食物生成一个选项
|
||||
- 如果图片中只有一种食物,也要生成一个包含该食物的数组选项
|
||||
- label字段要简洁易懂,格式如"一条鱼 200卡"、"一碗米饭 150卡"
|
||||
- 营养数据要合理估算
|
||||
- 最多生成8个选项,优先选择主要食物
|
||||
- 对于复合菜品(如盖浇饭、汤面等),既可以作为整体记录,也可以分解为主要组成部分
|
||||
|
||||
3. **模糊情况:**
|
||||
- 如果图片模糊但能看出是食物相关,设置 isFoodDetected: true,但返回空的recognizedItems数组
|
||||
- analysisText 说明"图片模糊,无法准确识别食物"`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,15 +527,22 @@ export class DietAnalysisService {
|
||||
} catch (parseError) {
|
||||
this.logger.error(`食物识别JSON解析失败: ${parseError}`);
|
||||
return {
|
||||
recognizedItems: [],
|
||||
items: [],
|
||||
analysisText: '图片分析失败:无法解析识别结果',
|
||||
confidence: 0
|
||||
confidence: 0,
|
||||
isFoodDetected: false,
|
||||
nonFoodMessage: '图片分析失败,请重新上传图片'
|
||||
};
|
||||
}
|
||||
|
||||
// 检查是否识别到食物
|
||||
const isFoodDetected = parsedResult.isFoodDetected !== false; // 默认为true,除非明确设置为false
|
||||
const nonFoodMessage = parsedResult.nonFoodMessage || '';
|
||||
|
||||
const recognizedItems: FoodConfirmationOption[] = [];
|
||||
|
||||
if (parsedResult.recognizedItems && Array.isArray(parsedResult.recognizedItems)) {
|
||||
// 只有在识别到食物时才处理食物项目
|
||||
if (isFoodDetected && parsedResult.recognizedItems && Array.isArray(parsedResult.recognizedItems)) {
|
||||
parsedResult.recognizedItems.forEach((item: any, index: number) => {
|
||||
if (item.foodName && item.calories) {
|
||||
recognizedItems.push({
|
||||
@@ -532,10 +563,22 @@ export class DietAnalysisService {
|
||||
});
|
||||
}
|
||||
|
||||
// 根据是否识别到食物设置不同的分析文本
|
||||
let analysisText = parsedResult.analysisText || '';
|
||||
if (!isFoodDetected) {
|
||||
analysisText = analysisText || '图片中未检测到食物';
|
||||
} else if (recognizedItems.length === 0) {
|
||||
analysisText = analysisText || '图片模糊,无法准确识别食物';
|
||||
} else {
|
||||
analysisText = analysisText || '已识别图片中的食物';
|
||||
}
|
||||
|
||||
return {
|
||||
recognizedItems,
|
||||
analysisText: parsedResult.analysisText || '已识别图片中的食物',
|
||||
confidence: Math.min(100, Math.max(0, parsedResult.confidence || 0))
|
||||
items: recognizedItems,
|
||||
analysisText,
|
||||
confidence: Math.min(100, Math.max(0, parsedResult.confidence || 0)),
|
||||
isFoodDetected,
|
||||
nonFoodMessage: !isFoodDetected ? (nonFoodMessage || '图片中未检测到食物,请上传包含食物的图片') : undefined
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user