Spaces:
Running
Running
| // --- CONFIGURATION --- | |
| // Set this to your Railway URL | |
| let BACKEND_URL = "https://prod-infinit-memory-production.up.railway.app"; | |
| // Safety: Remove trailing slash if the user adds one | |
| if (BACKEND_URL.endsWith('/')) BACKEND_URL = BACKEND_URL.slice(0, -1); | |
| const chatContainer = document.getElementById('chat-container'); | |
| const userInput = document.getElementById('user-input'); | |
| const sendBtn = document.getElementById('send-btn'); | |
| const statsDisplay = document.getElementById('pipeline-stats'); | |
| // BYOK Elements | |
| const settingsToggle = document.getElementById('settings-toggle'); | |
| const settingsPanel = document.getElementById('settings-panel'); | |
| const apiKeyInput = document.getElementById('api-key-input'); | |
| const llmModelInput = document.getElementById('llm-model-input'); | |
| const embedModelInput = document.getElementById('embed-model-input'); | |
| // Load saved settings from localStorage | |
| apiKeyInput.value = localStorage.getItem('byok_api_key') || ''; | |
| llmModelInput.value = localStorage.getItem('byok_llm_model') || 'openai/gpt-4o-mini'; | |
| embedModelInput.value = localStorage.getItem('byok_embed_model') || 'qwen/qwen3-embedding-8b'; | |
| // Toggle Settings Panel | |
| settingsToggle.addEventListener('click', () => { | |
| settingsPanel.classList.toggle('active'); | |
| }); | |
| /** | |
| * Adds a message bubble to the chat container | |
| */ | |
| function addMessage(text, role) { | |
| // Remove welcome message if it exists | |
| const welcome = document.querySelector('.welcome-message'); | |
| if (welcome) welcome.remove(); | |
| const msgDiv = document.createElement('div'); | |
| msgDiv.classList.add('message', `${role}-message`); | |
| msgDiv.textContent = text; | |
| chatContainer.appendChild(msgDiv); | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| return msgDiv; | |
| } | |
| /** | |
| * Adds a visual typing indicator | |
| */ | |
| function addLoadingIndicator() { | |
| const loader = document.createElement('div'); | |
| loader.classList.add('message', 'bot-message', 'loading-msg'); | |
| loader.innerHTML = ` | |
| <div class="typing-indicator"> | |
| <span></span><span></span><span></span> | |
| </div> | |
| `; | |
| chatContainer.appendChild(loader); | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| return loader; | |
| } | |
| /** | |
| * Main function to send message and get BYOK response | |
| */ | |
| async function sendMessage() { | |
| const text = userInput.value.trim(); | |
| if (!text) return; | |
| // Persist settings to localStorage | |
| localStorage.setItem('byok_api_key', apiKeyInput.value); | |
| localStorage.setItem('byok_llm_model', llmModelInput.value); | |
| localStorage.setItem('byok_embed_model', embedModelInput.value); | |
| // Clear input and add user message | |
| userInput.value = ''; | |
| userInput.style.height = 'auto'; | |
| addMessage(text, 'user'); | |
| // Add loading indicator | |
| const loader = addLoadingIndicator(); | |
| try { | |
| const response = await fetch(`${BACKEND_URL}/chat`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ | |
| message: text, | |
| api_key: apiKeyInput.value || null, | |
| llm_model: llmModelInput.value || null, | |
| embed_model: embedModelInput.value || null | |
| }) | |
| }); | |
| const data = await response.json(); | |
| // Remove loader and add bot response | |
| loader.remove(); | |
| if (data.answer) { | |
| addMessage(data.answer, 'bot'); | |
| // Update performance stats | |
| const pipeTime = data.total_time ? data.total_time.toFixed(1) : '--'; | |
| const retTime = data.timings && data.timings.retrieval ? data.timings.retrieval.toFixed(2) : '--'; | |
| statsDisplay.textContent = `Pipeline: ${pipeTime}s | Retrieval: ${retTime}s`; | |
| } else { | |
| addMessage('Error: No response from engine.', 'bot'); | |
| } | |
| } catch (err) { | |
| if (loader) loader.remove(); | |
| addMessage(`Error: ${err.message}`, 'bot'); | |
| } | |
| } | |
| /** | |
| * Helper for suggestion buttons | |
| */ | |
| function useSuggestion(text) { | |
| userInput.value = text; | |
| sendMessage(); | |
| } | |
| // Event Listeners | |
| sendBtn.addEventListener('click', sendMessage); | |
| userInput.addEventListener('keydown', (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| // Auto-resize textarea as user types | |
| userInput.addEventListener('input', function () { | |
| this.style.height = 'auto'; | |
| this.style.height = (this.scrollHeight) + 'px'; | |
| }); |