📜
settings_copy2.js
Back
📝 Javascript ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
// settings.js - Settings Management (function () { console.log("[settings] Loading Settings interface..."); // --- Model Configuration --- const MODEL_CONFIG = { 'grok-code-fast-1': { provider: 'xai', name: 'Grok Code Fast 1', icon: 'Robot', color: '#8b5cf6' }, 'deepseek-chat': { provider: 'deepseek', name: 'DeepSeek Chat', icon: 'Brain', color: '#3b82f6' }, 'deepseek-reasoner': { provider: 'deepseek', name: 'DeepSeek Reasoner',icon: 'Brain', color: '#3b82f6' }, 'gpt-4o': { provider: 'openai', name: 'GPT-4o', icon: 'Star', color: '#10b981' }, 'gpt-4o-mini': { provider: 'openai', name: 'GPT-4o Mini', icon: 'Star', color: '#10b981' }, 'grok-3': { provider: 'xai', name: 'Grok 3', icon: 'Robot', color: '#8b5cf6' }, /* === CLAUDE MODELS (one of each) === */ 'claude-sonnet-4-5': { provider: 'anthropic', name: 'Claude Sonnet 4.5', icon: 'Feather', color: '#fbbf24' }, 'claude-haiku-4-5': { provider: 'anthropic', name: 'Claude Haiku 4.5', icon: 'Zap', color: '#38bdf8' }, 'claude-opus-4-1': { provider: 'anthropic', name: 'Claude Opus 4.1', icon: 'Crown', color: '#ef4444' } }; const API_ENDPOINT = 'api.php'; // --- Default prompts (fallback if .txt files fail) --- const DEFAULT_PROMPTS = { chat: 'You are a helpful AI assistant for web development.', snippets: 'You are an expert at writing small, focused code snippets. Provide concise, working code examples.', fullCode: 'You are an expert full-stack developer. Provide complete, production-ready code solutions.' }; // --- Load a .txt file --- async function loadPromptFile(filename) { try { const resp = await fetch(filename + "?v=" + Date.now()); if (!resp.ok) throw new Error(); return (await resp.text()).trim(); } catch (e) { console.warn(`[settings] Failed to load ${filename}`); return null; } } // --- Load prompts from .txt files if not in localStorage --- async function loadPromptsFromFiles() { const [chat, snippets, fullCode] = await Promise.all([ loadPromptFile('chat.txt'), loadPromptFile('snippet.txt'), loadPromptFile('full.txt') ]); return { chat: chat || DEFAULT_PROMPTS.chat, snippets: snippets || DEFAULT_PROMPTS.snippets, fullCode: fullCode || DEFAULT_PROMPTS.fullCode }; } // --- Load settings from localStorage, fallback to .txt files --- let settings = { defaultModel: localStorage.getItem('settings_defaultModel') || 'grok-code-fast-1', maxTokens: parseInt(localStorage.getItem('settings_maxTokens')) || 2000, temperature: parseFloat(localStorage.getItem('settings_temperature')) || 0.7, chatPrompt: localStorage.getItem('settings_chatPrompt'), snippetsPrompt: localStorage.getItem('settings_snippetsPrompt'), fullCodePrompt: localStorage.getItem('settings_fullCodePrompt'), responseMode: localStorage.getItem('settings_responseMode') || 'normal', currentMode: localStorage.getItem('settings_currentMode') || 'chat' }; // Load from .txt if any prompt is missing if (!settings.chatPrompt || !settings.snippetsPrompt || !settings.fullCodePrompt) { (async () => { const filePrompts = await loadPromptsFromFiles(); settings.chatPrompt = settings.chatPrompt || filePrompts.chat; settings.snippetsPrompt = settings.snippetsPrompt || filePrompts.snippets; settings.fullCodePrompt = settings.fullCodePrompt || filePrompts.fullCode; console.log("[settings] Loaded default prompts from .txt files"); })(); } // --- Save settings to localStorage --- function saveSettings() { localStorage.setItem('settings_defaultModel', settings.defaultModel); localStorage.setItem('settings_maxTokens', settings.maxTokens); localStorage.setItem('settings_temperature', settings.temperature); localStorage.setItem('settings_chatPrompt', settings.chatPrompt); localStorage.setItem('settings_snippetsPrompt', settings.snippetsPrompt); localStorage.setItem('settings_fullCodePrompt', settings.fullCodePrompt); localStorage.setItem('settings_responseMode', settings.responseMode); localStorage.setItem('settings_currentMode', settings.currentMode); console.log('[settings] Settings saved:', settings); window.dispatchEvent(new CustomEvent('settingsUpdated', { detail: settings })); } // --- Reset prompts to .txt files --- async function resetToDefaultPrompts() { const filePrompts = await loadPromptsFromFiles(); settings.chatPrompt = filePrompts.chat; settings.snippetsPrompt = filePrompts.snippets; settings.fullCodePrompt = filePrompts.fullCode; localStorage.removeItem('settings_chatPrompt'); localStorage.removeItem('settings_snippetsPrompt'); localStorage.removeItem('settings_fullCodePrompt'); saveSettings(); return filePrompts; } // --- Settings Slide Configuration --- const settingsSlide = { title: 'Settings', html: ` <div style="height: 100%; overflow-y: auto; padding: 20px; background: #0a0a0a;"> <h2 style="color: #fff; font-size: 24px; margin-bottom: 24px; font-weight: 700;">Settings</h2> <!-- AI Configuration Section --> <div style="background: #1a1a1a; border: 2px solid #2a2a2a; border-radius: 8px; padding: 20px; margin-bottom: 20px;"> <h3 style="color: #fff; font-size: 18px; margin-bottom: 16px; font-weight: 600;">AI Configuration</h3> <div style="margin-bottom: 20px;"> <label style="display: block; color: #888; font-size: 13px; font-weight: 600; margin-bottom: 8px;">Default AI Model:</label> <select id="settingsDefaultModel" style="width: 100%; padding: 10px 12px; background: #2a2a2a; border: 1px solid #3a3a3a; border-radius: 4px; color: #e0e0e0; font-size: 14px; font-family: monospace; cursor: pointer; outline: none;"> <option value="grok-code-fast-1">Grok Code Fast 1</option> <option value="deepseek-chat">DeepSeek Chat</option> <option value="deepseek-reasoner">DeepSeek Reasoner</option> <option value="gpt-4o">GPT-4o</option> <option value="gpt-4o-mini">GPT-4o Mini</option> <option value="grok-3">Grok 3</option> <option value="claude-sonnet-4-5">Claude Sonnet 4.5</option> <option value="claude-haiku-4-5">Claude Haiku 4.5</option> <option value="claude-opus-4-1">Claude Opus 4.1</option> </select> </div> <div style="margin-bottom: 20px;"> <label style="display: block; color: #888; font-size: 13px; font-weight: 600; margin-bottom: 8px;">Max Tokens: <span id="maxTokensValue" style="color: #16a34a;">2000</span></label> <input type="range" id="settingsMaxTokens" min="500" max="8000" step="100" value="2000" style="width: 100%; cursor: pointer;" /> <div style="display: flex; justify-content: space-between; color: #666; font-size: 11px; margin-top: 4px;"> <span>500</span> <span>8000</span> </div> </div> <div style="margin-bottom: 20px;"> <label style="display: block; color: #888; font-size: 13px; font-weight: 600; margin-bottom: 8px;">Temperature: <span id="temperatureValue" style="color: #16a34a;">0.7</span></label> <input type="range" id="settingsTemperature" min="0" max="2" step="0.1" value="0.7" style="width: 100%; cursor: pointer;" /> <div style="display: flex; justify-content: space-between; color: #666; font-size: 11px; margin-top: 4px;"> <span>0.0 (Focused)</span> <span>2.0 (Creative)</span> </div> </div> <button id="saveSettingsBtn" style="width: 100%; padding: 12px; background: #16a34a; border: 1px solid #15803d; border-radius: 4px; color: #fff; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.2s;">Save Settings</button> </div> <!-- System Prompts Section --> <div style="background: #1a1a1a; border: 2px solid #2a2a2a; border-radius: 8px; padding: 20px; margin-bottom: 20px;"> <h3 style="color: #fff; font-size: 18px; margin-bottom: 16px; font-weight: 600;">System Prompts & Mode</h3> <div style="margin-bottom: 20px;"> <label style="display: block; color: #888; font-size: 13px; font-weight: 600; margin-bottom: 8px;">Active Mode:</label> <select id="settingsCurrentMode" style="width: 100%; padding: 10px 12px; background: #2a2a2a; border: 1px solid #3a3a3a; border-radius: 4px; color: #e0e0e0; font-size: 14px; font-family: monospace; cursor: pointer; outline: none;"> <option value="chat">Chat Mode</option> <option value="snippets">Snippets Mode</option> <option value="fullcode">Full Code Mode</option> </select> <div style="margin-top: 8px; padding: 8px 12px; background: rgba(139, 92, 246, 0.1); border: 1px solid #8b5cf6; border-radius: 4px; color: #c4b5fd; font-size: 11px; line-height: 1.4;"> This determines which system prompt is used for your conversations. </div> </div> <div style="margin-bottom: 20px;"> <label style="display: block; color: #888; font-size: 13px; font-weight: 600; margin-bottom: 8px;">Chat Mode Prompt:</label> <textarea id="settingsChatPrompt" placeholder="System prompt for general chat..." style="width: 100%; min-height: 80px; padding: 10px 12px; background: #2a2a2a; border: 1px solid #3a3a3a; border-radius: 4px; color: #e0e0e0; font-size: 13px; font-family: 'Segoe UI', sans-serif; resize: vertical; outline: none;"></textarea> </div> <div style="margin-bottom: 20px;"> <label style="display: block; color: #888; font-size: 13px; font-weight: 600; margin-bottom: 8px;">Snippets Mode Prompt:</label> <textarea id="settingsSnippetsPrompt" placeholder="System prompt for code snippets..." style="width: 100%; min-height: 80px; padding: 10px 12px; background: #2a2a2a; border: 1px solid #3a3a3a; border-radius: 4px; color: #e0e0e0; font-size: 13px; font-family: 'Segoe UI', sans-serif; resize: vertical; outline: none;"></textarea> </div> <div style="margin-bottom: 20px;"> <label style="display: block; color: #888; font-size: 13px; font-weight: 600; margin-bottom: 8px;">Full Code Mode Prompt:</label> <textarea id="settingsFullCodePrompt" placeholder="System prompt for full code solutions..." style="width: 100%; min-height: 80px; padding: 10px 12px; background: #2a2a2a; border: 1px solid #3a3a3a; border-radius: 4px; color: #e0e0e0; font-size: 13px; font-family: 'Segoe UI', sans-serif; resize: vertical; outline: none;"></textarea> </div> <div style="display: flex; gap: 10px; margin-bottom: 0;"> <button id="resetPromptsBtn" style="flex: 1; padding: 10px; background: #dc2626; border: 1px solid #b91c1c; border-radius: 4px; color: #fff; font-size: 13px; font-weight: 600; cursor: pointer;">Return to Default</button> <select id="settingsResponseMode" style="flex: 1; padding: 10px 12px; background: #2a2a2a; border: 1px solid #3a3a3a; border-radius: 4px; color: #e0e0e0; font-size: 14px; font-family: monospace; cursor: pointer; outline: none;"> <option value="normal">Normal (Formatted response)</option> <option value="raw">Raw (Plain text only)</option> </select> </div> <div style="margin-top: 8px; padding: 8px 12px; background: rgba(59, 130, 246, 0.1); border: 1px solid #3b82f6; border-radius: 4px; color: #93c5fd; font-size: 11px; line-height: 1.4;"> <strong>Normal:</strong> AI provides explanations with code.<br> <strong>Raw:</strong> AI returns only code without commentary. </div> </div> <!-- Model Information --> <div style="background: #1a1a1a; border: 2px solid #2a2a2a; border-radius: 8px; padding: 20px;"> <h3 style="color: #fff; font-size: 18px; margin-bottom: 16px; font-weight: 600;">Model Information</h3> <div id="modelInfoContainer" style="font-size: 13px; line-height: 1.6;"></div> </div> </div> `, onRender(el) { console.log('[settings] Rendering settings interface'); const defaultModelSelect = el.querySelector('#settingsDefaultModel'); const maxTokensSlider = el.querySelector('#settingsMaxTokens'); const maxTokensValue = el.querySelector('#maxTokensValue'); const temperatureSlider = el.querySelector('#settingsTemperature'); const temperatureValue = el.querySelector('#temperatureValue'); const chatPrompt = el.querySelector('#settingsChatPrompt'); const snippetsPrompt = el.querySelector('#settingsSnippetsPrompt'); const fullCodePrompt = el.querySelector('#settingsFullCodePrompt'); const responseMode = el.querySelector('#settingsResponseMode'); const currentMode = el.querySelector('#settingsCurrentMode'); const saveBtn = el.querySelector('#saveSettingsBtn'); const resetBtn = el.querySelector('#resetPromptsBtn'); const modelInfoContainer = el.querySelector('#modelInfoContainer'); // Populate current values defaultModelSelect.value = settings.defaultModel; maxTokensSlider.value = settings.maxTokens; maxTokensValue.textContent = settings.maxTokens; temperatureSlider.value = settings.temperature; temperatureValue.textContent = settings.temperature.toFixed(1); chatPrompt.value = settings.chatPrompt; snippetsPrompt.value = settings.snippetsPrompt; fullCodePrompt.value = settings.fullCodePrompt; responseMode.value = settings.responseMode; currentMode.value = settings.currentMode; // Live updates maxTokensSlider.addEventListener('input', () => { maxTokensValue.textContent = maxTokensSlider.value; }); temperatureSlider.addEventListener('input', () => { temperatureValue.textContent = parseFloat(temperatureSlider.value).toFixed(1); }); // Model info function updateModelInfo() { const modelKey = defaultModelSelect.value; const model = MODEL_CONFIG[modelKey]; if (!model) return; const r = parseInt(model.color.slice(1,3), 16); const g = parseInt(model.color.slice(3,5), 16); const b = parseInt(model.color.slice(5,7), 16); modelInfoContainer.innerHTML = ` <div style="padding: 12px; background: rgba(${r}, ${g}, ${b}, 0.1); border: 1px solid ${model.color}; border-radius: 6px; margin-bottom: 12px;"> <div style="font-size: 16px; margin-bottom: 8px;">${model.icon} <strong style="color: #fff;">${model.name}</strong></div> <div style="color: #888;">Provider: <span style="color: #e0e0e0; font-family: monospace;">${model.provider}</span></div> </div> <div style="color: #666; font-size: 12px; line-height: 1.6;"> <p style="margin-bottom: 8px;"><strong style="color: #888;">Max Tokens:</strong> Controls the maximum length of the response.</p> <p style="margin-bottom: 8px;"><strong style="color: #888;">Temperature:</strong> Controls creativity (0 = focused, 2 = creative).</p> </div> `; } defaultModelSelect.addEventListener('change', updateModelInfo); updateModelInfo(); // Save saveBtn.addEventListener('click', () => { settings.defaultModel = defaultModelSelect.value; settings.maxTokens = parseInt(maxTokensSlider.value); settings.temperature = parseFloat(temperatureSlider.value); settings.chatPrompt = chatPrompt.value.trim(); settings.snippetsPrompt = snippetsPrompt.value.trim(); settings.fullCodePrompt = fullCodePrompt.value.trim(); settings.responseMode = responseMode.value; settings.currentMode = currentMode.value; saveSettings(); saveBtn.textContent = 'Saved!'; saveBtn.style.background = '#15803d'; setTimeout(() => { saveBtn.textContent = 'Save Settings'; saveBtn.style.background = '#16a34a'; }, 1500); }); // Reset to .txt defaults resetBtn.addEventListener('click', async () => { if (!confirm("Restore all prompts from .txt files?")) return; resetBtn.disabled = true; resetBtn.textContent = "Loading..."; try { const filePrompts = await resetToDefaultPrompts(); chatPrompt.value = filePrompts.chat; snippetsPrompt.value = filePrompts.snippets; fullCodePrompt.value = filePrompts.fullCode; alert("Prompts restored!"); } catch (e) { alert("Failed to load defaults."); } finally { resetBtn.disabled = false; resetBtn.textContent = "Return to Default"; } }); // Hover saveBtn.addEventListener('mouseenter', () => { if (saveBtn.textContent === 'Save Settings') saveBtn.style.background = '#15803d'; }); saveBtn.addEventListener('mouseleave', () => { if (saveBtn.textContent === 'Save Settings') saveBtn.style.background = '#16a34a'; }); } }; // --- Expose Settings API --- window.Settings = { open: () => { if (window.AppOverlay) { window.AppOverlay.open([settingsSlide]); } else { console.error('[settings] AppOverlay not available'); } }, slide: settingsSlide, get: () => ({ ...settings }), getModelConfig: (modelKey) => MODEL_CONFIG[modelKey], getAllModels: () => MODEL_CONFIG, getApiEndpoint: () => API_ENDPOINT }; console.log('[settings] Settings interface loaded with settings:', settings); })();