361 lines
17 KiB
HTML
361 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,'&').replace(/</g,'<').replace(/>/g,'>')
|
|
.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,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
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 === -->
|
|
<!-- V29 SECURITY: archi-meta-badge.js removed from public iframe -->
|
|
|
|
<script src="/api/a11y-auto-enhancer.js" defer></script>
|
|
</body>
|
|
</html>
|