const form = document.getElementById('chat-form'); const input = document.getElementById('user-input'); const sendBtn = document.getElementById('send-btn'); const chatHistory = document.getElementById('chat-history'); const apiKeyInput = document.getElementById('api-key'); const dot = document.getElementById('connection-dot'); const statusText = document.getElementById('connection-text'); let conversation = []; // Auto-adjust textarea height input.addEventListener('input', function () { this.style.height = 'auto'; this.style.height = (this.scrollHeight) + 'px'; if (this.value.trim() !== '' && apiKeyInput.value.trim() !== '') { sendBtn.disabled = false; } else { sendBtn.disabled = true; } }); input.addEventListener('keydown', function (e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); if (!sendBtn.disabled) form.dispatchEvent(new Event('submit')); } }); apiKeyInput.addEventListener('input', () => { if (apiKeyInput.value.trim().length > 10) { dot.className = 'dot online'; statusText.textContent = 'API Key Ready'; if (input.value.trim() !== '') sendBtn.disabled = false; } else { dot.className = 'dot offline'; statusText.textContent = 'Waiting for key...'; sendBtn.disabled = true; } }); function appendBubble(role, htmlContent) { const bubble = document.createElement('div'); bubble.className = `bubble ${role}`; const avatar = document.createElement('div'); avatar.className = 'avatar'; avatar.innerHTML = role === 'assistant' ? '' : ''; const msg = document.createElement('div'); msg.className = 'message'; msg.innerHTML = htmlContent; bubble.appendChild(avatar); bubble.appendChild(msg); chatHistory.appendChild(bubble); chatHistory.scrollTop = chatHistory.scrollHeight; return msg; } form.addEventListener('submit', async (e) => { e.preventDefault(); const userText = input.value.trim(); if (!userText) return; const apiKey = apiKeyInput.value.trim(); const llmModel = document.getElementById('llm-model').value.trim(); const embedModel = document.getElementById('embed-model').value.trim(); const endpoint = "https://prod-infinit-memory-production.up.railway.app/v1/chat/completions"; const username = document.getElementById('username').value.trim() || 'demo_user'; if (!apiKey) { alert("Please enter your OpenRouter API Key."); return; } // UI Update input.value = ''; input.style.height = 'auto'; sendBtn.disabled = true; appendBubble('user', `

${userText}

`); conversation.push({ role: "user", content: userText }); // Show typing const typingMsg = appendBubble('assistant', '
Connecting to Backend...
Injecting context and pinging OpenRouter
'); try { const payload = { model: llmModel, embed_model: embedModel, user: username, messages: conversation }; const response = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify(payload) }); if (!response.ok) { let errText = await response.text(); throw new Error(`Server Error (${response.status}): ${errText}`); } const data = await response.json(); const aiAnswer = data.choices[0].message.content; // Update conversation history conversation.push({ role: "assistant", content: aiAnswer }); // Parse markdown and show typingMsg.innerHTML = marked.parse(aiAnswer); } catch (err) { console.error(err); typingMsg.innerHTML = `Connection failed: ${err.message}`; // Remove the failed user message from internal state conversation.pop(); } if (input.value.trim() !== '') sendBtn.disabled = false; });