Files
html/wevia-widget.html
2026-04-19 22:10:02 +02:00

359 lines
17 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>WEVIA Chat</title>
<style>
:root { --bg:#0a0f1a; --card:#141a2e; --tx:#e8e8f0; --tx2:#8888a0; --acc:#7c3aed; --acc2:#9b8afb; --border:#1e293b; }
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif; background:var(--bg); color:var(--tx); height:100vh; display:flex; flex-direction:column; overflow:hidden; }
/* Header */
.header { background:linear-gradient(135deg,#667eea,#764ba2); padding:10px 16px; display:flex; align-items:center; gap:10px; flex-shrink:0; }
.header-logo { width:28px; height:28px; border-radius:8px; background:rgba(255,255,255,0.15); display:flex; align-items:center; justify-content:center; font-size:14px; }
.header-title { font-size:14px; font-weight:700; color:#fff; }
.header-sub { font-size:10px; color:rgba(255,255,255,0.7); }
.header-status { margin-left:auto; display:flex; align-items:center; gap:5px; font-size:10px; color:rgba(255,255,255,0.8); }
.header-status::before { content:''; width:6px; height:6px; border-radius:50%; background:#34d399; }
/* Messages */
.messages { flex:1; overflow-y:auto; padding:12px; display:flex; flex-direction:column; gap:8px; }
.messages::-webkit-scrollbar { width:4px; }
.messages::-webkit-scrollbar-thumb { background:rgba(255,255,255,0.1); border-radius:2px; }
.msg { max-width:88%; padding:10px 14px; border-radius:14px; font-size:13px; line-height:1.5; word-wrap:break-word; animation:fadeIn .2s ease; }
@keyframes fadeIn { from{opacity:0;transform:translateY(4px)} to{opacity:1;transform:translateY(0)} }
.msg.user { align-self:flex-end; background:var(--acc); color:#fff; border-bottom-right-radius:4px; }
.msg.ai { align-self:flex-start; background:var(--card); color:var(--tx); border:1px solid var(--border); border-bottom-left-radius:4px; }
.msg.ai .provider { font-size:9px; color:var(--acc2); margin-bottom:4px; font-weight:600; letter-spacing:0.5px; text-transform:uppercase; }
.msg.greeting { text-align:center; align-self:center; background:transparent; border:none; padding:20px; max-width:100%; }
.msg.greeting .logo { font-size:36px; margin-bottom:8px; }
.msg.greeting .title { font-size:15px; font-weight:700; background:linear-gradient(135deg,#a78bfa,#06b6d4); -webkit-background-clip:text; -webkit-text-fill-color:transparent; }
.msg.greeting .sub { font-size:12px; color:var(--tx2); margin-top:4px; }
.typing { display:flex; gap:4px; padding:6px 0; }
.typing span { width:6px; height:6px; border-radius:50%; background:var(--acc2); animation:bounce .6s infinite alternate; }
.typing span:nth-child(2) { animation-delay:.2s; }
.typing span:nth-child(3) { animation-delay:.4s; }
@keyframes bounce { to{opacity:.3;transform:translateY(-4px)} }
/* Quick actions */
.quick-actions { display:none; gap:6px; padding:4px 12px 8px; flex-wrap:wrap; flex-shrink:0; }
.quick-btn { background:var(--card); border:1px solid var(--border); color:var(--tx2); font-size:11px; padding:5px 10px; border-radius:16px; cursor:pointer; transition:all .15s; white-space:nowrap; }
.quick-btn:hover { border-color:var(--acc); color:var(--acc2); background:rgba(124,58,237,0.1); }
/* Input */
.input-area { padding:8px 12px 12px; flex-shrink:0; border-top:1px solid var(--border); }
.input-row { display:flex; gap:8px; align-items:center; background:var(--card); border:1px solid var(--border); border-radius:20px; padding:4px 6px 4px 14px; transition:border-color .2s; }
.input-row:focus-within { border-color:var(--acc); }
.input-row input { flex:1; background:none; border:none; outline:none; color:var(--tx); font-size:13px; font-family:inherit; }
.input-row input::placeholder { color:var(--tx2); }
.send-btn { width:32px; height:32px; border-radius:50%; background:var(--acc); border:none; color:#fff; font-size:14px; cursor:pointer; display:flex; align-items:center; justify-content:center; transition:all .15s; flex-shrink:0; }
.send-btn:hover { background:#6d28d9; transform:scale(1.05); }
.send-btn:disabled { opacity:.4; cursor:default; transform:none; }
/* Markdown basic */
.msg.ai p { margin:4px 0; }
.msg.ai strong, .msg.ai b { color:#a78bfa; }
.msg.ai code { background:rgba(255,255,255,0.06); padding:1px 4px; border-radius:3px; font-size:12px; font-family:monospace; }
.msg.ai ul, .msg.ai ol { padding-left:18px; margin:4px 0; }
.msg.ai a { color:var(--acc2); text-decoration:underline; }
</style>
<style>
.wevia-progress{width:100%;background:rgba(99,102,241,.15);border-radius:8px;overflow:hidden;height:6px;margin:8px 0}
.wevia-progress-bar{height:100%;background:linear-gradient(90deg,#6366f1,#a78bfa,#6366f1);background-size:200%;animation:weviaShimmer 1.5s infinite;border-radius:8px;transition:width .3s}
.wevia-progress-text{font-size:11px;color:#a0a0b0;margin-top:4px;text-align:center}
@keyframes weviaShimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
</style>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>mermaid.initialize({startOnLoad:false,theme:'dark',themeVariables:{primaryColor:'#7c3aed',primaryTextColor:'#e8e8f0',lineColor:'#9b8afb',secondaryColor:'#1e293b',tertiaryColor:'#141a2e'}});</script>
<style>
.mermaid-container{background:#0d1117;border:1px solid var(--border);border-radius:10px;padding:16px;margin:8px 0;overflow-x:auto}
.mermaid-container svg{max-width:100%;height:auto}
.code-block-wrap{background:#0d1117;border:1px solid var(--border);border-radius:10px;padding:12px;margin:8px 0;overflow-x:auto;position:relative}
.code-block-wrap pre{margin:0;white-space:pre-wrap;word-break:break-word;font-family:monospace;font-size:12px;color:#c9d1d9;line-height:1.5}
.code-block-wrap .cb-lang{position:absolute;top:6px;right:10px;font-size:9px;color:#7c3aed;text-transform:uppercase;letter-spacing:1px}
.code-block-wrap .cb-copy{position:absolute;top:4px;right:50px;background:rgba(124,58,237,0.2);border:1px solid rgba(124,58,237,0.3);color:#a78bfa;font-size:10px;padding:2px 8px;border-radius:4px;cursor:pointer}
.svg-logo-container{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:16px;margin:8px 0;text-align:center}
.svg-logo-container svg{max-width:200px;max-height:200px}
</style>
<style>.in-widget .header{display:none!important}.in-widget #chat{height:100vh!important;padding-top:8px}</style><script>if(window!==window.parent)document.documentElement.classList.add("in-widget")</script>
<script>
if (window !== window.top) {
document.addEventListener('DOMContentLoaded', function() {
var h = document.querySelector('.header');
if (h) h.style.display = 'none';
});
}
</script>
</head>
<body>
<div class="header">
<div class="header-logo">🧠</div>
<div>
<div class="header-title">WEVIA</div>
<div class="header-sub">Assistant IA</div>
</div>
<div class="header-status">En ligne</div><a href="/wevia" target="_top" style="margin-left:6px;color:rgba(255,255,255,.7);font-size:11px;text-decoration:none">[Plein ecran]</a>
</div>
<div class="messages" id="messages">
<div class="msg greeting">
<div class="logo">🧠</div>
<div class="sub">Comment puis-je vous aider ?<br><a href="/wevia" target="_top" style="display:inline-flex;align-items:center;gap:6px;margin-top:10px;padding:8px 16px;background:linear-gradient(135deg,#667eea,#764ba2);color:white;text-decoration:none;border-radius:20px;font-size:11px;font-weight:600">Ouvrir en plein ecran</a></div>
</div>
</div>
<div class="quick-actions" id="quickActions">
<button class="quick-btn" onclick="sendQuick('Qui est WEVAL ?')">WEVAL</button>
<button class="quick-btn" onclick="sendQuick('Vos expertises ?')">Expertises</button>
<button class="quick-btn" onclick="sendQuick('Solutions IA et Cloud')">IA & Cloud</button>
<button class="quick-btn" onclick="sendQuick('Transformation digitale')">Transfo Digitale</button>
<button class="quick-btn" onclick="sendQuick('ERP SAP et Vistex')">ERP & SAP</button>
<button class="quick-btn" onclick="sendQuick('Life Sciences et Pharma')">Life Sciences</button>
<button class="quick-btn" onclick="sendQuick('Marketing et recrutement')">Marketing</button>
<button class="quick-btn" onclick="sendQuick('Contactez-nous')">Contact</button>
</div>
<div class="input-area">
<div class="input-row">
<input type="text" id="input" placeholder="Posez votre question..." autocomplete="off" autofocus>
<button class="send-btn" id="sendBtn" onclick="send()"></button>
</div>
</div>
<script>
var convId = null;
var busy = false;
var msgEl = document.getElementById('messages');
var inputEl = document.getElementById('input');
var sendBtnEl = document.getElementById('sendBtn');
var quickEl = document.getElementById('quickActions');
inputEl.addEventListener('keydown', function(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } });
function sendQuick(txt) { inputEl.value = txt; send(); }
function addMsg(text, cls, showProvider) {
var div = document.createElement('div');
div.className = 'msg ' + cls;
if (showProvider) {
var prov = document.createElement('div');
prov.className = 'provider';
prov.textContent = '';
div.appendChild(prov);
}
if (cls === 'ai') {
div.innerHTML += formatMd(text);
} else {
div.textContent = text;
}
msgEl.appendChild(div);
msgEl.scrollTop = msgEl.scrollHeight;
if (cls === 'ai') {
var mms = div.querySelectorAll('pre.mermaid:not([data-processed])');
mms.forEach(function(el) {
try {
var code = el.textContent.trim();
code = code.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
code = code.replace(/'/g, ' ');
el.textContent = code;
mermaid.run({nodes:[el]}).then(function(){
el.setAttribute('data-processed','true');
}).catch(function(e){
console.warn('Mermaid err:', e);
});
} catch(e) { console.warn('Mermaid parse:', e); }
});
}
return div;
}
function showTyping() {
var div = document.createElement('div');
div.className = 'msg ai';
div.id = 'typing';
div.innerHTML = '<div class="typing"><span></span><span></span><span></span></div>';
msgEl.appendChild(div);
msgEl.scrollTop = msgEl.scrollHeight;
}
function hideTyping() {
var el = document.getElementById('typing');
if (el) el.remove();
}
function formatMd(text) {
if (!text) return '';
var blocks = [];
text = text.replace(/```(\w*)\n([\s\S]*?)```/g, function(m, lang, code) {
var idx = blocks.length;
blocks.push({lang: lang.toLowerCase(), code: code.trim()});
return '%%BLOCK_' + idx + '%%';
});
text = text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
.replace(/\*\*(.+?)\*\*/g,'<strong>$1</strong>')
.replace(/\*(.+?)\*/g,'<em>$1</em>')
.replace(/`(.+?)`/g,'<code>$1</code>')
.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,'<img src="$2" alt="$1" style="max-width:100%;border-radius:8px;margin:8px 0">')
.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2" target="_blank">$1</a>')
.replace(/^[\-\*] (.+)/gm,'<li>$1</li>')
.replace(/(<li>.*<\/li>)/gs,'<ul>$1</ul>')
.replace(/\n{2,}/g,'</p><p>')
.replace(/\n/g,'<br>')
.replace(/^/,'<p>').replace(/$/,'</p>');
blocks.forEach(function(b, i) {
var ph = '%%BLOCK_' + i + '%%';
var rpl = '';
if (b.lang === 'mermaid') {
var mid = 'mm_' + Date.now() + '_' + i;
rpl = '<div class="mermaid-container"><pre class="mermaid" id="' + mid + '">' + b.code + '</pre></div>';
} else if (b.lang === 'svg') {
rpl = '<div class="svg-logo-container">' + b.code + '</div>';
} else {
var esc = b.code.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
rpl = '<div class="code-block-wrap"><span class="cb-lang">' + (b.lang||'code') + '</span><button class="cb-copy" onclick="navigator.clipboard.writeText(this.nextElementSibling.textContent)">Copier</button><pre>' + esc + '</pre></div>';
}
text = text.replace(ph, rpl);
});
return text;
}
function send() {
if (busy) return;
var text = inputEl.value.trim();
if (!text) return;
inputEl.value = '';
addMsg(text, 'user');
quickEl.style.display = 'none';
busy = true;
sendBtnEl.disabled = true;
showTyping();
var body = { message: text, lang: 'fr' };
if (convId) body.conversation_id = convId;
fetch('/api/wevia-json-api.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
})
.then(function(r) { return r.json(); })
.then(function(d) {
hideTyping();
if (d.conversation_id) convId = d.conversation_id;
addMsg(d.response || 'Désolé, une erreur est survenue.', 'ai', true);
})
.catch(function(err) {
hideTyping();
addMsg('Erreur de connexion. Réessayez.', 'ai', false);
})
.finally(function() {
busy = false;
sendBtnEl.disabled = false;
inputEl.focus();
});
}
</script>
<script>
function weviaProgress(container,startMs){
if(!container)return;
var el=document.createElement('div');
el.className='wevia-pb-wrap';
el.innerHTML='<div class="wevia-progress"><div class="wevia-progress-bar" style="width:5%"></div></div><div class="wevia-progress-text">Analyse en cours...</div>';
container.appendChild(el);
var bar=el.querySelector('.wevia-progress-bar'),txt=el.querySelector('.wevia-progress-text');
var steps=['Connexion au moteur IA...','Analyse de votre demande...','Génération de la réponse...','Finalisation...'];
var iv=setInterval(function(){
var elapsed=(Date.now()-startMs)/1000;
var pct=Math.min(95,5+elapsed*3);
bar.style.width=pct+'%';
var si=Math.min(3,Math.floor(elapsed/3));
txt.textContent=steps[si]+' ('+Math.round(elapsed)+'s)';
if(elapsed>25)txt.textContent='Presque termine... ('+Math.round(elapsed)+'s)';
},300);
return {el:el,stop:function(){clearInterval(iv);bar.style.width='100%';txt.textContent='Termine!';}};
}
</script>
<script>
if (window !== window.top) {
document.addEventListener('DOMContentLoaded', function() {
var h = document.querySelector('.header');
if (h) h.style.display = 'none';
});
}
</script>
<!-- CARTO_REMOVED -->
<!-- === OPUS UNIVERSAL DRILL-DOWN v1 19avr — append-only, doctrine #14 === -->
<script>
(function(){
if (window.__opusUniversalDrill) return; window.__opusUniversalDrill = true;
var d = document;
var m = d.createElement('div');
m.id = 'opus-udrill';
m.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.82);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:99995;padding:20px;cursor:pointer';
var inner = d.createElement('div');
inner.id = 'opus-udrill-in';
inner.style.cssText = 'max-width:900px;width:100%;max-height:90vh;overflow:auto;background:#0b0d15;border:1px solid rgba(99,102,241,0.35);border-radius:14px;padding:28px;cursor:default;box-shadow:0 20px 60px rgba(0,0,0,0.6);color:#e2e8f0;font:14px/1.55 Inter,system-ui,sans-serif';
inner.addEventListener('click', function(e){ e.stopPropagation(); });
m.appendChild(inner);
m.addEventListener('click', function(){ m.style.display='none'; });
d.addEventListener('keydown', function(e){ if(e.key==='Escape') m.style.display='none'; });
(d.body || d.documentElement).appendChild(m);
function openCard(card) {
var html = '<div style="display:flex;justify-content:flex-end;margin-bottom:14px"><button id="opus-udrill-close" style="padding:6px 14px;background:#171b2a;border:1px solid rgba(99,102,241,0.25);color:#e2e8f0;border-radius:8px;cursor:pointer;font-size:12px">✕ Fermer (Esc)</button></div>';
html += '<div style="transform-origin:top left;font-size:1.05em">' + card.outerHTML + '</div>';
inner.innerHTML = html;
d.getElementById('opus-udrill-close').onclick = function(){ m.style.display='none'; };
m.style.display = 'flex';
}
function wire(root) {
var sels = '.card,[class*="card"],.kpi,[class*="kpi"],.stat,[class*="stat"],.tile,[class*="tile"],.metric,[class*="metric"],.widget,[class*="widget"]';
var cards = root.querySelectorAll(sels);
for (var i = 0; i < cards.length; i++) {
var c = cards[i];
if (c.__opusWired) continue;
if (c.closest('button, a, input, select, textarea, #opus-udrill')) continue;
var r = c.getBoundingClientRect();
if (r.width < 60 || r.height < 40) continue;
c.__opusWired = true;
c.style.cursor = 'pointer';
c.setAttribute('role','button');
c.setAttribute('tabindex','0');
c.addEventListener('click', function(ev){
if (ev.target.closest('[data-pp-id]') && window.__opusDrillInit) return;
if (ev.target.closest('a,button,input,select')) return;
ev.preventDefault(); ev.stopPropagation();
openCard(this);
});
c.addEventListener('keydown', function(ev){ if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();openCard(this);} });
}
}
var initRun = function(){ wire(d.body || d.documentElement); };
if (d.readyState === 'loading') d.addEventListener('DOMContentLoaded', initRun);
else initRun();
var mo = new MutationObserver(function(muts){
var newCard = false;
for (var i=0;i<muts.length;i++) if (muts[i].addedNodes.length) { newCard = true; break; }
if (newCard) initRun();
});
mo.observe(d.body || d.documentElement, {childList:true, subtree:true});
})();
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN END === -->
</body>
</html>