247 lines
15 KiB
HTML
247 lines
15 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>WEVAL — Wiring & Comparison Dashboard</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Outfit:wght@300;500;700;900&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{--bg:#0a0e17;--bg2:#111827;--bg3:#1e293b;--bd:#1e293b;--fg:#e2e8f0;--fg2:#94a3b8;--fg3:#64748b;--go:#f59e0b;--gn:#22c55e;--rd:#ef4444;--bl:#3b82f6;--vi:#8b5cf6;--cy:#06b6d4;--pk:#ec4899}
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
body{background:var(--bg);color:var(--fg);font-family:'Outfit',sans-serif;min-height:100vh}
|
||
.top{background:linear-gradient(135deg,#0f172a 0%,#1a1040 50%,#0f2027 100%);padding:24px 32px;border-bottom:1px solid var(--bd)}
|
||
.top h1{font-size:28px;font-weight:900;background:linear-gradient(90deg,var(--go),var(--pk),var(--vi));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
|
||
.top p{color:var(--fg2);font-size:13px;margin-top:4px}
|
||
.tabs{display:flex;gap:2px;padding:8px 32px;background:var(--bg2);border-bottom:1px solid var(--bd)}
|
||
.tab{padding:8px 20px;cursor:pointer;border-radius:6px 6px 0 0;font-size:12px;font-weight:700;color:var(--fg3);transition:.2s}
|
||
.tab:hover{color:var(--fg);background:var(--bg3)}
|
||
.tab.on{color:var(--go);background:var(--bg);border:1px solid var(--bd);border-bottom:1px solid var(--bg)}
|
||
.main{padding:24px 32px}
|
||
.panel{display:none}
|
||
.panel.on{display:block}
|
||
.kpis{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:24px}
|
||
.kpi{background:var(--bg2);border:1px solid var(--bd);border-radius:8px;padding:14px;text-align:center}
|
||
.kpi-v{font-size:28px;font-weight:900;font-family:'JetBrains Mono'}
|
||
.kpi-l{font-size:10px;color:var(--fg3);margin-top:2px}
|
||
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px;margin-top:16px}
|
||
.card{background:var(--bg2);border:1px solid var(--bd);border-radius:8px;padding:14px;transition:.2s}
|
||
.card:hover{border-color:var(--vi);transform:translateY(-2px)}
|
||
.card-h{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}
|
||
.card-n{font-weight:700;font-size:14px}
|
||
.card-n a{color:inherit;text-decoration:none}
|
||
.card-n a:hover{color:var(--go)}
|
||
.tag{font-size:8px;padding:2px 6px;border-radius:4px;font-weight:700;text-transform:uppercase}
|
||
.tag-gn{background:rgba(34,197,94,.2);color:var(--gn)}
|
||
.tag-rd{background:rgba(239,68,68,.2);color:var(--rd)}
|
||
.tag-bl{background:rgba(59,130,246,.2);color:var(--bl)}
|
||
.tag-vi{background:rgba(139,92,246,.2);color:var(--vi)}
|
||
.tag-go{background:rgba(245,158,11,.2);color:var(--go)}
|
||
.card-row{display:flex;justify-content:space-between;font-size:11px;padding:3px 0;border-bottom:1px solid rgba(255,255,255,.03)}
|
||
.card-row:last-child{border:0}
|
||
.card-k{color:var(--fg3)}
|
||
.card-v{font-family:'JetBrains Mono';font-size:10px}
|
||
.bar{height:4px;background:var(--bg3);border-radius:2px;margin-top:6px;overflow:hidden}
|
||
.bar-f{height:100%;border-radius:2px;transition:width 1s ease}
|
||
table{width:100%;border-collapse:collapse;font-size:11px}
|
||
th{text-align:left;padding:8px;color:var(--fg3);border-bottom:1px solid var(--bd);font-size:9px;text-transform:uppercase;position:sticky;top:0;background:var(--bg)}
|
||
td{padding:6px 8px;border-bottom:1px solid rgba(255,255,255,.03)}
|
||
tr:hover{background:var(--bg3)}
|
||
.dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:4px}
|
||
.dot-gn{background:var(--gn)}.dot-rd{background:var(--rd)}.dot-go{background:var(--go)}
|
||
.sc{font-family:'JetBrains Mono';font-weight:700}
|
||
.opus-bar{display:flex;align-items:center;gap:8px;margin:16px 0;padding:12px;background:var(--bg2);border:1px solid var(--bd);border-radius:8px}
|
||
.opus-bar .bar{flex:1;height:8px}
|
||
.loading{text-align:center;padding:40px;color:var(--fg3)}
|
||
@media(max-width:768px){.kpis{grid-template-columns:repeat(3,1fr)}.grid{grid-template-columns:1fr}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="top">
|
||
<h1>⚡ WEVAL Wiring & Comparison</h1>
|
||
<p>Dashboard dynamique — Benchmark IA × OSS Discovery × Architecture · Données temps réel</p>
|
||
</div>
|
||
<div class="tabs">
|
||
<div class="tab on" onclick="sw(0)">🔌 Wiring Map</div>
|
||
<div class="tab" onclick="sw(1)">⚔️ WEVAL vs Opus</div>
|
||
<div class="tab" onclick="sw(2)">🧩 OSS Skills</div>
|
||
<div class="tab" onclick="sw(3)">📊 Full Comparison</div>
|
||
</div>
|
||
<div class="main">
|
||
|
||
<!-- TAB 0: WIRING MAP -->
|
||
<div class="panel on" id="p0"><div class="loading">Chargement...</div></div>
|
||
|
||
<!-- TAB 1: WEVAL vs OPUS -->
|
||
<div class="panel" id="p1"><div class="loading">Chargement...</div></div>
|
||
|
||
<!-- TAB 2: OSS SKILLS -->
|
||
<div class="panel" id="p2"><div class="loading">Chargement...</div></div>
|
||
|
||
<!-- TAB 3: FULL COMPARISON TABLE -->
|
||
<div class="panel" id="p3"><div class="loading">Chargement...</div></div>
|
||
|
||
</div>
|
||
<script>
|
||
const $ = id => document.getElementById(id);
|
||
function sw(n){document.querySelectorAll('.tab').forEach((t,i)=>{t.classList.toggle('on',i===n)});document.querySelectorAll('.panel').forEach((p,i)=>{p.classList.toggle('on',i===n)})}
|
||
|
||
let BENCH={},OSS={},SOT={};
|
||
|
||
async function load(){
|
||
try{
|
||
const [b,o,s]=await Promise.all([
|
||
fetch('/api/ai-benchmark-cache.json?t='+Date.now()).then(r=>r.json()),
|
||
fetch('/api/oss-cache.json?t='+Date.now()).then(r=>r.json()).catch(()=>({})),
|
||
fetch('/api/source-of-truth.json?t='+Date.now()).then(r=>r.json()).catch(()=>({}))
|
||
]);
|
||
BENCH=b;OSS=o;SOT=s;
|
||
renderWiring();renderVsOpus();renderOSS();renderComparison();
|
||
}catch(e){$('p0').innerHTML='<p style="color:var(--rd)">Erreur: '+e+'</p>'}
|
||
}
|
||
|
||
function renderWiring(){
|
||
const A=BENCH.all_ais||{};
|
||
const wired=Object.entries(A).filter(([n,a])=>a.wired);
|
||
const notWired=Object.entries(A).filter(([n,a])=>!a.wired);
|
||
const agents=SOT.agents||{};
|
||
let h=`<div class="kpis">
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--gn)">${wired.length}</div><div class="kpi-l">WIRED</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--rd)">${notWired.length}</div><div class="kpi-l">NOT WIRED</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--vi)">${Object.keys(A).length}</div><div class="kpi-l">TOTAL AIs</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--go)">${BENCH.report?.combined_avg||'?'}/90</div><div class="kpi-l">COMBINED</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--cy)">0€</div><div class="kpi-l">COÛT TOTAL</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--gn)">${Math.round(wired.length/Object.keys(A).length*100)}%</div><div class="kpi-l">COVERAGE</div></div>
|
||
</div>`;
|
||
h+=`<h3 style="color:var(--gn);margin-bottom:12px">✅ ${wired.length} IAs Wirées dans WEVAL</h3><div class="grid">`;
|
||
wired.sort((a,b)=>(b[1].avg||0)-(a[1].avg||0));
|
||
for(const [n,a] of wired){
|
||
const col=a.type==='sovereign'?'var(--vi)':a.type==='agent'?'var(--gn)':a.type==='security'?'var(--rd)':a.type==='chatbot'?'var(--bl)':a.type==='search'?'var(--cy)':a.type==='testing'?'var(--pk)':a.type==='composite'?'var(--go)':'var(--fg3)';
|
||
h+=`<div class="card">
|
||
<div class="card-h"><div class="card-n"><a href="${a.url||'#'}" target="_blank">${a.icon||''} ${n}</a></div><span class="tag tag-gn">✅ WIRED</span></div>
|
||
<div class="card-row"><span class="card-k">Type</span><span class="tag" style="background:${col}22;color:${col}">${a.type}</span></div>
|
||
<div class="card-row"><span class="card-k">Score</span><span class="card-v sc" style="color:${col}">${a.avg}/90</span></div>
|
||
<div class="card-row"><span class="card-k">Rôle</span><span class="card-v">${(a.used_in||'').slice(0,40)}</span></div>
|
||
<div class="card-row"><span class="card-k">Cas d'usage</span><span class="card-v">${(a.usecase||'').slice(0,40)}</span></div>
|
||
<div class="card-row"><span class="card-k">Coût</span><span class="card-v">${a.cost||'?'}</span></div>
|
||
<div class="bar"><div class="bar-f" style="width:${Math.round(a.avg/90*100)}%;background:${col}"></div></div>
|
||
</div>`;
|
||
}
|
||
h+=`</div>`;
|
||
if(notWired.length){
|
||
h+=`<h3 style="color:var(--rd);margin:24px 0 12px">❌ ${notWired.length} Non Wirées (Références)</h3><div class="grid">`;
|
||
for(const [n,a] of notWired){
|
||
h+=`<div class="card" style="opacity:.6">
|
||
<div class="card-h"><div class="card-n"><a href="${a.url||'#'}" target="_blank">${a.icon||''} ${n}</a></div><span class="tag tag-rd">❌</span></div>
|
||
<div class="card-row"><span class="card-k">Score</span><span class="card-v sc">${a.avg}/90</span></div>
|
||
<div class="card-row"><span class="card-k">Coût</span><span class="card-v">${a.cost||'💰'}</span></div>
|
||
</div>`;
|
||
}
|
||
h+=`</div>`;
|
||
}
|
||
$('p0').innerHTML=h;
|
||
}
|
||
|
||
function renderVsOpus(){
|
||
const A=BENCH.all_ais||{};
|
||
const weval=A.WEVAL_COMBINED||{avg:93};
|
||
const opus=A.Claude_Opus_4_6||A['Claude_Opus_4.6']||{avg:90};
|
||
const sov=Object.entries(A).filter(([n,a])=>a.wired&&a.type==='sovereign');
|
||
const agents=Object.entries(A).filter(([n,a])=>a.wired&&a.type==='agent');
|
||
const pct=Math.round(weval.avg/opus.avg*100);
|
||
|
||
let h=`<div class="opus-bar">
|
||
<span style="font-size:24px">🌟</span>
|
||
<div><div style="font-weight:900;font-size:18px">WEVAL Combined: <span style="color:var(--gn)">${weval.avg}</span> vs Opus: <span style="color:var(--go)">${opus.avg}</span></div>
|
||
<div style="font-size:11px;color:var(--fg2)">${pct}% d'Opus · ${pct>100?'SUPÉRIEUR':'Inférieur'} à Claude Opus 4.6</div></div>
|
||
<div class="bar"><div class="bar-f" style="width:${Math.min(pct,100)}%;background:${pct>=100?'var(--gn)':'var(--go)'}"></div></div>
|
||
</div>`;
|
||
|
||
h+=`<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:16px">`;
|
||
// Avantages WEVAL
|
||
h+=`<div class="card"><div class="card-h"><span class="card-n" style="color:var(--gn)">✅ Avantages WEVAL</span></div>
|
||
<div class="card-row"><span class="card-k">Coût</span><span class="card-v" style="color:var(--gn)">0€/mois</span></div>
|
||
<div class="card-row"><span class="card-k">Providers</span><span class="card-v">${sov.length} sovereign cascade</span></div>
|
||
<div class="card-row"><span class="card-k">Agents</span><span class="card-v">${agents.length} autonomes</span></div>
|
||
<div class="card-row"><span class="card-k">Failover</span><span class="card-v">Auto cascade 7 niveaux</span></div>
|
||
<div class="card-row"><span class="card-k">Souveraineté</span><span class="card-v">100% (Ollama local)</span></div>
|
||
<div class="card-row"><span class="card-k">RGPD</span><span class="card-v">EU data residency (Mistral)</span></div>
|
||
<div class="card-row"><span class="card-k">Consensus</span><span class="card-v">MoA 4 providers · 9.8/10</span></div>
|
||
</div>`;
|
||
// Avantages Opus
|
||
h+=`<div class="card"><div class="card-h"><span class="card-n" style="color:var(--go)">🏆 Avantages Opus</span></div>
|
||
<div class="card-row"><span class="card-k">Raisonnement</span><span class="card-v">Meilleur single-model</span></div>
|
||
<div class="card-row"><span class="card-k">Code</span><span class="card-v">Analyse complexe supérieure</span></div>
|
||
<div class="card-row"><span class="card-k">Coût</span><span class="card-v" style="color:var(--rd)">~$200/mois API</span></div>
|
||
<div class="card-row"><span class="card-k">Dépendance</span><span class="card-v" style="color:var(--rd)">Cloud US · Anthropic</span></div>
|
||
<div class="card-row"><span class="card-k">Rate limit</span><span class="card-v" style="color:var(--rd)">Oui</span></div>
|
||
<div class="card-row"><span class="card-k">Failover</span><span class="card-v" style="color:var(--rd)">Aucun</span></div>
|
||
<div class="card-row"><span class="card-k">Souveraineté</span><span class="card-v" style="color:var(--rd)">0%</span></div>
|
||
</div></div>`;
|
||
|
||
// Économies
|
||
h+=`<div class="kpis" style="margin-top:16px">
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--gn)">$0</div><div class="kpi-l">COÛT MENSUEL</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--rd)">$200</div><div class="kpi-l">OPUS API/MOIS</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--gn)">$2,400</div><div class="kpi-l">ÉCONOMIE/AN</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--go)">${pct}%</div><div class="kpi-l">% D'OPUS</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--vi)">7</div><div class="kpi-l">CASCADE LEVELS</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--gn)">100%</div><div class="kpi-l">SOUVERAIN</div></div>
|
||
</div>`;
|
||
$('p1').innerHTML=h;
|
||
}
|
||
|
||
function renderOSS(){
|
||
const R=OSS.report||{};const S=OSS.skills||{};
|
||
const tools=R.total||70;const skills=S.total||1935;
|
||
let h=`<div class="kpis">
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--bl)">${tools}</div><div class="kpi-l">TOOLS WIRED</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--vi)">${skills}</div><div class="kpi-l">SKILLS</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--gn)">${R.wire_pct||100}%</div><div class="kpi-l">WIRE RATE</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--cy)">${R.not_wired||0}</div><div class="kpi-l">NOT WIRED</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--go)">${R.categories||12}</div><div class="kpi-l">CATEGORIES</div></div>
|
||
<div class="kpi"><div class="kpi-v" style="color:var(--gn)">0€</div><div class="kpi-l">COÛT</div></div>
|
||
</div>`;
|
||
h+=`<p style="color:var(--fg2);font-size:12px;margin-bottom:12px">Données depuis <a href="/oss-discovery.html" target="_blank" style="color:var(--bl)">/oss-discovery.html</a></p>`;
|
||
const items=R.by_status||OSS.tools||[];
|
||
if(Array.isArray(items)&&items.length){
|
||
h+=`<div class="grid">`;
|
||
for(const t of items.slice(0,20)){
|
||
h+=`<div class="card"><div class="card-h"><div class="card-n">${t.name||t}</div><span class="tag tag-gn">wired</span></div></div>`;
|
||
}
|
||
h+=`</div>`;
|
||
}
|
||
$('p2').innerHTML=h;
|
||
}
|
||
|
||
function renderComparison(){
|
||
const A=BENCH.all_ais||{};
|
||
const lb=(BENCH.leaderboard||[]).sort((a,b)=>b.score-a.score);
|
||
let h=`<div style="overflow-x:auto"><table>
|
||
<tr><th>#</th><th>AI</th><th>Type</th><th>Score</th><th>%Opus</th><th>Wired</th><th>Coût</th><th>Utilisé dans</th><th>Cas d'usage</th><th>Lien</th></tr>`;
|
||
lb.forEach((x,i)=>{
|
||
const a=A[x.name]||{};
|
||
const pct=Math.round(x.score/90*100);
|
||
const wc=a.wired?'var(--gn)':'var(--rd)';
|
||
h+=`<tr>
|
||
<td>${i+1}</td>
|
||
<td style="font-weight:700">${a.icon||''} ${x.name}</td>
|
||
<td><span class="tag" style="background:rgba(255,255,255,.05)">${a.type||'?'}</span></td>
|
||
<td class="sc" style="color:${x.score>=85?'var(--gn)':x.score>=75?'var(--go)':'var(--fg3)'}">${x.score}</td>
|
||
<td>${pct}%</td>
|
||
<td style="color:${wc}">${a.wired?'✅':'❌'}</td>
|
||
<td style="font-size:9px">${a.cost||'?'}</td>
|
||
<td style="font-size:9px;max-width:150px;overflow:hidden;text-overflow:ellipsis">${a.used_in||'-'}</td>
|
||
<td style="font-size:9px;max-width:150px;overflow:hidden;text-overflow:ellipsis">${a.usecase||'-'}</td>
|
||
<td><a href="${a.url||'#'}" target="_blank" style="color:var(--bl);font-size:10px">Ouvrir →</a></td>
|
||
</tr>`;
|
||
});
|
||
h+=`</table></div>`;
|
||
$('p3').innerHTML=h;
|
||
}
|
||
|
||
load();
|
||
setInterval(load,60000);
|
||
</script>
|
||
</body>
|
||
</html>
|