// ========================================== // Chat Switchboard - Main Application // ========================================== function init() { console.log('🔀 Chat Switchboard initializing...'); loadSettings(); loadChats(); loadModels(); initializeEventListeners(); updateQuickModelSelector(); renderChatHistory(); console.log('✅ Chat Switchboard ready'); } function initializeEventListeners() { // Settings modal document.getElementById('settingsBtn').addEventListener('click', openSettings); document.getElementById('configureBtn').addEventListener('click', openSettings); document.getElementById('closeModalBtn').addEventListener('click', closeSettings); document.getElementById('cancelBtn').addEventListener('click', closeSettings); document.getElementById('saveBtn').addEventListener('click', handleSaveSettings); document.getElementById('fetchModelsBtn').addEventListener('click', () => fetchModels(true)); // Chat controls document.getElementById('newChatBtn').addEventListener('click', newChat); document.getElementById('sendBtn').addEventListener('click', sendMessage); document.getElementById('stopBtn').addEventListener('click', stopGeneration); document.getElementById('regenerateBtn').addEventListener('click', regenerateResponse); document.getElementById('toggleSidebarBtn').addEventListener('click', toggleSidebar); document.getElementById('quickFetchBtn').addEventListener('click', () => fetchModels(false)); // Quick model selector document.getElementById('quickModel').addEventListener('change', function() { if (this.value) { State.settings.model = this.value; saveSettings(); } }); // Export dropdown document.getElementById('exportBtn').addEventListener('click', function(e) { e.stopPropagation(); document.getElementById('exportDropdown').classList.toggle('show'); }); document.addEventListener('click', function() { document.getElementById('exportDropdown').classList.remove('show'); }); // Message input const messageInput = document.getElementById('messageInput'); messageInput.addEventListener('keydown', handleKeyDown); messageInput.addEventListener('input', function() { this.style.height = 'auto'; this.style.height = Math.min(this.scrollHeight, 200) + 'px'; }); // Settings modal model sync document.getElementById('model').addEventListener('change', function() { if (this.value) document.getElementById('modelCustom').value = ''; }); document.getElementById('modelCustom').addEventListener('input', function() { if (this.value) document.getElementById('model').value = ''; }); // Close modal on overlay click document.getElementById('settingsModal').addEventListener('click', function(e) { if (e.target === this) closeSettings(); }); // Global keyboard shortcuts document.addEventListener('keydown', function(e) { if (e.ctrlKey && e.key === ',') { e.preventDefault(); openSettings(); } if (e.ctrlKey && e.key === 'b') { e.preventDefault(); toggleSidebar(); } if (e.key === 'Escape') { if (State.isGenerating) { stopGeneration(); } else if (document.getElementById('settingsModal').classList.contains('active')) { closeSettings(); } } }); } function handleKeyDown(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } } function handleSaveSettings() { State.settings.apiEndpoint = document.getElementById('apiEndpoint').value.trim(); State.settings.apiKey = document.getElementById('apiKey').value.trim(); const modelCustom = document.getElementById('modelCustom').value.trim(); const modelSelect = document.getElementById('model').value; State.settings.model = modelCustom || modelSelect || 'gpt-3.5-turbo'; State.settings.stream = document.getElementById('streamResponse').checked; State.settings.saveHistory = document.getElementById('saveHistory').checked; State.settings.showThinking = document.getElementById('showThinking').checked; State.settings.systemPrompt = document.getElementById('systemPrompt').value.trim(); State.settings.maxTokens = parseInt(document.getElementById('maxTokens').value) || 4096; State.settings.temperature = parseFloat(document.getElementById('temperature').value) || 0.7; State.settings.topP = parseFloat(document.getElementById('topP').value) || 1; State.settings.presencePenalty = parseFloat(document.getElementById('presencePenalty').value) || 0; saveSettings(); updateQuickModelSelector(); closeSettings(); showToast('✅ Settings saved', 'success'); } function newChat() { State.currentChatId = null; document.getElementById('chatMessages').innerHTML = `

Start a Conversation

Type a message below to begin

`; document.getElementById('regenerateBtn').style.display = 'none'; renderChatHistory(); document.getElementById('messageInput').focus(); } function loadChat(chatId) { const chat = getChat(chatId); if (chat) { State.currentChatId = chatId; if (chat.model) { State.settings.model = chat.model; updateQuickModelSelector(); } renderMessages(chat.messages); renderChatHistory(); updateRegenerateButton(chat.messages); } } function handleDeleteChat(chatId, event) { event.stopPropagation(); if (confirm('Delete this chat?')) { deleteChat(chatId); if (State.currentChatId === chatId) { newChat(); } renderChatHistory(); showToast('🗑️ Chat deleted', 'success'); } } async function sendMessage() { const input = document.getElementById('messageInput'); const message = input.value.trim(); if (!message || State.isGenerating) return; if (!State.settings.apiEndpoint || !State.settings.apiKey) { showToast('⚠️ Configure API settings first', 'warning'); openSettings(); return; } input.value = ''; input.style.height = 'auto'; let messages = []; if (State.settings.systemPrompt) { messages.push({ role: 'system', content: State.settings.systemPrompt }); } if (State.currentChatId) { const chat = getChat(State.currentChatId); if (chat) messages = [...chat.messages]; } messages.push({ role: 'user', content: message, timestamp: new Date().toISOString() }); if (!State.currentChatId) { const title = message.substring(0, 50) + (message.length > 50 ? '...' : ''); const chat = createChat(title, messages); State.currentChatId = chat.id; } else { updateChat(State.currentChatId, { messages }); } renderMessages(messages); renderChatHistory(); await sendApiRequest(messages); } async function regenerateResponse() { if (State.isGenerating || !State.currentChatId) return; const chat = getChat(State.currentChatId); if (!chat || chat.messages.length === 0) return; // Remove last assistant message(s) while (chat.messages.length > 0 && chat.messages[chat.messages.length - 1].role === 'assistant') { chat.messages.pop(); } if (chat.messages.length === 0) return; updateChat(State.currentChatId, { messages: chat.messages }); renderMessages(chat.messages); await sendApiRequest(chat.messages); } // Initialize on DOM ready document.addEventListener('DOMContentLoaded', init);