🏛️

Atlas AI

Authentification Souveraine — Accès Réservé

let isFirstQuestion = true; let currentLang = 'fr'; function setLanguage(lang) { currentLang = lang; const btnFr = document.getElementById('lang-btn-fr'); const btnEn = document.getElementById('lang-btn-en'); if (lang === 'en') { btnEn.style.background = 'rgba(99, 102, 241, 0.2)'; btnEn.style.border = '1px solid #6366f1'; btnEn.style.color = 'white'; btnFr.style.background = 'transparent'; btnFr.style.border = '1px solid transparent'; btnFr.style.color = 'var(--text-muted)'; } else { btnFr.style.background = 'rgba(99, 102, 241, 0.2)'; btnFr.style.border = '1px solid #6366f1'; btnFr.style.color = 'white'; btnEn.style.background = 'transparent'; btnEn.style.border = '1px solid transparent'; btnEn.style.color = 'var(--text-muted)'; } } async function doSearch(overrideQuery = null) { const inputElem = document.getElementById('query-input'); const q = (overrideQuery || inputElem.value).trim(); const stack = document.getElementById('stack-select').value; const thread = document.getElementById('chat-thread'); if (!q) return; if (isFirstQuestion) { document.getElementById('empty-state')?.remove(); isFirstQuestion = false; } if (!overrideQuery) { inputElem.value = ''; } // 1. Render User Message Card const userCard = document.createElement('div'); userCard.className = 'user-msg-card'; userCard.innerHTML = `
👤 Romain de Pescara
${escapeHtml(q)}
`; thread.appendChild(userCard); // 2. Render Loading State const loadingCard = document.createElement('div'); loadingCard.className = 'answer-card'; loadingCard.innerHTML = `
🤖
Atlas consulte la base OpenViking et rédige la réponse technique...
`; thread.appendChild(loadingCard); window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); try { const token = localStorage.getItem('atlas_token'); const headers = {}; if (token) headers['Authorization'] = `Bearer ${token}`; const resp = await fetch(`/api/search?q=${encodeURIComponent(q)}&stack=${encodeURIComponent(stack)}&lang=${encodeURIComponent(currentLang)}`, { headers }); const data = await resp.json(); // Remove loading card loadingCard.remove(); // 3. Render Sub-Agent Answer Card with Inline Follow-up Reply Box const ansCard = document.createElement('div'); ansCard.className = 'answer-card'; const subLabel = stack === 'all' ? 'général' : 'atlas-' + stack; const parsedAnswer = typeof marked !== 'undefined' ? marked.parse(data.answer) : escapeHtml(data.answer); let sourcesHtml = ''; if (data.results && data.results.length > 0) { sourcesHtml = `
📂 Sources OpenViking Consultées (${data.results.length}) :
${data.results.map(res => `
${res.uri || 'viking://resources/atlas/'} Pertinence : ${Math.round((res.score || 0.75) * 100)}%
${escapeHtml(res.content || '')}
`).join('')}
`; } ansCard.innerHTML = `

🛡️ Réponse d'Atlas — Sub-Agent [${subLabel}]

${parsedAnswer}
${sourcesHtml}
`; thread.appendChild(ansCard); window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); } catch (e) { loadingCard.innerHTML = `
Erreur lors de la réponse d'Atlas.
`; } } function sendReply(inputElem) { const q = inputElem.value.trim(); if (!q) return; inputElem.value = ''; doSearch(q); } function openNewSubagentModal() { document.getElementById('modal-subagent').style.display = 'flex'; } function closeNewSubagentModal() { document.getElementById('modal-subagent').style.display = 'none'; document.getElementById('subagent-status').innerText = ''; } async function createSubagent() { const name = document.getElementById('new-subagent-name').value.trim(); const url = document.getElementById('new-subagent-url').value.trim(); const statusDiv = document.getElementById('subagent-status'); if (!name || !url) { statusDiv.style.color = '#ef4444'; statusDiv.innerText = 'Veuillez remplir le nom et l\'URL.'; return; } statusDiv.style.color = '#3b82f6'; statusDiv.innerText = '⚡ Création du Sub-Agent et déclenchement de l\'ingestion OpenViking...'; try { const token = localStorage.getItem('atlas_token'); const headers = { 'Content-Type': 'application/json' }; if (token) headers['Authorization'] = `Bearer ${token}`; const resp = await fetch('/api/subagent/create', { method: 'POST', headers: headers, body: JSON.stringify({ name, url }) }); const res = await resp.json(); if (resp.ok) { statusDiv.style.color = '#10b981'; statusDiv.innerText = res.message || 'Sub-Agent créé avec succès !'; // Add to select const select = document.getElementById('stack-select'); const opt = document.createElement('option'); opt.value = name; opt.innerText = `atlas-${name}`; opt.selected = true; select.appendChild(opt); setTimeout(() => { closeNewSubagentModal(); }, 2000); } else { statusDiv.style.color = '#ef4444'; statusDiv.innerText = res.error || 'Erreur lors de la création.'; } } catch(e) { statusDiv.style.color = '#ef4444'; statusDiv.innerText = 'Erreur réseau lors de la création du Sub-Agent.'; } } async function loadCustomSubagents() { try { const token = localStorage.getItem('atlas_token'); const headers = {}; if (token) headers['Authorization'] = `Bearer ${token}`; const resp = await fetch('/api/subagents', { headers }); if (resp.ok) { const data = await resp.json(); const select = document.getElementById('stack-select'); (data.subagents || []).forEach(s => { if (!select.querySelector(`option[value="${s.name}"]`)) { const opt = document.createElement('option'); opt.value = s.name; opt.innerText = `atlas-${s.name}`; select.appendChild(opt); } }); } } catch(e) {} } async function checkAuth() { try { const token = localStorage.getItem('atlas_token'); const headers = {}; if (token) headers['Authorization'] = `Bearer ${token}`; const resp = await fetch('/api/me', { headers }); if (resp.ok) { const data = await resp.json(); if (data.authenticated && data.user) { document.getElementById('login-overlay').style.display = 'none'; document.getElementById('app-container').style.display = 'block'; document.getElementById('user-name-display').innerText = `👤 ${data.user.name || data.user.email}`; loadCustomSubagents(); return; } } } catch(e) {} document.getElementById('login-overlay').style.display = 'flex'; document.getElementById('app-container').style.display = 'none'; } async function doLogin() { const email = document.getElementById('login-email').value.trim(); const password = document.getElementById('login-password').value; const errorDiv = document.getElementById('login-error'); if (!email || !password) { errorDiv.innerText = 'Veuillez saisir votre email et mot de passe.'; return; } errorDiv.innerText = 'Connexion en cours...'; errorDiv.style.color = '#3b82f6'; try { const resp = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }); const data = await resp.json(); if (resp.ok && data.status === 'success' && data.token) { errorDiv.innerText = ''; localStorage.setItem('atlas_token', data.token); checkAuth(); } else { errorDiv.style.color = '#ef4444'; errorDiv.innerText = data.error || 'Identifiants incorrects.'; } } catch(e) { errorDiv.style.color = '#ef4444'; errorDiv.innerText = 'Erreur de connexion au serveur d\'authentification.'; } } const SUBAGENT_DESCRIPTIONS = { "all": "Recherche globale sur l'ensemble du patrimoine d'ingénierie d'Antigravity Lab.", "omniroute": "Gateway LLM & Routeur d'API IA multi-providers (MiniMax, Gemini, DeepSeek).", "openviking": "Base de données vectorielle & Mémoire sémantique souveraine.", "dify": "Plateforme d'orchestration de workflows & agents IA visuels.", "hermes": "Orchestrateur & Runtime d'agents d'ingénierie autonomes.", "openclaw": "Infrastructure Docker & conteneurs applicatifs sous Hostinger/Hetzner.", "wazuh": "Sécurité SIEM / XDR & Détection des menaces et failles en temps réel.", "caddy": "Reverse Proxy web, gestion du trafic HTTP/2 et certificats Let's Encrypt SSL.", "paperclip": "Plateforme de gestion de tâches et tickets agentiques.", "stalwart": "Serveur de messagerie souverain (emails, SPF/DKIM/DMARC 10/10).", "buzz": "Système de messagerie & triage déterministe inter-agents.", "openhuman": "Hub d'interaction mobile & appairage appareils (iOS/macOS).", "antigravity-ide": "IDE agentique & Runtime d'exécution Jarvis (skills, workflows, tools)." }; function updateSubagentRoleInfo() { const select = document.getElementById('stack-select'); const val = select.value; const desc = SUBAGENT_DESCRIPTIONS[val] || "Sub-Agent personnalisé et documentation ingérée."; const infoDiv = document.getElementById('subagent-role-info'); infoDiv.innerHTML = `💡 Rôle du Sub-Agent [atlas-${val}] : ${desc}`; } async function doLogout() { try { await fetch('/api/logout', { method: 'POST' }); } catch(e) {} checkAuth(); } checkAuth(); function escapeHtml(text) { return text.replace(/&/g, "&").replace(//g, ">"); }