mhndayesh's picture
Upload app.js
10ad34e verified
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' ? '<i class="fa-solid fa-robot"></i>' : '<i class="fa-solid fa-user"></i>';
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', `<p>${userText}</p>`);
conversation.push({ role: "user", content: userText });
// Show typing
const typingMsg = appendBubble('assistant', '<div class="typing-indicator">Connecting to Backend...<br><small><i>Injecting context and pinging OpenRouter</i></small></div>');
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 = `<span style="color: #ef4444;">Connection failed: ${err.message}</span>`;
// Remove the failed user message from internal state
conversation.pop();
}
if (input.value.trim() !== '') sendBtn.disabled = false;
});