Files
html/api/em-live-inject.js
opus ab7ac0d344
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
17avr-EM-CEO-dashboard-premium-v2-deployed
2026-04-17 19:48:23 +02:00

211 lines
16 KiB
JavaScript
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.
/* WEVAL Enterprise Management — Live KPI Injector v2
Premium CEO Dashboard · 17 avril 2026
ENRICHIT sans écraser. Auto-refresh 60s.
*/
(function(){
const CACHE_URL = '/api/em-kpi-cache.json';
const FALLBACK = {
s204:{load:2.57,cpu_cores:8,ram_total_mb:31335,ram_free_mb:24989,disk_pct:"80%",fpm_workers:102,docker_containers:19},
s95:{load:5.01,disk_pct:"89%",status:"UP",ram_total_mb:15610,ram_free_mb:11532},
pmta:[{name:"SER6",status:"DOWN"},{name:"SER7",status:"DOWN"},{name:"SER8",status:"DOWN"},{name:"SER9",status:"DOWN"}],
assets:{html_pages:227,php_apis:559,wiki_entries:1399,vault_doctrines:32},
tools:{total:422},
sovereign:{status:"UP",active:13,total:13,primary:"Cerebras-fast",cost:"0\u20ac",
providers:["Cerebras-fast","Cerebras-think","Groq","Cloudflare-AI","Gemini","SambaNova","NVIDIA-NIM","Mistral","Groq-OSS","HF-Space","HF-Router","OpenRouter","GitHub-Models"]},
ethica:{total_hcps:146694,with_email:110120,with_phone:141112,gap_email:36574,pct_email:75.1,pct_phone:96.2,
by_country:[{country:"DZ",t:"107320",e:"78114"},{country:"MA",t:"19426",e:"14892"},{country:"TN",t:"17364",e:"14816"}]},
services:[{name:"DeerFlow",port:3002,status:"UP"},{name:"Qdrant",port:6333,status:"UP"},{name:"Ollama",port:11434,status:"UP"},{name:"Redis",port:6379,status:"UP"},{name:"Sovereign",port:4000,status:"UP"},{name:"SearXNG",port:8080,status:"UP"}],
whisper:{binary:"COMPILED",model:"142MB"},
git:{head:"17avr-6sigma",dirty:0,status:"CLEAN"},
nonreg:{total:153,passed:153,score:"100%"},
health:{score:6,max:6,pct:100},
grand_total:2658,
docker:[{name:"gitea",status:"Up"},{name:"qdrant",status:"Up"},{name:"redis",status:"Up"},{name:"searxng",status:"Up"},{name:"uptime-kuma",status:"Up"},{name:"vaultwarden",status:"Up"},{name:"prometheus",status:"Up"},{name:"loki",status:"Up"},{name:"listmonk",status:"Up"},{name:"deerflow",status:"Up"},{name:"n8n",status:"Up"},{name:"mattermost",status:"Up"},{name:"twenty",status:"Up"},{name:"langfuse",status:"Up"},{name:"plausible",status:"Up"},{name:"node-exporter",status:"Up"},{name:"twenty-redis",status:"Up"},{name:"plausible-db",status:"Up"},{name:"deerflow-api",status:"Up"}]
};
async function load(){
let d;
try {
const r = await fetch(CACHE_URL, {cache:'no-cache'});
d = await r.json();
} catch(e) {
d = FALLBACK;
}
// Update stat cards
const el=id=>document.getElementById(id);
if(el('statPages'))el('statPages').textContent=d.assets?.html_pages||'';
if(el('statApis'))el('statApis').textContent=d.assets?.php_apis||'';
if(el('statWiki'))el('statWiki').textContent=d.assets?.wiki_entries||'';
if(el('statVault'))el('statVault').textContent=d.assets?.vault_doctrines||'';
if(el('statSvc'))el('statSvc').textContent=(d.services?.filter(s=>s.status==='UP').length||0);
if(el('statIntents'))el('statIntents').textContent='20+';
if(el('statGrand'))el('statGrand').textContent=(d.grand_total||0).toLocaleString();
if(el('statHealth'))el('statHealth').textContent=(d.health?.pct||100)+'%';
// Inject Live Dashboard section
let sec = document.getElementById('liveCeoDash');
if(!sec){
sec = document.createElement('div');
sec.id = 'liveCeoDash';
const heroStats = document.querySelector('.hero-stats');
if(heroStats && heroStats.parentNode){
heroStats.parentNode.insertBefore(sec, heroStats.nextSibling);
} else { document.querySelector('.dash,.container,.main')?.appendChild(sec); }
}
sec.innerHTML = render(d);
}
function render(d){
const diskPct = parseInt(d.s204?.disk_pct)||0;
const diskClass = diskPct<80?'ld-bar-ok':diskPct<90?'ld-bar-warn':'ld-bar-danger';
const ramPct = Math.round(((d.s204?.ram_total_mb||1)-(d.s204?.ram_free_mb||0))/(d.s204?.ram_total_mb||1)*100);
const s95diskPct = parseInt(d.s95?.disk_pct)||0;
const s95diskClass = s95diskPct<80?'ld-bar-ok':s95diskPct<90?'ld-bar-warn':'ld-bar-danger';
const providers = (d.sovereign?.providers||[]).map(p=>`<span class="ld-pill-ia">${p}</span>`).join('');
const services = (d.services||[]).map(s=>`<div class="ld-svc-item ${s.status==='UP'?'ld-up':'ld-down'}"><div class="ld-svc-dot ${s.status==='UP'?'ld-dot-g':'ld-dot-r'}"></div><div class="ld-svc-name">${s.name}</div><div class="ld-svc-port">:${s.port}</div></div>`).join('');
const pmta = (d.pmta||[]).map(p=>`<span class="ld-pill-${p.status==='UP'?'up':'down'}">${p.name}</span>`).join('');
const docker = (d.docker||[]).map(c=>`<div class="ld-dock"><span class="ld-dock-n">${c.name}</span><span class="ld-dock-s">${c.status}</span></div>`).join('');
const maxHcp = Math.max(...(d.ethica?.by_country||[]).map(c=>parseInt(c.t)||0),1);
const countries = (d.ethica?.by_country||[]).map(c=>{
const flag = c.country==='DZ'?'\u{1F1E9}\u{1F1FF}':c.country==='MA'?'\u{1F1F2}\u{1F1E6}':c.country==='TN'?'\u{1F1F9}\u{1F1F3}':'\u{1F30D}';
const barW = Math.round((parseInt(c.t)||0)/maxHcp*100);
const barC = c.country==='DZ'?'ld-bar-dz':c.country==='MA'?'ld-bar-ma':'ld-bar-tn';
return `<div class="ld-country"><span class="ld-cflag">${flag}</span><span class="ld-cname">${c.country}</span><div class="ld-cbar-w"><div class="ld-cbar ${barC}" style="width:${barW}%"></div></div><span class="ld-cval">${parseInt(c.t).toLocaleString()}</span><span class="ld-ceml">${parseInt(c.e).toLocaleString()}</span></div>`;
}).join('');
return `<style>
#liveCeoDash{margin:16px 0;font-family:'DM Sans',system-ui,sans-serif}
.ld-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:12px 0}
.ld-grid2{grid-template-columns:repeat(2,1fr)}
.ld-card{background:rgba(14,18,32,0.85);border:1px solid rgba(255,255,255,0.06);border-radius:14px;padding:16px;backdrop-filter:blur(20px)}
.ld-title{font-size:11px;color:rgba(255,255,255,0.35);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px;display:flex;align-items:center;gap:6px}
.ld-dot-g{width:6px;height:6px;border-radius:50%;background:#10b981;box-shadow:0 0 8px #10b981;display:inline-block}
.ld-dot-r{width:6px;height:6px;border-radius:50%;background:#ef4444;box-shadow:0 0 8px #ef4444;display:inline-block}
.ld-big{font-size:32px;font-weight:700;font-family:'JetBrains Mono',monospace;color:#10b981;line-height:1}
.ld-sub{font-size:12px;color:rgba(255,255,255,0.5);margin-top:4px}
.ld-bar-wrap{height:8px;background:rgba(255,255,255,0.06);border-radius:4px;overflow:hidden;margin-top:6px}
.ld-bar-fill{height:100%;border-radius:4px;transition:width .8s}
.ld-bar-ok{background:linear-gradient(90deg,#10b981,#059669)}
.ld-bar-warn{background:linear-gradient(90deg,#f59e0b,#d97706)}
.ld-bar-danger{background:linear-gradient(90deg,#ef4444,#dc2626)}
.ld-bar-label{display:flex;justify-content:space-between;font-size:11px;margin-top:8px}
.ld-bar-label span:first-child{color:rgba(255,255,255,0.3)}
.ld-bar-label span:last-child{font-family:'JetBrains Mono',monospace}
.ld-pill-ia{display:inline-block;padding:2px 6px;border-radius:4px;font-size:10px;margin:1px;background:rgba(139,92,246,0.1);color:#a78bfa;border:1px solid rgba(139,92,246,0.2);font-family:'JetBrains Mono',monospace}
.ld-pill-up{display:inline-block;padding:2px 7px;border-radius:5px;font-size:10px;margin:1px;background:rgba(16,185,129,0.1);color:#10b981;border:1px solid rgba(16,185,129,0.2)}
.ld-pill-down{display:inline-block;padding:2px 7px;border-radius:5px;font-size:10px;margin:1px;background:rgba(239,68,68,0.1);color:#ef4444;border:1px solid rgba(239,68,68,0.2)}
.ld-svc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:6px}
.ld-svc-item{background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.06);border-radius:8px;padding:8px;text-align:center}
.ld-svc-item.ld-up{border-color:rgba(16,185,129,0.2)}
.ld-svc-item.ld-down{border-color:rgba(239,68,68,0.2)}
.ld-svc-dot{width:5px;height:5px;border-radius:50%;margin:0 auto 4px}
.ld-svc-name{font-size:10px;font-weight:600;color:#fff}
.ld-svc-port{font-size:9px;font-family:'JetBrains Mono',monospace;color:rgba(255,255,255,0.3)}
.ld-country{display:flex;align-items:center;gap:6px;padding:4px 0}
.ld-cflag{font-size:16px;width:22px}
.ld-cname{font-size:12px;font-weight:600;width:22px;color:#fff}
.ld-cbar-w{flex:1;height:8px;background:rgba(255,255,255,0.06);border-radius:4px;overflow:hidden}
.ld-cbar{height:100%;border-radius:4px}
.ld-bar-dz{background:linear-gradient(90deg,#10b981,#22d3ee)}
.ld-bar-ma{background:linear-gradient(90deg,#60a5fa,#a78bfa)}
.ld-bar-tn{background:linear-gradient(90deg,#f472b6,#a78bfa)}
.ld-cval{font-size:12px;font-family:'JetBrains Mono',monospace;color:rgba(255,255,255,0.6);width:58px;text-align:right}
.ld-ceml{font-size:11px;color:rgba(255,255,255,0.3);width:55px;text-align:right}
.ld-dock{display:flex;justify-content:space-between;padding:3px 0;border-bottom:1px solid rgba(255,255,255,0.03);font-size:11px}
.ld-dock-n{font-family:'JetBrains Mono',monospace;color:#fff}
.ld-dock-s{color:#10b981}
.ld-nr{font-size:48px;font-weight:700;font-family:'JetBrains Mono',monospace;color:#10b981;text-align:center;line-height:1}
.ld-metric-box{background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.06);border-radius:10px;padding:14px;text-align:center}
.ld-metric-val{font-size:22px;font-weight:700;font-family:'JetBrains Mono',monospace}
.ld-metric-lbl{font-size:9px;color:rgba(255,255,255,0.3);text-transform:uppercase;letter-spacing:1px;margin-top:3px}
.ld-section-head{font-size:13px;color:rgba(255,255,255,0.4);margin:16px 0 8px;display:flex;align-items:center;gap:8px}
.ld-live-badge{padding:3px 10px;border-radius:10px;font-size:10px;font-weight:600;background:rgba(16,185,129,0.12);color:#10b981;border:1px solid rgba(16,185,129,0.25)}
.ld-ts{text-align:right;font-size:10px;color:rgba(255,255,255,0.2);margin-top:8px;font-family:'JetBrains Mono',monospace}
@media(max-width:1200px){.ld-grid{grid-template-columns:1fr 1fr}}
@media(max-width:768px){.ld-grid,.ld-grid2{grid-template-columns:1fr}}
</style>
<div class="ld-section-head">\u{1F4CA} Live Infrastructure <span class="ld-live-badge">\u{1F534} LIVE</span></div>
<div class="ld-grid">
<div class="ld-card">
<div class="ld-title"><span class="ld-dot-g"></span> S204 — WEVIA + ETHICA</div>
<div class="ld-big">${d.s204?.load||'?'}</div>
<div class="ld-sub">Load avg \u00b7 ${d.s204?.cpu_cores||8} CPU \u00b7 ${Math.round((d.s204?.ram_total_mb||0)/1024)} GB RAM</div>
<div class="ld-sub">RAM libre: ${(d.s204?.ram_free_mb||0).toLocaleString()} MB \u00b7 FPM: ${d.s204?.fpm_workers||'?'} \u00b7 Docker: ${d.s204?.docker_containers||'?'}</div>
<div class="ld-bar-label"><span>Disk</span><span style="color:${diskPct<80?'#10b981':diskPct<90?'#f59e0b':'#ef4444'}">${d.s204?.disk_pct||'?'}</span></div>
<div class="ld-bar-wrap"><div class="ld-bar-fill ${diskClass}" style="width:${diskPct}%"></div></div>
<div class="ld-bar-label"><span>RAM</span><span style="color:#10b981">${ramPct}%</span></div>
<div class="ld-bar-wrap"><div class="ld-bar-fill ld-bar-ok" style="width:${ramPct}%"></div></div>
</div>
<div class="ld-card">
<div class="ld-title"><span class="${d.s95?.status==='UP'?'ld-dot-g':'ld-dot-r'}"></span> S95 — WEVADS + ARSENAL</div>
<div class="ld-big">${d.s95?.load||'?'}</div>
<div class="ld-sub">Load avg \u00b7 ${Math.round((d.s95?.ram_total_mb||0)/1024)} GB RAM</div>
<div class="ld-bar-label"><span>Disk</span><span style="color:${s95diskPct<80?'#10b981':s95diskPct<90?'#f59e0b':'#ef4444'}">${d.s95?.disk_pct||'?'}</span></div>
<div class="ld-bar-wrap"><div class="ld-bar-fill ${s95diskClass}" style="width:${s95diskPct}%"></div></div>
<div class="ld-sub" style="margin-top:10px">PMTA ECS (4 serveurs)</div>
<div style="margin-top:4px">${pmta}</div>
</div>
<div class="ld-card" style="display:flex;flex-direction:column;align-items:center;justify-content:center">
<div class="ld-title"><span class="ld-dot-g"></span> NONREG PLAYWRIGHT</div>
<div class="ld-nr">${d.nonreg?.passed||0}/${d.nonreg?.total||0}</div>
<div class="ld-sub">Score Playwright \u00b7 ${d.nonreg?.score||'?'} \u00b7 6\u03c3</div>
<svg width="110" height="110" viewBox="0 0 120 120" style="margin-top:12px">
<circle cx="60" cy="60" r="50" fill="none" stroke="rgba(255,255,255,0.06)" stroke-width="7"/>
<circle cx="60" cy="60" r="50" fill="none" stroke="#10b981" stroke-width="7" stroke-dasharray="314" stroke-dashoffset="0" stroke-linecap="round" transform="rotate(-90 60 60)"/>
<text x="60" y="58" text-anchor="middle" fill="#10b981" font-size="22" font-weight="700" font-family="JetBrains Mono,monospace">${d.health?.pct||100}</text>
<text x="60" y="72" text-anchor="middle" fill="rgba(255,255,255,0.3)" font-size="9">HEALTH %</text>
</svg>
</div>
</div>
<div class="ld-grid">
<div class="ld-card">
<div class="ld-title"><span class="ld-dot-g"></span> SOVEREIGN IA CASCADE \u00b7 0\u20ac</div>
<div style="font-size:26px;font-weight:700;font-family:JetBrains Mono,monospace;color:#a78bfa">${d.sovereign?.active||0}<span style="color:rgba(255,255,255,0.3);font-size:14px">/${d.sovereign?.total||0}</span></div>
<div class="ld-sub">Providers actifs \u00b7 Primary: ${d.sovereign?.primary||'?'}</div>
<div style="margin-top:8px">${providers}</div>
</div>
<div class="ld-card">
<div class="ld-title"><span class="ld-dot-g"></span> ETHICA B2B — MAGHREB</div>
<div style="font-size:26px;font-weight:700;font-family:JetBrains Mono,monospace">${(d.ethica?.total_hcps||0).toLocaleString()}</div>
<div class="ld-sub">${(d.ethica?.with_email||0).toLocaleString()} emails (${d.ethica?.pct_email||0}%) \u00b7 ${(d.ethica?.with_phone||0).toLocaleString()} phones (${d.ethica?.pct_phone||0}%)</div>
<div style="margin-top:10px">${countries}</div>
<div class="ld-sub" style="margin-top:6px">Gap: ${(d.ethica?.gap_email||0).toLocaleString()} emails manquants</div>
</div>
<div class="ld-card">
<div class="ld-title"><span class="ld-dot-g"></span> SERVICES LIVE</div>
<div class="ld-svc-grid">${services}</div>
<div style="margin-top:12px">
<div class="ld-sub"><b style="color:#fff">Git:</b> ${d.git?.head||'?'} \u00b7 <span style="color:${d.git?.status==='CLEAN'?'#10b981':'#f59e0b'}">${d.git?.status||'?'}</span></div>
<div class="ld-sub"><b style="color:#fff">Crons:</b> ${d.crons?.active||'?'} actifs \u00b7 <b style="color:#fff">Whisper:</b> ${d.whisper?.binary||'?'}</div>
</div>
</div>
</div>
<div class="ld-grid ld-grid2">
<div class="ld-card">
<div class="ld-title"><span class="ld-dot-g"></span> DOCKER \u00b7 ${d.docker?.length||0} CONTAINERS</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0 16px">${docker}</div>
</div>
<div class="ld-card">
<div class="ld-title"><span class="ld-dot-g"></span> M\u00c9TRIQUES CL\u00c9S</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
<div class="ld-metric-box"><div class="ld-metric-val" style="color:#a78bfa">0\u20ac</div><div class="ld-metric-lbl">Co\u00fbt IA mensuel</div></div>
<div class="ld-metric-box"><div class="ld-metric-val" style="color:#60a5fa">20/20</div><div class="ld-metric-lbl">WEVIA Intents 6\u03c3</div></div>
<div class="ld-metric-box"><div class="ld-metric-val" style="color:#f472b6">${d.ethica?.pct_email||75}%</div><div class="ld-metric-lbl">Email coverage</div></div>
<div class="ld-metric-box"><div class="ld-metric-val" style="color:#22d3ee">${d.whisper?.model||'142MB'}</div><div class="ld-metric-lbl">Whisper model</div></div>
</div>
<div style="margin-top:10px;padding:10px;background:rgba(255,255,255,0.02);border-radius:8px;border:1px solid rgba(255,255,255,0.05)">
<div style="font-size:10px;color:rgba(255,255,255,0.3);margin-bottom:4px">ARCHITECTURE</div>
<div style="font-size:11px;color:rgba(255,255,255,0.5);line-height:1.6">S204 (8cpu/32gb) \u2192 WEVIA+Ethica+Docker<br>S95 (16gb) \u2192 WEVADS+Arsenal+PG<br>4\u00d7 PMTA ECS Huawei<br>Sovereign \u2192 13 LLMs gratuits</div>
</div>
</div>
</div>
<div class="ld-ts">Derni\u00e8re MAJ: ${new Date().toLocaleString('fr-FR')} \u00b7 Auto-refresh 60s</div>`;
}
load();
setInterval(load, 60000);
})();