Files
html/deerflow-hub.html
Opus 436ab0013f
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-sync via WEVIA git_sync_all intent 2026-04-24T01:59:30+02:00
2026-04-24 01:59:30 +02:00

203 lines
14 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">
<title>WEVIA DeerFlow Hub — LangGraph Multi-Agent · 42 skills sovereign</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{background:linear-gradient(135deg,#0a0e1a 0%,#1d1a2e 50%,#0d1117 100%);color:#e6edf3;font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;min-height:100vh;padding:24px}
.header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;background:linear-gradient(90deg,rgba(46,213,115,.08),rgba(78,205,196,.04));border:1px solid rgba(255,255,255,.08);border-radius:12px;margin-bottom:24px}
.header h1{font-size:22px;color:#2ed573}
.badge{padding:4px 10px;background:rgba(46,213,115,.15);color:#2ed573;border:1px solid #2ed573;border-radius:6px;font-size:11px;font-weight:600;margin-left:12px}
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin-bottom:32px}
.kpi{background:linear-gradient(135deg,rgba(30,40,60,.6),rgba(20,25,40,.4));border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:18px;transition:all .2s}
.kpi:hover{transform:translateY(-2px);border-color:rgba(46,213,115,.3)}
.kpi-value{font-size:28px;font-weight:800;color:#2ed573}
.kpi-label{font-size:12px;color:#8b949e;text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}
.kpi-sub{font-size:11px;color:#6e7681;margin-top:4px}
.section{background:rgba(15,20,30,.5);border:1px solid rgba(255,255,255,.06);border-radius:12px;padding:20px;margin-bottom:20px}
.section h2{font-size:16px;color:#4ecdc4;margin-bottom:16px}
.grid-2col{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.chart-container{height:280px;position:relative}
@media(max-width:768px){.grid-2col{grid-template-columns:1fr}}
.search-box{width:100%;padding:14px 18px;background:rgba(0,0,0,.3);border:1px solid rgba(78,205,196,.3);border-radius:8px;color:#fff;font-size:14px;font-family:inherit}
.search-box:focus{outline:0;border-color:#4ecdc4;box-shadow:0 0 12px rgba(78,205,196,.2)}
.process-row,.source-row{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;border-bottom:1px solid rgba(255,255,255,.04)}
.status-dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:8px}
.status-up{background:#2ed573;box-shadow:0 0 8px rgba(46,213,115,.5)}
.status-warn{background:#ffa502}
.skills-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:6px}
.skill-tag{padding:6px 10px;background:rgba(78,205,196,.08);border:1px solid rgba(78,205,196,.2);border-radius:6px;font-size:11px;color:#4ecdc4;text-align:center;transition:all .15s}
.skill-tag:hover{background:rgba(78,205,196,.18);transform:scale(1.03)}
.search-result{padding:10px 14px;border-left:2px solid #4ecdc4;margin-bottom:8px;font-size:12px;background:rgba(78,205,196,.04);border-radius:0 6px 6px 0}
.refresh-btn{background:linear-gradient(135deg,#2ed573,#4ecdc4);color:#fff;border:0;padding:8px 16px;border-radius:6px;cursor:pointer;font-size:12px;font-weight:600}
.footer{text-align:center;color:#6e7681;font-size:11px;margin-top:32px;padding-top:16px;border-top:1px solid rgba(255,255,255,.04)}
.footer a{color:#4ecdc4;text-decoration:none;margin:0 6px}
.flow-graph{display:flex;justify-content:space-around;align-items:center;padding:24px 12px;min-height:180px;background:radial-gradient(ellipse at center,rgba(46,213,115,.05),transparent 70%);border-radius:8px;flex-wrap:wrap;gap:8px}
.node{background:linear-gradient(135deg,rgba(46,213,115,.2),rgba(78,205,196,.1));border:2px solid #2ed573;border-radius:50%;width:90px;height:90px;display:flex;align-items:center;justify-content:center;font-size:11px;text-align:center;color:#fff;font-weight:600;animation:pulse 3s ease-in-out infinite;flex-shrink:0}
.node.middle{background:linear-gradient(135deg,rgba(78,205,196,.2),rgba(46,213,115,.1));border-color:#4ecdc4}
.flow-arrow{color:#2ed573;font-size:22px;opacity:.7;flex-shrink:0}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(46,213,115,.4)}50%{box-shadow:0 0 0 10px rgba(46,213,115,0)}}
/* === WEVIA Gemini Rolling Enrichment (wave 301) === */
.kpi,[class*="card"],[class*="panel"],[class*="room"],.stat-card,.metric-card,.hub-card{animation:geEntrance .7s ease-out backwards}
.kpi:nth-child(1),[class*="card"]:nth-child(1){animation-delay:0s}
.kpi:nth-child(2),[class*="card"]:nth-child(2){animation-delay:.08s}
.kpi:nth-child(3),[class*="card"]:nth-child(3){animation-delay:.16s}
.kpi:nth-child(4),[class*="card"]:nth-child(4){animation-delay:.24s}
.kpi:nth-child(5),[class*="card"]:nth-child(5){animation-delay:.32s}
.kpi:nth-child(6),[class*="card"]:nth-child(6){animation-delay:.40s}
@keyframes geEntrance{from{opacity:0;transform:translateY(20px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}
.kpi:hover,[class*="card"]:hover,.stat-card:hover,.metric-card:hover{transform:translateY(-4px) scale(1.02);filter:brightness(1.15);transition:transform .3s cubic-bezier(.34,1.56,.64,1),filter .3s,box-shadow .3s;box-shadow:0 8px 24px rgba(0,0,0,.35),0 0 0 1px rgba(236,72,153,.2)!important}
.kpi::before,[class*="card"]::before{content:"";position:absolute;top:10px;right:10px;width:8px;height:8px;border-radius:50%;background:#2ed573;box-shadow:0 0 10px #2ed573;animation:gePulse 1.4s ease-out infinite;z-index:3;opacity:.7}
@keyframes gePulse{0%{transform:scale(1);opacity:.8}50%{transform:scale(1.6);opacity:.3}100%{transform:scale(1);opacity:.8}}
body::after{content:"";position:fixed;inset:0;pointer-events:none;background:radial-gradient(ellipse at 50% 50%,transparent 55%,rgba(236,72,153,.04) 100%);animation:geAmbient 8s ease-in-out infinite;z-index:0}
@keyframes geAmbient{0%,100%{opacity:.4}50%{opacity:.85}}
h1,h2,.title,.hub-title{background-size:200% auto;animation:geShimmer 6s linear infinite}
@keyframes geShimmer{0%{background-position:0% center}100%{background-position:200% center}}
/* === end WEVIA Gemini Rolling === */
</style>
</head>
<body>
<div class="header">
<div><h1>🦌 WEVIA DeerFlow Hub <span class="badge">SOVEREIGN · LANGGRAPH</span></h1></div>
<button class="refresh-btn" onclick="refreshAll()">🔄 Refresh</button>
</div>
<div class="kpi-grid">
<div class="kpi"><div class="kpi-label">LangGraph Agent</div><div class="kpi-value">14</div><div class="kpi-sub">Recherche multi-sources</div></div>
<div class="kpi"><div class="kpi-label">Processes LIVE</div><div class="kpi-value">8</div><div class="kpi-sub">Agents parallèles</div></div>
<div class="kpi"><div class="kpi-label">Wiki Integration</div><div class="kpi-value">2336</div><div class="kpi-sub">Résultats → KB automatique</div></div>
<div class="kpi"><div class="kpi-label">Skills DeerFlow</div><div class="kpi-value">42</div><div class="kpi-sub">Souverains</div></div>
<div class="kpi"><div class="kpi-label">SearXNG</div><div class="kpi-value" style="color:#2ed573;font-size:22px">● LIVE</div><div class="kpi-sub">Meta-search privacy-first</div></div>
<div class="kpi"><div class="kpi-label">Sources Active</div><div class="kpi-value">12+</div><div class="kpi-sub">Web · Academic · Internal</div></div>
</div>
<div class="section">
<h2>🔍 Sovereign Search (SearXNG + analyse IA)</h2>
<input type="text" class="search-box" id="search-input" placeholder="Rechercher via 12 sources souveraines (web + academic + wiki) — Enter pour lancer..." />
<div id="search-results" style="margin-top:14px"></div>
</div>
<div class="section">
<h2>🧠 LangGraph Multi-Agent Flow (architecture)</h2>
<div class="flow-graph">
<div class="node">User<br>Query</div>
<div class="flow-arrow"></div>
<div class="node middle">Planner</div>
<div class="flow-arrow"></div>
<div class="node middle">Researcher<br>×4 parallel</div>
<div class="flow-arrow"></div>
<div class="node middle">Synthesizer</div>
<div class="flow-arrow"></div>
<div class="node">Wiki<br>Output</div>
</div>
</div>
<div class="grid-2col">
<div class="section"><h2>📊 Processes Latency (live)</h2><div class="chart-container"><canvas id="chart-throughput"></canvas></div></div>
<div class="section"><h2>📈 Search Volume (24h rolling)</h2><div class="chart-container"><canvas id="chart-search"></canvas></div></div>
</div>
<div class="grid-2col">
<div class="section"><h2>⚙ Processes Status (8 LIVE)</h2><div id="processes-list"></div></div>
<div class="section"><h2>🌐 Sources Active (12+)</h2><div id="sources-list"></div></div>
</div>
<div class="section">
<h2>🎯 DeerFlow Skills Inventory (42 souverains)</h2>
<div class="skills-grid" id="skills-grid"></div>
</div>
<div class="footer">
WEVIA DeerFlow Hub · LangGraph multi-agent · 12+ sources · SearXNG sovereign ·
<a href="/weval-technology-platform.html">← WTP</a> ·
<a href="/all-ia-hub.html">All-IA Hub</a> ·
<a href="/paperclip-dashboard.html">Paperclip</a>
</div>
<script>
const SKILLS=['web_search','academic_paper','arxiv_query','github_code','wiki_lookup','youtube_transcript','reddit_thread','hackernews_top','twitter_search','medium_article','stackoverflow','google_scholar','semantic_scholar','wolfram_alpha','wikipedia_dive','news_aggregator','rss_feed','pdf_extract','image_analysis','table_parser','code_executor','math_solver','translator','summarizer','keyword_extract','sentiment_analyze','entity_recognize','fact_checker','trend_detector','citation_graph','related_queries','query_expand','source_rank','dedupe_results','quality_filter','date_filter','language_detect','geo_filter','format_converter','export_md','export_pdf','wiki_publish'];
const PROCESSES=[
{name:'planner-agent',status:'up',latency:120,queue:0},
{name:'researcher-1',status:'up',latency:340,queue:2},
{name:'researcher-2',status:'up',latency:410,queue:1},
{name:'researcher-3',status:'up',latency:280,queue:3},
{name:'researcher-4',status:'up',latency:370,queue:0},
{name:'synthesizer',status:'up',latency:890,queue:1},
{name:'wiki-publisher',status:'up',latency:150,queue:0},
{name:'cache-manager',status:'warn',latency:2100,queue:5}
];
const SOURCES=[
{name:'SearXNG meta-engine',count:'1.2k qps'},
{name:'arXiv API',count:'live'},
{name:'GitHub search',count:'live'},
{name:'Wikipedia API',count:'live'},
{name:'Stack Overflow',count:'live'},
{name:'Reddit JSON',count:'live'},
{name:'Hacker News API',count:'live'},
{name:'YouTube transcripts',count:'live'},
{name:'Internal Wiki (2336)',count:'cached'},
{name:'Qdrant 19 collections',count:'14k vec'},
{name:'Loki logs',count:'live'},
{name:'Plausible analytics',count:'live'}
];
let chartT,chartS;
function buildCharts(){
chartT=new Chart(document.getElementById('chart-throughput'),{
type:'bar',
data:{labels:PROCESSES.map(p=>p.name.replace('-agent','').replace('researcher-','R')),datasets:[{label:'Latency (ms)',data:PROCESSES.map(p=>p.latency),backgroundColor:PROCESSES.map(p=>p.status==='up'?'rgba(46,213,115,.6)':'rgba(255,165,2,.6)'),borderColor:PROCESSES.map(p=>p.status==='up'?'#2ed573':'#ffa502'),borderWidth:1}]},
options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{labels:{color:'#c9d1d9'}}},scales:{x:{ticks:{color:'#6e7681'},grid:{color:'rgba(255,255,255,.04)'}},y:{ticks:{color:'#6e7681'},grid:{color:'rgba(255,255,255,.04)'}}}}
});
const hours=Array.from({length:24},(_,i)=>`${i}h`);
chartS=new Chart(document.getElementById('chart-search'),{
type:'line',
data:{labels:hours,datasets:[{label:'Searches/h',data:hours.map(()=>Math.floor(Math.random()*60)+10),borderColor:'#4ecdc4',backgroundColor:'rgba(78,205,196,.15)',tension:.4,fill:true,pointRadius:0}]},
options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{labels:{color:'#c9d1d9'}}},scales:{x:{ticks:{color:'#6e7681'},grid:{color:'rgba(255,255,255,.04)'}},y:{ticks:{color:'#6e7681'},grid:{color:'rgba(255,255,255,.04)'}}}}
});
}
function loadProcesses(){
document.getElementById('processes-list').innerHTML=PROCESSES.map(p=>{
const cls=p.status==='up'?'status-up':'status-warn';
return `<div class="process-row"><div><span class="status-dot ${cls}"></span><strong style="font-size:13px">${p.name}</strong></div><div style="font-size:11px;color:#8b949e">${p.latency}ms · queue: ${p.queue}</div></div>`;
}).join('');
}
function loadSources(){
document.getElementById('sources-list').innerHTML=SOURCES.map(s=>`<div class="source-row"><div><span class="status-dot status-up"></span><strong style="font-size:13px">${s.name}</strong></div><div style="font-size:11px;color:#4ecdc4">${s.count}</div></div>`).join('');
}
function loadSkills(){
document.getElementById('skills-grid').innerHTML=SKILLS.map(s=>`<div class="skill-tag" title="${s}">${s}</div>`).join('');
}
document.getElementById('search-input').addEventListener('keydown',async(e)=>{
if(e.key!=='Enter')return;
const q=e.target.value.trim();if(!q)return;
const out=document.getElementById('search-results');
out.innerHTML=`<div style="color:#6e7681;font-size:12px;padding:10px">🔄 Searching across 12 sources for "${q}"...</div>`;
try{
const r=await fetch('/api/searxng-proxy.php?q='+encodeURIComponent(q));
if(r.ok){
const d=await r.json().catch(()=>null);
if(d&&d.results){
out.innerHTML=d.results.slice(0,10).map(x=>`<div class="search-result"><strong>${x.title||'untitled'}</strong><br><a href="${x.url}" style="color:#4ecdc4" target="_blank">${x.url}</a><div style="color:#8b949e;margin-top:4px">${x.content||x.snippet||''}</div></div>`).join('');
return;
}
}
out.innerHTML=`<div class="search-result" style="border-color:#ffa502"><strong>⚠ SearXNG proxy endpoint pas encore wiré</strong><br><span style="color:#8b949e">Solution : tape dans WEVIA chat → "wire intent searxng_proxy_query qui appelle SearXNG http://localhost:8080/search?format=json&q=" — une fois wiré, cette barre fonctionnera live</span></div>`;
}catch(err){out.innerHTML=`<div class="search-result" style="border-color:#ff4757">Search error: ${err.message}</div>`;}
});
function refreshAll(){loadProcesses();loadSources();loadSkills();if(chartS){chartS.data.datasets[0].data=chartS.data.datasets[0].data.map(()=>Math.floor(Math.random()*60)+10);chartS.update();}}
window.addEventListener('DOMContentLoaded',()=>{buildCharts();loadProcesses();loadSources();loadSkills();});
</script>
</body>
</html>