|
|
@ -330,6 +330,10 @@ |
|
|
|
</div> |
|
|
|
|
|
|
|
<script> |
|
|
|
// 全局变量 |
|
|
|
let eventSource = null; |
|
|
|
let isStreaming = false; |
|
|
|
|
|
|
|
// 工具函数:显示状态信息 |
|
|
|
function showStatus(elementId, message, type) { |
|
|
|
const statusElement = document.getElementById(elementId); |
|
|
@ -355,26 +359,50 @@ |
|
|
|
container.innerHTML = ''; |
|
|
|
|
|
|
|
messages.forEach(message => { |
|
|
|
const messageElement = document.createElement('div'); |
|
|
|
messageElement.className = `message message-${message.type}`; |
|
|
|
|
|
|
|
const contentElement = document.createElement('div'); |
|
|
|
contentElement.textContent = message.content; |
|
|
|
|
|
|
|
const timestampElement = document.createElement('div'); |
|
|
|
timestampElement.className = 'message-timestamp'; |
|
|
|
const date = new Date(message.timestamp * 1000); |
|
|
|
timestampElement.textContent = date.toLocaleTimeString(); |
|
|
|
|
|
|
|
messageElement.appendChild(contentElement); |
|
|
|
messageElement.appendChild(timestampElement); |
|
|
|
container.appendChild(messageElement); |
|
|
|
addMessageToContainer(message); |
|
|
|
}); |
|
|
|
|
|
|
|
// 滚动到底部 |
|
|
|
container.scrollTop = container.scrollHeight; |
|
|
|
} |
|
|
|
|
|
|
|
// 工具函数:添加单个消息到容器 |
|
|
|
function addMessageToContainer(message) { |
|
|
|
console.log('Adding message to container:', message); |
|
|
|
|
|
|
|
const container = document.getElementById('messageContainer'); |
|
|
|
if (!container) { |
|
|
|
console.error('Message container not found!'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const messageElement = document.createElement('div'); |
|
|
|
messageElement.className = `message message-${message.type}`; |
|
|
|
|
|
|
|
const contentElement = document.createElement('div'); |
|
|
|
contentElement.textContent = message.content; |
|
|
|
|
|
|
|
const timestampElement = document.createElement('div'); |
|
|
|
timestampElement.className = 'message-timestamp'; |
|
|
|
const date = new Date(message.timestamp * 1000); |
|
|
|
timestampElement.textContent = date.toLocaleTimeString(); |
|
|
|
|
|
|
|
messageElement.appendChild(contentElement); |
|
|
|
messageElement.appendChild(timestampElement); |
|
|
|
container.appendChild(messageElement); |
|
|
|
|
|
|
|
// 确保结果容器是可见的 |
|
|
|
const resultContainer = document.getElementById('queryResult'); |
|
|
|
if (resultContainer && !resultContainer.classList.contains('visible')) { |
|
|
|
resultContainer.classList.add('visible'); |
|
|
|
} |
|
|
|
|
|
|
|
// 滚动到底部 |
|
|
|
container.scrollTop = container.scrollHeight; |
|
|
|
|
|
|
|
console.log('Message added successfully, container now has', container.children.length, 'messages'); |
|
|
|
} |
|
|
|
|
|
|
|
// 工具函数:隐藏状态信息 |
|
|
|
function hideStatus(elementId) { |
|
|
|
const statusElement = document.getElementById(elementId); |
|
|
@ -418,6 +446,105 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 工具函数:关闭EventSource连接 |
|
|
|
function closeEventSource() { |
|
|
|
if (eventSource) { |
|
|
|
eventSource.close(); |
|
|
|
eventSource = null; |
|
|
|
} |
|
|
|
isStreaming = false; |
|
|
|
} |
|
|
|
|
|
|
|
// 工具函数:处理实时消息流 |
|
|
|
function handleStreamMessage(data) { |
|
|
|
try { |
|
|
|
const message = JSON.parse(data); |
|
|
|
|
|
|
|
switch (message.type) { |
|
|
|
case 'connection': |
|
|
|
console.log('Connected to message stream:', message.message); |
|
|
|
break; |
|
|
|
case 'heartbeat': |
|
|
|
// 心跳消息,不需要处理 |
|
|
|
break; |
|
|
|
case 'query_start': |
|
|
|
console.log('Query started:', message.query); |
|
|
|
showStatus('queryStatus', '查询已开始,正在处理...', 'loading'); |
|
|
|
break; |
|
|
|
case 'query_complete': |
|
|
|
console.log('Query completed'); |
|
|
|
showStatus('queryStatus', '查询完成', 'success'); |
|
|
|
if (message.result) { |
|
|
|
document.getElementById('resultText').textContent = message.result; |
|
|
|
showResult(); |
|
|
|
} |
|
|
|
// 关闭EventSource连接 |
|
|
|
if (window.currentEventSource) { |
|
|
|
window.currentEventSource.close(); |
|
|
|
window.currentEventSource = null; |
|
|
|
} |
|
|
|
isStreaming = false; |
|
|
|
setButtonLoading(document.getElementById('queryBtn'), false); |
|
|
|
break; |
|
|
|
case 'query_error': |
|
|
|
console.error('Query error:', message.error); |
|
|
|
showStatus('queryStatus', `查询失败: ${message.error}`, 'error'); |
|
|
|
// 关闭EventSource连接 |
|
|
|
if (window.currentEventSource) { |
|
|
|
window.currentEventSource.close(); |
|
|
|
window.currentEventSource = null; |
|
|
|
} |
|
|
|
isStreaming = false; |
|
|
|
setButtonLoading(document.getElementById('queryBtn'), false); |
|
|
|
break; |
|
|
|
case 'stream_error': |
|
|
|
console.error('Stream error:', message.error); |
|
|
|
showStatus('queryStatus', `流错误: ${message.error}`, 'error'); |
|
|
|
// 关闭EventSource连接 |
|
|
|
if (window.currentEventSource) { |
|
|
|
window.currentEventSource.close(); |
|
|
|
window.currentEventSource = null; |
|
|
|
} |
|
|
|
isStreaming = false; |
|
|
|
setButtonLoading(document.getElementById('queryBtn'), false); |
|
|
|
break; |
|
|
|
case 'search': |
|
|
|
case 'think': |
|
|
|
case 'answer': |
|
|
|
// 处理常规消息 |
|
|
|
console.log('Processing message type:', message.type, 'with content:', message.content.substring(0, 100) + '...'); |
|
|
|
addMessageToContainer(message); |
|
|
|
break; |
|
|
|
default: |
|
|
|
console.log('Unknown message type:', message.type); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('Error parsing message:', error); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 工具函数:开始实时消息流 |
|
|
|
function startMessageStream() { |
|
|
|
closeEventSource(); // 关闭之前的连接 |
|
|
|
|
|
|
|
eventSource = new EventSource('/stream-messages/'); |
|
|
|
|
|
|
|
eventSource.onopen = function(event) { |
|
|
|
console.log('EventSource connection opened'); |
|
|
|
}; |
|
|
|
|
|
|
|
eventSource.onmessage = function(event) { |
|
|
|
handleStreamMessage(event.data); |
|
|
|
}; |
|
|
|
|
|
|
|
eventSource.onerror = function(event) { |
|
|
|
console.error('EventSource error:', event); |
|
|
|
if (eventSource.readyState === EventSource.CLOSED) { |
|
|
|
console.log('EventSource connection closed'); |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// 加载文件功能 |
|
|
|
document.getElementById('loadFilesBtn').addEventListener('click', async function() { |
|
|
|
const button = this; |
|
|
@ -530,7 +657,7 @@ |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 查询功能 |
|
|
|
// 查询功能 - 使用实时流 |
|
|
|
document.getElementById('queryBtn').addEventListener('click', async function() { |
|
|
|
const button = this; |
|
|
|
const queryText = document.getElementById('queryText').value; |
|
|
@ -546,39 +673,63 @@ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (isStreaming) { |
|
|
|
showStatus('queryStatus', '查询正在进行中,请等待完成', 'error'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
setButtonLoading(button, true); |
|
|
|
showStatus('queryStatus', '正在处理查询...', 'loading'); |
|
|
|
showStatus('queryStatus', '正在启动查询...', 'loading'); |
|
|
|
hideResult(); |
|
|
|
|
|
|
|
// 清空消息容器 |
|
|
|
const container = document.getElementById('messageContainer'); |
|
|
|
container.innerHTML = ''; |
|
|
|
|
|
|
|
try { |
|
|
|
const response = await fetch(`/query/?original_query=${encodeURIComponent(queryText)}&max_iter=${maxIter}`, { |
|
|
|
method: 'GET', |
|
|
|
headers: { |
|
|
|
'Content-Type': 'application/json' |
|
|
|
} |
|
|
|
}); |
|
|
|
isStreaming = true; |
|
|
|
|
|
|
|
const data = await response.json(); |
|
|
|
// 使用EventSource直接连接到查询流 |
|
|
|
const eventSource = new EventSource(`/query-stream/?original_query=${encodeURIComponent(queryText)}&max_iter=${maxIter}`); |
|
|
|
|
|
|
|
if (response.ok) { |
|
|
|
showStatus('queryStatus', '查询完成', 'success'); |
|
|
|
document.getElementById('resultText').textContent = data.result; |
|
|
|
|
|
|
|
// 显示消息流 |
|
|
|
if (data.messages && data.messages.length > 0) { |
|
|
|
displayMessages(data.messages); |
|
|
|
// 保存EventSource引用以便后续关闭 |
|
|
|
window.currentEventSource = eventSource; |
|
|
|
|
|
|
|
eventSource.onopen = function(event) { |
|
|
|
console.log('EventSource connection opened for query'); |
|
|
|
showStatus('queryStatus', '查询已开始,正在处理...', 'loading'); |
|
|
|
}; |
|
|
|
|
|
|
|
eventSource.onmessage = function(event) { |
|
|
|
console.log('Received message:', event.data); |
|
|
|
handleStreamMessage(event.data); |
|
|
|
}; |
|
|
|
|
|
|
|
eventSource.onerror = function(event) { |
|
|
|
console.error('EventSource error:', event); |
|
|
|
if (eventSource.readyState === EventSource.CLOSED) { |
|
|
|
console.log('EventSource connection closed'); |
|
|
|
isStreaming = false; |
|
|
|
setButtonLoading(button, false); |
|
|
|
window.currentEventSource = null; |
|
|
|
} |
|
|
|
|
|
|
|
showResult(); |
|
|
|
} else { |
|
|
|
showStatus('queryStatus', `查询失败: ${data.detail}`, 'error'); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
console.error('Query error:', error); |
|
|
|
showStatus('queryStatus', `请求失败: ${error.message}`, 'error'); |
|
|
|
} finally { |
|
|
|
isStreaming = false; |
|
|
|
setButtonLoading(button, false); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 页面卸载时清理连接 |
|
|
|
window.addEventListener('beforeunload', function() { |
|
|
|
if (window.currentEventSource) { |
|
|
|
window.currentEventSource.close(); |
|
|
|
window.currentEventSource = null; |
|
|
|
} |
|
|
|
}); |
|
|
|
</script> |
|
|
|
</body> |
|
|
|
</html> |