Spaces:
Sleeping
Sleeping
| const chatMessages = document.getElementById('chatMessages'); | |
| const messageInput = document.getElementById('messageInput'); | |
| const sendBtn = document.getElementById('sendBtn'); | |
| const uploadBtn = document.getElementById('uploadBtn'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const documentList = document.getElementById('documentList'); | |
| const ragToggle = document.getElementById('ragToggle'); | |
| let sessionId = generateSessionId(); | |
| function generateSessionId() { | |
| return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); | |
| } | |
| function addMessage(content, isUser = false) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `message ${isUser ? 'user' : 'assistant'}`; | |
| messageDiv.textContent = content; | |
| chatMessages.appendChild(messageDiv); | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| return messageDiv; | |
| } | |
| function addLoadingMessage() { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'message loading'; | |
| messageDiv.textContent = 'Thinking...'; | |
| chatMessages.appendChild(messageDiv); | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| return messageDiv; | |
| } | |
| async function sendMessage() { | |
| const message = messageInput.value.trim(); | |
| if (!message) return; | |
| addMessage(message, true); | |
| messageInput.value = ''; | |
| sendBtn.disabled = true; | |
| const loadingMsg = addLoadingMessage(); | |
| try { | |
| const response = await fetch('/chat/stream', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| message: message, | |
| session_id: sessionId, | |
| use_rag: ragToggle.checked | |
| }) | |
| }); | |
| const reader = response.body.getReader(); | |
| const decoder = new TextDecoder(); | |
| loadingMsg.remove(); | |
| const assistantMsg = addMessage('', false); | |
| let fullResponse = ''; | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) break; | |
| const chunk = decoder.decode(value); | |
| const lines = chunk.split('\n'); | |
| for (const line of lines) { | |
| if (line.startsWith('data: ')) { | |
| const data = JSON.parse(line.slice(6)); | |
| if (data.chunk) { | |
| fullResponse += data.chunk; | |
| assistantMsg.textContent = fullResponse; | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| if (data.error) { | |
| assistantMsg.textContent = 'Error: ' + data.error; | |
| assistantMsg.style.color = '#dc3545'; | |
| } | |
| } | |
| } | |
| } | |
| } catch (error) { | |
| loadingMsg.remove(); | |
| addMessage('Error: ' + error.message, false); | |
| } finally { | |
| sendBtn.disabled = false; | |
| messageInput.focus(); | |
| } | |
| } | |
| messageInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| sendMessage(); | |
| } | |
| }); | |
| sendBtn.addEventListener('click', sendMessage); | |
| uploadBtn.addEventListener('click', () => { | |
| fileInput.click(); | |
| }); | |
| fileInput.addEventListener('change', async (e) => { | |
| const file = e.target.files[0]; | |
| if (!file) return; | |
| const formData = new FormData(); | |
| formData.append('file', file); | |
| uploadBtn.disabled = true; | |
| uploadBtn.textContent = 'Uploading...'; | |
| try { | |
| const response = await fetch('/documents/upload', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| if (response.ok) { | |
| const data = await response.json(); | |
| addMessage(`Document "${data.filename}" uploaded successfully! (${data.chunk_count} chunks)`, false); | |
| loadDocuments(); | |
| } else { | |
| const error = await response.json(); | |
| addMessage('Upload failed: ' + error.detail, false); | |
| } | |
| } catch (error) { | |
| addMessage('Upload error: ' + error.message, false); | |
| } finally { | |
| uploadBtn.disabled = false; | |
| uploadBtn.textContent = 'Upload Document'; | |
| fileInput.value = ''; | |
| } | |
| }); | |
| async function loadDocuments() { | |
| try { | |
| const response = await fetch('/documents/'); | |
| const documents = await response.json(); | |
| documentList.innerHTML = ''; | |
| documents.forEach(doc => { | |
| const docDiv = document.createElement('div'); | |
| docDiv.className = 'document-item'; | |
| const nameSpan = document.createElement('span'); | |
| nameSpan.className = 'document-name'; | |
| nameSpan.textContent = doc.filename; | |
| const deleteBtn = document.createElement('button'); | |
| deleteBtn.className = 'btn-delete'; | |
| deleteBtn.textContent = 'Delete'; | |
| deleteBtn.onclick = () => deleteDocument(doc.id); | |
| docDiv.appendChild(nameSpan); | |
| docDiv.appendChild(deleteBtn); | |
| documentList.appendChild(docDiv); | |
| }); | |
| } catch (error) { | |
| console.error('Failed to load documents:', error); | |
| } | |
| } | |
| async function deleteDocument(docId) { | |
| if (!confirm('Are you sure you want to delete this document?')) return; | |
| try { | |
| const response = await fetch(`/documents/${docId}`, { | |
| method: 'DELETE' | |
| }); | |
| if (response.ok) { | |
| loadDocuments(); | |
| addMessage('Document deleted successfully', false); | |
| } | |
| } catch (error) { | |
| addMessage('Delete failed: ' + error.message, false); | |
| } | |
| } | |
| loadDocuments(); |