+
+
+
${basicInfo.title}
+
+ Author: ${basicInfo.author}
+ Publication Date: ${basicInfo.publication_date}
+ Journal/Publisher: ${basicInfo.journal_publisher}
+
+
+
+
+
+
+
+
@@ -938,6 +1012,237 @@
function goBack() {
window.location.href = 'https://beta.obscura.work/lab/lab.html';
}
+
+ // Add chat dialog function
+ async function openChatDialog(referenceId, title) {
+ const modal = document.createElement('div');
+ modal.className = 'modal fade';
+ modal.id = 'chatModal';
+ modal.setAttribute('data-bs-backdrop', 'static');
+ modal.setAttribute('data-bs-keyboard', 'false');
+ modal.innerHTML = `
+
+ `;
+
+ document.body.appendChild(modal);
+ const modalInstance = new bootstrap.Modal(modal);
+ modalInstance.show();
+
+ // Load chat history
+ await loadChatHistory(referenceId);
+
+ // Add event listener for Enter key
+ const input = document.getElementById('questionInput');
+ input.addEventListener('keypress', (e) => {
+ if (e.key === 'Enter') {
+ sendQuestion(referenceId);
+ }
+ });
+
+ modal.addEventListener('hidden.bs.modal', () => {
+ document.body.removeChild(modal);
+ });
+ }
+
+ // Load chat history function
+ async function loadChatHistory(referenceId) {
+ const chatHistory = document.getElementById('chatHistory');
+ try {
+ const response = await fetch(`${API_BASE_URL}/references/${referenceId}/qa/history`, {
+ headers: {
+ 'Authorization': `Bearer ${token}`
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error('Failed to load chat history');
+ }
+
+ const history = await response.json();
+
+ if (history.length === 0) {
+ chatHistory.innerHTML = '
No chat history yet. Start a conversation!
';
+ return;
+ }
+
+ chatHistory.innerHTML = history.map(chat => `
+
+
+
👤
+
+ ${chat.question}
+
+
+
+
🤖
+
+ ${chat.answer}
+
+
+
+ ${new Date(chat.timestamp).toLocaleString()}
+
+
+ `).join('');
+
+ // Scroll to bottom
+ chatHistory.scrollTop = chatHistory.scrollHeight;
+
+ } catch (error) {
+ console.error('Failed to load chat history:', error);
+ chatHistory.innerHTML = '
Failed to load chat history
';
+ }
+ }
+
+ // Send question function
+ async function sendQuestion(referenceId) {
+ const input = document.getElementById('questionInput');
+ const question = input.value.trim();
+
+ if (!question) {
+ return;
+ }
+
+ const chatHistory = document.getElementById('chatHistory');
+
+ try {
+ // Clear input and disable it
+ input.value = '';
+ input.disabled = true;
+
+ // First, add the user's question to chat history
+ const questionDiv = document.createElement('div');
+ questionDiv.className = 'mb-3';
+ questionDiv.innerHTML = `
+
+ `;
+ chatHistory.appendChild(questionDiv);
+
+ // Then add the loading indicator
+ const loadingDiv = document.createElement('div');
+ loadingDiv.className = 'd-flex align-items-start mb-3';
+ loadingDiv.innerHTML = `
+
🤖
+
+
+
+ Loading...
+
+
Thinking...
+
+
+ `;
+
+ chatHistory.appendChild(loadingDiv);
+ chatHistory.scrollTop = chatHistory.scrollHeight;
+
+ // 发送问题并获取任务ID
+ const response = await fetch(`${API_BASE_URL}/references/${referenceId}/qa`, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${token}`,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ question })
+ });
+
+ if (!response.ok) {
+ throw new Error('Failed to send question');
+ }
+
+ const { task_id } = await response.json();
+
+ // 轮询获取任务结果
+ let result;
+ while (true) {
+ const taskResponse = await fetch(`${API_BASE_URL}/task/${task_id}`, {
+ headers: {
+ 'Authorization': `Bearer ${token}`
+ }
+ });
+
+ if (!taskResponse.ok) {
+ throw new Error('Failed to get task status');
+ }
+
+ const taskResult = await taskResponse.json();
+
+ if (taskResult.status === 'completed') {
+ result = taskResult;
+ break;
+ } else if (taskResult.status === 'failed') {
+ throw new Error(taskResult.error || 'Task failed');
+ }
+
+ // 等待1秒后再次查询
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+
+ // Remove loading indicator
+ loadingDiv.remove();
+
+ // Add AI's answer
+ const answerDiv = document.createElement('div');
+ answerDiv.className = 'd-flex align-items-start mb-3';
+ answerDiv.innerHTML = `
+
🤖
+
+ ${result.answer}
+
+ `;
+
+ // Add timestamp
+ const timestampDiv = document.createElement('div');
+ timestampDiv.className = 'text-end text-muted small mt-1 mb-3';
+ timestampDiv.textContent = new Date().toLocaleString();
+
+ chatHistory.appendChild(answerDiv);
+ chatHistory.appendChild(timestampDiv);
+ chatHistory.scrollTop = chatHistory.scrollHeight;
+
+ } catch (error) {
+ console.error('Failed to send question:', error);
+ const errorDiv = document.createElement('div');
+ errorDiv.className = 'd-flex align-items-start mb-3';
+ errorDiv.innerHTML = `
+
🤖
+
+ Failed to get answer: ${error.message}
+
+ `;
+ chatHistory.appendChild(errorDiv);
+ chatHistory.scrollTop = chatHistory.scrollHeight;
+ } finally {
+ input.disabled = false;
+ input.focus();
+ }
+ }