Files
plates-server/docs/diet-confirmation-flow-api.md
richarjiang ede5730647 feat: 实现饮食记录确认流程
- 新增饮食记录确认流程,将自动记录模式升级为用户确认模式,提升用户交互体验。
- 实现两阶段饮食记录流程,支持AI识别食物并生成确认选项,用户选择后记录到数据库并提供营养分析。
- 扩展DTO层,新增相关数据结构以支持确认流程。
- 更新服务层,新增处理确认逻辑的方法,优化饮食记录的创建流程。
- 增强API文档,详细说明新流程及使用建议,确保开发者理解和使用新功能。
2025-08-18 18:59:36 +08:00

6.6 KiB
Raw Blame History

饮食记录确认流程 API 文档

概述

新的饮食记录流程分为两个阶段:

  1. 图片识别阶段AI识别食物并返回确认选项
  2. 用户确认阶段:用户选择确认选项后记录到数据库

重要说明

⚠️ 流式响应兼容性当系统需要返回确认选项时会自动使用非流式模式返回JSON结构即使客户端请求了 stream: true。这确保了确认选项的正确显示。

API 流程

第一阶段:图片识别(返回确认选项)

请求示例:

POST /ai-coach/chat
{
  "conversationId": "user123-1234567890",
  "messages": [
    {
      "role": "user",
      "content": "#记饮食"
    }
  ],
  "imageUrls": ["https://example.com/food-image.jpg"],
  "stream": false
}

响应示例:

{
  "conversationId": "user123-1234567890",
  "data": {
    "content": "我识别到了以下食物,请选择要记录的内容:\n\n图片中识别到烤鱼和米饭看起来是一份营养均衡的晚餐。",
    "choices": [
      {
        "id": "food_0",
        "label": "一条烤鱼 220卡",
        "value": {
          "id": "food_0",
          "foodName": "烤鱼",
          "portion": "1条",
          "calories": 220,
          "mealType": "dinner",
          "nutritionData": {
            "proteinGrams": 35,
            "carbohydrateGrams": 2,
            "fatGrams": 8,
            "fiberGrams": 0
          }
        },
        "recommended": true
      },
      {
        "id": "food_1",
        "label": "一碗米饭 150卡",
        "value": {
          "id": "food_1",
          "foodName": "米饭",
          "portion": "1碗",
          "calories": 150,
          "mealType": "dinner",
          "nutritionData": {
            "proteinGrams": 3,
            "carbohydrateGrams": 32,
            "fatGrams": 0.5,
            "fiberGrams": 1
          }
        },
        "recommended": false
      }
    ],
    "interactionType": "food_confirmation",
    "pendingData": {
      "imageUrl": "https://example.com/food-image.jpg",
      "recognitionResult": {
        "recognizedItems": [...],
        "analysisText": "图片中识别到烤鱼和米饭...",
        "confidence": 85
      }
    },
    "context": {
      "command": "diet",
      "step": "confirmation"
    }
  }
}

第二阶段:用户确认选择

请求示例:

POST /ai-coach/chat
{
  "conversationId": "user123-1234567890",
  "messages": [
    {
      "role": "user",
      "content": "我选择记录烤鱼"
    }
  ],
  "selectedChoiceId": "food_0",
  "confirmationData": {
    "selectedOption": {
      "id": "food_0",
      "foodName": "烤鱼",
      "portion": "1条",
      "calories": 220,
      "mealType": "dinner",
      "nutritionData": {
        "proteinGrams": 35,
        "carbohydrateGrams": 2,
        "fatGrams": 8,
        "fiberGrams": 0
      }
    },
    "imageUrl": "https://example.com/food-image.jpg"
  },
  "stream": false
}

响应示例:

{
  "conversationId": "user123-1234567890",
  "text": "很好我已经为您记录了这份烤鱼1条约220卡路里。\n\n根据您的饮食记录这是一份优质的蛋白质来源包含35克蛋白质脂肪含量适中。建议搭配一些蔬菜来增加膳食纤维的摄入。\n\n您今天的饮食营养搭配看起来不错记得保持均衡的饮食习惯"
}

数据结构说明

AiChoiceOptionDto

{
  id: string;           // 选项唯一标识符
  label: string;        // 显示给用户的文本(如"一条鱼 200卡"
  value: any;          // 选项对应的数据
  recommended?: boolean; // 是否为推荐选项
}

AiResponseDataDto

{
  content: string;                    // AI回复的文本内容
  choices?: AiChoiceOptionDto[];      // 选择选项(可选)
  interactionType?: string;           // 交互类型:'text' | 'food_confirmation' | 'selection'
  pendingData?: any;                  // 需要用户确认的数据(可选)
  context?: any;                      // 上下文信息(可选)
}

FoodConfirmationOption

{
  id: string;                    // 唯一标识符
  label: string;                 // 显示文本
  foodName: string;              // 食物名称
  portion: string;               // 份量描述
  calories: number;              // 估算热量
  mealType: MealType;            // 餐次类型
  nutritionData: {               // 营养数据
    proteinGrams?: number;       // 蛋白质(克)
    carbohydrateGrams?: number;  // 碳水化合物(克)
    fatGrams?: number;           // 脂肪(克)
    fiberGrams?: number;         // 膳食纤维(克)
  };
}

错误处理

图片识别失败

如果图片模糊或无法识别食物API会返回正常的文本响应

{
  "conversationId": "user123-1234567890",
  "text": "抱歉,我无法清晰地识别图片中的食物。请确保图片清晰,光线充足,食物在画面中清晰可见,然后重新上传。"
}

无效的确认数据

如果第二阶段的确认数据无效,系统会返回错误提示:

{
  "conversationId": "user123-1234567890",
  "text": "确认数据无效,请重新选择要记录的食物。"
}

使用建议

  1. 图片质量:确保上传的图片清晰,光线充足,食物在画面中清晰可见
  2. 选择确认:用户可以选择多个食物选项,每次确认记录一种食物
  3. 营养分析:系统会基于用户的历史饮食记录提供个性化的营养分析和建议
  4. 流式响应处理
    • 客户端应该检查响应的 Content-Type
    • application/json:结构化数据(确认选项)
    • text/plain:流式文本
    • 当返回确认选项时,系统会忽略 stream 参数并返回JSON

客户端适配指南

响应类型检测

// 检查响应类型
if (response.headers['content-type'].includes('application/json')) {
  // 处理结构化数据(确认选项)
  const data = await response.json();
  if (data.data && data.data.choices) {
    // 显示选择选项
    showFoodConfirmationOptions(data.data.choices);
  }
} else {
  // 处理流式文本
  handleStreamResponse(response);
}

确认选择发送

// 用户选择后发送确认
const confirmationRequest = {
  conversationId: "user123-1234567890",
  messages: [{ role: "user", content: "我选择记录烤鱼" }],
  selectedChoiceId: "food_0",
  confirmationData: {
    selectedOption: selectedFoodOption,
    imageUrl: originalImageUrl
  },
  stream: true // 第二阶段可以使用流式
};