document.addEventListener('DOMContentLoaded', () => { // DOM Elements const apiKeyInput = document.getElementById('api-key'); const toggleKeyBtn = document.getElementById('toggle-key'); const modelSelect = document.getElementById('model-select'); const temperatureSlider = document.getElementById('temperature'); const tempValue = document.getElementById('temp-value'); const startChatBtn = document.getElementById('start-chat'); const modelInfo = document.getElementById('model-info'); const chatContainer = document.getElementById('chat-container'); const userInput = document.getElementById('user-input'); const sendBtn = document.getElementById('send-btn'); const clearChatBtn = document.getElementById('clear-chat'); const themeToggle = document.getElementById('theme-toggle'); const themeIcon = document.getElementById('theme-icon'); // State let chatActive = false; let conversationHistory = []; let models = []; let selectedModel = null; let embeddedDocument = null; let embedApiKey = ''; let embedModel = null; // Initialize fetchModels(); setupEventListeners(); setupEmbedListeners(); // Functions function setupEventListeners() { // Toggle API key visibility toggleKeyBtn.addEventListener('click', () => { const type = apiKeyInput.getAttribute('type') === 'password' ? 'text' : 'password'; apiKeyInput.setAttribute('type', type); feather.replace(); }); // Temperature slider temperatureSlider.addEventListener('input', () => { tempValue.textContent = temperatureSlider.value; }); // Model selection modelSelect.addEventListener('change', () => { const modelId = modelSelect.value; selectedModel = models.find(m => m.id === modelId); updateModelInfo(); }); // Start chat button startChatBtn.addEventListener('click', startChat); // Send message sendBtn.addEventListener('click', sendMessage); userInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }); // Clear chat clearChatBtn.addEventListener('click', clearChat); // Theme toggle themeToggle.addEventListener('click', toggleTheme); } async function fetchModels() { try { const response = await fetch('https://openrouter.ai/api/v1/models'); const data = await response.json(); models = data.data || []; populateModelSelect(); } catch (error) { console.error('Error fetching models:', error); addSystemMessage('Failed to load models. Please try again later.'); } } function populateModelSelect() { modelSelect.innerHTML = ''; models.forEach(model => { const option = document.createElement('option'); option.value = model.id; option.textContent = `${model.name} (${model.id})`; modelSelect.appendChild(option); }); } function updateModelInfo() { if (!selectedModel) { modelInfo.innerHTML = 'Select a model to see details'; return; } modelInfo.innerHTML = `

${selectedModel.name}

${selectedModel.id}

${selectedModel.pricing ? `

${(selectedModel.pricing.completion * 1000).toFixed(4)} / 1K tokens

${(selectedModel.pricing.prompt * 1000).toFixed(4)} prompt

` : ''}

${selectedModel.description || 'No description available'}

Provider ${selectedModel.provider || 'Unknown'}
Context ${selectedModel.context_length ? selectedModel.context_length.toLocaleString() : 'Unknown'} tokens
${selectedModel.top_provider ? `
Top Provider ${selectedModel.top_provider.name}
` : ''} ${selectedModel.features ? `
Features ${Object.keys(selectedModel.features).filter(k => selectedModel.features[k]).join(', ')}
` : ''}
${selectedModel.pricing ? `

Pricing Details

Prompt: ${(selectedModel.pricing.prompt * 1000).toFixed(4)} / 1K tokens

Completion: ${(selectedModel.pricing.completion * 1000).toFixed(4)} / 1K tokens

${selectedModel.pricing.request ? `

Request: ${selectedModel.pricing.request} / call

` : ''}
` : ''} `; } function startChat() { const apiKey = apiKeyInput.value.trim(); const modelId = modelSelect.value; if (!apiKey) { addSystemMessage('Please enter your OpenRouter API key'); return; } if (!modelId) { addSystemMessage('Please select a model'); return; } chatActive = true; conversationHistory = []; userInput.disabled = false; sendBtn.disabled = false; startChatBtn.disabled = true; startChatBtn.classList.add('opacity-50', 'cursor-not-allowed'); addSystemMessage(`Chat started with ${selectedModel.name}. Ready to chat!`); } async function sendMessage() { const message = userInput.value.trim(); if (!message || !chatActive) return; // Add user message to chat addMessageToChat('user', message); userInput.value = ''; // Show loading indicator const loadingId = addLoadingIndicator(); try { const response = await fetch('https://openrouter.ai/api/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKeyInput.value.trim()}` }, body: JSON.stringify({ model: selectedModel.id, messages: [ ...conversationHistory, { role: 'user', content: message } ], temperature: parseFloat(temperatureSlider.value) }) }); if (!response.ok) { throw new Error(`API error: ${response.status}`); } const data = await response.json(); const aiResponse = data.choices[0].message.content; // Remove loading indicator and add AI response removeLoadingIndicator(loadingId); addMessageToChat('assistant', aiResponse); // Update conversation history conversationHistory.push( { role: 'user', content: message }, { role: 'assistant', content: aiResponse } ); } catch (error) { console.error('Error:', error); removeLoadingIndicator(loadingId); addSystemMessage(`Error: ${error.message}`); } } function addMessageToChat(role, content) { const messageDiv = document.createElement('div'); messageDiv.className = `chat-bubble ${role === 'user' ? 'user-bubble' : 'ai-bubble'} fade-in`; messageDiv.textContent = content; chatContainer.appendChild(messageDiv); chatContainer.scrollTop = chatContainer.scrollHeight; } function addSystemMessage(content) { const messageDiv = document.createElement('div'); messageDiv.className = 'text-center text-gray-400 text-sm py-2 fade-in'; messageDiv.textContent = content; chatContainer.appendChild(messageDiv); chatContainer.scrollTop = chatContainer.scrollHeight; } function addLoadingIndicator() { const id = `loading-${Date.now()}`; const loadingDiv = document.createElement('div'); loadingDiv.id = id; loadingDiv.className = 'chat-bubble ai-bubble fade-in'; const dots = document.createElement('div'); dots.className = 'loading-dots'; dots.innerHTML = ''; loadingDiv.appendChild(dots); chatContainer.appendChild(loadingDiv); chatContainer.scrollTop = chatContainer.scrollHeight; return id; } function removeLoadingIndicator(id) { const element = document.getElementById(id); if (element) { element.remove(); } } function clearChat() { if (!chatActive) return; conversationHistory = []; chatContainer.innerHTML = ''; addSystemMessage('Chat cleared. Ready for new messages.'); } function setupEmbedListeners() { document.addEventListener('process-document', (e) => { embeddedDocument = e.detail.content; // Here you would typically call your embedding API // For demo purposes, we'll just store the content addSystemMessage('Document ready for processing! Use commands like:'); addSystemMessage('"Summarize chapter 3" or "Rewrite paragraph 5 to be more formal"'); }); } function toggleTheme() { const html = document.documentElement; html.classList.toggle('dark'); if (html.classList.contains('dark')) { themeIcon.setAttribute('data-feather', 'moon'); } else { themeIcon.setAttribute('data-feather', 'sun'); } feather.replace(); } });