Files
html/web-ia-status.html

342 lines
19 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 Command Center — Web-IA Orchestration</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500;700&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<style>
:root{
--bg:#08080c;--panel:rgba(18,18,26,0.55);--panel-hover:rgba(28,28,40,0.78);
--border:rgba(255,255,255,0.06);--border-hover:rgba(246,213,114,0.4);
--ink:#ebe6d8;--ink-dim:#9a9384;--ink-faint:#5a5650;
--gold:#f6d572;--gold-deep:#b8923c;--coral:#ff6b5e;--mint:#7fffd4;--azure:#8ecfff;
--font-display:'Cormorant Garamond',serif;--font-mono:'JetBrains Mono',ui-monospace,monospace;
--ease:cubic-bezier(.23,1,.32,1);
}
*{margin:0;padding:0;box-sizing:border-box}
html,body{background:var(--bg);color:var(--ink);font-family:var(--font-mono);min-height:100vh;overflow-x:hidden;font-weight:300;letter-spacing:.02em}
body::before{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;background:radial-gradient(ellipse 80% 60% at 20% 10%,rgba(246,213,114,0.08) 0%,transparent 55%),radial-gradient(ellipse 60% 80% at 85% 90%,rgba(142,207,255,0.06) 0%,transparent 55%)}
body::after{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;opacity:0.035;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E")}
main{position:relative;z-index:1;min-height:100vh;padding:40px 48px 96px;max-width:1680px;margin:0 auto}
.masthead{display:grid;grid-template-columns:1fr auto;align-items:end;gap:40px;margin-bottom:44px;padding-bottom:28px;border-bottom:1px solid var(--border)}
.eyebrow{display:flex;align-items:center;gap:14px;color:var(--gold);font-size:10px;font-weight:500;letter-spacing:.42em;text-transform:uppercase;margin-bottom:16px}
.eyebrow::before{content:"";width:28px;height:1px;background:var(--gold)}
.live-dot{width:6px;height:6px;border-radius:50%;background:var(--mint);box-shadow:0 0 12px var(--mint);animation:pulse 2s ease infinite}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.2)}}
h1{font-family:var(--font-display);font-weight:300;font-size:clamp(40px,5vw,72px);line-height:.95;letter-spacing:-.03em}
h1 em{font-style:italic;font-weight:400;color:var(--gold)}
.subtitle{max-width:560px;margin-top:18px;font-size:13px;line-height:1.75;color:var(--ink-dim)}
.kpis{display:flex;gap:36px}
.kpi{text-align:right}
.kpi-value{font-family:var(--font-display);font-size:44px;font-weight:300;line-height:1;color:var(--gold);font-variant-numeric:tabular-nums}
.kpi-label{font-size:9px;letter-spacing:.32em;text-transform:uppercase;color:var(--ink-faint);margin-top:6px}
.command-bar{display:flex;align-items:center;gap:12px;padding:14px 18px;background:var(--panel);backdrop-filter:blur(20px);border:1px solid var(--border);border-radius:2px;margin-bottom:36px;font-size:11px}
.cb-prompt{color:var(--gold);font-weight:500;letter-spacing:.12em}
.cb-path{color:var(--ink-dim);flex:1}
.cb-btn{padding:7px 14px;background:transparent;border:1px solid var(--border);color:var(--ink-dim);font-family:var(--font-mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;cursor:pointer;text-decoration:none;transition:all .3s var(--ease)}
.cb-btn:hover{border-color:var(--border-hover);color:var(--gold)}
.cb-btn.primary{background:var(--gold);color:#0a0a0f;border-color:var(--gold);font-weight:600}
.section-label{display:flex;align-items:center;gap:16px;font-size:10px;letter-spacing:.42em;text-transform:uppercase;color:var(--ink-faint);margin:28px 0 20px;font-weight:500}
.section-label::before,.section-label::after{content:"";flex:1;height:1px;background:var(--border)}
.section-label span{color:var(--gold)}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(420px,1fr));gap:18px}
.card{position:relative;padding:24px 26px;background:var(--panel);backdrop-filter:blur(20px);border:1px solid var(--border);border-radius:3px;overflow:hidden;opacity:0;animation:slideUp .8s var(--ease) forwards;transition:border-color .4s var(--ease),background .4s var(--ease)}
.card:nth-child(1){animation-delay:.05s}.card:nth-child(2){animation-delay:.1s}.card:nth-child(3){animation-delay:.15s}.card:nth-child(4){animation-delay:.2s}.card:nth-child(5){animation-delay:.25s}.card:nth-child(6){animation-delay:.3s}.card:nth-child(7){animation-delay:.35s}.card:nth-child(8){animation-delay:.4s}
@keyframes slideUp{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:translateY(0)}}
.card:hover{border-color:var(--border-hover);background:var(--panel-hover)}
.card-head{display:flex;align-items:baseline;gap:14px;margin-bottom:6px}
.card-mono{font-family:var(--font-display);font-size:40px;font-weight:400;line-height:.85;color:var(--gold);font-style:italic;letter-spacing:-.03em}
.card-title{flex:1}
.card-name{font-family:var(--font-display);font-size:24px;font-weight:400;letter-spacing:-.01em;line-height:1.1}
.card-url{font-size:10px;color:var(--ink-dim);margin-top:3px;letter-spacing:.02em}
.card-badge{font-size:9px;letter-spacing:.18em;text-transform:uppercase;padding:3px 8px;border-radius:2px;border:1px solid var(--border);color:var(--ink-faint);font-weight:500}
.card-status{display:flex;align-items:center;gap:10px;padding:9px 12px;margin:16px 0 14px;background:rgba(255,255,255,0.02);border:1px solid var(--border);border-radius:2px;font-size:10px;letter-spacing:.1em;text-transform:uppercase}
.dot{width:6px;height:6px;border-radius:50%;background:var(--ink-faint);flex-shrink:0;transition:all .3s var(--ease)}
.dot.ok{background:var(--mint);box-shadow:0 0 8px var(--mint);animation:pulse 2.4s ease infinite}
.dot.warn{background:var(--gold);box-shadow:0 0 8px var(--gold);animation:pulse 1.8s ease infinite}
.dot.bad{background:var(--coral);box-shadow:0 0 8px var(--coral)}
.status-label{flex:1;color:var(--ink-dim)}
.status-label.ok{color:var(--mint)}.status-label.warn{color:var(--gold)}.status-label.bad{color:var(--coral)}
.status-meta{color:var(--ink-faint);font-size:10px}
/* Prompt area */
.prompt-row{display:flex;gap:8px;margin-bottom:12px}
.prompt-input{flex:1;background:rgba(0,0,0,0.3);border:1px solid var(--border);border-radius:2px;padding:10px 12px;color:var(--ink);font-family:var(--font-mono);font-size:12px;font-weight:300;letter-spacing:0;transition:border-color .3s var(--ease);resize:vertical;min-height:48px;max-height:200px}
.prompt-input::placeholder{color:var(--ink-faint);font-style:italic}
.prompt-input:focus{outline:none;border-color:var(--gold)}
.actions{display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px}
.btn{padding:10px 12px;background:transparent;border:1px solid var(--border);color:var(--ink-dim);font-family:var(--font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;cursor:pointer;transition:all .3s var(--ease);text-decoration:none;text-align:center;border-radius:2px;font-weight:500}
.btn:hover{background:rgba(246,213,114,0.08);border-color:var(--gold);color:var(--gold)}
.btn.send{background:var(--gold);color:#0a0a0f;border-color:var(--gold);font-weight:600}
.btn.send:hover{background:var(--ink);border-color:var(--ink)}
.btn:disabled{opacity:.35;cursor:not-allowed}
.card-result{margin-top:12px;padding:14px 16px;background:rgba(0,0,0,0.35);border:1px solid var(--border);border-radius:2px;max-height:280px;overflow-y:auto;font-size:12px;line-height:1.65;color:var(--ink);white-space:pre-wrap;word-wrap:break-word;display:none;position:relative}
.card-result.shown{display:block;animation:fadeIn .4s var(--ease)}
@keyframes fadeIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
.card-result::before{content:"RESPONSE";position:sticky;top:0;display:block;margin-bottom:10px;font-size:8px;letter-spacing:.42em;color:var(--gold);font-weight:600;opacity:.7}
.card-result-meta{display:flex;justify-content:space-between;margin-top:12px;padding-top:10px;border-top:1px solid var(--border);font-size:9px;letter-spacing:.18em;color:var(--ink-faint);text-transform:uppercase}
.card-result-meta a{color:var(--gold);text-decoration:none;border-bottom:1px solid rgba(246,213,114,0.3)}
/* Progress line */
.progress{height:2px;background:var(--border);overflow:hidden;margin:12px 0;border-radius:1px;display:none}
.progress.shown{display:block}
.progress::before{content:"";display:block;height:100%;background:linear-gradient(90deg,transparent 0%,var(--gold) 50%,transparent 100%);width:40%;animation:progSlide 1.2s ease infinite}
@keyframes progSlide{0%{transform:translateX(-100%)}100%{transform:translateX(350%)}}
/* Toasts */
.toast-stack{position:fixed;bottom:32px;right:32px;z-index:9999;display:flex;flex-direction:column-reverse;gap:10px}
.toast{min-width:320px;padding:14px 18px;background:rgba(18,18,26,0.95);backdrop-filter:blur(24px);border:1px solid var(--border);border-left:2px solid var(--gold);border-radius:2px;font-size:12px;color:var(--ink-dim);box-shadow:0 20px 40px -12px rgba(0,0,0,0.6);animation:toastIn .5s var(--ease) forwards}
.toast-title{color:var(--gold);font-size:10px;letter-spacing:.28em;text-transform:uppercase;margin-bottom:5px;font-weight:500}
.toast.success{border-left-color:var(--mint)}.toast.success .toast-title{color:var(--mint)}
.toast.error{border-left-color:var(--coral)}.toast.error .toast-title{color:var(--coral)}
@keyframes toastIn{from{opacity:0;transform:translateX(24px)}to{opacity:1;transform:translateX(0)}}
footer{margin-top:72px;padding-top:28px;border-top:1px solid var(--border);display:flex;justify-content:space-between;font-size:10px;letter-spacing:.12em;color:var(--ink-faint)}
footer a{color:var(--ink-dim);text-decoration:none}footer a:hover{color:var(--gold)}
@media(max-width:900px){main{padding:28px 20px 72px}.masthead{grid-template-columns:1fr}.kpis{justify-content:flex-start}}
</style>
<!-- DOCTRINE-60-UX-ENRICH direct-inject-20260424-143941 -->
<style id="doctrine60-ux-direct">
/* DOCTRINE-60-UX-ENRICH injected-direct */
body::before {
content: '';
position: fixed;
top: 0; left: 0; width: 100vw; height: 100vh;
background: radial-gradient(circle at 50% 50%, rgba(100,180,255,0.08), transparent 60%);
pointer-events: none;
z-index: -1;
}
.card, .kpi, .panel, .btn {
transition: all 0.3s cubic-bezier(0.2,0,0.1,1);
}
.card:hover, .kpi:hover, .panel:hover {
box-shadow: 0 4px 20px rgba(100,180,255,0.2);
border-color: rgba(100,180,255,0.5);
}
@keyframes pulseD60 {
0%,100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.05); }
}
.pulse, .live-indicator, .active, .online {
animation: pulseD60 3s ease-in-out infinite;
}
.modal, .chat, .speech, .overlay {
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.enter-stagger {
animation: enterStagD60 0.5s cubic-bezier(0.2,0,0.1,1) forwards;
}
@keyframes enterStagD60 {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body>
<main>
<header class="masthead">
<div>
<div class="eyebrow"><span class="live-dot"></span> Doctrine 163 / 164 — Orchestration Live</div>
<h1>Web-IA<br><em>Command</em> Center</h1>
<p class="subtitle">Envoi de prompts aux 8 Web-IA gratuits via sessions persistantes. Selenium CDP attach — inférence illimitée sans coût API.</p>
</div>
<div class="kpis">
<div class="kpi"><div class="kpi-value" id="kpi-ok">0</div><div class="kpi-label">Sessions</div></div>
<div class="kpi"><div class="kpi-value" id="kpi-prompts">0</div><div class="kpi-label">Prompts</div></div>
<div class="kpi"><div class="kpi-value">8</div><div class="kpi-label">Providers</div></div>
</div>
</header>
<div class="command-bar">
<span class="cb-prompt">wevia://</span>
<span class="cb-path">/web-ia/command-center</span>
<a class="cb-btn primary" href="/vnc-picker.html">VNC Picker</a>
<a class="cb-btn" href="/novnc/vnc.html" target="_blank">noVNC</a>
<a class="cb-btn" href="/wevia-audit.html">Audit</a>
<a class="cb-btn" href="javascript:refreshAll()">Refresh All</a>
</div>
<div class="section-label"><span>Providers · Send Prompts</span></div>
<div class="grid" id="grid"></div>
<footer>
<div>WEVIA AUTONOMY — v1.7 · DOCTRINES 146164</div>
<div><a href="/wevia-audit.html">Audit</a> · <a href="/vnc-picker.html">Login</a> · <a href="https://weval-consulting.com">Home</a></div>
</footer>
</main>
<div class="toast-stack" id="toast-stack"></div>
<script>
const PROVIDERS=[
{slug:'openai',name:'ChatGPT',mono:'C',url:'https://chat.openai.com/'},
{slug:'anthropic',name:'Claude.ai',mono:'A',url:'https://claude.ai/'},
{slug:'google',name:'Gemini',mono:'G',url:'https://gemini.google.com/'},
{slug:'deepseek',name:'DeepSeek',mono:'D',url:'https://chat.deepseek.com/'},
{slug:'mistral',name:'Mistral',mono:'M',url:'https://chat.mistral.ai/'},
{slug:'poe',name:'Poe',mono:'P',url:'https://poe.com/'},
{slug:'perplexity',name:'Perplexity',mono:'Px',url:'https://www.perplexity.ai/'},
{slug:'hf',name:'HuggingFace',mono:'H',url:'https://huggingface.co/chat/'},
];
let promptsCount=0;
const state={};PROVIDERS.forEach(p=>state[p.slug]={status:'idle',response:null,busy:false,meta:''});
function toast(title,msg,kind){
const s=document.getElementById('toast-stack');
const t=document.createElement('div');
t.className='toast'+(kind?' '+kind:'');
t.innerHTML=`<div class="toast-title">${title}</div><div>${msg}</div>`;
s.appendChild(t);
setTimeout(()=>{t.style.opacity='0';t.style.transform='translateX(24px)';t.style.transition='all .4s';setTimeout(()=>t.remove(),400)},4600);
}
function render(){
const g=document.getElementById('grid');
g.innerHTML=PROVIDERS.map((p,i)=>{
const s=state[p.slug];
let dotCls='bad',lblCls='bad',lbl='No run yet',meta='idle';
if(s.status==='ok'){dotCls='ok';lblCls='ok';lbl='Session active';meta=s.meta||'ok'}
else if(s.status==='not_logged'){dotCls='warn';lblCls='warn';lbl='Login required';meta='not logged'}
else if(s.status==='running'){dotCls='warn';lblCls='warn';lbl='Running…';meta='in progress'}
else if(s.status==='error'){dotCls='bad';lblCls='bad';lbl='Error';meta=s.meta||'failed'}
const resShown=s.response?'shown':'';
return `<article class="card" data-slug="${p.slug}">
<div class="card-head">
<div class="card-mono">${p.mono}</div>
<div class="card-title">
<div class="card-name">${p.name}</div>
<div class="card-url">${p.url.replace('https://','')}</div>
</div>
<div class="card-badge">${String(i+1).padStart(2,'0')}/08</div>
</div>
<div class="card-status">
<div class="dot ${dotCls}"></div>
<div class="status-label ${lblCls}">${lbl}</div>
<div class="status-meta">${meta}</div>
</div>
<textarea class="prompt-input" id="pr-${p.slug}" placeholder="Type your prompt here…" rows="2"></textarea>
<div class="progress ${s.busy?'shown':''}" id="pg-${p.slug}"></div>
<div class="actions">
<a class="btn" href="/vnc-picker.html">Login</a>
<button class="btn send" onclick="send('${p.slug}')" ${s.busy?'disabled':''}>${s.busy?'Sending…':'Send'}</button>
<button class="btn" onclick="checkLatest('${p.slug}')">Check</button>
</div>
${s.response?`<div class="card-result shown" id="rs-${p.slug}">${escapeHtml(s.response.text)}<div class="card-result-meta"><span>${s.response.length||0} chars · ${s.response.mode||'?'}</span><a href="${s.response.proofs_url||'#'}" target="_blank">Proofs →</a></div></div>`:''}
</article>`;
}).join('');
updateKpis();
}
function escapeHtml(s){return (s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')}
function updateKpis(){
const ok=Object.values(state).filter(s=>s.status==='ok').length;
document.getElementById('kpi-ok').textContent=String(ok).padStart(2,'0');
document.getElementById('kpi-prompts').textContent=String(promptsCount).padStart(2,'0');
}
async function send(slug){
const el=document.getElementById('pr-'+slug);
const prompt=(el?.value||'').trim();
if(!prompt){toast('Empty','Prompt required','error');return}
const prov=PROVIDERS.find(p=>p.slug===slug);
state[slug].busy=true;state[slug].status='running';state[slug].meta='starting…';render();
toast('Sending',`${prov.name} · ${prompt.length} chars`);
promptsCount++;updateKpis();
try{
const r=await fetch(`/api/wevia-autowire-trigger.php?action=send-prompt&provider=${slug}&prompt=${encodeURIComponent(prompt)}`);
const d=await r.json();
if(d.ok){
state[slug].meta='run '+d.run_id;render();
setTimeout(()=>checkLatest(slug,true),25000);
setTimeout(()=>checkLatest(slug,true),45000);
setTimeout(()=>checkLatest(slug,true),65000);
}else{
state[slug].busy=false;state[slug].status='error';state[slug].meta=d.err||'fail';render();
toast('Failed',d.err||'launch failed','error');
}
}catch(e){
state[slug].busy=false;state[slug].status='error';state[slug].meta='network';render();
toast('Network error',e.message,'error');
}
}
async function checkLatest(slug,auto){
const prov=PROVIDERS.find(p=>p.slug===slug);
try{
const r=await fetch('/api/wevia-autowire-trigger.php?action=send-prompt-latest&provider='+slug);
const d=await r.json();
if(!d.ok||!d.result){state[slug].status='idle';state[slug].meta='no runs';render();return}
const res=d.result;
if(d.status==='in_progress'){state[slug].status='running';state[slug].busy=true;state[slug].meta='running…';render();return}
state[slug].busy=false;
if(res.ok){
state[slug].status='ok';
state[slug].meta=(res.response_length||0)+' chars';
state[slug].response={text:res.response_text||'',length:res.response_length||0,mode:res.mode||'fresh',proofs_url:res.proofs_url};
if(!auto) toast('Response','+' +(res.response_length||0)+' chars','success');
}else if(res.err==='not_logged_in'){
state[slug].status='not_logged';state[slug].meta='login required';
if(!auto) toast('Login required',`${prov.name} · VNC picker`,'error');
}else{
state[slug].status='error';state[slug].meta=(res.err||'failed').slice(0,36);
}
render();
}catch(e){toast('Network',e.message,'error')}
}
function refreshAll(){PROVIDERS.forEach(p=>checkLatest(p.slug,true));toast('Refresh','Polling 8 providers…')}
render();
refreshAll();
setInterval(refreshAll,20000);
// Cursor tilt on cards
document.addEventListener('mousemove',e=>{
document.querySelectorAll('.card').forEach(c=>{
const r=c.getBoundingClientRect();
const inside=e.clientX>=r.left&&e.clientX<=r.right&&e.clientY>=r.top&&e.clientY<=r.bottom;
if(inside){
const x=(e.clientX-r.left)/r.width-.5;const y=(e.clientY-r.top)/r.height-.5;
c.style.transform=`perspective(900px) rotateX(${-y*1.2}deg) rotateY(${x*1.2}deg)`;
}else{c.style.transform=''}
});
},{passive:true});
</script>
<!-- DOCTRINE-60-UX-JS --><script id="doctrine60-ux-js-direct">
// DOCTRINE-60-UX-JS staggered entrance
(function(){
if (!('IntersectionObserver' in window)) return;
const obs = new IntersectionObserver((entries) => {
entries.forEach((e, i) => {
if (e.isIntersecting) {
setTimeout(() => e.target.classList.add('enter-stagger'), i * 80);
obs.unobserve(e.target);
}
});
});
document.querySelectorAll('.card, .kpi, .panel').forEach(el => obs.observe(el));
})();
</script>
</body></html>