931 lines
54 KiB
HTML
931 lines
54 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
|
<title>WEVIA Master AI</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root{--bg:#0a0a0f;--s1:#101018;--s2:#16161f;--s3:#1c1c28;--bd:rgba(255,255,255,.06);--tx:#e8e6f0;--dim:#8888aa;--dim2:#555570;--acc:#00e87b;--acc2:rgba(0,232,123,.08);--red:#ff4466;--blue:#4488ff;--yellow:#ffc800;--cyan:#00d4ff;--font:'Inter',system-ui,sans-serif;--mono:'JetBrains Mono',monospace;--r:12px;--maxw:820px}
|
|
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
|
|
body{background:var(--bg);color:var(--tx);font-family:var(--font);height:100dvh;display:flex;overflow:hidden}
|
|
::selection{background:var(--acc);color:#000}
|
|
|
|
.sidebar{width:260px;background:var(--s1);border-right:1px solid var(--bd);display:flex;flex-direction:column;flex-shrink:0;transition:transform .3s}
|
|
.sb-head{padding:16px 20px;border-bottom:1px solid var(--bd);display:flex;align-items:center;gap:10px}
|
|
.sb-logo{font-family:var(--mono);font-weight:600;font-size:15px;color:var(--acc);letter-spacing:.05em}
|
|
.sb-logo small{color:var(--dim2);font-weight:400;font-size:10px;display:block;margin-top:2px;letter-spacing:.02em}
|
|
.sb-new{margin-left:auto;width:32px;height:32px;border-radius:8px;border:1px solid var(--bd);background:transparent;color:var(--dim);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px;transition:all .2s}
|
|
.sb-new:hover{border-color:var(--acc);color:var(--acc)}
|
|
|
|
.sb-label{padding:14px 20px 6px;font-family:var(--mono);font-size:9px;text-transform:uppercase;letter-spacing:.14em;color:var(--dim2)}
|
|
.sb-nav{flex:1;overflow-y:auto;padding:4px 10px}
|
|
.sb-item{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:var(--r);cursor:pointer;font-size:13px;color:var(--dim);transition:all .15s;margin-bottom:1px}
|
|
.sb-item:hover{background:var(--s2);color:var(--tx)}
|
|
.sb-item .ico{font-size:13px;width:20px;text-align:center;flex-shrink:0;opacity:.7}
|
|
|
|
.sb-foot{padding:12px 20px;border-top:1px solid var(--bd);font-family:var(--mono);font-size:9px;color:var(--dim2);line-height:1.8}
|
|
.dot{display:inline-block;width:5px;height:5px;border-radius:50%;margin-right:4px;animation:pulse 2s ease infinite}
|
|
.dot.g{background:var(--acc)}
|
|
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
|
|
|
|
.main{flex:1;display:flex;flex-direction:column;min-width:0}
|
|
.top{height:44px;border-bottom:1px solid var(--bd);display:flex;align-items:center;padding:0 20px;gap:10px;flex-shrink:0;background:var(--s1)}
|
|
.top-title{font-weight:500;font-size:13px}
|
|
.pills{margin-left:auto;display:flex;gap:5px}
|
|
.pill{font-family:var(--mono);font-size:8px;padding:2px 7px;border-radius:20px;border:1px solid var(--bd);color:var(--dim2)}
|
|
.pill.live{border-color:var(--acc);color:var(--acc)}
|
|
.menu-btn{display:none;width:32px;height:32px;border:none;background:none;color:var(--dim);cursor:pointer;font-size:18px}
|
|
|
|
.chat{flex:1;overflow-y:auto;padding:24px 0;scroll-behavior:smooth}
|
|
.chat::-webkit-scrollbar{width:4px}
|
|
.chat::-webkit-scrollbar-thumb{background:var(--bd);border-radius:2px}
|
|
.ci{max-width:var(--maxw);margin:0 auto;padding:0 24px}
|
|
|
|
/* WELCOME */
|
|
.welcome{text-align:center;padding:100px 20px 40px}
|
|
.welcome h1{font-family:var(--mono);font-size:32px;color:var(--acc);font-weight:700;letter-spacing:.08em}
|
|
.welcome p{color:var(--dim);font-size:13px;margin-top:8px}
|
|
.welcome-cards{display:grid;grid-template-columns:1fr 1fr;gap:10px;max-width:500px;margin:40px auto 0}
|
|
.wcard{background:var(--s2);border:1px solid var(--bd);border-radius:var(--r);padding:16px;cursor:pointer;text-align:center;transition:all .2s}
|
|
.wcard:hover{border-color:rgba(255,255,255,.12);background:var(--s3);transform:translateY(-1px)}
|
|
.wcard h3{font-size:13px;font-weight:500;margin-bottom:4px;display:flex;align-items:center;gap:6px}
|
|
.wcard p{font-size:11px;color:var(--dim2);line-height:1.4}
|
|
|
|
/* MESSAGES */
|
|
.msg{margin-bottom:20px;animation:fadeIn .3s ease}
|
|
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
|
|
.msg.user{display:flex;justify-content:flex-end}
|
|
.msg.user .bubble{background:var(--s3);border:1px solid var(--bd);border-radius:var(--r) var(--r) 4px var(--r);padding:12px 16px;max-width:75%;font-size:14px;line-height:1.6}
|
|
.msg.ai{display:flex;gap:12px;align-items:flex-start}
|
|
.msg.ai .av{width:28px;height:28px;border-radius:8px;background:var(--acc);color:#000;display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:11px;font-weight:700;flex-shrink:0;margin-top:2px}
|
|
.msg.ai .body{flex:1;min-width:0}
|
|
.msg.ai .content{font-size:14px;line-height:1.7;color:var(--tx)}
|
|
.msg.ai .content p{margin-bottom:10px}
|
|
.msg.ai .content strong{color:#fff}
|
|
.msg.ai .content h3{font-size:15px;margin:16px 0 6px;color:#fff}
|
|
.msg.ai .content code{font-family:var(--mono);font-size:12px;background:var(--s3);padding:2px 5px;border-radius:4px;color:var(--cyan)}
|
|
.msg.ai .content pre{background:var(--s2);border:1px solid var(--bd);border-radius:var(--r);padding:14px;margin:10px 0;overflow-x:auto;position:relative}
|
|
.msg.ai .content pre code{background:none;padding:0;color:var(--tx);font-size:12px;line-height:1.6}
|
|
.msg.ai .content ul,.msg.ai .content ol{margin:8px 0;padding-left:20px}
|
|
.msg.ai .content li{margin-bottom:4px}
|
|
|
|
.copy-btn{position:absolute;top:8px;right:8px;font-family:var(--mono);font-size:9px;padding:3px 8px;border-radius:4px;border:1px solid var(--bd);background:var(--s3);color:var(--dim);cursor:pointer;transition:all .2s}
|
|
.copy-btn:hover{color:var(--acc);border-color:var(--acc)}
|
|
|
|
/* THINKING INDICATOR (Claude-like) */
|
|
.thinking{display:flex;gap:12px;align-items:flex-start;margin-bottom:16px;animation:fadeIn .3s ease}
|
|
.thinking .av{width:28px;height:28px;border-radius:8px;background:var(--acc);color:#000;display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:11px;font-weight:700;flex-shrink:0}
|
|
.think-box{flex:1}
|
|
.think-steps{display:flex;flex-direction:column;gap:6px}
|
|
.think-step{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dim);font-family:var(--mono);padding:6px 12px;background:var(--s2);border-radius:8px;border-left:2px solid var(--acc);animation:slideIn .3s ease}
|
|
@keyframes slideIn{from{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:none}}
|
|
.think-step .spinner{width:12px;height:12px;border:2px solid var(--bd);border-top-color:var(--acc);border-radius:50%;animation:spin .8s linear infinite}
|
|
@keyframes spin{to{transform:rotate(360deg)}}
|
|
.think-step.done .spinner{display:none}
|
|
.think-step.done::before{content:'✓';color:var(--acc);font-size:11px;font-weight:bold}
|
|
.think-step .label{flex:1}
|
|
.think-step .val{color:var(--dim2);font-size:10px}
|
|
|
|
/* META TAGS */
|
|
.meta{display:flex;flex-wrap:wrap;gap:4px;margin-top:10px}
|
|
.tag{font-family:var(--mono);font-size:9px;padding:2px 7px;border-radius:6px;border:1px solid var(--bd);color:var(--dim2)}
|
|
.tag.t0{border-color:var(--acc);color:var(--acc)}
|
|
.tag.t1{border-color:var(--blue);color:var(--blue)}
|
|
.tag.rag{border-color:var(--yellow);color:var(--yellow)}
|
|
|
|
/* INPUT */
|
|
.input-area{border-top:1px solid var(--bd);padding:12px 24px 16px;background:var(--s1)}
|
|
.input-wrap{max-width:var(--maxw);margin:0 auto;position:relative}
|
|
.input-box{display:flex;align-items:flex-end;background:var(--s2);border:1px solid var(--bd);border-radius:var(--r);padding:10px 52px 10px 16px;transition:border-color .2s}
|
|
.input-box:focus-within{border-color:rgba(255,255,255,.15)}
|
|
textarea{width:100%;background:none;border:none;color:var(--tx);font-family:var(--font);font-size:14px;resize:none;outline:none;line-height:1.5;max-height:160px}
|
|
textarea::placeholder{color:var(--dim2)}
|
|
.send-btn{position:absolute;right:14px;bottom:14px;width:34px;height:34px;border-radius:10px;background:var(--acc);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .15s}
|
|
.send-btn:hover{background:#00ff88;transform:scale(1.05)}
|
|
.send-btn:active{transform:scale(.95)}
|
|
.send-btn:disabled{opacity:.2;cursor:default;transform:none}
|
|
.send-btn svg{width:15px;height:15px;stroke:#000;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
|
|
.input-hint{max-width:var(--maxw);margin:6px auto 0;font-family:var(--mono);font-size:9px;color:var(--dim2);display:flex;justify-content:space-between}
|
|
|
|
/* DROP ZONE */
|
|
.drop-overlay{display:none;position:fixed;inset:0;z-index:100;background:rgba(0,232,123,.06);backdrop-filter:blur(4px);align-items:center;justify-content:center}
|
|
.drop-overlay.show{display:flex}
|
|
.drop-box{border:2px dashed var(--acc);border-radius:20px;padding:60px 80px;text-align:center;color:var(--acc);font-size:18px;font-weight:500;animation:dropPulse 1.5s ease infinite}
|
|
@keyframes dropPulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(1.02)}}
|
|
|
|
/* FILE PREVIEW */
|
|
.file-preview{display:flex;gap:8px;padding:8px 0;flex-wrap:wrap}
|
|
.file-chip{display:flex;align-items:center;gap:6px;background:var(--s3);border:1px solid var(--bd);border-radius:8px;padding:5px 10px;font-size:11px;color:var(--dim);font-family:var(--mono);animation:fadeIn .2s ease}
|
|
.file-chip img{width:32px;height:32px;border-radius:4px;object-fit:cover}
|
|
.file-chip .remove{cursor:pointer;color:var(--red);font-size:14px;margin-left:4px;opacity:.6;transition:opacity .2s}
|
|
.file-chip .remove:hover{opacity:1}
|
|
.file-chip .fsize{color:var(--dim2);font-size:9px}
|
|
|
|
/* ATTACH BUTTON */
|
|
.attach-btn{position:absolute;left:10px;bottom:14px;width:32px;height:32px;border-radius:8px;border:none;background:transparent;color:var(--dim);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}
|
|
.attach-btn:hover{color:var(--acc);background:var(--acc2)}
|
|
.attach-btn svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
|
|
|
|
/* IMAGE IN MESSAGE */
|
|
.msg-image{max-width:300px;border-radius:var(--r);margin-top:8px;border:1px solid var(--bd)}
|
|
|
|
/* CURSOR BLINK */
|
|
.cursor{display:inline-block;width:2px;height:16px;background:var(--acc);animation:blink 1s step-end infinite;vertical-align:text-bottom;margin-left:2px}
|
|
@keyframes blink{0%,100%{opacity:1}50%{opacity:0}}
|
|
|
|
/* SCROLL TO BOTTOM */
|
|
.scroll-btn{position:fixed;bottom:100px;right:40px;width:36px;height:36px;border-radius:50%;background:var(--s2);border:1px solid var(--bd);color:var(--dim);cursor:pointer;display:none;align-items:center;justify-content:center;font-size:16px;transition:all .2s;z-index:10}
|
|
.scroll-btn:hover{border-color:var(--acc);color:var(--acc)}
|
|
.scroll-btn.show{display:flex}
|
|
|
|
|
|
.voice-btn{position:absolute;right:52px;bottom:14px;width:34px;height:34px;border-radius:10px;background:transparent;border:1px solid var(--bd);color:var(--dim);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}
|
|
.voice-btn:hover{border-color:var(--acc);color:var(--acc)}
|
|
.voice-btn.recording{background:var(--red);border-color:var(--red);color:#fff;animation:pulse 1s ease infinite}
|
|
.voice-btn svg{width:15px;height:15px;fill:currentColor}
|
|
.tts-btn{font-family:var(--mono);font-size:9px;padding:2px 6px;border-radius:4px;border:1px solid var(--bd);background:transparent;color:var(--dim2);cursor:pointer;margin-left:4px}
|
|
.tts-btn:hover{color:var(--acc);border-color:var(--acc)}
|
|
/* MOBILE */
|
|
.sb-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:49}
|
|
@media(max-width:768px){
|
|
.sidebar{position:fixed;left:0;top:0;bottom:0;z-index:50;transform:translateX(-100%)}
|
|
.sidebar.open{transform:none}
|
|
.sb-overlay.show{display:block}
|
|
.menu-btn{display:flex}
|
|
.welcome-cards{grid-template-columns:1fr}
|
|
}
|
|
.voice-btn{position:absolute!important;right:88px;top:50%;transform:translateY(-50%);z-index:5;width:32px;height:32px;opacity:0.5}.voice-btn:hover{opacity:1}</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="drop-overlay" id="dropZone"><div class="drop-box">📎 Déposez vos fichiers ici<br><small style="font-size:12px;color:var(--dim)">Images, PDF, code — WEVIA analyse tout</small></div></div>
|
|
<button class="scroll-btn" id="scrollBtn" onclick="scrollChat()">↓</button>
|
|
|
|
<div class="sb-overlay" id="overlay" onclick="toggleSb()"></div>
|
|
|
|
<div class="sidebar" id="sidebar">
|
|
<div class="sb-head">
|
|
<div class="sb-logo">WEVIA<small>Master AI v3.0</small></div>
|
|
<button class="sb-new" onclick="newChat()" title="Nouvelle conversation">+</button>
|
|
</div>
|
|
<div class="sb-label">Agents</div>
|
|
<div class="sb-nav">
|
|
<div class="sb-item" onclick="q('agent monitor full health check')"><span class="ico">🖥</span>Monitor Infra</div>
|
|
<div class="sb-item" onclick="q('agent devops check memory processes docker')"><span class="ico">⚙️</span>DevOps Check</div>
|
|
<div class="sb-item" onclick="q('agent ethica count HCP top specialties')"><span class="ico">💊</span>Ethica HCP</div>
|
|
<div class="sb-item" onclick="q('agent security scan SSL certificates')"><span class="ico">🔒</span>Security Audit</div>
|
|
</div>
|
|
<div class="sb-label">Raccourcis</div>
|
|
<div class="sb-nav">
|
|
<div class="sb-item" onclick="q('Statut complet infrastructure WEVAL S204 S95 S151')"><span class="ico">📊</span>Statut Infra</div>
|
|
<div class="sb-item" onclick="q('Liste les providers IA gratuits de WEVIA')"><span class="ico">🤖</span>Providers IA</div>
|
|
<div class="sb-item" onclick="q('Combien de vecteurs Qdrant et quelles collections?')"><span class="ico">🧠</span>RAG Status</div>
|
|
<div class="sb-item" onclick="q('Quels modèles Ollama sur S204?')"><span class="ico">🎯</span>Modèles Ollama</div>
|
|
<div class="sb-item" onclick="q('Comment scraper Ethica DabaDoc Casablanca?')"><span class="ico">🔬</span>Ethica Scraping</div>
|
|
<div class="sb-item" onclick="q('Plan souveraineté IA totale WEVAL')"><span class="ico">🏛</span>Souveraineté</div>
|
|
<div class="sb-item" onclick="window.open('/api/wevia-master-api.php?dashboard','_blank')"><span class="ico">📈</span>Dashboard</div>
|
|
</div>
|
|
<div class="sb-foot">
|
|
<span class="dot g"></span> 15 providers LIVE | 0€<br>
|
|
<span class="dot g"></span> Ollama 9 modèles | 24GB<br>
|
|
<span class="dot g"></span> RAG 15,128 vecteurs
|
|
</div>
|
|
</div>
|
|
|
|
<div class="main">
|
|
<div class="top">
|
|
<button class="menu-btn" onclick="toggleSb()">☰</button>
|
|
<span class="top-title">WEVIA Master AI</span>
|
|
<div class="pills">
|
|
<span class="pill live" id="tp-status">● LIVE</span>
|
|
<span class="pill" id="tp-provider">—</span>
|
|
<span class="pill" id="tp-rag">RAG</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="chat" id="chat">
|
|
<div class="ci" id="ci">
|
|
<div class="welcome" id="welcome">
|
|
<h1>WEVIA</h1>
|
|
<p>IA souveraine — 15 providers — RAG 14K vecteurs — 146 tools — 629 skills</p>
|
|
<div class="welcome-cards">
|
|
<div class="wcard" onclick="q('Statut infrastructure S204/S95/S151')"><h3>📊 Statut Infrastructure</h3><p>Analyse complète S204/S95/S151</p></div>
|
|
<div class="wcard" onclick="q('Scrapers Ethica DabaDoc pour HCP pharma')"><h3>💊 Ethica HCP Pharma</h3><p>Scrapers, DB, enrichissement</p></div>
|
|
<div class="wcard" onclick="q('Architecture IA WEVIA Master: router, RAG, agents')"><h3>🧠 Architecture IA</h3><p>Router, RAG, agents, cascade</p></div>
|
|
<div class="wcard" onclick="q('Script PHP monitoring Docker et alerte')"><h3>💻 Code Generation</h3><p>Scripts, APIs, monitoring</p></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="input-area">
|
|
<div class="input-wrap">
|
|
<div class="file-preview" id="filePreview"></div>
|
|
<div class="input-box">
|
|
<button class="attach-btn" onclick="document.getElementById('fileInput').click()" title="Joindre un fichier">
|
|
<svg viewBox="0 0 24 24"><path d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48"/></svg>
|
|
</button>
|
|
<textarea id="input" rows="1" placeholder="Demandez à WEVIA..." oninput="resize(this)" onkeydown="onKey(event)" style="padding-left:36px"></textarea>
|
|
</div>
|
|
<button class="voice-btn" id="voiceBtn mic-inside" onclick="toggleVoice()" title="Parler à WEVIA"><svg viewBox="0 0 24 24"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3zM19 10v2a7 7 0 0 1-14 0v-2H3v2a9 9 0 0 0 8 8.94V23h2v-2.06A9 9 0 0 0 21 12v-2h-2z"/></svg></button>
|
|
<button class="send-btn" id="sendBtn" onclick="send()">
|
|
<svg viewBox="0 0 24 24"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
|
|
</button>
|
|
<input type="file" id="fileInput" multiple accept="image/*,.pdf,.txt,.py,.php,.js,.json,.csv,.md" style="display:none" onchange="handleFiles(this.files)">
|
|
</div>
|
|
<div class="input-hint">
|
|
<span>Enter envoyer · Shift+Enter nouvelle ligne · 📎 Glissez-déposez des fichiers</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const STREAM='/api/wevia-autonomous.php';
|
|
const AGENT='/api/wevia-agent-loop.php';
|
|
let hist=[];
|
|
|
|
function toggleSb(){document.getElementById('sidebar').classList.toggle('open');document.getElementById('overlay').classList.toggle('show');}
|
|
function newChat(){hist=[];document.getElementById('ci').innerHTML=document.querySelector('.welcome')?.outerHTML||'';const w=document.getElementById('welcome');if(w)w.style.display='';}
|
|
function resize(el){el.style.height='auto';el.style.height=Math.min(el.scrollHeight,160)+'px';}
|
|
function onKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();send();}}
|
|
function q(t){document.getElementById('input').value=t;send();if(innerWidth<768)toggleSb();}
|
|
function scrollChat(){document.getElementById('chat').scrollTop=document.getElementById('chat').scrollHeight;}
|
|
function esc(s){return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');}
|
|
|
|
function md(text){
|
|
if(!text)return'';
|
|
let h=esc(text);
|
|
h=h.replace(/```(\w*)\n?([\s\S]*?)```/g,(_,lang,code)=>`<pre><button class="copy-btn" onclick="copyCode(this)">copier</button><code>${code.trim()}</code></pre>`);
|
|
h=h.replace(/`([^`]+)`/g,'<code>$1</code>');
|
|
h=h.replace(/\*\*([^*]+)\*\*/g,'<strong>$1</strong>');
|
|
h=h.replace(/^### (.+)$/gm,'<h3>$1</h3>');
|
|
h=h.replace(/^- (.+)$/gm,'<li>$1</li>');
|
|
h=h.replace(/\n{2,}/g,'</p><p>');
|
|
h=h.replace(/\n/g,'<br>');
|
|
return'<p>'+h+'</p>';
|
|
}
|
|
|
|
function copyCode(btn){navigator.clipboard.writeText(btn.nextElementSibling.textContent).then(()=>{btn.textContent='copié!';setTimeout(()=>btn.textContent='copier',1500);});}
|
|
|
|
function addUser(msg){
|
|
const w=document.getElementById('welcome');if(w)w.style.display='none';
|
|
const ci=document.getElementById('ci');
|
|
const d=document.createElement('div');d.className='msg user';
|
|
d.innerHTML=`<div class="bubble">${esc(msg)}</div>`;
|
|
ci.appendChild(d);scroll();
|
|
}
|
|
|
|
function showThinking(){
|
|
const ci=document.getElementById('ci');
|
|
const d=document.createElement('div');d.className='thinking';d.id='thinkBox';
|
|
d.innerHTML=`<div class="av">W</div><div class="think-box"><div class="think-steps" id="thinkSteps"></div></div>`;
|
|
ci.appendChild(d);scroll();
|
|
}
|
|
|
|
function addThinkStep(label,val){
|
|
const steps=document.getElementById('thinkSteps');if(!steps)return;
|
|
const s=document.createElement('div');s.className='think-step';
|
|
s.innerHTML=`<div class="spinner"></div><span class="label">${label}</span><span class="val">${val||''}</span>`;
|
|
steps.appendChild(s);scroll();
|
|
return s;
|
|
}
|
|
|
|
function completeStep(step,val){
|
|
if(!step)return;
|
|
step.classList.add('done');
|
|
if(val)step.querySelector('.val').textContent=val;
|
|
}
|
|
|
|
function removeThinking(){const t=document.getElementById('thinkBox');if(t)t.remove();}
|
|
|
|
function startStream(){
|
|
const ci=document.getElementById('ci');
|
|
const d=document.createElement('div');d.className='msg ai';
|
|
d.innerHTML=`<div class="av">W</div><div class="body"><div class="content" id="streamOut"></div></div>`;
|
|
ci.appendChild(d);scroll();
|
|
return document.getElementById('streamOut');
|
|
}
|
|
|
|
function finishStream(el,meta){
|
|
el.removeAttribute('id');
|
|
if(meta){
|
|
const body=el.closest('.body');
|
|
let h='<div class="meta">';
|
|
if(meta.tier!==undefined){const c=meta.tier<=0?'t0':'t1';h+=`<span class="tag ${c}">T${meta.tier} ${meta.provider}</span>`;}
|
|
if(meta.model)h+=`<span class="tag">${meta.model.substring(0,25)}</span>`;
|
|
if(meta.latency_ms)h+=`<span class="tag">${meta.latency_ms}ms</span>`;
|
|
if(meta.rag>0)h+=`<span class="tag rag">RAG ${meta.rag}</span>`;
|
|
if(meta.mem>0)h+=`<span class="tag rag">MEM ${meta.mem}</span>`;
|
|
h+='<span class="tag">0€</span><button class="tts-btn" onclick="speakText(this.closest(\'\'.msg-body\'\').querySelector(\'\'.content\'\').textContent)">🔊</button></div>';
|
|
body.insertAdjacentHTML('beforeend',h);
|
|
document.getElementById('tp-provider').textContent=meta.provider;
|
|
}
|
|
}
|
|
|
|
function addAIMsg(content,meta){
|
|
const ci=document.getElementById('ci');
|
|
const d=document.createElement('div');d.className='msg ai';
|
|
let metaH='';
|
|
if(meta){
|
|
metaH='<div class="meta">';
|
|
if(meta.provider)metaH+=`<span class="tag t1">${meta.provider}</span>`;
|
|
if(meta.latency_ms)metaH+=`<span class="tag">${meta.latency_ms}ms</span>`;
|
|
metaH+='<span class="tag">0€</span></div>';
|
|
}
|
|
d.innerHTML=`<div class="av">W</div><div class="body"><div class="content">${md(content)}</div>${metaH}</div>`;
|
|
ci.appendChild(d);scroll();
|
|
}
|
|
|
|
async function send(){
|
|
const el=document.getElementById('input');
|
|
const msg=el.value.trim();if(!msg)return;
|
|
el.value='';el.style.height='auto';
|
|
document.getElementById('sendBtn').disabled=true;
|
|
addUser(msg);
|
|
hist.push({role:'user',content:msg});
|
|
|
|
const isAgent=/agent\s+(monitor|devops|ethica|security)/i.exec(msg);
|
|
|
|
try{
|
|
if(isAgent){
|
|
// AGENT MODE
|
|
const id=isAgent[1].toLowerCase();
|
|
const goal=msg.replace(isAgent[0],'').trim()||'full check';
|
|
showThinking();
|
|
const s1=addThinkStep(`Lancement agent ${id}...`);
|
|
const s2=addThinkStep('Exécution des étapes...');
|
|
const r=await fetch(`${AGENT}?agent=${id}&goal=${encodeURIComponent(goal)}`,{signal:AbortSignal.timeout(120000)});
|
|
const data=await r.json();
|
|
completeStep(s1,`${data.steps_count||'?'} étapes`);
|
|
completeStep(s2,`${data.total_time_ms||'?'}ms`);
|
|
setTimeout(()=>{
|
|
removeThinking();
|
|
let c=`**Agent ${id}** — ${data.steps_count||'?'} étapes | ${data.total_time_ms||'?'}ms\n\n`;
|
|
if(data.summary)c+=data.summary+'\n\n';
|
|
if(data.steps){c+='**Détail:**\n';for(const s of data.steps){const a=s.action||{};c+=`- **Step ${s.step}**: \`${a.action||'?'}\``;if(a.cmd)c+=` → \`${a.cmd.substring(0,80)}\``;c+='\n';if(s.result?.output)c+=`\`\`\`\n${s.result.output.substring(0,300)}\n\`\`\`\n`;}}
|
|
addAIMsg(c,{provider:'agent-'+id,latency_ms:data.total_time_ms});
|
|
},500);
|
|
}else{
|
|
// STREAMING MODE avec thinking steps
|
|
showThinking();
|
|
const s1=addThinkStep('Recherche mémoire...');
|
|
const s2=addThinkStep('Recherche RAG...');
|
|
|
|
const resp=await fetch(STREAM,{
|
|
method:'POST',
|
|
headers:{'Content-Type':'application/json'},
|
|
body:JSON.stringify({message:msg,history:hist.slice(-10)}),
|
|
signal:AbortSignal.timeout(90000)
|
|
});
|
|
|
|
const reader=resp.body.getReader();
|
|
const dec=new TextDecoder();
|
|
let buf='',full='',provider='',model='',lat=0,ragN=0,memN=0,started=false,streamEl=null;
|
|
|
|
while(true){
|
|
const{done,value}=await reader.read();
|
|
if(done)break;
|
|
buf+=dec.decode(value,{stream:true});
|
|
const lines=buf.split('\n');buf=lines.pop();
|
|
|
|
for(const line of lines){
|
|
if(!line.startsWith('data: ')||line==='data: [DONE]')continue;
|
|
try{
|
|
const d=JSON.parse(line.slice(6));
|
|
|
|
if(d.type==='memory'){
|
|
memN=d.count||0;
|
|
completeStep(s1,memN>0?`${memN} souvenirs`:'aucun');
|
|
}
|
|
if(d.type==='rag'){
|
|
ragN=d.count||0;
|
|
completeStep(s2,ragN>0?`${ragN} résultats | ${d.latency||0}ms`:'aucun');
|
|
}
|
|
if(d.type==='start'){
|
|
provider=d.provider;model=d.model;
|
|
const s3=addThinkStep(`Connexion ${d.provider}...`);
|
|
completeStep(s3,d.model?.substring(0,25));
|
|
setTimeout(()=>{removeThinking();},300);
|
|
}
|
|
if(d.type==='token'){
|
|
if(!started){started=true;streamEl=startStream();}
|
|
full+=d.content;
|
|
streamEl.innerHTML=md(full);
|
|
scroll();
|
|
}
|
|
if(d.type==='done'){
|
|
lat=d.latency_ms;ragN=d.rag||ragN;
|
|
}
|
|
}catch(e){}
|
|
}
|
|
}
|
|
|
|
if(streamEl){
|
|
finishStream(streamEl,{tier:1,provider,model,latency_ms:lat,rag:ragN,mem:memN});
|
|
}else{
|
|
removeThinking();
|
|
addAIMsg('Aucune réponse reçue. Réessayez.',{provider:'error'});
|
|
}
|
|
hist.push({role:'assistant',content:full});
|
|
}
|
|
}catch(e){
|
|
removeThinking();
|
|
addAIMsg(`Erreur: ${e.message}. Réessayez avec une question plus courte.`,{provider:'error'});
|
|
}
|
|
|
|
document.getElementById('sendBtn').disabled=false;
|
|
el.focus();
|
|
}
|
|
|
|
|
|
// === VOICE: Speech-to-Text + Text-to-Speech ===
|
|
let recognition = null;
|
|
let isRecording = false;
|
|
|
|
function toggleVoice() {
|
|
if (!("webkitSpeechRecognition" in window || "SpeechRecognition" in window)) {
|
|
alert("Votre navigateur ne supporte pas la reconnaissance vocale.");
|
|
return;
|
|
}
|
|
if (isRecording) { stopVoice(); return; }
|
|
|
|
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
recognition = new SR();
|
|
recognition.lang = "fr-FR";
|
|
recognition.continuous = false;
|
|
recognition.interimResults = true;
|
|
|
|
recognition.onstart = () => {
|
|
isRecording = true;
|
|
document.getElementById("voiceBtn mic-inside").classList.add("recording");
|
|
};
|
|
recognition.onresult = (e) => {
|
|
let transcript = "";
|
|
for (let i = e.resultIndex; i < e.results.length; i++) {
|
|
transcript += e.results[i][0].transcript;
|
|
}
|
|
document.getElementById("input").value = transcript;
|
|
resize(document.getElementById("input"));
|
|
};
|
|
recognition.onend = () => {
|
|
isRecording = false;
|
|
document.getElementById("voiceBtn mic-inside").classList.remove("recording");
|
|
if (document.getElementById("input").value.trim()) send();
|
|
};
|
|
recognition.onerror = (e) => {
|
|
isRecording = false;
|
|
document.getElementById("voiceBtn mic-inside").classList.remove("recording");
|
|
};
|
|
recognition.start();
|
|
}
|
|
|
|
function stopVoice() {
|
|
if (recognition) recognition.stop();
|
|
isRecording = false;
|
|
document.getElementById("voiceBtn mic-inside").classList.remove("recording");
|
|
}
|
|
|
|
function speakText(text) {
|
|
if (!("speechSynthesis" in window)) return;
|
|
const u = new SpeechSynthesisUtterance(text.replace(/[*#`\[\]]/g, "").substring(0, 500));
|
|
u.lang = "fr-FR";
|
|
u.rate = 1.1;
|
|
speechSynthesis.speak(u);
|
|
}
|
|
|
|
document.getElementById('input').focus();
|
|
|
|
// === FILE HANDLING ===
|
|
let pendingFiles = [];
|
|
|
|
function handleFiles(fileList) {
|
|
for (const f of fileList) {
|
|
if (f.size > 10 * 1024 * 1024) { alert('Max 10MB'); continue; }
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
pendingFiles.push({ name: f.name, size: f.size, type: f.type, data: e.target.result });
|
|
renderFilePreview();
|
|
};
|
|
if (f.type.startsWith('image/')) reader.readAsDataURL(f);
|
|
else reader.readAsDataURL(f);
|
|
}
|
|
}
|
|
|
|
function renderFilePreview() {
|
|
const el = document.getElementById('filePreview');
|
|
el.innerHTML = pendingFiles.map((f, i) => {
|
|
const sz = f.size < 1024 ? f.size + 'B' : (f.size / 1024).toFixed(0) + 'KB';
|
|
const img = f.type.startsWith('image/') ? `<img src="${f.data}" alt="">` : '';
|
|
return `<div class="file-chip">${img}<span>${f.name}</span><span class="fsize">${sz}</span><span class="remove" onclick="removeFile(${i})">✕</span></div>`;
|
|
}).join('');
|
|
}
|
|
|
|
function removeFile(i) { pendingFiles.splice(i, 1); renderFilePreview(); }
|
|
|
|
// === DRAG & DROP ===
|
|
let dragCount = 0;
|
|
document.addEventListener('dragenter', (e) => { e.preventDefault(); dragCount++; document.getElementById('dropZone').classList.add('show'); });
|
|
document.addEventListener('dragleave', (e) => { e.preventDefault(); dragCount--; if (dragCount <= 0) { dragCount = 0; document.getElementById('dropZone').classList.remove('show'); } });
|
|
document.addEventListener('dragover', (e) => e.preventDefault());
|
|
document.addEventListener('drop', (e) => {
|
|
e.preventDefault(); dragCount = 0;
|
|
document.getElementById('dropZone').classList.remove('show');
|
|
if (e.dataTransfer.files.length) handleFiles(e.dataTransfer.files);
|
|
});
|
|
|
|
// === SCROLL BUTTON ===
|
|
const chatEl = document.getElementById('chat');
|
|
chatEl.addEventListener('scroll', () => {
|
|
const atBottom = chatEl.scrollHeight - chatEl.scrollTop - chatEl.clientHeight < 100;
|
|
document.getElementById('scrollBtn').classList.toggle('show', !atBottom);
|
|
});
|
|
|
|
// === ENHANCED SEND (with files) ===
|
|
const origSend = send;
|
|
const _send = send;
|
|
send = async function() {
|
|
if (pendingFiles.length > 0) {
|
|
const el = document.getElementById('input');
|
|
const msg = el.value.trim() || 'Analyse ce fichier';
|
|
el.value = ''; el.style.height = 'auto';
|
|
document.getElementById('sendBtn').disabled = true;
|
|
|
|
// Show user message with file previews
|
|
const w = document.getElementById('welcome'); if (w) w.style.display = 'none';
|
|
const ci = document.getElementById('ci');
|
|
const d = document.createElement('div'); d.className = 'msg user';
|
|
let filesHtml = pendingFiles.map(f => {
|
|
if (f.type.startsWith('image/')) return `<img class="msg-image" src="${f.data}">`;
|
|
return `<div class="file-chip"><span>📄 ${f.name}</span></div>`;
|
|
}).join('');
|
|
d.innerHTML = `<div class="bubble">${esc(msg)}${filesHtml}</div>`;
|
|
ci.appendChild(d); scroll();
|
|
|
|
hist.push({ role: 'user', content: msg });
|
|
|
|
// If image, use vision API
|
|
const imageFile = pendingFiles.find(f => f.type.startsWith('image/'));
|
|
if (imageFile) {
|
|
showThinking();
|
|
const s1 = addThinkStep('Analyse image via Vision...');
|
|
|
|
try {
|
|
const resp = await fetch('/api/wevia-vision-api.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ image_base64: imageFile.data.split(',')[1], prompt: msg }),
|
|
signal: AbortSignal.timeout(30000)
|
|
});
|
|
const data = await resp.json();
|
|
completeStep(s1, `${data.provider} ${data.latency_ms}ms`);
|
|
setTimeout(() => {
|
|
removeThinking();
|
|
addAIMsg(data.content || 'Analyse terminée.', { provider: data.provider, latency_ms: data.latency_ms });
|
|
}, 300);
|
|
} catch (e) {
|
|
removeThinking();
|
|
addAIMsg(`Erreur vision: ${e.message}`, { provider: 'error' });
|
|
}
|
|
} else {
|
|
// Non-image file: include content in message
|
|
let fileContent = '';
|
|
for (const f of pendingFiles) {
|
|
if (f.data.includes('base64,')) {
|
|
try { fileContent += '\n\nFichier ' + f.name + ':\n' + atob(f.data.split(',')[1]).substring(0, 5000); } catch(e) {}
|
|
}
|
|
}
|
|
document.getElementById('input').value = msg + fileContent;
|
|
pendingFiles = []; renderFilePreview();
|
|
document.getElementById('sendBtn').disabled = false;
|
|
return _send();
|
|
}
|
|
|
|
pendingFiles = []; renderFilePreview();
|
|
document.getElementById('sendBtn').disabled = false;
|
|
return;
|
|
}
|
|
return _send();
|
|
};
|
|
|
|
// === PASTE IMAGE ===
|
|
document.getElementById('input').addEventListener('paste', (e) => {
|
|
const items = e.clipboardData?.items;
|
|
if (!items) return;
|
|
for (const item of items) {
|
|
if (item.type.startsWith('image/')) {
|
|
e.preventDefault();
|
|
const file = item.getAsFile();
|
|
handleFiles([file]);
|
|
}
|
|
}
|
|
});
|
|
|
|
</script>
|
|
|
|
<script>
|
|
// WEVIA UX Enhancement v2 — inject inside sidebar properly
|
|
document.addEventListener('DOMContentLoaded', function(){
|
|
var sb = document.querySelector('.sidebar-items, .sb-items, nav');
|
|
if (!sb) { var items = document.querySelectorAll('.sb-item'); if(items.length) sb = items[0].parentElement; }
|
|
if (!sb) return;
|
|
|
|
// Make sidebar scrollable
|
|
sb.style.overflowY = 'auto';
|
|
sb.style.maxHeight = 'calc(100vh - 180px)';
|
|
sb.style.paddingBottom = '60px';
|
|
|
|
// Add new sections
|
|
var html = '';
|
|
var tools = [
|
|
['consensus expert meilleur LLM','\ud83e\udde0','Consensus'],
|
|
['status mirofish','\ud83d\udc1f','MiroFish'],
|
|
['status deerflow research','\ud83e\udd8c','DeerFlow'],
|
|
['status paperclip CEO agent','\ud83d\udcce','Paperclip'],
|
|
['screenshot https://weval-consulting.com','\ud83d\udcf8','Screenshot'],
|
|
];
|
|
tools.forEach(function(t){ html += '<div class="sb-item" onclick="q(\''+t[0]+'\')"><span class="ico">'+t[1]+'</span>'+t[2]+'</div>'; });
|
|
|
|
html += '';
|
|
var actions = [
|
|
['docker containers status','\ud83d\udc33','Docker'],
|
|
['git log recent','\ud83d\udcc2','Git'],
|
|
['cron list taches actives','\u23f0','Crons'],
|
|
['liste boites email','\ud83d\udce7','Email'],
|
|
['execute python print(42)','\ud83d\udcbb','Code Exec'],
|
|
['nettoie les logs','\ud83e\uddf9','Cleanup'],
|
|
];
|
|
actions.forEach(function(t){ html += '<div class="sb-item" onclick="q(\''+t[0]+'\')"><span class="ico">'+t[1]+'</span>'+t[2]+'</div>'; });
|
|
|
|
html += '';
|
|
var oss = [
|
|
['collections qdrant vectors','\ud83d\udd0d','Qdrant'],
|
|
['status n8n workflows','\ud83d\udd04','n8n'],
|
|
['nginx config vhosts','\ud83c\udf10','Nginx'],
|
|
['diagnostique systeme complet','\ud83d\udd27','Debug'],
|
|
['status vault gold backup','\ud83d\udcbe','Backup'],
|
|
];
|
|
oss.forEach(function(t){ html += '<div class="sb-item" onclick="q(\''+t[0]+'\')"><span class="ico">'+t[1]+'</span>'+t[2]+'</div>'; });
|
|
|
|
sb.insertAdjacentHTML('beforeend', html);
|
|
|
|
// Enhance welcome: add 4 more cards
|
|
var grid = document.querySelector('[style*="grid-template-columns"]');
|
|
if (grid && !document.getElementById('extra-cards-added')) {
|
|
var extra = document.createElement('div');
|
|
extra.id = 'extra-cards-added';
|
|
extra.style.cssText = 'display:grid;grid-template-columns:1fr 1fr;gap:10px;max-width:560px;margin:12px auto 0';
|
|
extra.innerHTML = [
|
|
['scan SSL securite headers','\ud83d\udd12','Security Audit','SSL, headers, ports'],
|
|
['consensus expert meilleur LLM 2026','\ud83e\udde0','Consensus IA','3 experts debattent'],
|
|
['docker containers status','\ud83d\udc33','Docker Services','24 containers'],
|
|
['execute python: import platform; print(platform.node())','\ud83d\udcbb','Code Execution','Python, PHP, Bash'],
|
|
].map(function(c){ return '<div onclick="q(\''+c[0]+'\')" style="background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.08);border-radius:12px;padding:14px;cursor:pointer;transition:border-color .2s" onmouseover="this.style.borderColor=\'rgba(255,255,255,0.2)\'" onmouseout="this.style.borderColor=\'rgba(255,255,255,0.08)\'"><span>'+c[1]+'</span> <b style="color:#eee">'+c[2]+'</b><br><small style="color:#888">'+c[3]+'</small></div>'; }).join('');
|
|
grid.parentElement.insertBefore(extra, grid.nextSibling);
|
|
}
|
|
});
|
|
</script>
|
|
<script>(function(){
|
|
if(document.getElementById('wx5')){return;}
|
|
var s=document.createElement('style');
|
|
s.textContent=`
|
|
/* SIDEBAR CLEAN */
|
|
.sb-cat{font-size:9px!important;letter-spacing:1.5px!important;color:rgba(255,255,255,0.22)!important;padding:12px 14px 3px!important;font-weight:600!important}
|
|
.sb-item{font-size:11.5px!important;padding:5px 12px!important;border-radius:6px!important;margin:1px 6px!important;transition:all .12s!important;color:rgba(255,255,255,0.5)!important}
|
|
.sb-item:hover{background:rgba(100,220,160,0.07)!important;color:#fff!important}
|
|
|
|
/* WELCOME CENTERED + COMPACT */
|
|
.welcome{display:flex!important;flex-direction:column!important;align-items:center!important;justify-content:center!important;text-align:center!important;padding:16px 20px!important;min-height:auto!important}
|
|
.welcome h1{font-size:36px!important;font-weight:700!important;letter-spacing:8px!important;background:linear-gradient(135deg,#64dca0,#4a9eff,#a78bfa)!important;-webkit-background-clip:text!important;-webkit-text-fill-color:transparent!important;margin:0 0 4px!important}
|
|
.welcome>p{color:rgba(255,255,255,0.25)!important;font-size:12px!important;margin:0 0 16px!important}
|
|
|
|
/* CARDS - COMPACT 2x4 GRID */
|
|
.wx-grid{display:grid!important;grid-template-columns:repeat(2,1fr)!important;gap:8px!important;width:100%!important;max-width:560px!important;margin:0 auto!important}
|
|
.wx-grid>div{background:rgba(255,255,255,0.02)!important;border:1px solid rgba(255,255,255,0.06)!important;border-radius:12px!important;padding:12px 14px!important;cursor:pointer!important;transition:all .2s!important;text-align:center!important;display:flex!important;flex-direction:column!important;align-items:center!important;gap:2px!important}
|
|
.wx-grid>div:hover{border-color:rgba(100,220,160,0.35)!important;background:rgba(100,220,160,0.04)!important;transform:translateY(-2px)!important;box-shadow:0 8px 20px rgba(0,0,0,0.2)!important}
|
|
.wx-grid .ci{font-size:20px!important;margin-bottom:2px!important}
|
|
.wx-grid b{color:#ddd!important;font-size:12.5px!important;font-weight:600!important}
|
|
.wx-grid small{color:rgba(255,255,255,0.25)!important;font-size:10.5px!important}
|
|
|
|
/* INPUT - CENTERED BUTTONS */
|
|
.input-wrap{display:flex!important;align-items:center!important;gap:6px!important;padding:6px 12px!important;background:rgba(30,30,30,0.95)!important;border:1px solid rgba(255,255,255,0.08)!important;border-radius:16px!important;max-width:700px!important;margin:0 auto!important;width:calc(100% - 40px)!important}
|
|
.input-box{flex:1!important;position:relative!important;display:flex!important;align-items:center!important;background:transparent!important;border:none!important;padding:0!important;margin:0!important}
|
|
.input-box textarea{background:transparent!important;border:none!important;outline:none!important;color:#eee!important;font-size:14px!important;width:100%!important;padding:6px 8px 6px 36px!important;resize:none!important}
|
|
.attach-btn{position:absolute!important;left:8px!important;top:50%!important;transform:translateY(-50%)!important;z-index:5!important;opacity:0.35!important;transition:opacity .2s!important;background:none!important;border:none!important;cursor:pointer!important}
|
|
.attach-btn:hover{opacity:0.8!important}
|
|
.voice-btn{flex-shrink:0!important;opacity:0.3!important;transition:opacity .2s!important;background:none!important;border:none!important;cursor:pointer!important;position:static!important;transform:none!important}
|
|
.voice-btn:hover{opacity:0.8!important}
|
|
.send-btn{flex-shrink:0!important;opacity:0.9!important;background:rgb(100,220,160)!important;border:none!important;border-radius:10px!important;width:36px!important;height:36px!important;cursor:pointer!important;display:flex!important;align-items:center!important;justify-content:center!important;transition:all .2s!important;position:static!important;transform:none!important}
|
|
.send-btn:hover{background:rgb(80,200,140)!important;transform:scale(1.05)!important}
|
|
.file-preview{display:none!important}
|
|
|
|
/* NO DOUBLE SCROLLBAR */
|
|
.sidebar{overflow-y:auto!important;overflow-x:hidden!important}
|
|
.sidebar::-webkit-scrollbar{width:2px}
|
|
.sidebar::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.04);border-radius:2px}
|
|
`;
|
|
document.head.appendChild(s);
|
|
|
|
/* Clean wrong items */
|
|
['AnythingLLM','CrewAI','Flowise','AIOS','Browser-Use'].forEach(function(w){
|
|
document.querySelectorAll('.sb-item').forEach(function(el){if(el.textContent.indexOf(w)>=0)el.remove();});
|
|
});
|
|
var seen={};document.querySelectorAll('.sb-cat').forEach(function(c){var t=c.textContent.trim();if(seen[t])c.remove();seen[t]=1;});
|
|
|
|
/* Sidebar sections */
|
|
console.log('WX5 SB SEARCH',document.querySelectorAll('.sb-item').length);var sb=document.querySelector('.sb-item');if(!sb)return;
|
|
var p=sb.parentElement;
|
|
p.style.overflowY='auto';p.style.maxHeight='calc(100vh - 150px)';p.style.paddingBottom='40px';
|
|
|
|
function S(cat,items){
|
|
var h='<div class="sb-cat">'+cat+'</div>';
|
|
items.forEach(function(i){h+='<div class="sb-item" data-w5="1" onclick="q(\''+i[2]+'\')"><span class="ico">'+i[0]+'</span> '+i[1]+'</div>';});
|
|
p.insertAdjacentHTML('beforeend',h);
|
|
}
|
|
if(!document.querySelector('[data-w5]')){
|
|
S('\u2728 IA AGENTS',[['\ud83e\udde0','Consensus','consensus expert meilleur LLM'],['\ud83d\udc1f','MiroFish','status mirofish'],['\ud83e\udd8c','DeerFlow','status deerflow'],['\ud83d\udcce','Paperclip','status paperclip'],['\ud83e\udd16','DeepAgent','status deepagent'],['\ud83e\uddea','Opus Deep','analyse profonde']]);
|
|
S('\ud83d\udcbb CODE',[['\ud83d\udc07','CodeRabbit','code review'],['\ud83e\udd80','Claw-Code','status claw-code'],['\ud83d\udd0d','Nuclei','scan nuclei'],['\ud83d\udee1','CrowdSec','status CrowdSec'],['\ud83d\udd12','SSL','scan SSL'],['\u2328','Execute','execute python print(42)']]);
|
|
S('\ud83d\ude80 OPS',[['\ud83d\udc33','Docker','docker containers'],['\ud83c\udf10','Nginx','nginx config'],['\ud83d\udcc2','Git','git log'],['\u23f0','Crons','cron list'],['\ud83d\udce7','Email','liste email'],['\ud83d\udcf8','Screenshot','screenshot weval-consulting.com'],['\ud83e\uddf9','Cleanup','nettoie logs'],['\ud83d\udcbe','Backup','status vault gold']]);
|
|
S('\ud83e\udde9 OSS',[['\ud83d\udd0d','Qdrant','collections qdrant'],['\ud83d\udd04','n8n','status n8n'],['\ud83c\udf0e','SearXNG','recherche WEVAL'],['\ud83e\udd86','Goose','status goose'],['\ud83c\udf10','Browser','status browser-use'],['\ud83d\udcda','AnythingLLM','status anythingllm'],['\ud83e\udde9','CrewAI','status crewai'],['\ud83d\udd17','Flowise','status flowise'],['\ud83e\uddbe','AIOS','status aios'],['\ud83d\udd2e','Dify','status dify'],['\ud83d\udcda','554 Skills','liste skills']]);
|
|
S('\ud83d\udca4 DREAM ENGINE',[['\ud83c\udf19','autoDream','dream consolider memoires Qdrant'],['\u26a1','KAIROS','kairos daemon proactif alertes'],['\ud83d\udcdd','ULTRAPLAN','ultraplan architecture microservices'],['\ud83d\udddc','Compress','compress texte contexte'],['\ud83e\ude79','Self-Heal','heal memoire contradictions']]);
|
|
S('\ud83c\udfe2 ENTERPRISE',[['\ud83d\udcca','Dashboard','dashboard entreprise WEVAL stats'],['\ud83c\udfaf','Strategie','strategie WEVAL Consulting 2026'],['\ud83d\udcc8','Pipeline','pipeline commercial deals actifs'],['\ud83d\udcb0','Financier','plan financier revenus couts'],['\ud83d\uddd3','Roadmap','roadmap produit Q2 Q3 2026'],['\u2694','Concurrents','analyse concurrentielle Maroc'],['\ud83e\udd1d','Partenaires','strategie partenaires SAP Huawei Vistex'],['\ud83d\udc65','RH','plan recrutement equipe 2026'],['\ud83d\udcca','KPIs','indicateurs performance WEVAL'],['\ud83d\ude80','Evolution','plan evolution entreprise 12 mois']]);
|
|
S('\ud83c\udfdb ECOSYSTEM WEVAL',[['\ud83d\udce7','WEVIA Life','status wevia-life emails opps'],['\ud83d\udda5','Blade IA','status blade agent razer'],['\ud83d\udee0','PowerToys','ouvre powertoys DNS SSL QR Hash'],['\ud83d\udcbc','CRM','status CRM deals'],['\u2705','L99 Tests','status L99 passed total'],['\ud83d\udccb','NonReg','status nonreg 153 tests'],['\ud83c\udfd7','Architecture','architecture WEVIA complete'],['\ud83d\ude80','Ops Center','status ops-center 36 tools'],['\ud83c\udf0e','Tech Radar','status tech-radar 101 tools'],['\ud83d\udcdd','WEVADS','status wevads 79 modules'],['\ud83d\udcc5','Booking','booking calendly WEVAL']]);
|
|
S('\ud83d\udd75 DARK & ARSENAL',[['\ud83d\udd0d','Nuclei Scan','scan nuclei vulnerabilites weval-consulting.com'],['\ud83d\udd12','Gitleaks','scan gitleaks secrets code'],['\ud83d\udee1','Trivy','scan trivy containers vulnerabilites'],['\ud83d\udd75','Sherlock','sherlock OSINT username'],['\ud83d\udce7','Holehe','holehe OSINT email'],['\ud83c\udf10','Amass','amass subdomains weval-consulting.com'],['\ud83d\udcca','ADX Stats','status ADX contacts campaigns'],['\ud83d\udc8a','Ethica DB','status ethica medecins validated'],['\ud83d\udd04','Arsenal','status arsenal sentinel S95'],['\ud83d\udd77','Scrapers','status scrapers ethica']]);
|
|
S('\u26a1 PROVIDERS',[['\ud83c\udf1f','13 Providers','liste providers IA'],['\ud83e\udde0','R1 671B','test deepseek R1'],['\ud83d\ude80','Cerebras','test cerebras'],['\ud83d\udcca','Ollama','modeles Ollama']]);
|
|
}
|
|
|
|
/* Replace welcome cards - COMPACT */
|
|
var wc=document.querySelector('.welcome-cards');
|
|
if(wc){
|
|
var g=document.createElement('div');g.className='wx-grid';
|
|
g.innerHTML=[
|
|
['\ud83d\udcca','Audit Infra','S204\u2022S95\u2022S151','audit complet RAM disk Docker'],
|
|
['\ud83d\udc8a','Ethica HCP','131K m\u00e9decins','status ethica count HCP'],
|
|
['\ud83e\udde0','Consensus','3 IA experts','consensus expert stack IA'],
|
|
['\ud83d\udd12','Security','SSL\u2022Nuclei','scan SSL nuclei securite'],
|
|
['\ud83d\udc33','Docker','24 containers','docker containers status'],
|
|
['\ud83d\udcbb','Code Exec','Python\u2022PHP','execute python: print(42)'],
|
|
['\ud83e\udd8c','Research','800 skills','deerflow recherche IA'],
|
|
['\ud83d\ude80','Architecture','182 routes','architecture WEVIA Master'],
|
|
].map(function(c){return'<div onclick="q(\''+c[3]+'\')"><span class="ci">'+c[0]+'</span><b>'+c[1]+'</b><br><small>'+c[2]+'</small></div>';}).join('');
|
|
wc.parentElement.replaceChild(g,wc);
|
|
}
|
|
var wsub=document.querySelector('.welcome>p');
|
|
if(wsub)wsub.textContent='IA souveraine \u2014 15 providers \u2014 R1 671B \u2014 146 tools \u2014 800 skills \u2014 0\u20ac';
|
|
|
|
document.createElement('div').id='wx5';document.body.appendChild(document.getElementById('wx5')||Object.assign(document.createElement('div'),{id:'wx5'}));
|
|
})();
|
|
|
|
/* WEVIA Stream Premium — Rich response rendering */
|
|
(function(){
|
|
if(document.getElementById('wsp'))return;
|
|
|
|
var s=document.createElement('style');
|
|
s.textContent=`
|
|
/* RICH MESSAGE RENDERING */
|
|
.msg-assistant{font-family:'Plus Jakarta Sans','Inter',sans-serif!important}
|
|
.msg-assistant pre{background:rgba(0,0,0,0.3)!important;border:1px solid rgba(255,255,255,0.08)!important;border-radius:10px!important;padding:14px!important;overflow-x:auto!important;font-size:12px!important;line-height:1.5!important}
|
|
.msg-assistant code{font-family:'JetBrains Mono',monospace!important;font-size:12px!important;background:rgba(255,255,255,0.06)!important;padding:1px 5px!important;border-radius:4px!important}
|
|
.msg-assistant pre code{background:none!important;padding:0!important}
|
|
.msg-assistant h1,.msg-assistant h2,.msg-assistant h3{color:#64dca0!important;font-weight:600!important;margin:12px 0 6px!important}
|
|
.msg-assistant h1{font-size:18px!important;border-bottom:1px solid rgba(255,255,255,0.08)!important;padding-bottom:6px!important}
|
|
.msg-assistant h2{font-size:15px!important}
|
|
.msg-assistant h3{font-size:13px!important;color:rgba(255,255,255,0.5)!important}
|
|
.msg-assistant strong{color:#e8e8e8!important}
|
|
.msg-assistant ul,.msg-assistant ol{padding-left:20px!important;margin:6px 0!important}
|
|
.msg-assistant li{margin:3px 0!important;line-height:1.5!important}
|
|
.msg-assistant table{border-collapse:collapse!important;width:100%!important;margin:8px 0!important;font-size:12px!important}
|
|
.msg-assistant th{background:rgba(100,220,160,0.1)!important;color:#64dca0!important;padding:6px 10px!important;text-align:left!important;font-weight:600!important;border-bottom:1px solid rgba(255,255,255,0.1)!important}
|
|
.msg-assistant td{padding:5px 10px!important;border-bottom:1px solid rgba(255,255,255,0.04)!important}
|
|
.msg-assistant tr:hover td{background:rgba(255,255,255,0.02)!important}
|
|
/* ACTION BADGES */
|
|
.action-badge{display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:8px;font-size:11px;font-weight:500;margin:2px 4px 2px 0}
|
|
.action-badge.exec{background:rgba(100,220,160,0.1);color:#64dca0;border:1px solid rgba(100,220,160,0.2)}
|
|
.action-badge.error{background:rgba(255,80,80,0.1);color:#ff5050;border:1px solid rgba(255,80,80,0.2)}
|
|
.action-badge.info{background:rgba(80,160,255,0.1);color:#50a0ff;border:1px solid rgba(80,160,255,0.2)}
|
|
/* STATS CARDS */
|
|
.stat-row{display:flex;gap:8px;margin:8px 0;flex-wrap:wrap}
|
|
.stat-card{background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);border-radius:10px;padding:10px 14px;flex:1;min-width:100px;text-align:center}
|
|
.stat-card .stat-value{font-size:20px;font-weight:700;color:#64dca0}
|
|
.stat-card .stat-label{font-size:10px;color:rgba(255,255,255,0.35);text-transform:uppercase;letter-spacing:1px;margin-top:2px}
|
|
/* PROGRESS */
|
|
.stream-progress{display:flex;align-items:center;gap:8px;padding:8px 12px;background:rgba(255,255,255,0.02);border-radius:8px;margin:4px 0;font-size:12px;color:rgba(255,255,255,0.4)}
|
|
.stream-progress .dot{width:6px;height:6px;border-radius:50%;background:#64dca0;animation:blink 1.2s infinite}
|
|
@keyframes blink{0%,100%{opacity:1}50%{opacity:0.2}}
|
|
/* COPY BUTTON */
|
|
.copy-btn{position:absolute;top:6px;right:6px;background:rgba(255,255,255,0.08);border:none;border-radius:4px;color:rgba(255,255,255,0.4);padding:3px 8px;font-size:10px;cursor:pointer;opacity:0;transition:opacity .2s}
|
|
pre:hover .copy-btn{opacity:1}
|
|
.copy-btn:hover{color:#fff;background:rgba(255,255,255,0.15)}
|
|
`;
|
|
document.head.appendChild(s);
|
|
|
|
// Post-process messages: convert markdown-like to rich HTML
|
|
var observer = new MutationObserver(function(mutations){
|
|
mutations.forEach(function(m){
|
|
m.addedNodes.forEach(function(node){
|
|
if(node.nodeType===1 && (node.classList.contains('msg')||node.classList.contains('bubble')||node.querySelector)){
|
|
// Find text content that looks like markdown
|
|
var el = node.classList.contains('msg-assistant') ? node : node.querySelector('.msg-assistant,.assistant');
|
|
if(!el||el.dataset.rendered) return;
|
|
|
|
var html = el.innerHTML;
|
|
// Convert code blocks
|
|
html = html.replace(/\x60\x60\x60(\w*)\n?([\s\S]*?)\x60\x60\x60/g, function(m,lang,code){
|
|
return '<pre style="position:relative"><code class="lang-'+lang+'">'+code.trim()+'</code><button class="copy-btn" onclick="navigator.clipboard.writeText(this.previousElementSibling.textContent)">copy</button></pre>';
|
|
});
|
|
// Convert **bold**
|
|
html = html.replace(/\*\*([^*]+)\*\*/g, '<strong></strong>');
|
|
// Convert inline code
|
|
html = html.replace(/\x60([^\x60]+)\x60/g, '<code></code>');
|
|
// Convert ## headers
|
|
html = html.replace(/^### (.+)$/gm, '<h3></h3>');
|
|
html = html.replace(/^## (.+)$/gm, '<h2></h2>');
|
|
html = html.replace(/^# (.+)$/gm, '<h1></h1>');
|
|
// Convert - lists
|
|
html = html.replace(/^- (.+)$/gm, '<li></li>');
|
|
|
|
if(html !== el.innerHTML){
|
|
el.innerHTML = html;
|
|
el.dataset.rendered = '1';
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
var chatArea = document.querySelector('.chat-messages,.messages,.chat-area');
|
|
if(chatArea){
|
|
observer.observe(chatArea, {childList:true, subtree:true});
|
|
}
|
|
|
|
var d=document.createElement('div');d.id='wsp';document.body.appendChild(d);
|
|
})();
|
|
|
|
|
|
|
|
/* ═══ WEVIA AUTO-AUDIT UX FIXES (self-recommended) ═══ */
|
|
(function(){
|
|
if(document.getElementById('wux'))return;
|
|
var s=document.createElement('style');
|
|
s.id='wux-css';
|
|
s.textContent=`
|
|
/* 1. CARDS: hover premium avec translateY + glow */
|
|
.wcard{transition:transform .22s cubic-bezier(.22,1,.36,1),box-shadow .22s ease!important;cursor:pointer!important}
|
|
.wcard:hover{transform:translateY(-3px)!important;box-shadow:0 8px 25px rgba(100,220,160,0.15),0 4px 10px rgba(0,0,0,0.2)!important;border-color:rgba(100,220,160,0.3)!important}
|
|
.wcard:active{transform:translateY(0)!important;transition:.08s!important}
|
|
|
|
/* 2. SIDEBAR: active state + hover glow */
|
|
.sb-item{transition:all .18s ease!important;border-radius:8px!important;margin:1px 6px!important;padding:7px 10px!important}
|
|
.sb-item:hover{background:rgba(100,220,160,0.08)!important;padding-left:14px!important}
|
|
.sb-item:active{background:rgba(100,220,160,0.15)!important;transform:scale(0.98)}
|
|
|
|
/* 3. MICRO-ANIMATIONS: tout element interactif */
|
|
button,a,.send-btn,.voice-btn,.attach-btn{transition:all .2s ease!important}
|
|
button:hover,.send-btn:hover{transform:scale(1.05)!important;filter:brightness(1.15)!important}
|
|
.send-btn:active,.voice-btn:active{transform:scale(0.95)!important}
|
|
|
|
/* 4. CONTRASTE: texte secondaire plus lisible */
|
|
.wcard>div:last-child{color:rgba(255,255,255,0.5)!important}
|
|
.sb-cat{color:rgba(100,220,160,0.7)!important;letter-spacing:1.5px!important;font-size:10px!important;font-weight:700!important}
|
|
|
|
/* 5. INPUT: focus glow premium */
|
|
textarea:focus{box-shadow:0 0 0 2px rgba(100,220,160,0.3),0 0 20px rgba(100,220,160,0.05)!important;border-color:rgba(100,220,160,0.4)!important}
|
|
.input-wrap{transition:box-shadow .2s ease!important}
|
|
.input-wrap:focus-within{box-shadow:0 0 0 1px rgba(100,220,160,0.2),0 4px 20px rgba(0,0,0,0.15)!important}
|
|
|
|
/* 6. TITLE: plus grand + meilleur gradient */
|
|
.welcome h1{font-size:52px!important;letter-spacing:12px!important;background:linear-gradient(135deg,#64dca0,#50b4ff,#a080ff)!important;-webkit-background-clip:text!important;-webkit-text-fill-color:transparent!important;font-weight:800!important}
|
|
.welcome p{font-size:13px!important;color:rgba(255,255,255,0.45)!important;letter-spacing:0.5px!important}
|
|
|
|
/* 7. SCROLLBAR premium */
|
|
::-webkit-scrollbar{width:5px!important}
|
|
::-webkit-scrollbar-track{background:transparent!important}
|
|
::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.1)!important;border-radius:10px!important}
|
|
::-webkit-scrollbar-thumb:hover{background:rgba(100,220,160,0.3)!important}
|
|
|
|
/* 8. MESSAGE BUBBLES: premium */
|
|
.msg{border-radius:14px!important;padding:14px 18px!important;line-height:1.65!important;font-size:13.5px!important}
|
|
.msg-assistant{background:rgba(255,255,255,0.03)!important;border:1px solid rgba(255,255,255,0.05)!important}
|
|
|
|
/* 9. STATUS BAR: glass effect */
|
|
.status-bar,.footer-stats{backdrop-filter:blur(10px)!important;background:rgba(20,20,30,0.8)!important}
|
|
|
|
/* 10. ANIMATIONS: smooth page load */
|
|
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
|
|
.wcard{animation:fadeIn .4s ease backwards!important}
|
|
.wcard:nth-child(1){animation-delay:0s!important}
|
|
.wcard:nth-child(2){animation-delay:.05s!important}
|
|
.wcard:nth-child(3){animation-delay:.1s!important}
|
|
.wcard:nth-child(4){animation-delay:.15s!important}
|
|
.wcard:nth-child(5){animation-delay:.2s!important}
|
|
.wcard:nth-child(6){animation-delay:.25s!important}
|
|
.wcard:nth-child(7){animation-delay:.3s!important}
|
|
.wcard:nth-child(8){animation-delay:.35s!important}
|
|
.sb-item{animation:fadeIn .3s ease backwards!important}
|
|
`;
|
|
document.head.appendChild(s);
|
|
var d=document.createElement('div');d.id='wux';document.body.appendChild(d);
|
|
})();
|
|
</script><script defer src="wevia-claude.js?v=2"></script></body>
|
|
</html>
|