# 饮食记录确认流程客户端实现 ## 概述 已完成对客户端的改动,支持饮食记录确认流程的新API结构。实现了对非流式JSON响应的处理,能够正确显示食物选择选项,并支持用户确认选择。 ## 主要改动 ### 1. 数据结构扩展 在 `app/(tabs)/coach.tsx` 中添加了新的类型定义: ```typescript // AI选择选项数据结构 type AiChoiceOption = { id: string; label: string; value: any; recommended?: boolean; }; // 餐次类型 type MealType = 'breakfast' | 'lunch' | 'dinner' | 'snack'; // 食物确认选项数据结构 type FoodConfirmationOption = { id: string; label: string; foodName: string; portion: string; calories: number; mealType: MealType; nutritionData: { proteinGrams?: number; carbohydrateGrams?: number; fatGrams?: number; fiberGrams?: number; }; }; // AI响应数据结构 type AiResponseData = { content: string; choices?: AiChoiceOption[]; interactionType?: 'text' | 'food_confirmation' | 'selection'; pendingData?: any; context?: any; }; ``` ### 2. 消息结构扩展 扩展了 `ChatMessage` 类型以支持新的字段: ```typescript type ChatMessage = { id: string; role: Role; content: string; attachments?: MessageAttachment[]; choices?: AiChoiceOption[]; // 新增:选择选项 interactionType?: string; // 新增:交互类型 pendingData?: any; // 新增:待确认数据 context?: any; // 新增:上下文信息 }; ``` ### 3. 响应处理逻辑 #### 支持非流式JSON响应 修改了 `sendRequestInternal` 函数以检测和处理非流式JSON响应: ```typescript // 如果是非流式请求,直接调用API并处理响应 if (!body.stream) { try { const response = await api.post<{ conversationId?: string; data?: AiResponseData; text?: string }>('/api/ai-coach/chat', body); // 处理响应 if (response.data) { // 结构化响应(可能包含选择选项) const assistantMsg: ChatMessage = { id: assistantId, role: 'assistant', content: response.data.content, choices: response.data.choices, interactionType: response.data.interactionType, pendingData: response.data.pendingData, context: response.data.context, }; // ... 更新消息状态 } // ... } } ``` #### 流式响应中的JSON检测 在流式响应处理中添加了JSON检测逻辑: ```typescript const onChunk = (chunk: string) => { // 尝试解析是否为JSON结构化数据(可能是确认选项) try { const parsed = JSON.parse(chunk); if (parsed && parsed.data && parsed.data.choices) { // 处理结构化响应(包含选择选项) // ... 创建带选择选项的消息 return; } } catch { // 不是JSON,继续作为普通文本处理 } // ... 正常的文本流处理 }; ``` ### 4. 选择选项UI组件 在 `renderBubbleContent` 函数中添加了选择选项的渲染逻辑: ```typescript // 检查是否有选择选项需要显示 if (item.choices && item.choices.length > 0 && item.interactionType === 'food_confirmation') { return ( {item.content || ''} {item.choices.map((choice) => ( handleChoiceSelection(choice, item)} > {choice.label} {choice.recommended && ( 推荐 )} ))} ); } ``` ### 5. 选择确认逻辑 实现了 `handleChoiceSelection` 函数处理用户选择: ```typescript async function handleChoiceSelection(choice: AiChoiceOption, message: ChatMessage) { try { // 构建确认请求 const confirmationText = `我选择记录${choice.label}`; // 发送确认消息,包含选择的数据 await sendStreamWithConfirmation(confirmationText, choice.id, { selectedOption: choice.value, imageUrl: message.pendingData?.imageUrl }); } catch (e: any) { Alert.alert('选择失败', e?.message || '选择失败,请重试'); } } ``` ### 6. 确认数据发送 添加了 `sendStreamWithConfirmation` 函数: ```typescript async function sendStreamWithConfirmation(text: string, selectedChoiceId: string, confirmationData: any) { const historyForServer = convertToServerMessages(messages); const cid = ensureConversationId(); const body = { conversationId: cid, messages: [...historyForServer, { role: 'user' as const, content: text }], selectedChoiceId, confirmationData, stream: false, // 确认阶段使用非流式 }; await sendRequestInternal(body, text); } ``` ### 7. UI样式 添加了选择选项相关的样式: ```typescript choicesContainer: { gap: 8, }, choiceButton: { backgroundColor: 'rgba(255,255,255,0.9)', borderWidth: 1, borderColor: 'rgba(187,242,70,0.3)', borderRadius: 12, padding: 12, }, choiceButtonRecommended: { borderColor: 'rgba(187,242,70,0.6)', backgroundColor: 'rgba(187,242,70,0.1)', }, // ... 其他相关样式 ``` ## 使用流程 1. **用户发送饮食图片**:用户点击"#记饮食"并上传食物图片 2. **AI识别返回选项**:服务器返回食物识别结果和确认选项(非流式JSON) 3. **显示选择选项**:客户端渲染食物选择选项,推荐项目带有特殊标识 4. **用户选择确认**:用户点击某个选项 5. **发送确认数据**:客户端发送确认请求,包含选择的食物数据 6. **记录完成**:服务器记录饮食数据并返回确认消息 ## 兼容性 - 保持对现有流式文本响应的完全兼容 - 自动检测响应类型(JSON vs 文本流) - 旧的饮食记录方式(文字输入)继续正常工作 - 缓存和会话管理支持新的消息结构 ## 技术要点 1. **响应类型检测**:客户端能够自动识别JSON结构化响应和普通文本流 2. **状态管理**:新增状态正确地保存到本地缓存 3. **用户体验**:选择选项有清晰的视觉反馈,推荐选项突出显示 4. **错误处理**:完整的错误处理机制,确保用户体验流畅 5. **性能优化**:避免不必要的重渲染,保持界面响应性 这个实现完全符合API文档的要求,支持饮食记录的两阶段确认流程,并保持了与现有功能的兼容性。