import { api, postTextStream, type TextStreamCallbacks } from '@/services/api'; import type { CreateDietRecordDto, MealType } from './dietRecords'; export interface NutritionLabelData { energy: number; // 能量 (kJ/千卡) protein: number; // 蛋白质 (g) fat: number; // 脂肪 (g) carbohydrate: number; // 碳水化合物 (g) sodium: number; // 钠 (mg) fiber?: number; // 膳食纤维 (g) sugar?: number; // 糖 (g) servingSize?: string; // 每份量 } export interface NutritionLabelAnalysisResult { id: string; imageUri: string; nutritionData: NutritionLabelData; confidence: number; analyzedAt: string; foodName?: string; // 识别出的食物名称 brand?: string; // 品牌 } export interface NutritionLabelAnalysisRequest { imageUri: string; } // 新API返回的营养成分项 export interface NutritionItem { key: string; name: string; value: string; analysis: string; } // 新API返回的响应格式 export interface NutritionAnalysisResponse { success: boolean; data: NutritionItem[]; message?: string; // 仅在失败时返回 } // 新API请求参数 export interface NutritionAnalysisRequest { imageUrl: string; } /** * 分析营养成分表(非流式) */ export async function analyzeNutritionLabel(request: NutritionLabelAnalysisRequest): Promise { return api.post('/ai-coach/nutrition-label-analysis', request); } /** * 流式分析营养成分表 */ export async function analyzeNutritionLabelStream( request: NutritionLabelAnalysisRequest, callbacks: TextStreamCallbacks ) { const body = { imageUri: request.imageUri, stream: true }; return postTextStream('/ai-coach/nutrition-label-analysis', body, callbacks, { timeoutMs: 120000 }); } /** * 保存成分表分析结果到饮食记录 */ export async function saveNutritionLabelToDietRecord( analysisResult: NutritionLabelAnalysisResult, mealType: MealType ): Promise { const dietRecordData: CreateDietRecordDto = { mealType, foodName: analysisResult.foodName || '成分表分析食物', foodDescription: `品牌: ${analysisResult.brand || '未知'}`, portionDescription: analysisResult.nutritionData.servingSize || '100g', estimatedCalories: analysisResult.nutritionData.energy, proteinGrams: analysisResult.nutritionData.protein, carbohydrateGrams: analysisResult.nutritionData.carbohydrate, fatGrams: analysisResult.nutritionData.fat, fiberGrams: analysisResult.nutritionData.fiber, sugarGrams: analysisResult.nutritionData.sugar, sodiumMg: analysisResult.nutritionData.sodium, source: 'vision', mealTime: new Date().toISOString(), imageUrl: analysisResult.imageUri, aiAnalysisResult: analysisResult, }; return api.post('/diet-records', dietRecordData); } /** * 分析营养成分表图片(新API) * 需要先上传图片到COS获取URL,然后调用此接口 */ export async function analyzeNutritionImage(request: NutritionAnalysisRequest): Promise { try { const response = await api.post('/diet-records/analyze-nutrition-image', request); // 处理不同的响应格式 if (Array.isArray(response)) { // 如果直接返回数组,包装成标准格式 return { success: true, data: response as NutritionItem[] }; } else if (response && typeof response === 'object') { // 如果是对象,检查是否已经是标准格式 if (response.success !== undefined && response.data) { return response as NutritionAnalysisResponse; } else if (Array.isArray(response.data)) { // 如果有data字段且是数组,包装成标准格式 return { success: true, data: response.data as NutritionItem[] }; } } // 如果都不匹配,返回错误 throw new Error('无法解析API返回结果'); } catch (error) { console.error('[NUTRITION_ANALYSIS] API调用失败:', error); return { success: false, data: [], message: error instanceof Error ? error.message : '分析失败' }; } }