From 2bdb9e7f100274cd71afae8ce72c3492fb41fe7c Mon Sep 17 00:00:00 2001 From: hubian <908234780@qq.com> Date: Mon, 13 Apr 2026 23:45:17 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=98=BE=E7=A4=BA=E9=87=8D=E5=A4=8D=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用 lastSentMessageWithFiles 判断避免重复显示 - 图片在前端直接显示预览(base64) - 文本文件显示名称和内容摘要 - extra_data 保存图片/文件信息用于历史记录 --- main_v2.py | 33 ++++++++++++++++++++++++++--- templates/index.html | 50 +++++++++++++++++++++++++++++--------------- 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/main_v2.py b/main_v2.py index 27adc6a..b03dd06 100644 --- a/main_v2.py +++ b/main_v2.py @@ -785,13 +785,31 @@ async def websocket_endpoint(websocket: WebSocket, user_id: str): continue # 处理文件内容,添加到消息 + image_contents = [] # 图片内容(用于视觉模型) if files: for f in files: if f.get('type') and f['type'].startswith('image/'): + # 图片:记录 base64 数据,后续可能用于视觉模型 + image_contents.append({ + 'name': f['name'], + 'type': f['type'], + 'data': f.get('content', '') # base64 数据 + }) message += f"\n[图片: {f['name']}]" elif f.get('content'): - # 文本文件内容 + # 文本文件:直接添加内容 message += f"\n\n文件 {f['name']} 内容:\n{f['content'][:3000]}" + if len(f['content']) > 3000: + message += "...(内容过长已截断)" + + # 保存图片信息到 extra_data(用于历史记录) + extra_data_for_msg = None + if image_contents: + # 只保存图片 URL(不保存完整 base64) + extra_data_for_msg = { + 'images': [{'name': i['name'], 'type': i['type']} for i in image_contents], + 'files': [{'name': f['name'], 'type': f['type']} for f in files if not f['type'].startswith('image/')] + } # 1. 获取Agent配置 agent_config = agent_service.get_agent_config(current_agent_id) @@ -905,13 +923,22 @@ async def websocket_endpoint(websocket: WebSocket, user_id: str): 'duration_ms': duration_ms }) - # 5. 保存用户消息到数据库(包含搜索结果) + # 5. 保存用户消息到数据库 + extra_data_to_save = None + if search_results_for_client: + extra_data_to_save = {'search_results': search_results_for_client, 'search_query': message} + if extra_data_for_msg: + if extra_data_to_save: + extra_data_to_save.update(extra_data_for_msg) + else: + extra_data_to_save = extra_data_for_msg + user_msg = conv_service.add_message( conversation_id=conversation.id, role='user', content=message, source='web', - extra_data={'search_results': search_results_for_client, 'search_query': message} if search_results_for_client else None + extra_data=extra_data_to_save ) # 6. 获取对话历史(包含刚保存的用户消息) diff --git a/templates/index.html b/templates/index.html index 5c8e018..d956b50 100644 --- a/templates/index.html +++ b/templates/index.html @@ -296,11 +296,12 @@ case 'stream_end': document.getElementById('sendBtn').disabled = false; break; case 'user_message': lastUserMessage = data.message.content; // 存储最后一条用户消息 - // 如果是刚发送的消息,已经显示了,不再重复显示 - if (!isRegenerating && data.message.content !== lastSentMessage) { + // 如果是刚发送的消息(包含文件),已经显示了,不再重复显示 + if (!isRegenerating && data.message.content !== lastSentMessage && data.message.content !== lastSentMessageWithFiles) { appendMessage('user', data.message.content); } - lastSentMessage = null; // 清除标记 + lastSentMessage = null; + lastSentMessageWithFiles = null; // 清除标记 // 注意:不要在这里重置 isRegenerating,要等 assistant_message 处理后再重置 break; case 'assistant_message': @@ -826,6 +827,7 @@ } let lastSentFiles = null; // 记录发送的文件 + let lastSentMessageWithFiles = null; // 记录包含文件信息的完整消息 // 显示带文件的用户消息 function appendMessageWithFiles(role, content, files) { @@ -835,35 +837,49 @@ const div = document.createElement('div'); div.className = `message ${role}`; - // 构建消息内容 - let msgContent = content; + const avatar = role === 'user' ? '👤' : '🤖'; + let html = `
${avatar}
`; + + // 显示文本内容 + if (content) { + html += `
${escapeHtml(content)}
`; + } + + // 显示文件(图片直接显示,文本文件显示名称) if (files && files.length > 0) { + html += '
'; lastSentFiles = files.map(f => ({ name: f.name, type: f.type, content: f.content })); - // 添加文件信息到消息 - let filesText = '\n\n[附件]'; for (const f of files) { if (f.type.startsWith('image/')) { - filesText += `\n图片: ${f.name}`; + // 图片直接显示 + html += `
`; } else { - filesText += `\n文件: ${f.name}`; - // 文本文件显示内容摘要 - if (!f.type.startsWith('image/') && f.content && f.content.length < 2000) { - filesText += `\n内容: ${f.content.substring(0, 500)}${f.content.length > 500 ? '...' : ''}`; + // 文本文件显示名称和内容摘要 + html += `
`; + html += `
${f.name}
`; + if (f.content && f.content.length < 2000) { + html += `
${escapeHtml(f.content.substring(0, 300))}${f.content.length > 300 ? '...' : ''}
`; } + html += '
'; } } - msgContent += filesText; + html += '
'; + + // 记录完整消息(用于判断是否重复显示) + lastSentMessageWithFiles = content + '\n[文件:' + files.map(f => f.name).join(',') + ']'; } - const avatar = role === 'user' ? '👤' : '🤖'; - let html = `
${avatar}
`; - html += `
${escapeHtml(msgContent)}
`; - html += ``; + html += '
'; + div.innerHTML = html; + container.appendChild(div); + + container.scrollTop = container.scrollHeight; + } html += `
`; html += '
'; div.innerHTML = html;