// AI Chat Panel — DashCaddy AI Intent Router frontend (function() { let chatMessages = []; let chatHistory = []; function createChatPanel() { const existing = document.getElementById('ai-chat-panel'); if (existing) existing.remove(); const panel = document.createElement('div'); panel.id = 'ai-chat-panel'; panel.style.cssText = ` position: fixed; bottom: 80px; right: 20px; width: 400px; max-width: 95vw; height: 500px; max-height: 70vh; background: var(--bg-card, #1a1a2e); border: 1px solid var(--border, #333); border-radius: 12px; display: none; flex-direction: column; z-index: 9999; box-shadow: 0 8px 32px rgba(0,0,0,0.4); `; panel.innerHTML = `
🤖
AI Assistant
Pattern matching • No key needed
👋 Hi! I can help you deploy apps, diagnose issues, and manage your server. Try:
`; document.body.appendChild(panel); } function toggle() { let panel = document.getElementById('ai-chat-panel'); if (!panel) { createChatPanel(); panel = document.getElementById('ai-chat-panel'); } panel.style.display = panel.style.display === 'flex' ? 'none' : 'flex'; if (panel.style.display === 'flex') document.getElementById('ai-chat-input').focus(); } function addMessage(role, text, extra) { const container = document.getElementById('ai-chat-messages'); if (!container) return; const div = document.createElement('div'); const isUser = role === 'user'; div.style.cssText = isUser ? 'align-self:flex-end; background:rgba(99,102,241,0.15); border-radius:10px 10px 2px 10px; padding:10px 14px; max-width:85%; font-size:0.85rem;' : 'align-self:flex-start; background:rgba(255,255,255,0.05); border-radius:10px 10px 10px 2px; padding:10px 14px; max-width:85%; font-size:0.85rem;'; div.textContent = text; container.appendChild(div); // Extra content (recommendations, action buttons) if (extra) { const extraDiv = document.createElement('div'); extraDiv.style.cssText = 'align-self:flex-start; max-width:85%; margin-top:4px;'; if (extra.disclaimer) { const disc = document.createElement('div'); disc.style.cssText = 'font-size:0.7rem; color:var(--text-muted,#666); padding:6px 8px; line-height:1.4; margin-top:4px;'; disc.textContent = '⚠️ ' + extra.disclaimer; extraDiv.appendChild(disc); } if (extra.recommendations) { extra.recommendations.forEach(rec => { const btn = document.createElement('button'); btn.textContent = `📦 Deploy ${rec.app}`; btn.style.cssText = 'display:block; margin:4px 0; background:rgba(34,197,94,0.12); border:1px solid rgba(34,197,94,0.3); border-radius:8px; padding:8px 12px; cursor:pointer; font-size:0.8rem; color:#4ade80;'; btn.onclick = () => window.aiChat.send('Deploy ' + rec.app); extraDiv.appendChild(btn); }); } if (extra.appId) { const btn = document.createElement('button'); btn.textContent = `🚀 Deploy ${extra.appId}`; btn.style.cssText = 'display:block; margin:4px 0; background:rgba(34,197,94,0.12); border:1px solid rgba(34,197,94,0.3); border-radius:8px; padding:8px 12px; cursor:pointer; font-size:0.8rem; color:#4ade80;'; btn.onclick = () => window.aiChat.deploy(extra.appId); extraDiv.appendChild(btn); } if (extra.suggestions) { const list = document.createElement('div'); list.style.cssText = 'font-size:0.78rem; color:var(--text-muted,#888); padding:4px 0;'; list.innerHTML = extra.suggestions.map(s => '• ' + s).join('
'); extraDiv.appendChild(list); } if (extra.action === 'diagnose') { const btn = document.createElement('button'); btn.textContent = '🔍 Run Diagnostics'; btn.style.cssText = 'display:block; margin:4px 0; background:rgba(251,191,36,0.12); border:1px solid rgba(251,191,36,0.3); border-radius:8px; padding:8px 12px; cursor:pointer; font-size:0.8rem; color:#fbbf24;'; btn.onclick = () => window.location.href = '#health'; extraDiv.appendChild(btn); } if (extra.action === 'backup') { const btn = document.createElement('button'); btn.textContent = '💾 Create Backup'; btn.style.cssText = 'display:block; margin:4px 0; background:rgba(99,102,241,0.12); border:1px solid rgba(99,102,241,0.3); border-radius:8px; padding:8px 12px; cursor:pointer; font-size:0.8rem; color:#a5b4fc;'; btn.onclick = () => { if (window.createBackup) window.createBackup(); }; extraDiv.appendChild(btn); } container.appendChild(extraDiv); } container.scrollTop = container.scrollHeight; } async function send(prefilled) { const input = document.getElementById('ai-chat-input'); const message = prefilled || input.value.trim(); if (!message) return; input.value = ''; addMessage('user', message); // Typing indicator const container = document.getElementById('ai-chat-messages'); const typing = document.createElement('div'); typing.id = 'ai-typing'; typing.style.cssText = 'align-self:flex-start; color:var(--text-muted,#666); font-size:0.8rem; padding:8px 14px;'; typing.textContent = '🤖 Thinking...'; container.appendChild(typing); container.scrollTop = container.scrollHeight; try { const res = await secureFetch('/api/v1/ai/intent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message, context: {} }) }); const data = await res.json(); typing.remove(); if (data.success !== false && data.data) { const r = data.data; const response = r.response || {}; addMessage('ai', response.message || r.response?.message || 'Action: ' + (r.action || r.intent), response); } else { addMessage('ai', data.error || 'Sorry, something went wrong.'); } } catch (e) { typing.remove(); addMessage('ai', 'Connection error: ' + e.message); } } async function deploy(appId) { addMessage('user', 'Deploy ' + appId); addMessage('ai', `Launching ${appId} from the catalog...`); // Trigger the app selector with this app if (window.openAppSelector) { window.openAppSelector(appId); } else { addMessage('ai', `Search for ${appId} in the App Catalog to deploy it.`); } } window.aiChat = { send, deploy, toggle }; window.toggleAIChat = toggle; })();