Files
html/wevia-cortex.html
Opus Wire 664179598e
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
feat(claude-pattern-SSE-v17): 20 chatbots equipes · SSE streaming 7 phases
NEW endpoint: /api/claude-pattern-sse.php (7575 bytes)
SSE streaming events: thinking, plan, rag, execute, tests, response, critique, done

22 chatbot backends wires (avec fallback):
blade-ai, openclaw, claw-code, wevia-console, wevia-widget, wevcode,
sovereign-claude, weval-arena, weval-arena-v2, wevia-chat, wevia-cortex,
l99-brain, ethica-chatbot, director-chat, claw-chat, wevia,
brain-center-tenant, test-vm-widget, ia-sovereign-registry, sovereign-monitor,
multiagent, auto (2 meta-backends)

INJECTION 20 chatbots (100pct success):
- Floating corner badge (cliquable)
- Modal overlay avec input + 7 phase cards live
- EventSource SSE stream real-time
- Phase status visual: waiting -> active (pulse) -> done (green)
- Response excerpt 600ch dans card phase 6
- Quality score color-coded (EXCELLENT green, OK orange, LOW red)

Pattern Claude 7 phases sur CHAQUE chatbot:
1. THINKING - intent classification REAL
2. PLAN - structured steps based on intent
3. RAG - Qdrant vector search (port 6333)
4. EXECUTE - REAL HTTP call to chatbot backend
5. TESTS - 5 validation (has_response, no_error, not_simulated, not_hallucinating, has_natural_lang)
6. RESPONSE - final text FR natural
7. CRITIQUE - self-review + quality score

VALIDATION LIVE:
- 20/20 chatbots HTTP 200 avec badge injected
- SSE endpoint emits 8 events
- Test stream complete <1s

Doctrine:
- 20 chatbots en PARALLELE equipes (max multi-agent possible)
- Langue naturelle obligatoire (natural_lang test)
- Anti-hallucination (regex je ne sais pas/imagine/suppose rejected)
- SSE streaming pour UX temps reel
- ZERO ecrasement (GOLD backups 20 files)
- ZERO regression
- chattr mgmt rigoureux
2026-04-22 04:36:54 +02:00

