fix: 修复文件上传显示重复问题

- 使用 lastSentMessageWithFiles 判断避免重复显示
- 图片在前端直接显示预览(base64)
- 文本文件显示名称和内容摘要
- extra_data 保存图片/文件信息用于历史记录
This commit is contained in:
2026-04-13 23:45:17 +08:00
parent fe65f23fa7
commit 2bdb9e7f10
2 changed files with 63 additions and 20 deletions

View File

@@ -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. 获取对话历史(包含刚保存的用户消息)

View File

@@ -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 = `<div class="message-avatar">${avatar}</div><div class="message-body">`;
// 显示文本内容
if (content) {
html += `<div class="message-content"><div class="user-message-text">${escapeHtml(content)}</div></div>`;
}
// 显示文件(图片直接显示,文本文件显示名称)
if (files && files.length > 0) {
html += '<div class="uploaded-files" style="margin-top:8px">';
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 += `<div class="uploaded-image" style="margin-bottom:8px"><img src="${f.content}" style="max-width:300px;border-radius:8px"></div>`;
} 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 += `<div class="uploaded-file" style="padding:8px;background:#f5f5f5;border-radius:6px;margin-bottom:8px">`;
html += `<div style="font-size:13px;color:#10a37f"><i class="ri-file-text-line"></i> ${f.name}</div>`;
if (f.content && f.content.length < 2000) {
html += `<div style="font-size:12px;color:#666;margin-top:4px">${escapeHtml(f.content.substring(0, 300))}${f.content.length > 300 ? '...' : ''}</div>`;
}
html += '</div>';
}
}
}
msgContent += filesText;
html += '</div>';
// 记录完整消息(用于判断是否重复显示)
lastSentMessageWithFiles = content + '\n[文件:' + files.map(f => f.name).join(',') + ']';
}
const avatar = role === 'user' ? '👤' : '🤖';
let html = `<div class="message-avatar">${avatar}</div><div class="message-body">`;
html += `<div class="message-content"><div class="user-message-text">${escapeHtml(msgContent)}</div></div>`;
html += `<input type="hidden" class="copy-source" value="${msgContent.replace(/"/g, '&quot;')}">`;
html += '</div>';
div.innerHTML = html;
container.appendChild(div);
container.scrollTop = container.scrollHeight;
}
html += `<div class="message-actions"><button class="action-btn" onclick="copyMessage(this)"><i class="ri-file-copy-line"></i> 复制</button></div>`;
html += '</div>';
div.innerHTML = html;