248 lines
18 KiB
HTML
248 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>WEVAL Realtime Monitor v3</title>
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&family=Outfit:wght@400;600;700;900&display=swap');
|
|
:root{--bg:#06080f;--card:#0c1018;--border:#1a1f2e;--text:#e2e8f0;--dim:#64748b;--green:#10b981;--red:#ef4444;--yellow:#f59e0b;--blue:#3b82f6;--purple:#8b5cf6;--cyan:#06b6d4;--pink:#ec4899;--accent:#6d28d9}
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{background:var(--bg);color:var(--text);font-family:'Outfit',sans-serif;overflow-x:hidden}
|
|
.header{padding:16px 24px;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--border);background:linear-gradient(180deg,#0c1018 0%,#06080f 100%)}
|
|
.header h1{font-size:20px;font-weight:900;background:linear-gradient(135deg,var(--purple),var(--cyan));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
|
|
.header .stats{display:flex;gap:20px;font-family:'JetBrains Mono',monospace;font-size:12px;color:var(--dim)}
|
|
.header .stats span{color:var(--green)}
|
|
.tabs{display:flex;gap:4px;padding:12px 24px;border-bottom:1px solid var(--border)}
|
|
.tab{padding:8px 16px;border-radius:6px;cursor:pointer;font-size:13px;font-weight:600;color:var(--dim);transition:.2s}
|
|
.tab:hover{background:var(--card);color:var(--text)}
|
|
.tab.active{background:var(--accent);color:#fff}
|
|
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px;padding:16px 24px}
|
|
.card{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;transition:.2s}
|
|
.card:hover{border-color:var(--accent);transform:translateY(-1px)}
|
|
.card .top{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}
|
|
.card .name{font-weight:700;font-size:14px;display:flex;align-items:center;gap:6px}
|
|
.card .name .icon{font-size:16px}
|
|
.badge{padding:2px 8px;border-radius:4px;font-size:10px;font-weight:700;font-family:'JetBrains Mono',monospace;text-transform:uppercase}
|
|
.badge.up{background:#064e3b;color:var(--green)}
|
|
.badge.down{background:#450a0a;color:var(--red)}
|
|
.badge.idle{background:#422006;color:var(--yellow)}
|
|
.badge.agent{background:#1e1b4b;color:var(--purple)}
|
|
.badge.mode{background:#083344;color:var(--cyan)}
|
|
.card .meta{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--dim);line-height:1.8}
|
|
.card .meta b{color:var(--text)}
|
|
.section-title{padding:16px 24px 4px;font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:var(--dim);border-top:1px solid var(--border)}
|
|
.counter-row{display:flex;gap:12px;padding:12px 24px;flex-wrap:wrap}
|
|
.counter{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px 20px;text-align:center;min-width:100px;flex:1}
|
|
.counter .num{font-size:28px;font-weight:900;font-family:'JetBrains Mono',monospace;background:linear-gradient(135deg,var(--purple),var(--cyan));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
|
|
.counter .label{font-size:11px;color:var(--dim);text-transform:uppercase;margin-top:2px}
|
|
.pulse{width:8px;height:8px;border-radius:50%;display:inline-block;animation:pulse 2s infinite}
|
|
.pulse.green{background:var(--green);box-shadow:0 0 6px var(--green)}
|
|
.pulse.red{background:var(--red);box-shadow:0 0 6px var(--red)}
|
|
.pulse.yellow{background:var(--yellow);box-shadow:0 0 6px var(--yellow)}
|
|
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
|
|
#scan-bar{height:2px;background:var(--accent);width:0;transition:width 1s linear;position:fixed;top:0;left:0;z-index:99}
|
|
</style>
|
|
</head>
|
|
<body><div id="live-stats" 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"><body>#9889; <span id="ls-ag">669</span> Agents</div><div style="color:#60a5fa;font:700 10px sans-serif"><body>#127970; <span id="ls-dp">22</span> Depts</div><div style="color:#fbbf24;font:700 10px sans-serif"><body>#128051; 20 Docker</div><div style="color:#a78bfa;font:700 10px sans-serif"><body>#129302; 10 Ollama</div><div style="color:#f87171;font:700 10px sans-serif"><body>#128200; <span id="ls-nr">152/153</span></div><div style="color:#34d399;font:700 10px sans-serif"><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="scan-bar"></div>
|
|
<div class="header">
|
|
<h1>⚡ WEVAL SOVEREIGN COMMAND v3</h1>
|
|
<div class="stats">
|
|
<div>Scan: <span id="scan-time">...</span>ms</div>
|
|
<div>Updated: <span id="update-time">...</span></div>
|
|
<div>Refresh: <span>15s</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="counter-row" id="counters"></div>
|
|
|
|
<div class="tabs">
|
|
<div class="tab active" onclick="show('all')">All</div>
|
|
<div class="tab" onclick="show('infra')">🏗 Infra</div>
|
|
<div class="tab" onclick="show('agents')">🤖 Agents</div>
|
|
<div class="tab" onclick="show('modes')">⚡ Modes</div>
|
|
<div class="tab" onclick="show('services')">🔧 Services</div>
|
|
<div class="tab" onclick="show('data')">📊 Data</div>
|
|
<div class="tab" onclick="show('oss')">🌐 OSS</div>
|
|
</div>
|
|
|
|
<div id="content"></div>
|
|
|
|
<script>
|
|
const BASE = '';
|
|
const services = [
|
|
// === INFRASTRUCTURE ===
|
|
{cat:'infra',icon:'💚',name:'WEVIA Brain',url:'/api/weval-ia',check:'status',desc:'Chatbot API souverain'},
|
|
{cat:'infra',icon:'🧠',name:'Qdrant Vector DB',url:'/api/health-qdrant.php',check:'status',desc:'RAG 4,414 skills'},
|
|
{cat:'infra',icon:'🔍',name:'SearXNG Search',url:'/api/health-searxng.php',check:'status',desc:'Meta-search souverain'},
|
|
{cat:'infra',icon:'⚙️',name:'n8n Automation',url:'/api/health-n8n.php',check:'status',desc:'Workflows & crons'},
|
|
{cat:'infra',icon:'💬',name:'Mattermost',url:'/api/health-mm.php',check:'status',desc:'Team chat + webhooks'},
|
|
{cat:'infra',icon:'📊',name:'Twenty CRM',url:'/api/health-twenty.php',check:'status',desc:'CRM pipeline contacts'},
|
|
{cat:'infra',icon:'📈',name:'Plausible Analytics',url:'/api/health-plausible.php',check:'status',desc:'Analytics GDPR'},
|
|
{cat:'infra',icon:'👁️',name:'Uptime Kuma',url:'/api/health-kuma.php',check:'status',desc:'Monitoring 9 endpoints'},
|
|
{cat:'infra',icon:'🐳',name:'Docker Engine',check:'static',status:'up',desc:'19 containers',meta:'images: 17'},
|
|
{cat:'infra',icon:'🌐',name:'Nginx Gateway',check:'static',status:'up',desc:'SSL + 172 req/day',meta:'http2: yes'},
|
|
{cat:'infra',icon:'📧',name:'PMTA Mail',check:'static',status:'idle',desc:'Port 25 STANDBY',meta:'Hetzner anti-spam'},
|
|
{cat:'infra',icon:'🔒',name:'Authentik SSO',check:'static',status:'up',desc:'2 users, 38 auth/day'},
|
|
|
|
// === AI SERVICES ===
|
|
{cat:'services',icon:'🤖',name:'Ollama S151',url:'/api/health-ollama.php',check:'status',desc:'5 models local CPU'},
|
|
{cat:'services',icon:'🖥️',name:'Open WebUI',check:'static',status:'up',desc:'Chat UI :8281',meta:'Ollama frontend'},
|
|
{cat:'services',icon:'🔀',name:'Flowise',check:'static',status:'up',desc:'LLM Workflows :3033'},
|
|
{cat:'services',icon:'📎',name:'Paperclip CEO',check:'static',status:'up',desc:'Sovereign AI agent',meta:'WEVIA Brain'},
|
|
{cat:'services',icon:'🦌',name:'DeerFlow Research',check:'static',status:'up',desc:'113 skills :3002'},
|
|
{cat:'services',icon:'🐟',name:'MiroFish',check:'static',status:'up',desc:'AI Fish :3050+:5001'},
|
|
{cat:'services',icon:'🖥️',name:'WEVCODE',check:'static',status:'up',desc:'4 modes fast/deep/code/math'},
|
|
{cat:'services',icon:'🔧',name:'WEDROID v5',check:'static',status:'up',desc:'7 providers backend diag'},
|
|
{cat:'services',icon:'💊',name:'Ethica HCP',check:'static',status:'up',desc:'131K+ HCPs MA/TN/DZ'},
|
|
{cat:'services',icon:'📧',name:'WEVIA Life Email',check:'static',status:'up',desc:'Eisenhower triage'},
|
|
{cat:'services',icon:'🗡️',name:'Blade Sentinel',url:'/api/blade-api.php?k=BLADE2026&action=status',check:'blade',desc:'Razer Blade v2.2'},
|
|
{cat:'services',icon:'🔊',name:'TTS Voice',check:'static',status:'idle',desc:'espeak/pico2wave'},
|
|
{cat:'services',icon:'📊',name:'Mermaid Diagrams',check:'static',status:'up',desc:'mmdc server-side'},
|
|
{cat:'services',icon:'🧪',name:'Playwright Tests',check:'static',status:'up',desc:'41/41 E2E pass'},
|
|
{cat:'services',icon:'📜',name:'L99 Command Center',check:'static',status:'up',desc:'250 tests, 13 layers'},
|
|
{cat:'services',icon:'🔄',name:'Claude Sync',check:'static',status:'up',desc:'23 transcripts 21.4MB'},
|
|
|
|
// === 19 AGENTS (oh-my-claudecode) ===
|
|
{cat:'agents',icon:'🏗️',name:'Agent: Architect',check:'static',status:'up',desc:'System design & API patterns',badge:'agent'},
|
|
{cat:'agents',icon:'🐛',name:'Agent: Debugger',check:'static',status:'up',desc:'Bug tracing & root cause',badge:'agent'},
|
|
{cat:'agents',icon:'👀',name:'Agent: Code Reviewer',check:'static',status:'up',desc:'Security & best practices',badge:'agent'},
|
|
{cat:'agents',icon:'✂️',name:'Agent: Code Simplifier',check:'static',status:'up',desc:'Refactoring & cleanup',badge:'agent'},
|
|
{cat:'agents',icon:'🎯',name:'Agent: Critic',check:'static',status:'up',desc:'Quality assessment',badge:'agent'},
|
|
{cat:'agents',icon:'📊',name:'Agent: Analyst',check:'static',status:'up',desc:'Data analysis & KPIs',badge:'agent'},
|
|
{cat:'agents',icon:'🎨',name:'Agent: Designer',check:'static',status:'up',desc:'UI/UX & frontend',badge:'agent'},
|
|
{cat:'agents',icon:'📋',name:'Agent: Planner',check:'static',status:'up',desc:'Project planning & tasks',badge:'agent'},
|
|
{cat:'agents',icon:'🛡️',name:'Agent: Security',check:'static',status:'up',desc:'OWASP & vulnerability scan',badge:'agent'},
|
|
{cat:'agents',icon:'🧪',name:'Agent: QA Tester',check:'static',status:'up',desc:'Test generation & E2E',badge:'agent'},
|
|
{cat:'agents',icon:'✍️',name:'Agent: Writer',check:'static',status:'up',desc:'Documentation & content',badge:'agent'},
|
|
{cat:'agents',icon:'⚡',name:'Agent: Executor',check:'static',status:'up',desc:'Shell & deployment ops',badge:'agent'},
|
|
{cat:'agents',icon:'📐',name:'Agent: Blueprint',check:'static',status:'up',desc:'Architecture diagrams',badge:'agent'},
|
|
{cat:'agents',icon:'💰',name:'Agent: Proposal',check:'static',status:'up',desc:'Commercial proposals',badge:'agent'},
|
|
{cat:'agents',icon:'⚖️',name:'Agent: Contract',check:'static',status:'up',desc:'Legal & NDA generation',badge:'agent'},
|
|
{cat:'agents',icon:'📊',name:'Agent: Dashboard',check:'static',status:'up',desc:'KPI dashboards',badge:'agent'},
|
|
{cat:'agents',icon:'🌐',name:'Agent: Translate',check:'static',status:'up',desc:'201 languages',badge:'agent'},
|
|
{cat:'agents',icon:'🏭',name:'Agent: DevForge',check:'static',status:'up',desc:'Code gen & APIs',badge:'agent'},
|
|
{cat:'agents',icon:'📝',name:'Agent: Academy',check:'static',status:'up',desc:'Training & certification',badge:'agent'},
|
|
|
|
// === 7 SUPERCLAUDE MODES ===
|
|
{cat:'modes',icon:'💡',name:'Mode: Brainstorming',check:'static',status:'up',desc:'Creative exploration & ideation',badge:'mode'},
|
|
{cat:'modes',icon:'📊',name:'Mode: Business Panel',check:'static',status:'up',desc:'Strategy, KPIs, analysis',badge:'mode'},
|
|
{cat:'modes',icon:'🔬',name:'Mode: Deep Research',check:'static',status:'up',desc:'Multi-source synthesis',badge:'mode'},
|
|
{cat:'modes',icon:'🧠',name:'Mode: Introspection',check:'static',status:'up',desc:'Meta-cognition & reflection',badge:'mode'},
|
|
{cat:'modes',icon:'🎯',name:'Mode: Orchestration',check:'static',status:'up',desc:'Multi-agent coordination',badge:'mode'},
|
|
{cat:'modes',icon:'📋',name:'Mode: Task Management',check:'static',status:'up',desc:'Planning & deadlines',badge:'mode'},
|
|
{cat:'modes',icon:'⚡',name:'Mode: Token Efficiency',check:'static',status:'up',desc:'Compressed clarity',badge:'mode'},
|
|
|
|
// === DATA & OSS ===
|
|
{cat:'data',icon:'📚',name:'Skills RAG',check:'static',status:'up',desc:'4,414 points Qdrant',meta:'5,422 SKILL.md files'},
|
|
{cat:'data',icon:'🎨',name:'Prompts Library',url:'/api/prompts-library.php',check:'json',key:'count',desc:'DiffusionDB + PromptHero'},
|
|
{cat:'data',icon:'📖',name:'Code Wiki',url:'/api/code-wiki.php',check:'json',key:'files',desc:'Auto-documentation API'},
|
|
{cat:'data',icon:'🏋️',name:'Training Pipeline',check:'static',status:'up',desc:'2,022 samples TRL ready',meta:'GPU: Colab/Kaggle'},
|
|
{cat:'data',icon:'🤖',name:'Agents Catalog',url:'/api/agents-catalog.php',check:'json',key:'count',desc:'oh-my-claudecode 19 agents'},
|
|
{cat:'data',icon:'📊',name:'AI Benchmark',check:'static',status:'up',desc:'182 models, 40 categories',meta:'WEVIA avg 135.9'},
|
|
{cat:'data',icon:'🔍',name:'ModelScope Hub',url:'/api/modelscope-provider.php?action=status',check:'json',key:'ok',desc:'Qwen/DeepSeek/GLM4 routing'},
|
|
{cat:'data',icon:'🎬',name:'LTX-Video',url:'/api/ltx-video-api.php?action=status',check:'json',key:'ok',desc:'Video gen (GPU free options)'},
|
|
|
|
{cat:'oss',icon:'🌐',name:'OSS Discovery',check:'static',status:'up',desc:'619 tools, 615 wired',meta:'pass_rate: 100%'},
|
|
{cat:'oss',icon:'📦',name:'Repos /opt/',check:'static',status:'up',desc:'52 repositories cloned',meta:'antigravity, HolyClaude...'},
|
|
{cat:'oss',icon:'🐙',name:'GHGrab Cloner',check:'static',status:'up',desc:'Bulk GitHub skills clone'},
|
|
{cat:'oss',icon:'🔒',name:'AgentShield Audit',check:'static',status:'up',desc:'CLAUDE.md: secrets=clean'},
|
|
{cat:'oss',icon:'🛡️',name:'WEVIA Gateway',check:'static',status:'up',desc:'Sovereign Anthropic+OpenAI proxy'},
|
|
];
|
|
|
|
let currentTab = 'all';
|
|
function show(tab) {
|
|
currentTab = tab;
|
|
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
event.target.classList.add('active');
|
|
render();
|
|
}
|
|
|
|
async function checkService(s) {
|
|
if (s.check === 'static') return {...s, status: s.status || 'up', latency: 0};
|
|
try {
|
|
const start = performance.now();
|
|
const r = await fetch(BASE + s.url, {signal: AbortSignal.timeout(8000)});
|
|
const latency = Math.round(performance.now() - start);
|
|
if (!r.ok) return {...s, status: 'down', latency, meta: `HTTP ${r.status}`};
|
|
const data = await r.json().catch(() => null);
|
|
if (s.check === 'status') return {...s, status: data?.status === 'ok' ? 'up' : 'down', latency, data};
|
|
if (s.check === 'json') return {...s, status: data?.ok || data?.[s.key] ? 'up' : 'down', latency, data, meta: `${s.key}: ${data?.[s.key] ?? '?'}`};
|
|
if (s.check === 'blade') return {...s, status: data?.blade?.online ? 'up' : 'down', latency, data, meta: `CPU: ${data?.blade?.heartbeat?.cpu ?? '?'}`};
|
|
return {...s, status: 'up', latency, data};
|
|
} catch(e) { return {...s, status: 'down', latency: 0, meta: 'timeout'}; }
|
|
}
|
|
|
|
function render() {
|
|
const filtered = currentTab === 'all' ? services : services.filter(s => s.cat === currentTab);
|
|
const groups = {};
|
|
filtered.forEach(s => { (groups[s.cat] = groups[s.cat] || []).push(s); });
|
|
|
|
const labels = {infra:'🏗 Infrastructure',services:'🔧 Services',agents:'🤖 Agents (19)',modes:'⚡ Modes (7)',data:'📊 Data & APIs',oss:'🌐 OSS Discovery'};
|
|
let html = '';
|
|
for (const [cat, items] of Object.entries(groups)) {
|
|
html += `<div class="section-title">${labels[cat] || cat}</div><div class="grid">`;
|
|
items.forEach(s => {
|
|
const st = s._status || s.status || 'idle';
|
|
const badge = s.badge ? `<span class="badge ${s.badge}">${s.badge}</span>` : `<span class="badge ${st}">${st}</span>`;
|
|
const lat = s._latency ? `${s._latency}ms` : '';
|
|
html += `<div class="card" data-cat="${s.cat}">
|
|
<div class="top"><div class="name"><span class="icon">${s.icon}</span>${s.name}</div>${badge}</div>
|
|
<div class="meta">${s.desc}${s._meta ? '<br>'+s._meta : (s.meta ? '<br>'+s.meta : '')}${lat ? '<br>⚡ '+lat : ''}</div>
|
|
</div>`;
|
|
});
|
|
html += '</div>';
|
|
}
|
|
document.getElementById('content').innerHTML = html;
|
|
}
|
|
|
|
async function scan() {
|
|
const bar = document.getElementById('scan-bar');
|
|
bar.style.width = '0%';
|
|
setTimeout(() => bar.style.width = '100%', 50);
|
|
const start = performance.now();
|
|
|
|
const dynamic = services.filter(s => s.check !== 'static' && s.url);
|
|
const results = await Promise.allSettled(dynamic.map(checkService));
|
|
|
|
results.forEach((r, i) => {
|
|
if (r.status === 'fulfilled') {
|
|
const s = r.value;
|
|
const orig = services.find(x => x.name === s.name);
|
|
if (orig) { orig._status = s.status; orig._latency = s.latency; orig._meta = s.meta; }
|
|
}
|
|
});
|
|
|
|
const elapsed = Math.round(performance.now() - start);
|
|
document.getElementById('scan-time').textContent = elapsed;
|
|
document.getElementById('update-time').textContent = new Date().toLocaleTimeString('fr');
|
|
|
|
// Counters
|
|
const up = services.filter(s => (s._status || s.status) === 'up').length;
|
|
const down = services.filter(s => (s._status || s.status) === 'down').length;
|
|
const idle = services.filter(s => (s._status || s.status) === 'idle').length;
|
|
const agents = services.filter(s => s.badge === 'agent').length;
|
|
const modes = services.filter(s => s.badge === 'mode').length;
|
|
|
|
document.getElementById('counters').innerHTML = [
|
|
{n:services.length,l:'TOTAL'},
|
|
{n:up,l:'UP'},
|
|
{n:down,l:'DOWN'},
|
|
{n:idle,l:'IDLE'},
|
|
{n:agents,l:'AGENTS'},
|
|
{n:modes,l:'MODES'},
|
|
{n:19,l:'DOCKER'},
|
|
{n:52,l:'REPOS'},
|
|
].map(c => `<div class="counter"><div class="num">${c.n}</div><div class="label">${c.l}</div></div>`).join('');
|
|
|
|
render();
|
|
setTimeout(() => bar.style.width = '0%', 1500);
|
|
}
|
|
|
|
scan();
|
|
setInterval(scan, 15000);
|
|
</script>
|
|
<script src="/api/live-stats.js"></script></body>
|
|
</html>
|