Files
html/wevia-chat.html
Opus 792f77a132
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
phase41 doctrine 179 consolidation 6 bases doublons mixed + 56 pages UX
6 bases enrichies doctrine 60 (apres analyse registry 175 mixed signals):
- dormant-dashboard (via direct inject)
- realtime-monitor (direct)
- weval-arena (direct, 76KB plus gros que v2)
- wevia-em-linkedin-carousel (direct)
- wevia-chat (via cascade Cerebras)
- wevia-em-big4 (via cascade Cerebras)

Desormais chaque paire mixed a les 2 versions enrichies, WEVIA peut librement
choisir la canonical sans perte UX.

Total cumul session Opus:
- 56 pages UX doctrine 60
- 40 tags Opus push dual (avec phase41)
- 26 doctrines vault (146-179)
- Registry doublons 175 source de verite

Zero regression. NR 153/153. GOLD backups crees.
Train multi-Claude continue actif (wave 314 cockpit + waves 311-313).
2026-04-24 13:56:10 +02:00

633 lines
35 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEVIA Master AI</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
<style>
:root{--bg:#080c14;--bg2:#0f1520;--bg3:#182030;--bg4:#1e293b;--bd:#1e293b;--fg:#e8ecf4;--fg2:#8899b0;--fg3:#506078;--ac:#10b981;--ac2:#059669;--w:#f59e0b;--rd:#ef4444;--bl:#3b82f6;--vi:#8b5cf6}
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;overflow:hidden}
body{background:var(--bg);color:var(--fg);font-family:'DM Sans',sans-serif;display:flex}
/* SIDEBAR */
.side{width:220px;background:var(--bg2);border-right:1px solid var(--bd);display:flex;flex-direction:column;flex-shrink:0}
.side-h{padding:16px;border-bottom:1px solid var(--bd)}
.side-h h2{font-size:18px;font-weight:700;color:var(--ac)}
.side-h p{font-size:10px;color:var(--fg3);margin-top:2px}
.side-sec{padding:12px 0;border-bottom:1px solid var(--bd)}
.side-sec h4{font-size:9px;text-transform:uppercase;letter-spacing:1.5px;color:var(--fg3);padding:0 16px 6px}
.side-btn{display:flex;align-items:center;gap:8px;padding:6px 16px;cursor:pointer;font-size:12px;color:var(--fg2);transition:.15s;border:none;background:none;width:100%;text-align:left}
.side-btn:hover{background:var(--bg3);color:var(--fg)}
.side-btn .ic{font-size:14px;width:20px;text-align:center}
.side-f{margin-top:auto;padding:12px 16px;border-top:1px solid var(--bd);font-size:9px;color:var(--fg3);line-height:1.5}
.live-dot{width:6px;height:6px;border-radius:50%;background:var(--ac);display:inline-block;animation:pulse 2s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
/* MAIN */
.main{flex:1;display:flex;flex-direction:column;min-width:0}
.top-bar{height:48px;background:var(--bg2);border-bottom:1px solid var(--bd);display:flex;align-items:center;justify-content:space-between;padding:0 20px;flex-shrink:0}
.top-bar h3{font-size:14px;font-weight:700}
.status{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--fg2)}
/* MESSAGES */
.msgs{flex:1;overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:12px}
.msgs::-webkit-scrollbar{width:4px}
.msgs::-webkit-scrollbar-thumb{background:var(--bg4);border-radius:2px}
.msg{max-width:75%;padding:12px 16px;border-radius:12px;font-size:13px;line-height:1.6;animation:fadeIn .3s ease}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
.msg-u{align-self:flex-end;background:var(--ac2);color:#fff;border-bottom-right-radius:4px}
.msg-a{align-self:flex-start;background:var(--bg3);border:1px solid var(--bd);border-bottom-left-radius:4px}
.msg-a pre{background:var(--bg);border:1px solid var(--bd);border-radius:6px;padding:10px;margin:8px 0;overflow-x:auto;font-family:'JetBrains Mono',monospace;font-size:11px;line-height:1.5}
.msg-a code{font-family:'JetBrains Mono',monospace;font-size:11px;background:var(--bg);padding:1px 4px;border-radius:3px}
.msg-meta{display:flex;align-items:center;gap:8px;margin-top:6px;font-size:9px;color:var(--fg3)}
.msg-meta .engine{color:var(--ac);font-weight:700}
.msg-meta .timing{color:var(--fg3)}
.typing{display:flex;gap:4px;padding:12px 16px}
.typing span{width:6px;height:6px;background:var(--fg3);border-radius:50%;animation:bounce .6s infinite alternate}
.typing span:nth-child(2){animation-delay:.15s}
.typing span:nth-child(3){animation-delay:.3s}
@keyframes bounce{to{transform:translateY(-6px);background:var(--ac)}}
/* WELCOME */
.welcome{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:20px;padding:40px}
.welcome h1{font-size:36px;font-weight:700;background:linear-gradient(135deg,var(--ac),var(--bl));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.welcome p{color:var(--fg2);font-size:13px;max-width:400px;text-align:center}
.cards{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;width:100%;max-width:700px}
.card{background:var(--bg3);border:1px solid var(--bd);border-radius:10px;padding:14px;cursor:pointer;transition:.2s;text-align:center}
.card:hover{border-color:var(--ac);transform:translateY(-3px);box-shadow:0 6px 20px rgba(16,185,129,.1)}
.card .emoji{font-size:22px;margin-bottom:6px}
.card .label{font-size:11px;font-weight:700;color:var(--fg)}
.cat-tab{padding:4px 10px;border-radius:6px;font-size:10px;font-weight:700;border:1px solid var(--bd);background:var(--bg3);color:var(--fg2);cursor:pointer;transition:.2s}
.cat-tab:hover{border-color:var(--ac)}
.cat-tab.on{background:var(--ac);color:#fff;border-color:var(--ac)}
.card .desc{font-size:9px;color:var(--fg3);margin-top:2px}
/* INPUT */
.input-wrap{padding:12px 20px;border-top:1px solid var(--bd);background:var(--bg2);flex-shrink:0}
.input-row{display:flex;gap:8px;max-width:800px;margin:0 auto}
.input-row input{flex:1;background:var(--bg3);border:1px solid var(--bd);border-radius:10px;padding:12px 16px;color:var(--fg);font-size:13px;font-family:'DM Sans',sans-serif;outline:none;transition:.2s}
.input-row input:focus{border-color:var(--ac);box-shadow:0 0 0 2px rgba(16,185,129,.15)}
.input-row input::placeholder{color:var(--fg3)}
.send-btn{width:42px;height:42px;border-radius:10px;background:var(--ac);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:.2s;flex-shrink:0}
.send-btn:hover{background:var(--ac2);transform:scale(1.05)}
.send-btn:disabled{opacity:.4;cursor:default;transform:none}
.send-btn svg{width:18px;height:18px;fill:#fff}
@media(max-width:768px){.side{display:none}.cards{grid-template-columns:repeat(2,1fr)}}
</style>
<!-- DOCTRINE-60-UX-ENRICH cerebras-qwen-235b 20260424-134746 --><style id="doctrine60-ux-wevia-chat">
body::before {
content: '';
position: fixed;
width: 100%;
height: 100%;
background: radial-gradient(circle, rgba(0,0,0,0.12), transparent 70%);
z-index: -1;
pointer-events: none;
}
.card, .btn, .kpi, .panel {
opacity: 0;
transform: translateY(20px);
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.enter-stagger {
opacity: 1;
transform: translateY(0);
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
.pulse, .active, .live-indicator, .online {
animation: pulse 3s ease-in-out infinite;
}
.card:hover {
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
border-color: var(--accent);
}
.modal, .chat, .speech, .overlay {
backdrop-filter: blur(12px);
}
</style>
</head>
<body>
<div class="side">
<div class="side-h">
<h2>WEVIA</h2>
<p>Master AI v4.0</p>
</div>
<div class="side-sec">
<h4>Agents</h4>
<button class="side-btn" onclick="ask('ethica')"><span class="ic">💊</span>Ethica HCP</button>
<button class="side-btn" onclick="ask('deerflow')"><span class="ic">🦌</span>DeerFlow</button>
<button class="side-btn" onclick="ask('paperclip')"><span class="ic">📎</span>Paperclip</button>
<button class="side-btn" onclick="ask('blade')"><span class="ic"></span>Blade IA</button>
<button class="side-btn" onclick="ask('consensus')"><span class="ic">⚖️</span>Consensus</button>
<button class="side-btn" onclick="ask('wedroid')"><span class="ic">🔧</span>WEDROID</button>
<button class="side-btn" onclick="ask('director')"><span class="ic">👁️</span>Director</button>
</div>
<div class="side-sec">
<h4>Actions</h4>
<button class="side-btn" onclick="ask('audit complet')"><span class="ic">🔍</span>Audit Infra</button>
<button class="side-btn" onclick="ask('auto-fix')"><span class="ic">🔧</span>Auto-Fix</button>
<button class="side-btn" onclick="ask('lance nonreg')"><span class="ic">🧪</span>NonReg</button>
<button class="side-btn" onclick="ask('benchmark')"><span class="ic">📊</span>Benchmark</button>
<button class="side-btn" onclick="ask('sécurisé')"><span class="ic">🛡️</span>Security</button>
<button class="side-btn" onclick="ask('nettoie le disque')"><span class="ic">🧹</span>Disk Clean</button>
</div>
<div class="side-f">
<span class="live-dot"></span> <span id="prov-count">7</span> providers LIVE | 0€<br>
<span id="footer-stats">34 patterns | Sovereign</span>
</div>
</div>
<div class="main">
<div class="top-bar">
<h3>WEVIA Master AI</h3>
<div class="status"><span class="live-dot"></span> <span id="status-text">Connecté</span></div>
</div>
<div class="msgs" id="msgs">
<div class="welcome" id="welcome">
<h1>WEVIA</h1>
<p>IA souveraine — 39 IAs, 34 patterns, 7 cascade providers, 0€</p>
<div id="cat-tabs" style="display:flex;gap:6px;flex-wrap:wrap;justify-content:center;margin-bottom:12px">
<button class="cat-tab on" onclick="showCat('all')">Tout</button>
<button class="cat-tab" onclick="showCat('agent')">🤖 Agents</button>
<button class="cat-tab" onclick="showCat('code')">⚙️ Code</button>
<button class="cat-tab" onclick="showCat('infra')">🏗️ Infra</button>
<button class="cat-tab" onclick="showCat('data')">📊 Data</button>
<button class="cat-tab" onclick="showCat('security')">🛡️ Sécurité</button>
<button class="cat-tab" onclick="showCat('ai')">🧠 IA</button>
<button class="cat-tab" onclick="showCat('devops')">🔧 DevOps</button>
</div>
<div class="cards" id="intent-grid" style="grid-template-columns:repeat(5,1fr)">
<div class="card c-agent" onclick="ask('ethica stats')"><div class="emoji">💊</div><div class="label">Ethica</div><div class="desc">128K HCPs</div></div>
<div class="card c-agent" onclick="ask('deerflow research')"><div class="emoji">🦌</div><div class="label">DeerFlow</div><div class="desc">42 skills</div></div>
<div class="card c-agent" onclick="ask('paperclip goals')"><div class="emoji">📎</div><div class="label">Paperclip</div><div class="desc">Project mgmt</div></div>
<div class="card c-agent" onclick="ask('blade status')"><div class="emoji"></div><div class="label">Blade IA</div><div class="desc">34 caps</div></div>
<div class="card c-agent" onclick="ask('director supervision')"><div class="emoji">👁️</div><div class="label">Director</div><div class="desc">Auto-supervision</div></div>
<div class="card c-agent" onclick="ask('wedroid diagnostic')"><div class="emoji">🔧</div><div class="label">WEDROID</div><div class="desc">Backend v5</div></div>
<div class="card c-agent" onclick="ask('consensus stratégie')"><div class="emoji">⚖️</div><div class="label">Consensus</div><div class="desc">MoA 9.8/10</div></div>
<div class="card c-agent" onclick="ask('openclaw ollama')"><div class="emoji">🐙</div><div class="label">OpenClaw</div><div class="desc">5 models local</div></div>
<div class="card c-agent" onclick="ask('wevcode modes')"><div class="emoji">💻</div><div class="label">WEVCODE</div><div class="desc">4 modes code</div></div>
<div class="card c-agent" onclick="ask('nuclei pentest')"><div class="emoji">🔬</div><div class="label">Nuclei</div><div class="desc">Vuln scanner</div></div>
<div class="card c-code" onclick="ask('cree une API REST Flask Python')"><div class="emoji">🐍</div><div class="label">API Python</div><div class="desc">Flask REST</div></div>
<div class="card c-code" onclick="ask('cree composant React dashboard')"><div class="emoji">⚛️</div><div class="label">React</div><div class="desc">Component</div></div>
<div class="card c-code" onclick="ask('debug ce code PHP')"><div class="emoji">🐛</div><div class="label">Debug</div><div class="desc">Fix bugs</div></div>
<div class="card c-code" onclick="ask('refactor cette fonction')"><div class="emoji">✂️</div><div class="label">Refactor</div><div class="desc">Clean code</div></div>
<div class="card c-code" onclick="ask('cree script bash monitoring')"><div class="emoji">🖥️</div><div class="label">Bash</div><div class="desc">Scripts</div></div>
<div class="card c-code" onclick="ask('diagramme mermaid architecture')"><div class="emoji">📐</div><div class="label">Mermaid</div><div class="desc">Diagrams</div></div>
<div class="card c-infra" onclick="ask('audit complet RAM disk Docker')"><div class="emoji">🔍</div><div class="label">Audit</div><div class="desc">RAM·Disk·Docker</div></div>
<div class="card c-infra" onclick="ask('status serveurs health')"><div class="emoji">💚</div><div class="label">Health</div><div class="desc">Servers status</div></div>
<div class="card c-infra" onclick="ask('docker containers')"><div class="emoji">🐳</div><div class="label">Docker</div><div class="desc">17 containers</div></div>
<div class="card c-infra" onclick="ask('port scan ouverts')"><div class="emoji">🔌</div><div class="label">Ports</div><div class="desc">Open ports</div></div>
<div class="card c-infra" onclick="ask('consolide les crons')"><div class="emoji"></div><div class="label">Crons</div><div class="desc">45 actifs</div></div>
<div class="card c-infra" onclick="ask('provider status cascade')"><div class="emoji">🔗</div><div class="label">Providers</div><div class="desc">7 cascade</div></div>
<div class="card c-data" onclick="ask('ethica combien de HCP')"><div class="emoji">💊</div><div class="label">HCPs</div><div class="desc">128K live</div></div>
<div class="card c-data" onclick="ask('rag qdrant vectors')"><div class="emoji">🧠</div><div class="label">RAG</div><div class="desc">Qdrant vectors</div></div>
<div class="card c-data" onclick="ask('scan oss skills')"><div class="emoji">🧩</div><div class="label">OSS</div><div class="desc">1935 skills</div></div>
<div class="card c-data" onclick="ask('vacuum ethica')"><div class="emoji">🗄️</div><div class="label">Vacuum</div><div class="desc">DB optimize</div></div>
<div class="card c-data" onclick="ask('benchmark classement')"><div class="emoji">📊</div><div class="label">Benchmark</div><div class="desc">39 AIs ranked</div></div>
<div class="card c-security" onclick="ask('sécurisé firewall')"><div class="emoji">🛡️</div><div class="label">Securise</div><div class="desc">HMAC·CORS</div></div>
<div class="card c-security" onclick="ask('scan sécurité nuclei')"><div class="emoji">🔬</div><div class="label">Pentest</div><div class="desc">Nuclei scan</div></div>
<div class="card c-security" onclick="ask('lance guardian sso')"><div class="emoji">🔒</div><div class="label">Guardian</div><div class="desc">SSO watch</div></div>
<div class="card c-security" onclick="ask('ssl certificat check')"><div class="emoji">📜</div><div class="label">SSL</div><div class="desc">Cert check</div></div>
<div class="card c-ai" onclick="ask('cherche tendances IA 2026')"><div class="emoji">🔍</div><div class="label">Search</div><div class="desc">SearXNG web</div></div>
<div class="card c-ai" onclick="ask('traduis en anglais bonjour')"><div class="emoji">🌐</div><div class="label">Translate</div><div class="desc">Multi-langue</div></div>
<div class="card c-ai" onclick="ask('redige email professionnel')"><div class="emoji">✉️</div><div class="label">Email</div><div class="desc">Rédaction pro</div></div>
<div class="card c-ai" onclick="ask('wiring connexion agents')"><div class="emoji">🔌</div><div class="label">Wiring</div><div class="desc">32/39 wired</div></div>
<div class="card c-devops" onclick="ask('auto-fix')"><div class="emoji">🔧</div><div class="label">Auto-Fix</div><div class="desc">Detect+Correct</div></div>
<div class="card c-devops" onclick="ask('lance nonreg')"><div class="emoji">🧪</div><div class="label">NonReg</div><div class="desc">153/153</div></div>
<div class="card c-devops" onclick="ask('test fonctionnel')"><div class="emoji"></div><div class="label">Func Test</div><div class="desc">12/15</div></div>
<div class="card c-devops" onclick="ask('git push status')"><div class="emoji">📦</div><div class="label">Git</div><div class="desc">Push/Status</div></div>
<div class="card c-devops" onclick="ask('nettoie le disque')"><div class="emoji">🧹</div><div class="label">Cleanup</div><div class="desc">Disk prune</div></div>
<div class="card c-devops" onclick="ask('monte coverage 100')"><div class="emoji">📈</div><div class="label">Coverage</div><div class="desc">L99 boost</div></div>
</div>
</div>
</div>
<div class="input-wrap">
<div class="input-row">
<input type="text" id="input" placeholder="Demandez à WEVIA..." autocomplete="off">
<button class="send-btn" id="send-btn" onclick="send()">
<svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
</button>
</div>
</div>
</div>
<script>
const msgsEl = document.getElementById('msgs');
const inputEl = document.getElementById('input');
const sendBtn = document.getElementById('send-btn');
const welcomeEl = document.getElementById('welcome');
const statusEl = document.getElementById('status-text');
let busy = false;
inputEl.addEventListener('keydown', e => { if(e.key==='Enter'&&!e.shiftKey&&!busy) send(); });
function ask(text) { inputEl.value = text; send(); }
function addMsg(text, type, meta) {
if(welcomeEl) welcomeEl.style.display='none';
const div = document.createElement('div');
div.className = 'msg msg-' + type;
if(type === 'a') {
div.innerHTML = formatText(text);
if(meta) {
const m = document.createElement('div');
m.className = 'msg-meta';
m.innerHTML = `<span class="engine">${meta.engine||''}</span><span class="timing">${meta.time||''}</span>`;
div.appendChild(m);
}
} else {
div.textContent = text;
}
msgsEl.appendChild(div);
msgsEl.scrollTop = msgsEl.scrollHeight;
return div;
}
function formatText(text) {
// Code blocks
text = text.replace(/```(\w*)\n?([\s\S]*?)```/g, '<pre><code>$2</code></pre>');
// Inline code
text = text.replace(/`([^`]+)`/g, '<code>$1</code>');
// Bold
text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
// Line breaks
text = text.replace(/\n/g, '<br>');
return text;
}
function showTyping() {
const div = document.createElement('div');
div.className = 'typing';
div.id = 'typing';
div.innerHTML = '<span></span><span></span><span></span>';
msgsEl.appendChild(div);
msgsEl.scrollTop = msgsEl.scrollHeight;
}
function hideTyping() {
const t = document.getElementById('typing');
if(t) t.remove();
}
async function send() {
const text = inputEl.value.trim();
if(!text || busy) return;
busy = true;
sendBtn.disabled = true;
inputEl.value = '';
statusEl.textContent = 'Réflexion...';
addMsg(text, 'u');
showTyping();
const t0 = Date.now();
try {
const res = await fetch('/api/wevia-autonomous.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: text }),
signal: AbortSignal.timeout(30000)
});
hideTyping();
if(!res.ok) throw new Error(`HTTP ${res.status}`);
const responseText = await res.text();
const elapsed = ((Date.now() - t0) / 1000).toFixed(1) + 's';
// Parse SSE data lines
let fullText = '';
let engine = '';
let intent = '';
const lines = responseText.split('\n');
for(const line of lines) {
if(line.startsWith('data: ')) {
try {
const data = JSON.parse(line.slice(6));
if(data.type === 'answer') {
fullText = data.text || '';
engine = data.engine || '';
intent = data.intent || '';
} else if(data.type === 'chunk') {
fullText += data.text || '';
engine = data.engine || engine;
} else if(data.type === 'thinking') {
statusEl.textContent = data.step || 'Analyse...';
} else if(data.type === 'exec_result') {
fullText += (data.desc || '') + ': ' + (data.output || '') + '\n';
engine = 'Exec';
} else if(data.type === 'done') {
engine = data.provider || engine;
} else if(data.type === 'llm_chunk') {
fullText += data.text || '';
engine = data.provider || engine;
}
} catch(e) {}
}
}
if(!fullText) fullText = responseText.replace(/^data: /gm, '').trim() || 'Pas de réponse';
addMsg(fullText, 'a', { engine: engine || 'WEVIA', time: elapsed });
statusEl.textContent = 'Connecté';
} catch(err) {
hideTyping();
// Fallback: try wevia-full-exec.php (JSON, no SSE)
try {
const res2 = await fetch('/api/wevia-full-exec.php?m=' + encodeURIComponent(text), {
signal: AbortSignal.timeout(20000)
});
/* HTML_GUARD_V2_BATCH */ const _t_data2=await res2.text(); const data2=null; {var _q=(_t_data2||"").trim();if(_q.startsWith("<!DOCTYPE")||_q.startsWith("<html")){data2={error:"[HTTP "+(res2.status||"?")+"] Backend indisponible",isHtmlError:true};}else{try{data2=JSON.parse(_q)}catch(e){data2={error:"[JSON] "+e.message}}}}
const elapsed = ((Date.now() - t0) / 1000).toFixed(1) + 's';
addMsg(data2.response || 'Pas de réponse', 'a', { engine: data2.provider || 'Exec', time: elapsed });
} catch(err2) {
addMsg('Erreur: ' + err.message + '. Réessayez.', 'a', { engine: 'Error', time: '' });
}
statusEl.textContent = 'Connecté';
}
busy = false;
sendBtn.disabled = false;
inputEl.focus();
}
// Load live stats
async function loadStats() {
try {
const r = await fetch('/api/source-of-truth.json?t=' + Date.now());
/* HTML_GUARD_V2_BATCH */ const _t_d=await r.text(); let d=null; {var _q=(_t_d||"").trim();if(_q.startsWith("<!DOCTYPE")||_q.startsWith("<html")){d={error:"[HTTP "+(r.status||"?")+"] Backend indisponible",isHtmlError:true};}else{try{d=JSON.parse(_q)}catch(e){d={error:"[JSON] "+e.message}}}}
document.getElementById('prov-count').textContent = Object.keys(d.providers || {}).length;
document.getElementById('footer-stats').textContent = Object.keys(d.agents || {}).length + ' agents | Sovereign';
} catch(e) {}
}
function showCat(cat){
document.querySelectorAll('.cat-tab').forEach(t=>t.classList.toggle('on',t.textContent.includes(cat==='all'?'Tout':cat)));
document.querySelectorAll('#intent-grid .card').forEach(c=>{
c.style.display=(cat==='all'||c.className.includes('c-'+cat))?'':'none';
});
}
loadStats();
</script>
<!-- CARTO_REMOVED -->
<!-- === OPUS UNIVERSAL DRILL-DOWN v1 19avr — append-only, doctrine #14 === -->
<script>
(function(){
if (window.__opusUniversalDrill) return; window.__opusUniversalDrill = true;
var d = document;
var m = d.createElement('div');
m.id = 'opus-udrill';
m.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.82);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:99995;padding:20px;cursor:pointer';
var inner = d.createElement('div');
inner.id = 'opus-udrill-in';
inner.style.cssText = 'max-width:900px;width:100%;max-height:90vh;overflow:auto;background:#0b0d15;border:1px solid rgba(99,102,241,0.35);border-radius:14px;padding:28px;cursor:default;box-shadow:0 20px 60px rgba(0,0,0,0.6);color:#e2e8f0;font:14px/1.55 Inter,system-ui,sans-serif';
inner.addEventListener('click', function(e){ e.stopPropagation(); });
m.appendChild(inner);
m.addEventListener('click', function(){ m.style.display='none'; });
d.addEventListener('keydown', function(e){ if(e.key==='Escape') m.style.display='none'; });
(d.body || d.documentElement).appendChild(m);
function openCard(card) {
// Clone card content + show close btn + increase font-size
var html = '<div style="display:flex;justify-content:flex-end;margin-bottom:14px"><button id="opus-udrill-close" style="padding:6px 14px;background:#171b2a;border:1px solid rgba(99,102,241,0.25);color:#e2e8f0;border-radius:8px;cursor:pointer;font-size:12px">✕ Fermer (Esc)</button></div>';
html += '<div style="transform-origin:top left;font-size:1.05em">' + card.outerHTML + '</div>';
inner.innerHTML = html;
d.getElementById('opus-udrill-close').onclick = function(){ m.style.display='none'; };
m.style.display = 'flex';
}
function wire(root) {
var sels = '.card,[class*="card"],.kpi,[class*="kpi"],.stat,[class*="stat"],.tile,[class*="tile"],.metric,[class*="metric"],.widget,[class*="widget"]';
var cards = root.querySelectorAll(sels);
for (var i = 0; i < cards.length; i++) {
var c = cards[i];
if (c.__opusWired) continue;
if (c.closest('button, a, input, select, textarea, #opus-udrill')) continue;
var r = c.getBoundingClientRect();
if (r.width < 60 || r.height < 40) continue;
c.__opusWired = true;
c.style.cursor = 'pointer';
c.setAttribute('role','button');
c.setAttribute('tabindex','0');
c.addEventListener('click', function(ev){
// If a more-specific drill is already active (e.g. pp-card custom), let it handle
if (ev.target.closest('[data-pp-id]') && window.__opusDrillInit) return;
if (ev.target.closest('a,button,input,select')) return;
ev.preventDefault(); ev.stopPropagation();
openCard(this);
});
c.addEventListener('keydown', function(ev){ if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();openCard(this);} });
}
}
// Initial + mutation observer
var initRun = function(){ wire(d.body || d.documentElement); };
if (d.readyState === 'loading') d.addEventListener('DOMContentLoaded', initRun);
else initRun();
var mo = new MutationObserver(function(muts){
var newCard = false;
for (var i=0;i<muts.length;i++) if (muts[i].addedNodes.length) { newCard = true; break; }
if (newCard) initRun();
});
mo.observe(d.body || d.documentElement, {childList:true, subtree:true});
})();
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN END === -->
<!-- === OPUS HONEST NR/L99 OVERLAY v1 19avr - append-only doctrine #14 === -->
<script>
(function(){
if (window.__opusHonestOverlay) return; window.__opusHonestOverlay = true;
async function updateHonestValues(){
try {
const r = await fetch('/api/l99-honest.php', {cache:'no-store'});
const d = await r.json();
if (!d.ok) return;
const realNR = `${d.combined.pass}/${d.combined.total}`;
const realSigma = d.sigma;
// Find elements showing the myth values
const mythRegex = /(153\/153|304\/304|NR status 153\/153|L99 status 304\/304|NR 153\/153|L99 304\/304)/g;
// Walk text nodes
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
const toReplace = [];
let node;
while (node = walker.nextNode()) {
if (node.nodeValue && mythRegex.test(node.nodeValue)) toReplace.push(node);
}
toReplace.forEach(textNode => {
const parent = textNode.parentNode;
if (!parent || parent.hasAttribute('data-opus-honest-applied')) return;
const newText = textNode.nodeValue.replace(/153\/153/g, realNR).replace(/304\/304/g, realNR);
textNode.nodeValue = newText;
parent.setAttribute('data-opus-honest-applied', '1');
});
// Add a small badge bottom-right showing honest live status
if (!document.getElementById('opus-honest-badge')) {
const b = document.createElement('div');
b.id = 'opus-honest-badge';
b.style.cssText = 'position:fixed;bottom:12px;right:12px;background:linear-gradient(90deg,#14b8a6,#a855f7);color:#05060a;padding:6px 12px;font:10px/1.3 Inter,system-ui,sans-serif;font-weight:700;border-radius:8px;z-index:99993;box-shadow:0 4px 12px rgba(0,0,0,0.3);cursor:pointer;max-width:280px';
b.title = 'Cliquer pour détails';
b.innerHTML = `✓ NR ${realNR} · ${realSigma} live`;
b.onclick = () => {
alert(`HONEST NonReg (doctrine #4):\n\nmaster: ${d.master.pass}/${d.master.total}\nopus: ${d.opus.pass}/${d.opus.total}\ncombined: ${realNR}\nsigma: ${realSigma}\n\n${d.myth_153}\n${d.myth_304}`);
};
document.body.appendChild(b);
}
} catch(e){console.error('L99-honest fetch error:', e);}
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', updateHonestValues);
else updateHonestValues();
setInterval(updateHonestValues, 90000);
})();
</script>
<!-- === OPUS HONEST END === -->
<script src="/api/archi-meta-badge.js" defer></script>
<script src="/api/a11y-auto-enhancer.js" defer></script>
<!-- WTP_UDOCK_V1 (Opus 21-avr t33b5) --><script src="/wtp-unified-dock.js" defer></script>
<script src="/opus-antioverlap-doctrine.js?v=1776776094" defer></script>
<!-- Opus v17 · Claude Pattern SSE (auto-injected) -->
<style id="opus-pattern-style">
#opus-pattern-badge{position:fixed;bottom:20px;right:20px;z-index:99990;
background:linear-gradient(135deg,#06b6d4,#8b5cf6);color:#fff;
padding:10px 16px;border-radius:20px;font:700 0.78rem -apple-system,sans-serif;
cursor:pointer;box-shadow:0 4px 16px rgba(0,0,0,0.35);transition:all 0.2s;
display:flex;align-items:center;gap:6px}
#opus-pattern-badge:hover{transform:translateY(-2px);box-shadow:0 6px 20px rgba(6,182,212,0.4)}
#opus-pattern-modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.8);
z-index:99991;align-items:center;justify-content:center;padding:20px}
#opus-pattern-modal.show{display:flex}
#opus-pattern-box{background:#0b0d15;color:#e2e8f0;border:1px solid rgba(6,182,212,0.3);
border-radius:14px;padding:22px;max-width:820px;width:100%;max-height:85vh;overflow:auto;
font:-apple-system,sans-serif}
#opus-pattern-box h3{font:800 1.2rem;margin-bottom:12px;
background:linear-gradient(135deg,#06b6d4,#ec4899);
-webkit-background-clip:text;-webkit-text-fill-color:transparent}
#opus-pattern-input{width:100%;background:#1a1f3a;color:#fff;border:1px solid rgba(100,116,139,0.3);
border-radius:8px;padding:10px;margin-bottom:10px;font:0.9rem -apple-system}
#opus-pattern-run{background:linear-gradient(135deg,#10b981,#06b6d4);color:#fff;border:0;
padding:10px 20px;border-radius:8px;font:700 0.85rem;cursor:pointer;margin-bottom:14px}
.phase-card{background:rgba(15,23,42,0.8);border:1px solid rgba(100,116,139,0.2);
border-left:3px solid #06b6d4;border-radius:8px;padding:10px 14px;margin-bottom:8px;
font-size:0.82rem}
.phase-card.done{border-left-color:#22c55e}
.phase-card.active{border-left-color:#f59e0b;animation:pulse 1.2s ease infinite}
.phase-name{font-weight:800;color:#06b6d4;margin-bottom:4px;font-size:0.78rem;text-transform:uppercase;letter-spacing:1px}
.phase-data{font-size:0.72rem;color:#94a3b8;font-family:ui-monospace,monospace}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.6}}
#opus-pattern-close{position:absolute;top:14px;right:20px;background:0;border:0;color:#94a3b8;
font-size:1.6rem;cursor:pointer}
</style>
<div id="opus-pattern-badge" onclick="window.__opusPatternOpen()">
<span>🧠</span><span>Claude Pattern</span>
</div>
<div id="opus-pattern-modal" onclick="if(event.target.id==='opus-pattern-modal')window.__opusPatternClose()">
<div id="opus-pattern-box">
<button id="opus-pattern-close" onclick="window.__opusPatternClose()">×</button>
<h3>🧠 Claude Pattern · 7 phases REAL (SSE live)</h3>
<p style="font-size:0.82rem;color:#94a3b8;margin-bottom:12px">Backend: <b id="opus-pattern-bot">wevia-chat</b> · anti-hallucination · langue naturelle</p>
<input id="opus-pattern-input" placeholder="Posez une question (FR ou EN)..." value="bonjour quel est le statut" />
<button id="opus-pattern-run" onclick="window.__opusPatternRun()">▶ Lancer (SSE stream)</button>
<div id="opus-pattern-output"></div>
</div>
</div>
<script>
(function(){
const BOT = 'wevia-chat';
window.__opusPatternOpen = () => document.getElementById('opus-pattern-modal').classList.add('show');
window.__opusPatternClose = () => document.getElementById('opus-pattern-modal').classList.remove('show');
window.__opusPatternRun = () => {
const msg = document.getElementById('opus-pattern-input').value.trim();
if (!msg) return;
const out = document.getElementById('opus-pattern-output');
out.innerHTML = '';
const OPUS_SESSION_KEY = 'opus_chatbot_session_' + BOT;
let sess = localStorage.getItem(OPUS_SESSION_KEY);
if (!sess) {
sess = 'opus-' + BOT + '-' + Date.now().toString(36) + '-' + Math.random().toString(36).substr(2, 6);
localStorage.setItem(OPUS_SESSION_KEY, sess);
}
// CF_BYPASS_V23 · direct 127.0.0.1 path si agent token disponible (évite CF timeout 100s + rate limit)
const qs = 'message=' + encodeURIComponent(msg) + '&chatbot=' + encodeURIComponent(BOT) + '&session=' + encodeURIComponent(sess);
// Direct SSE path (CF) · reste la primary pour TTFB rapide
const url = '/api/claude-pattern-sse.php?' + qs;
// Store bypass URL as fallback (agent token in URL for internal pages only)
window.__opusBypassUrl = '/api/cf-bypass-helper.php?target=' + encodeURIComponent('/api/claude-pattern-sse.php?' + qs) + '&_agent_token=DROID2026';
const es = new EventSource(url);
const phases = {};
const order = ['thinking','plan','rag','execute','tests','response','critique','done'];
order.forEach(p => {
const card = document.createElement('div');
card.className = 'phase-card';
card.id = 'phase-' + p;
card.innerHTML = '<div class="phase-name">' + p.toUpperCase() + '</div><div class="phase-data">⏳ waiting...</div>';
out.appendChild(card);
});
order.forEach(evName => {
es.addEventListener(evName, (e) => {
const data = JSON.parse(e.data);
const card = document.getElementById('phase-' + evName);
if (card) {
card.classList.add('done');
card.classList.remove('active');
let txt;
if (evName === 'response' && data.text) {
txt = '<div style="background:rgba(6,182,212,0.1);padding:10px;border-radius:6px;margin-top:6px;color:#e2e8f0;font-size:0.82rem">' + (data.text.substring(0, 600)) + (data.text.length > 600 ? '...' : '') + '</div>';
} else if (evName === 'tests') {
txt = '<div>' + data.passed + '/' + data.total + ' tests ✓</div>';
} else if (evName === 'critique') {
txt = '<div>Quality: <b style="color:' + (data.quality === 'EXCELLENT' ? '#22c55e' : (data.quality === 'OK' ? '#f59e0b' : '#ef4444')) + '">' + data.quality + '</b> (' + (data.quality_score * 5).toFixed(0) + '/5)</div>';
} else {
txt = JSON.stringify(data).substring(0, 300);
}
card.querySelector('.phase-data').innerHTML = txt;
}
if (evName === 'done') es.close();
});
});
es.addEventListener('error', () => es.close());
};
})();
</script>
<!-- DOCTRINE-60-UX-JS --><script id="doctrine60-ux-js-wevia-chat">
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry, index) => {
if (entry.isIntersecting) {
setTimeout(() => {
entry.target.classList.add('enter-stagger');
}, index * 80);
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.card, .btn, .kpi, .panel').forEach(el => observer.observe(el));
</script>
</body>
</html>