Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>RAG Chat Application</title> | |
| <style> | |
| body { | |
| font-family: Arial, sans-serif; | |
| margin: 0; | |
| padding: 0; | |
| background-color: #f5f5f5; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| header { | |
| background-color: #282c34; | |
| color: white; | |
| padding: 20px; | |
| text-align: center; | |
| } | |
| header h1 { | |
| margin: 0; | |
| } | |
| .upload-container { | |
| background-color: white; | |
| border-radius: 8px; | |
| box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); | |
| padding: 30px; | |
| margin: 30px 0; | |
| text-align: center; | |
| } | |
| .upload-container.hidden { | |
| display: none; | |
| } | |
| .chat-container { | |
| display: none; | |
| background-color: white; | |
| border-radius: 8px; | |
| box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); | |
| height: 70vh; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .chat-container.visible { | |
| display: flex; | |
| } | |
| .file-info { | |
| background-color: #f1f1f1; | |
| padding: 10px 20px; | |
| border-bottom: 1px solid #e0e0e0; | |
| text-align: left; | |
| } | |
| .chat-messages { | |
| flex-grow: 1; | |
| overflow-y: auto; | |
| padding: 20px; | |
| } | |
| .welcome-message { | |
| text-align: center; | |
| color: #555; | |
| margin: 30px 0; | |
| } | |
| .message { | |
| max-width: 70%; | |
| margin-bottom: 15px; | |
| padding: 10px 15px; | |
| border-radius: 8px; | |
| font-size: 14px; | |
| line-height: 1.5; | |
| position: relative; | |
| } | |
| .user-message { | |
| background-color: #2196F3; | |
| color: white; | |
| border-bottom-right-radius: 0; | |
| margin-left: auto; | |
| } | |
| .ai-message { | |
| background-color: #f1f1f1; | |
| color: #333; | |
| border-bottom-left-radius: 0; | |
| } | |
| .message.error { | |
| background-color: #ffebee; | |
| color: #d32f2f; | |
| } | |
| .message-sender { | |
| font-weight: bold; | |
| margin-bottom: 5px; | |
| font-size: 12px; | |
| } | |
| .chat-input-form { | |
| display: flex; | |
| padding: 15px; | |
| border-top: 1px solid #e0e0e0; | |
| } | |
| .chat-input { | |
| flex-grow: 1; | |
| padding: 12px 15px; | |
| border: 1px solid #e0e0e0; | |
| border-radius: 4px; | |
| font-size: 14px; | |
| } | |
| .send-button { | |
| background-color: #2196F3; | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| padding: 0 20px; | |
| margin-left: 10px; | |
| cursor: pointer; | |
| font-size: 14px; | |
| } | |
| .send-button:disabled { | |
| background-color: #ccc; | |
| } | |
| .file-input { | |
| display: none; | |
| } | |
| .file-label { | |
| display: inline-block; | |
| padding: 12px 20px; | |
| background-color: #4CAF50; | |
| color: white; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| margin-bottom: 20px; | |
| } | |
| .upload-button { | |
| padding: 12px 30px; | |
| background-color: #2196F3; | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-size: 16px; | |
| } | |
| .upload-button:disabled { | |
| background-color: #ccc; | |
| } | |
| .error-message { | |
| color: #d32f2f; | |
| margin: 10px 0; | |
| } | |
| .loading { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| gap: 8px; | |
| margin-bottom: 15px; | |
| } | |
| .loading .dot { | |
| width: 8px; | |
| height: 8px; | |
| background-color: #2196F3; | |
| border-radius: 50%; | |
| animation: bounce 1.4s infinite ease-in-out both; | |
| } | |
| .loading .dot:nth-child(1) { | |
| animation-delay: -0.32s; | |
| } | |
| .loading .dot:nth-child(2) { | |
| animation-delay: -0.16s; | |
| } | |
| @keyframes bounce { | |
| 0%, 80%, 100% { | |
| transform: scale(0); | |
| } | |
| 40% { | |
| transform: scale(1); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <h1>RAG Chat Application</h1> | |
| </header> | |
| <div class="container"> | |
| <div id="upload-container" class="upload-container"> | |
| <h2>Upload a Document</h2> | |
| <p>Upload a text or PDF file to start chatting</p> | |
| <div> | |
| <input type="file" id="file-input" class="file-input" accept=".txt,.pdf"> | |
| <label for="file-input" class="file-label" id="file-label">Choose a file</label> | |
| </div> | |
| <div id="error-message" class="error-message"></div> | |
| <button id="upload-button" class="upload-button" disabled>Upload</button> | |
| </div> | |
| <div id="chat-container" class="chat-container"> | |
| <div class="file-info"> | |
| <p>Using file: <strong id="filename-display"></strong></p> | |
| </div> | |
| <div id="chat-messages" class="chat-messages"> | |
| <div class="welcome-message"> | |
| <h3>Welcome to the RAG Chat!</h3> | |
| <p>Ask questions about the document you uploaded.</p> | |
| </div> | |
| </div> | |
| <form id="chat-form" class="chat-input-form"> | |
| <input type="text" id="chat-input" class="chat-input" placeholder="Ask a question about your document..."> | |
| <button type="submit" id="send-button" class="send-button">Send</button> | |
| </form> | |
| </div> | |
| </div> | |
| <script> | |
| // Generate a session ID | |
| const sessionId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); | |
| // DOM elements | |
| const uploadContainer = document.getElementById('upload-container'); | |
| const chatContainer = document.getElementById('chat-container'); | |
| const fileInput = document.getElementById('file-input'); | |
| const fileLabel = document.getElementById('file-label'); | |
| const uploadButton = document.getElementById('upload-button'); | |
| const errorMessage = document.getElementById('error-message'); | |
| const filenameDisplay = document.getElementById('filename-display'); | |
| const chatMessages = document.getElementById('chat-messages'); | |
| const chatForm = document.getElementById('chat-form'); | |
| const chatInput = document.getElementById('chat-input'); | |
| const sendButton = document.getElementById('send-button'); | |
| // Event listeners | |
| fileInput.addEventListener('change', handleFileChange); | |
| uploadButton.addEventListener('click', handleUpload); | |
| chatForm.addEventListener('submit', handleChatSubmit); | |
| // Handle file selection | |
| function handleFileChange(e) { | |
| const file = e.target.files[0]; | |
| if (!file) { | |
| fileLabel.textContent = 'Choose a file'; | |
| uploadButton.disabled = true; | |
| return; | |
| } | |
| // Check file type | |
| if (file.type !== 'text/plain' && file.type !== 'application/pdf') { | |
| errorMessage.textContent = 'Please select a text or PDF file'; | |
| fileLabel.textContent = 'Choose a file'; | |
| uploadButton.disabled = true; | |
| return; | |
| } | |
| // Check file size (2MB max) | |
| if (file.size > 2 * 1024 * 1024) { | |
| errorMessage.textContent = 'File size must be less than 2MB'; | |
| fileLabel.textContent = 'Choose a file'; | |
| uploadButton.disabled = true; | |
| return; | |
| } | |
| fileLabel.textContent = file.name; | |
| errorMessage.textContent = ''; | |
| uploadButton.disabled = false; | |
| } | |
| // Handle file upload | |
| async function handleUpload() { | |
| const file = fileInput.files[0]; | |
| if (!file) { | |
| errorMessage.textContent = 'Please select a file'; | |
| return; | |
| } | |
| // Disable upload button and show loading state | |
| uploadButton.disabled = true; | |
| uploadButton.textContent = 'Uploading...'; | |
| errorMessage.textContent = ''; | |
| const formData = new FormData(); | |
| formData.append('file', file); | |
| formData.append('session_id', sessionId); | |
| try { | |
| const response = await fetch('/upload', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| const data = await response.json(); | |
| if (data.status === 'success') { | |
| // Show chat container and hide upload container | |
| uploadContainer.style.display = 'none'; | |
| chatContainer.style.display = 'flex'; | |
| filenameDisplay.textContent = file.name; | |
| } else { | |
| errorMessage.textContent = data.message || 'Failed to upload file'; | |
| } | |
| } catch (error) { | |
| console.error('Error uploading file:', error); | |
| errorMessage.textContent = 'Failed to upload file'; | |
| } finally { | |
| uploadButton.textContent = 'Upload'; | |
| uploadButton.disabled = false; | |
| } | |
| } | |
| // Handle chat submission | |
| async function handleChatSubmit(e) { | |
| e.preventDefault(); | |
| const message = chatInput.value.trim(); | |
| if (!message) { | |
| return; | |
| } | |
| // Disable input and button | |
| chatInput.disabled = true; | |
| sendButton.disabled = true; | |
| // Add user message to chat | |
| addMessage(message, 'user'); | |
| // Clear input | |
| chatInput.value = ''; | |
| // Add loading indicator | |
| const loadingElement = document.createElement('div'); | |
| loadingElement.className = 'loading'; | |
| loadingElement.innerHTML = ` | |
| <div class="dot"></div> | |
| <div class="dot"></div> | |
| <div class="dot"></div> | |
| `; | |
| chatMessages.appendChild(loadingElement); | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| try { | |
| const response = await fetch('/query', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| session_id: sessionId, | |
| query: message | |
| }) | |
| }); | |
| const data = await response.json(); | |
| // Remove loading indicator | |
| chatMessages.removeChild(loadingElement); | |
| // Add AI response to chat | |
| addMessage(data.response, 'ai'); | |
| } catch (error) { | |
| console.error('Error getting response:', error); | |
| // Remove loading indicator | |
| chatMessages.removeChild(loadingElement); | |
| // Add error message | |
| addMessage('Sorry, there was an error processing your request.', 'ai', true); | |
| } finally { | |
| chatInput.disabled = false; | |
| sendButton.disabled = false; | |
| chatInput.focus(); | |
| } | |
| } | |
| // Add message to chat | |
| function addMessage(text, sender, isError = false) { | |
| // Remove welcome message if it exists | |
| const welcomeMessage = document.querySelector('.welcome-message'); | |
| if (welcomeMessage) { | |
| chatMessages.removeChild(welcomeMessage); | |
| } | |
| const messageElement = document.createElement('div'); | |
| messageElement.className = `message ${sender}-message${isError ? ' error' : ''}`; | |
| const senderElement = document.createElement('div'); | |
| senderElement.className = 'message-sender'; | |
| senderElement.textContent = sender === 'user' ? 'You' : 'AI'; | |
| const textElement = document.createElement('div'); | |
| textElement.className = 'message-text'; | |
| textElement.textContent = text; | |
| messageElement.appendChild(senderElement); | |
| messageElement.appendChild(textElement); | |
| chatMessages.appendChild(messageElement); | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| </script> | |
| </body> | |
| </html> |