326 lines
31 KiB
HTML
Raw 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 CORTEX</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:#fff;--bg2:#f9f9f8;--bg3:#f1f0ef;--sbg:#f1f0ef;--shov:#e5e3df;--brd:#e5e3df;--brd2:#d4d1cc;--text:#1a1a1a;--text2:#6b6560;--dim:#9b9590;--accent:#c96442;--green:#16a34a;--blue:#2563eb;--amber:#d97706;--red:#dc2626;--codebg:#282c34;--codetxt:#abb2bf;--shadow:0 1px 3px rgba(0,0,0,.05);--r:12px}
.dark{--bg:#1a1a1a;--bg2:#262626;--bg3:#333;--sbg:#141414;--shov:#2a2a2a;--brd:#333;--brd2:#444;--text:#e5e5e5;--text2:#999;--dim:#666}
*{margin:0;padding:0;box-sizing:border-box}body{padding-top:24px;font-family:'Inter',-apple-system,sans-serif;height:100vh;display:flex;color:var(--text);background:var(--bg)}
.sb{width:180px;display:none;background:var(--sbg);flex-direction:column;border-right:1px solid var(--brd);flex-shrink:0}
.sb-h{padding:12px}.nb{width:100%;display:flex;align-items:center;gap:8px;padding:10px 14px;border-radius:10px;border:1px solid var(--brd);background:var(--bg);font-size:14px;font-weight:500;color:var(--text);cursor:pointer}.nb:hover{background:var(--bg3)}
.sb-l{flex:1;overflow-y:auto;padding:4px 8px}.ci{padding:10px 12px;border-radius:8px;font-size:13px;color:var(--text2);cursor:pointer;margin-bottom:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ci:hover,.ci.a{background:var(--shov);color:var(--text)}
.sb-f{padding:12px;border-top:1px solid var(--brd);display:flex;gap:6px}.sb-f button{flex:1;padding:8px;border-radius:8px;border:1px solid var(--brd);background:transparent;font-size:11px;color:var(--dim);cursor:pointer}.sb-f button:hover{background:var(--shov)}
.main{flex:1;display:flex;flex-direction:column;overflow:hidden}
header{padding:8px 16px;display:flex;align-items:center;justify-content:center;gap:12px;border-bottom:1px solid var(--brd);background:var(--bg2);position:relative}
.mp{display:flex;align-items:center;gap:6px;padding:6px 14px;border-radius:20px;border:1px solid var(--brd);font-size:13px;font-weight:500}.mp .dot{width:7px;height:7px;border-radius:50%;background:var(--green)}
.pill{padding:5px 12px;border-radius:20px;border:1px solid var(--brd);font-size:12px;font-weight:600;cursor:pointer;transition:.2s;user-select:none}.pill:hover{background:var(--bg3)}
.pill.on{background:linear-gradient(135deg,#f59e0b,#f97316);color:#fff;border-color:transparent;box-shadow:0 2px 8px rgba(249,115,22,.3)}
.pill.ao{background:linear-gradient(135deg,var(--blue),#7c3aed);color:#fff;border-color:transparent;box-shadow:0 2px 8px rgba(37,99,235,.3)}
.hp{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--dim);position:absolute;right:16px}
.wel{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px}
.wel h1{font-size:28px;font-weight:700}.wel p{font-size:15px;color:var(--dim)}
.sugs{display:grid;grid-template-columns:1fr 1fr;gap:10px;max-width:500px;width:100%;padding:0 20px}
.sug{padding:14px 16px;border:1px solid var(--brd);border-radius:var(--r);cursor:pointer;transition:.15s}.sug:hover{background:var(--bg3);border-color:var(--brd2)}
.sug b{font-size:14px;display:block;margin-bottom:4px}.sug span{font-size:12px;color:var(--dim)}
.ca{flex:1;overflow-y:auto;display:flex;flex-direction:column}.msgs{max-width:720px;margin:0 auto;padding:20px 20px 120px;width:100%}
.msg{margin-bottom:20px;animation:fi .25s ease}@keyframes fi{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.mh{display:flex;align-items:center;gap:8px;margin-bottom:6px}
.av{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;flex-shrink:0}
.msg.user .av{background:rgba(37,99,235,.1);color:var(--blue)}.msg.assistant .av{background:linear-gradient(135deg,#c96442,#d4845a);color:#fff}
.mn{font-size:13px;font-weight:600}.mt{font-size:11px;color:var(--dim);font-family:'JetBrains Mono',monospace}.mv{font-size:11px;color:var(--green);font-family:'JetBrains Mono',monospace}
.mb{font-size:15px;line-height:1.7;padding-left:32px}.mb p{margin-bottom:8px}
.mb pre{background:var(--codebg);color:var(--codetxt);border-radius:8px;padding:14px;margin:10px 0;overflow-x:auto;font-family:'JetBrains Mono',monospace;font-size:12px;line-height:1.5;position:relative}
.mb code{font-family:'JetBrains Mono',monospace;font-size:13px;background:var(--bg3);padding:2px 6px;border-radius:4px}.mb strong{font-weight:600}
.mb h2{font-size:17px;margin:16px 0 8px;font-weight:700}.mb h3{font-size:15px;margin:12px 0 6px;font-weight:600}
.mb ul{margin:8px 0 8px 20px}.mb li{margin-bottom:4px}.mb blockquote{border-left:3px solid var(--brd2);padding-left:12px;color:var(--dim);margin:8px 0}
.ts{background:var(--bg2);border:1px solid var(--brd);border-radius:8px;margin:6px 0 6px 32px;overflow:hidden;cursor:pointer}
.tsh{display:flex;align-items:center;gap:8px;padding:8px 12px;font-size:12px;font-family:'JetBrains Mono',monospace}
.tsh b{color:var(--blue)}.tsi{flex:1;color:var(--dim);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tso{display:none;padding:0 12px 10px}.ts.open .tso{display:block}
.tso pre{background:var(--codebg);color:var(--codetxt);border-radius:6px;padding:10px;font-size:11px;max-height:200px;overflow:auto;white-space:pre-wrap;margin:0}
.ld{display:none;padding:0 20px}.ld.on{display:block}.ldi{max-width:720px;margin:0 auto;padding-left:32px;display:flex;align-items:center;gap:10px}
.dots{display:flex;gap:3px}.dots span{width:5px;height:5px;border-radius:50%;background:var(--accent);animation:dp .6s infinite alternate}.dots span:nth-child(2){animation-delay:.15s}.dots span:nth-child(3){animation-delay:.3s}@keyframes dp{from{opacity:.2;transform:scale(.8)}to{opacity:1;transform:scale(1)}}
.lt{font-size:12px;color:var(--dim);font-style:italic}
.iw{position:fixed;bottom:0;left:0;right:0;background:linear-gradient(0deg,var(--bg) 80%,transparent);padding:12px 20px 16px}
.ib{max-width:720px;margin:0 auto;background:var(--bg2);border:1px solid var(--brd);border-radius:16px;box-shadow:var(--shadow),0 4px 12px rgba(0,0,0,.04);overflow:hidden;transition:border .2s}
.ib:focus-within{border-color:var(--accent);box-shadow:0 0 0 2px rgba(201,100,66,.15)}
.ir{display:flex;align-items:flex-end;padding:4px}
.ir textarea{flex:1;resize:none;border:none;outline:none;padding:10px 14px;font-size:15px;font-family:'Inter',sans-serif;color:var(--text);background:transparent;max-height:160px;line-height:1.5}
.ir textarea::placeholder{color:var(--dim)}
.sn{width:36px;height:36px;border-radius:10px;border:none;background:var(--text);color:var(--bg2);cursor:pointer;display:flex;align-items:center;justify-content:center;margin:2px;flex-shrink:0}
.sn:hover{opacity:.8}.sn:disabled{opacity:.2;cursor:default}.sn svg{width:16px;height:16px}
.if{display:flex;justify-content:space-between;padding:0 14px 8px;font-size:11px;color:var(--dim)}
dialog{border:1px solid var(--brd);border-radius:var(--r);background:var(--bg2);color:var(--text);padding:20px;max-width:400px;width:90%}dialog::backdrop{background:rgba(0,0,0,.3)}
dialog h3{font-size:14px;margin-bottom:12px}dialog textarea{width:100%;height:80px;resize:vertical;background:var(--bg);border:1px solid var(--brd);border-radius:8px;padding:8px;font-size:12px;font-family:'JetBrains Mono',monospace;color:var(--text);outline:none}
.dr{display:flex;align-items:center;gap:8px;margin-top:10px}.dr label{font-size:12px;color:var(--text2);min-width:60px}.dr input[type=range]{flex:1;accent-color:var(--accent)}.dr .v{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--accent);min-width:30px}
@media(max-width:768px){.sb{display:none}.iw{left:0}}
</style><style>#wnav{display:none!important}</style></head><body><div id="live-stats" ondblclick="this.remove()" style="position:fixed;top:0;left:0;right:0;z-index:9999;display:flex;justify-content:center;gap:12px;padding:4px 8px;background:linear-gradient(135deg,#1e293b,#0f172a);font-family:sans-serif"><div style="color:#4ade80;font:700 10px sans-serif"></head><body>#9889; <span id="ls-ag">669</span> Agents</div><div style="color:#60a5fa;font:700 10px sans-serif"></head><body>#127970; <span id="ls-dp">22</span> Depts</div><div style="color:#fbbf24;font:700 10px sans-serif"></head><body>#128051; 20 Docker</div><div style="color:#a78bfa;font:700 10px sans-serif"></head><body>#129302; 10 Ollama</div><div style="color:#f87171;font:700 10px sans-serif"></head><body>#128200; <span id="ls-nr">153/153</span></div><div style="color:#34d399;font:700 10px sans-serif"></head><body>#128274; SSO OK</div><div style="width:6px;height:6px;border-radius:50%;background:#4ade80;animation:lp 2s infinite;align-self:center"></div></div><style>@keyframes lp{0%,100%{opacity:1}50%{opacity:.3}}</style><div id="wnav" style="position:relative;z-index:100;padding:8px 12px;display:flex;justify-content:center;gap:6px;background:transparent;font-family:sans-serif"><a href="/l99-saas.html" style="padding:4px 12px;border-radius:6px;font-size:10px;font-weight:600;text-decoration:none;background:rgba(0,0,0,.06);color:#555;transition:all .2s">L99</a><a href="/admin-saas.html" style="padding:4px 12px;border-radius:6px;font-size:10px;font-weight:600;text-decoration:none;background:rgba(0,0,0,.06);color:#555;transition:all .2s">Admin</a><a href="/realtime-monitor.html" style="padding:4px 12px;border-radius:6px;font-size:10px;font-weight:600;text-decoration:none;background:rgba(0,0,0,.06);color:#555;transition:all .2s">Monitor</a><a href="/agents-goodjob.html" style="padding:4px 12px;border-radius:6px;font-size:10px;font-weight:600;text-decoration:none;background:rgba(0,0,0,.06);color:#555;transition:all .2s">Enterprise</a><a href="/sovereign-claude.html" style="padding:4px 12px;border-radius:6px;font-size:10px;font-weight:600;text-decoration:none;background:rgba(0,0,0,.06);color:#555;transition:all .2s">Sovereign</a><a href="/cyber-monitor.html" style="padding:4px 12px;border-radius:6px;font-size:10px;font-weight:600;text-decoration:none;background:rgba(0,0,0,.06);color:#555;transition:all .2s">Cyber</a></div>
56a
<div class="sb"><div class="sb-h"><button class="nb" onclick="newChat()">+ Nouveau chat</button></div><div class="sb-l" id="sbl"></div><div class="sb-f"><button onclick="document.body.classList.toggle('dark')">◐ Thème</button><button onclick="document.getElementById('cfg').showModal()">⚙ Config</button></div></div>
<div class="main">
<header><div class="mp"><span class="dot" id="hd"></span><span>WEVIA CORTEX v2.1.89</span></div><div class="pill on" id="tp" onclick="turbo=!turbo;this.classList.toggle('on',turbo);updL()">⚡ Turbo</div><div class="pill ao" id="ap" onclick="agent=!agent;this.classList.toggle('ao',agent);updL()">🤖 Agent</div><span class="hp" id="hp">...</span></header>
<div class="wel" id="wel"><h1>Bonjour, Yanis</h1><p>Comment puis-je vous aider aujourd'hui ?</p><div class="sugs"><div class="sug" onclick="ask('Audit infrastructure: Analyse l\'état complet de S204, S95 et S151')"><b>Audit infrastructure</b><span>État de S204, S95, S151</span></div><div class="sug" onclick="ask('Status Ethica: Combien de HCPs par pays, derniers enrichissements')"><b>Status Ethica</b><span>HCPs, enrichissements</span></div><div class="sug" onclick="ask('Architecture WEVAL: Explique la stack technique complète avec tous les services')"><b>Architecture WEVAL</b><span>Stack technique complète</span></div><div class="sug" onclick="ask('NonReg: Lance les tests et montre les résultats')"><b>NonReg status</b><span>Derniers tests NonReg</span></div></div></div>
<div class="ca" id="ca"><div class="msgs" id="msgs"></div></div>
<div class="ld" id="ld"><div class="ldi"><div class="dots"><span></span><span></span><span></span></div><span class="lt" id="ldt">Réflexion...</span></div></div>
<div class="iw"><div class="ib"><div class="ir"><textarea id="inp" placeholder="Message à WEVIA CORTEX..." rows="1" onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();send()}" oninput="this.style.height='auto';this.style.height=Math.min(this.scrollHeight,160)+'px'"></textarea><button class="sn" id="sb" onclick="send()"><svg viewBox="0 0 16 16" fill="currentColor"><path d="M1.5 1.5l13 6.5-13 6.5V9l8-1-8-1z"/></svg></button></div><div class="if"><span id="ml">Turbo ⚡ + Agent 🤖</span><span id="tc"></span></div></div></div>
</div>
<dialog id="cfg"><h3>Configuration</h3><textarea id="sys">Tu es l'assistant IA souverain de WEVAL Consulting. Direct, technique, expert en ERP/SAP, cloud, cybersécurité et IA. En mode Agent, utilise les outils (bash, read_file, sentinel, api_call) pour scanner et corriger l'infrastructure. Réponds en français.</textarea><div class="dr"><label>Temp</label><input type="range" min="0" max="100" value="10" oninput="document.getElementById('tv').textContent=(this.value/100).toFixed(2)"><span class="v" id="tv">0.10</span></div><div class="dr"><label>Max tok</label><input type="range" min="100" max="4096" value="2048" step="100" oninput="document.getElementById('mtv').textContent=this.value"><span class="v" id="mtv">2048</span></div><div class="dr" style="margin-top:16px"><button onclick="document.getElementById('cfg').close()" style="width:100%;padding:10px;border-radius:8px;border:none;background:var(--text);color:var(--bg);font-size:13px;font-weight:600;cursor:pointer">Fermer</button></div></dialog>
<script>
const API='/api/wevia-stream-api.php';
const API_LEGACY='/api/wevia-sovereign-proxy.php';
let H=[],turbo=true,agent=true,gen=false,ttok=0,nreq=0;
let chats=[{id:1,t:'Nouveau chat',m:[]}],ci=0;
function updL(){document.getElementById('ml').textContent=(turbo?'Turbo ⚡':'Local 🏠')+' + '+(agent?'Agent 🤖':'Chat 💬')}
function newChat(){chats.push({id:Date.now(),t:'Nouveau chat',m:[]});ci=chats.length-1;H=[];document.getElementById('msgs').innerHTML='';document.getElementById('wel').style.display='flex';document.getElementById('ca').style.display='none';rSb()}
function rSb(){document.getElementById('sbl').innerHTML=chats.map((c,i)=>'<div class="ci'+(i===ci?' a':'')+'" onclick="swC('+i+')">'+c.t+'</div>').join('')}
function swC(i){ci=i;H=chats[i].m.map(m=>({role:m.r,content:m.t}));var el=document.getElementById('msgs');el.innerHTML='';chats[i].m.forEach(function(m){rMsg(m.r,m.t,m.o||{})});document.getElementById('wel').style.display=chats[i].m.length?'none':'flex';document.getElementById('ca').style.display=chats[i].m.length?'flex':'none';rSb()}
function ask(t){document.getElementById('inp').value=t;send()}
function esc(s){return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')}
function md(t){t=t.replace(/```(\w*)\n?([\s\S]*?)```/g,function(m,l,c){var id='c'+Math.random().toString(36).slice(2,7);return'<pre><code id="'+id+'">'+esc(c.trim())+'</code></pre>'});t=t.replace(/`([^`]+)`/g,'<code>$1</code>');t=t.replace(/\*\*([^*]+)\*\*/g,'<strong>$1</strong>');t=t.replace(/^### (.+)$/gm,'<h3>$1</h3>');t=t.replace(/^## (.+)$/gm,'<h2>$1</h2>');t=t.replace(/^\- (.+)$/gm,'<li>$1</li>');t=t.replace(/(<li>[\s\S]*?<\/li>)/g,'<ul>$1</ul>');t=t.replace(/<\/ul>\s*<ul>/g,'');t=t.replace(/^> (.+)$/gm,'<blockquote>$1</blockquote>');t=t.replace(/\n\n/g,'</p><p>');return'<p>'+t+'</p>'}
function rMsg(role,content,o){o=o||{};var el=document.getElementById('msgs'),tm=new Date().toLocaleTimeString('fr',{hour:'2-digit',minute:'2-digit'});
var steps='';if(o.steps&&o.steps.length){steps=o.steps.map(function(s){var ic={bash:'>_',read_file:'F',edit_file:'E',sentinel:'S',api_call:'A'}[s.tool]||'?';return'<div class="ts" onclick="this.classList.toggle(\'open\')"><div class="tsh"><b>['+ic+'] '+s.tool+'</b><span class="tsi">'+esc(JSON.stringify(s.input).slice(0,60))+'</span><span>'+(s.is_error?'ERR':'OK')+'</span></div><div class="tso"><pre>'+esc((s.output||'').slice(0,800))+'</pre></div></div>'}).join('')}
var via=o.provider?'<span class="mv">via '+o.provider+'</span>':'';var lat=o.latency?'<span class="mt"> '+o.latency+'</span>':'';
el.innerHTML+='<div class="msg '+role+'"><div class="mh"><div class="av">'+(role==='user'?'Y':'S')+'</div><span class="mn">'+(role==='user'?'Vous':'WEVIA CORTEX')+'</span><span class="mt">'+tm+'</span>'+via+lat+'</div>'+steps+'<div class="mb">'+(role==='user'?'<p>'+esc(content)+'</p>':md(content))+'</div></div>';document.getElementById('ca').scrollTop=document.getElementById('ca').scrollHeight}
async function send(){var sys=document.getElementById('sys')?document.getElementById('sys').value:'';var inp=document.getElementById('inp'),text=inp.value.trim();if(!text||gen)return;inp.value='';inp.style.height='auto';
document.getElementById('wel').style.display='none';document.getElementById('ca').style.display='flex';
rMsg('user',text);H.push({role:'user',content:text});chats[ci].m.push({r:'user',t:text});
if(chats[ci].t==='Nouveau chat'){chats[ci].t=text.slice(0,35);rSb()}
gen=true;document.getElementById('ld').classList.add('on');document.getElementById('ldt').textContent=agent?'Agent autonome...':'Réflexion...';document.getElementById('sb').disabled=true;
var sys=document.getElementById('sys').value,temp=parseFloat(document.getElementById('tv').textContent),maxT=parseInt(document.getElementById('mtv').textContent),t0=performance.now();
try{var r=await fetch(API,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:text,system:sys})});
var lat=performance.now()-t0,ls=lat<1e3?Math.round(lat)+'ms':(lat/1e3).toFixed(1)+'s',prov=r.headers.get('X-Provider')||'cerebras';
var txt='',prov='cerebras',mdl='',lat2='';
// SSE streaming reader
var reader=r.body.getReader(),dec=new TextDecoder(),buf='';
var aiDiv=document.createElement('div');aiDiv.className='msg ai';aiDiv.innerHTML='<div class="mc" id="stream-out"></div>';var _msgs=document.getElementById('msgs');_msgs.appendChild(aiDiv);var mc=aiDiv.querySelector('.mc');
while(true){var rd=await reader.read();if(rd.done)break;buf+=dec.decode(rd.value,{stream:true});var lns=buf.split('\n');buf=lns.pop();
for(var ln of lns){if(!ln.startsWith('data: '))continue;try{var ev=JSON.parse(ln.slice(6));if(ev.type==='token'){txt+=ev.content;mc.innerHTML=txt.replace(/\n/g,'<br>');_msgs.scrollTop=_msgs.scrollHeight}if(ev.type==='start'){prov=ev.provider||'cerebras';mdl=ev.model||''}if(ev.type==='done'){lat2=ev.latency_ms?ev.latency_ms+'ms':''}}catch(e){}}}
document.getElementById('ld').classList.remove('on');
mc.innerHTML+='<div style="margin-top:8px;font-size:10px;color:#999">via '+prov+' '+(mdl?mdl.split('-').slice(0,3).join('-'):'')+' '+lat2+'</div>';
gen=false;document.getElementById('sb').disabled=false;document.getElementById('inp').focus();H.push({role:'assistant',content:txt});chats[ci].m.push({r:'assistant',t:txt,o:{provider:prov}});return;var data={response:txt,provider:prov}
document.getElementById('ld').classList.remove('on');
if(data.error){rMsg('assistant','Erreur: '+(data.error.message||JSON.stringify(data.error)),{provider:prov,latency:ls})}
else{var txt=(data.content||[]).map(function(b){return b.text||''}).join('\n\n');if(!txt)txt='[Pas de réponse]';
var steps=data.agent?data.agent.steps:[];rMsg('assistant',txt,{provider:prov,latency:ls,steps:steps});
H.push({role:'assistant',content:txt});chats[ci].m.push({r:'assistant',t:txt,o:{provider:prov,latency:ls,steps:steps}});
ttok+=(data.usage?data.usage.input_tokens:0)+(data.usage?data.usage.output_tokens:0);nreq++;
document.getElementById('tc').textContent=ttok+' tok';document.getElementById('hp').textContent=prov}}
catch(e){document.getElementById('ld').classList.remove('on');rMsg('assistant','Erreur: '+e.message,{})}
gen=false;document.getElementById('sb').disabled=false;inp.focus()}
async function health(){try{var r=await fetch('/api/wevia-master-api.php?health',{signal:AbortSignal.timeout(5e3)});/* HTML_GUARD_V2_BATCH */ var _t_d=await r.text(); var d; {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('hd').style.background=d.status==='ok'?'var(--green)':'var(--red)';document.getElementById('hp').textContent=d.primary||'cerebras-235B'}catch(e){document.getElementById('hd').style.background='var(--red)'}}
health();setInterval(health,30000);rSb();document.getElementById('inp').focus();
</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-cortex</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-cortex';
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 url = '/api/claude-pattern-sse.php?message=' + encodeURIComponent(msg) + '&chatbot=' + encodeURIComponent(BOT);
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>
</body></html>