fix: 修复手动测试发现的3项问题
1. food-encyclopedia: 修复 v-for key id:index TypeError - :key 改为 :key="index",避免 WeChat 小程序 key 表达式异常 - filteredFoodList 加本地搜索过滤 + null item 过滤 - normalizeFoodItem 新增英文→中文分类名映射(grain→谷薯类等) - loadFoodList/handleSearch 过滤 null 条目 2. ToolKnowledgeServiceImpl: 修复 TooManyResultsException - getNutrientDetail 查询新增 LIMIT 1 + ORDER BY knowledge_id DESC - 防止 DB 中同名营养素存在多条导致 selectOne 异常 3. ai-nutritionist: 统一走 Coze API,移除 KieAI Gemini 路径 - sendToAI 文本/多模态均改为 api.cozeChat + pollChatStatus - 支持 type='text'/'multimodal'/图片 三种消息类型构建 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -629,57 +629,59 @@ export default {
|
||||
async sendToAI(content, type) {
|
||||
this.isLoading = true;
|
||||
|
||||
// BUG-005:文本/多模态必须走 KieAI Gemini;请求体 { messages: [{ role: 'user', content: 用户输入 }], stream: false }
|
||||
// 回复仅从 data.choices[0].message.content 取,禁止使用 getAIResponse 等固定话术
|
||||
if (type === 'text' || type === 'multimodal') {
|
||||
try {
|
||||
const messages = [{ role: 'user', content: content }];
|
||||
const response = await api.kieaiGeminiChat({ messages, stream: false });
|
||||
this.isLoading = false;
|
||||
if (response && response.code === 200 && response.data) {
|
||||
const data = response.data;
|
||||
const choice = data.choices && data.choices[0];
|
||||
const msgObj = choice && choice.message;
|
||||
const rawContent = msgObj != null ? msgObj.content : undefined;
|
||||
const reply = rawContent != null && rawContent !== undefined ? this.extractReplyContent(rawContent) : '';
|
||||
// BUG-005: 仅展示接口返回的 data.choices[0].message.content,不使用固定话术
|
||||
this.messageList.push({ role: 'ai', content: reply.trim() || '未能获取到有效回复。' });
|
||||
} else {
|
||||
const msg = (response && response.message) || '发起对话失败';
|
||||
this.messageList.push({ role: 'ai', content: '请求失败:' + msg });
|
||||
}
|
||||
this.scrollToBottom();
|
||||
} catch (error) {
|
||||
console.error('KieAI 对话失败:', error);
|
||||
this.isLoading = false;
|
||||
const errMsg = (error && (error.message || error.msg)) || '请稍后再试';
|
||||
this.messageList.push({ role: 'ai', content: '请求失败:' + errMsg });
|
||||
this.scrollToBottom();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 仅图片且未合并(旧 Coze 路径,保留兼容)
|
||||
// 统一走 Coze API(文本、多模态、图片均使用 Coze Bot)
|
||||
const userId = this.uid || (uni.getStorageSync('userInfo') || {}).id || 'default_user';
|
||||
try {
|
||||
const messages = [];
|
||||
let fileInfo = content;
|
||||
if (typeof fileInfo === 'string') {
|
||||
try { fileInfo = JSON.parse(fileInfo); } catch (e) { /* 非JSON */ }
|
||||
}
|
||||
const fileId = (fileInfo && fileInfo.id) || (fileInfo && fileInfo.file_id) || '';
|
||||
if (fileId) {
|
||||
if (type === 'text') {
|
||||
// 纯文字消息
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: JSON.stringify([{ type: 'image', file_id: fileId }]),
|
||||
content_type: 'object_string'
|
||||
});
|
||||
} else {
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: '我发送了一张图片,请帮我分析',
|
||||
content: typeof content === 'string' ? content : JSON.stringify(content),
|
||||
content_type: 'text'
|
||||
});
|
||||
} else if (type === 'multimodal') {
|
||||
// 图文混合:content 为 parts 数组 [{ type: 'text', text }, { type: 'image_url', ... }]
|
||||
const parts = Array.isArray(content) ? content : [{ type: 'text', text: String(content) }];
|
||||
const textPart = parts.find(p => p && p.type === 'text');
|
||||
const imgPart = parts.find(p => p && (p.type === 'image_url' || p.type === 'image'));
|
||||
if (imgPart) {
|
||||
const fileId = imgPart.file_id || (imgPart.image_url && imgPart.image_url.url) || '';
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: JSON.stringify([
|
||||
...(textPart ? [{ type: 'text', text: textPart.text }] : []),
|
||||
{ type: 'image', file_id: fileId }
|
||||
]),
|
||||
content_type: 'object_string'
|
||||
});
|
||||
} else {
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: textPart ? textPart.text : JSON.stringify(content),
|
||||
content_type: 'text'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 图片路径(旧路径,content 为 fileInfo 对象)
|
||||
let fileInfo = content;
|
||||
if (typeof fileInfo === 'string') {
|
||||
try { fileInfo = JSON.parse(fileInfo); } catch (e) { /* 非JSON */ }
|
||||
}
|
||||
const fileId = (fileInfo && fileInfo.id) || (fileInfo && fileInfo.file_id) || '';
|
||||
if (fileId) {
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: JSON.stringify([{ type: 'image', file_id: fileId }]),
|
||||
content_type: 'object_string'
|
||||
});
|
||||
} else {
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: '我发送了一张图片,请帮我分析',
|
||||
content_type: 'text'
|
||||
});
|
||||
}
|
||||
}
|
||||
const requestData = {
|
||||
botId: this.botId,
|
||||
|
||||
Reference in New Issue
Block a user