fix: 修复文件上传显示重复问题
- 使用 lastSentMessageWithFiles 判断避免重复显示 - 图片在前端直接显示预览(base64) - 文本文件显示名称和内容摘要 - extra_data 保存图片/文件信息用于历史记录
This commit is contained in:
33
main_v2.py
33
main_v2.py
@@ -785,13 +785,31 @@ async def websocket_endpoint(websocket: WebSocket, user_id: str):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# 处理文件内容,添加到消息
|
# 处理文件内容,添加到消息
|
||||||
|
image_contents = [] # 图片内容(用于视觉模型)
|
||||||
if files:
|
if files:
|
||||||
for f in files:
|
for f in files:
|
||||||
if f.get('type') and f['type'].startswith('image/'):
|
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']}]"
|
message += f"\n[图片: {f['name']}]"
|
||||||
elif f.get('content'):
|
elif f.get('content'):
|
||||||
# 文本文件内容
|
# 文本文件:直接添加内容
|
||||||
message += f"\n\n文件 {f['name']} 内容:\n{f['content'][:3000]}"
|
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配置
|
# 1. 获取Agent配置
|
||||||
agent_config = agent_service.get_agent_config(current_agent_id)
|
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
|
'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(
|
user_msg = conv_service.add_message(
|
||||||
conversation_id=conversation.id,
|
conversation_id=conversation.id,
|
||||||
role='user',
|
role='user',
|
||||||
content=message,
|
content=message,
|
||||||
source='web',
|
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. 获取对话历史(包含刚保存的用户消息)
|
# 6. 获取对话历史(包含刚保存的用户消息)
|
||||||
|
|||||||
@@ -296,11 +296,12 @@
|
|||||||
case 'stream_end': document.getElementById('sendBtn').disabled = false; break;
|
case 'stream_end': document.getElementById('sendBtn').disabled = false; break;
|
||||||
case 'user_message':
|
case 'user_message':
|
||||||
lastUserMessage = data.message.content; // 存储最后一条用户消息
|
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);
|
appendMessage('user', data.message.content);
|
||||||
}
|
}
|
||||||
lastSentMessage = null; // 清除标记
|
lastSentMessage = null;
|
||||||
|
lastSentMessageWithFiles = null; // 清除标记
|
||||||
// 注意:不要在这里重置 isRegenerating,要等 assistant_message 处理后再重置
|
// 注意:不要在这里重置 isRegenerating,要等 assistant_message 处理后再重置
|
||||||
break;
|
break;
|
||||||
case 'assistant_message':
|
case 'assistant_message':
|
||||||
@@ -826,6 +827,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let lastSentFiles = null; // 记录发送的文件
|
let lastSentFiles = null; // 记录发送的文件
|
||||||
|
let lastSentMessageWithFiles = null; // 记录包含文件信息的完整消息
|
||||||
|
|
||||||
// 显示带文件的用户消息
|
// 显示带文件的用户消息
|
||||||
function appendMessageWithFiles(role, content, files) {
|
function appendMessageWithFiles(role, content, files) {
|
||||||
@@ -835,35 +837,49 @@
|
|||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.className = `message ${role}`;
|
div.className = `message ${role}`;
|
||||||
|
|
||||||
// 构建消息内容
|
const avatar = role === 'user' ? '👤' : '🤖';
|
||||||
let msgContent = content;
|
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) {
|
if (files && files.length > 0) {
|
||||||
|
html += '<div class="uploaded-files" style="margin-top:8px">';
|
||||||
lastSentFiles = files.map(f => ({
|
lastSentFiles = files.map(f => ({
|
||||||
name: f.name,
|
name: f.name,
|
||||||
type: f.type,
|
type: f.type,
|
||||||
content: f.content
|
content: f.content
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// 添加文件信息到消息
|
|
||||||
let filesText = '\n\n[附件]';
|
|
||||||
for (const f of files) {
|
for (const f of files) {
|
||||||
if (f.type.startsWith('image/')) {
|
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 {
|
} else {
|
||||||
filesText += `\n文件: ${f.name}`;
|
// 文本文件显示名称和内容摘要
|
||||||
// 文本文件显示内容摘要
|
html += `<div class="uploaded-file" style="padding:8px;background:#f5f5f5;border-radius:6px;margin-bottom:8px">`;
|
||||||
if (!f.type.startsWith('image/') && f.content && f.content.length < 2000) {
|
html += `<div style="font-size:13px;color:#10a37f"><i class="ri-file-text-line"></i> ${f.name}</div>`;
|
||||||
filesText += `\n内容: ${f.content.substring(0, 500)}${f.content.length > 500 ? '...' : ''}`;
|
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>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
html += '</div>';
|
||||||
msgContent += filesText;
|
|
||||||
|
// 记录完整消息(用于判断是否重复显示)
|
||||||
|
lastSentMessageWithFiles = content + '\n[文件:' + files.map(f => f.name).join(',') + ']';
|
||||||
}
|
}
|
||||||
|
|
||||||
const avatar = role === 'user' ? '👤' : '🤖';
|
html += '</div>';
|
||||||
let html = `<div class="message-avatar">${avatar}</div><div class="message-body">`;
|
div.innerHTML = html;
|
||||||
html += `<div class="message-content"><div class="user-message-text">${escapeHtml(msgContent)}</div></div>`;
|
container.appendChild(div);
|
||||||
html += `<input type="hidden" class="copy-source" value="${msgContent.replace(/"/g, '"')}">`;
|
|
||||||
|
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 class="message-actions"><button class="action-btn" onclick="copyMessage(this)"><i class="ri-file-copy-line"></i> 复制</button></div>`;
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
|
|||||||
Reference in New Issue
Block a user