// Main application script document.addEventListener('DOMContentLoaded', function() { initializeApp(); }); function initializeApp() { // Feather icons - initialize after components load setTimeout(() => { if (typeof feather !== 'undefined') { feather.replace(); } }, 100); // API Type switcher const apiTypeSelect = document.getElementById('apiType'); if (apiTypeSelect) { const apiKeyField = document.getElementById('apiKeyField'); const apiUrlField = document.getElementById('apiUrlField'); const modelField = document.getElementById('modelField'); apiTypeSelect.addEventListener('change', function() { // Reset all fields to hidden first apiKeyField.classList.add('hidden'); apiUrlField.classList.add('hidden'); modelField.classList.add('hidden'); // Show fields based on selection if (this.value === 'CUSTOM') { // For custom API, show all fields apiKeyField.classList.remove('hidden'); apiUrlField.classList.remove('hidden'); modelField.classList.remove('hidden'); } else if (this.value === 'MODELAPI_KEY') { apiKeyField.classList.remove('hidden'); modelField.classList.remove('hidden'); } else if (this.value === 'CUSTOM_API_URL') { apiUrlField.classList.remove('hidden'); modelField.classList.remove('hidden'); } }); } // Character upload preview const charUpload = document.getElementById('charUpload'); if (charUpload) { const charPreview = document.getElementById('charPreview'); const charAvatar = document.getElementById('charAvatar'); const charName = document.getElementById('charName'); const charVersion = document.getElementById('charVersion'); charUpload.addEventListener('change', function(e) { const file = e.target.files[0]; if (!file) return; const fileName = file.name; const isPNG = fileName.endsWith('.png'); const isJSON = fileName.endsWith('.json'); if (!isPNG && !isJSON) { alert('Please upload a PNG or JSON character card.'); return; } if (isPNG) { const version = fileName.includes('v3') ? 'v3' : 'v2'; charName.textContent = fileName.replace('.png', '').replace('_v2', '').replace('_v3', ''); charVersion.textContent = `Chara Card ${version}`; } else if (isJSON) { const reader = new FileReader(); reader.onload = function(event) { try { const jsonData = JSON.parse(event.target.result); charName.textContent = jsonData.data?.name || jsonData.name || 'Unnamed Character'; charVersion.textContent = `JSON Character`; } catch (error) { console.error('Error parsing JSON:', error); charName.textContent = 'Invalid JSON'; charVersion.textContent = 'Error'; } }; reader.readAsText(file); } // Set random avatar for preview const seed = Math.floor(Math.random() * 100) + 1; charAvatar.src = `http://static.photos/abstract/200x200/${seed}`; charPreview.classList.remove('hidden'); }); } // Save system prompt const savePromptBtn = document.getElementById('savePrompt'); if (savePromptBtn) { const systemPromptText = document.getElementById('systemPrompt'); savePromptBtn.addEventListener('click', function() { const prompt = systemPromptText.value.trim(); if (prompt) { localStorage.setItem('systemPrompt', prompt); showToast('System prompt saved!', 'success'); } else { localStorage.removeItem('systemPrompt'); showToast('System prompt cleared.', 'info'); } }); // Load saved prompt const savedPrompt = localStorage.getItem('systemPrompt'); if (savedPrompt) { systemPromptText.value = savedPrompt; } } // Save persona const savePersonaBtn = document.getElementById('savePersona'); if (savePersonaBtn) { const personaName = document.getElementById('personaName'); const personaDesc = document.getElementById('personaDesc'); const personaAvatar = document.getElementById('personaAvatar'); savePersonaBtn.addEventListener('click', function() { const persona = { name: personaName.value.trim(), description: personaDesc.value.trim(), avatar: null }; if (personaAvatar.files[0]) { const reader = new FileReader(); reader.onload = function(e) { persona.avatar = e.target.result; savePersonaData(persona); }; reader.readAsDataURL(personaAvatar.files[0]); } else { savePersonaData(persona); } }); function savePersonaData(persona) { localStorage.setItem('userPersona', JSON.stringify(persona)); showToast('Persona saved successfully!', 'success'); } // Load saved persona const savedPersona = localStorage.getItem('userPersona'); if (savedPersona) { try { const persona = JSON.parse(savedPersona); personaName.value = persona.name || ''; personaDesc.value = persona.description || ''; } catch (e) { console.error('Error loading persona:', e); } } } // Save LLM config const saveConfigBtn = document.getElementById('saveConfig'); if (saveConfigBtn) { const topPInput = document.getElementById('topP'); const topKInput = document.getElementById('topK'); const maxTokensInput = document.getElementById('maxTokens'); const contextSizeInput = document.getElementById('contextSize'); const apiKeyInput = document.getElementById('apiKey'); const apiUrlInput = document.getElementById('apiUrl'); const modelInput = document.getElementById('model'); saveConfigBtn.addEventListener('click', function() { const config = { apiType: apiTypeSelect.value, apiKey: apiKeyInput.value, apiUrl: apiUrlInput.value, model: modelInput.value, topP: parseFloat(topPInput.value), topK: parseInt(topKInput.value), maxTokens: parseInt(maxTokensInput.value), contextSize: parseInt(contextSizeInput.value), timestamp: new Date().toISOString() }; localStorage.setItem('llmConfig', JSON.stringify(config)); showToast('LLM configuration applied!', 'success'); }); // Load saved config const savedConfig = localStorage.getItem('llmConfig'); if (savedConfig) { try { const config = JSON.parse(savedConfig); apiTypeSelect.value = config.apiType || 'CUSTOM'; apiKeyInput.value = config.apiKey || ''; apiUrlInput.value = config.apiUrl || ''; modelInput.value = config.model || ''; topPInput.value = config.topP || 0.9; topKInput.value = config.topK || 40; maxTokensInput.value = config.maxTokens || 2048; contextSizeInput.value = config.contextSize || 12000; // Trigger change to show correct fields apiTypeSelect.dispatchEvent(new Event('change')); } catch (e) { console.error('Error loading config:', e); } } // Initialize API type display apiTypeSelect.dispatchEvent(new Event('change')); } } // Toast notification function showToast(message, type = 'info') { const toast = document.createElement('div'); toast.className = `fixed top-6 right-6 px-6 py-3 rounded-lg shadow-2xl z-50 transform transition-transform translate-x-full ${type === 'success' ? 'bg-green-800/90' : 'bg-blue-800/90'}`; toast.textContent = message; const icon = document.createElement('i'); icon.setAttribute('data-feather', type === 'success' ? 'check-circle' : 'info'); icon.className = 'inline mr-2'; toast.prepend(icon); document.body.appendChild(toast); feather.replace(); setTimeout(() => { toast.classList.remove('translate-x-full'); }, 10); setTimeout(() => { toast.classList.add('translate-x-full'); setTimeout(() => toast.remove(), 300); }, 3000); } // Export config for use in chat page window.getLLMConfig = function() { const config = localStorage.getItem('llmConfig'); return config ? JSON.parse(config) : null; }; window.getSystemPrompt = function() { return localStorage.getItem('systemPrompt') || ''; }; window.getUserPersona = function() { const persona = localStorage.getItem('userPersona'); return persona ? JSON.parse(persona) : null; };