Files
weval-consulting/wevia-enhance-v2.js

306 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* WEVIA Enhancement v2 — Radical Fix
* 1. Force emojis on ALL bot responses (client-side)
* 2. Kill horizontal split (CSS override)
* 3. Arabic voice TTS
*/
(function(){
'use strict';
// ═══════════════════════════════════════════════
// 1. KILL SPLIT — Force single-column layout
// ═══════════════════════════════════════════════
var killSplitCSS = document.createElement('style');
killSplitCSS.textContent = [
// Ensure only active panel shows, full width
'.panel{display:none!important;width:100%!important;max-width:100%!important;flex:1!important}',
'.panel.a{display:flex!important;flex-direction:column!important;width:100%!important}',
// Main area: single column, no side-by-side
'.mn{display:flex!important;flex-direction:column!important;width:100%!important;max-width:100%!important}',
// Chat takes full width
'.chat{width:100%!important;max-width:100%!important}',
'.msg{max-width:90%!important}',
// Artifacts grid full width when shown
'#artGrid{width:100%!important}',
// Input area full width
'.inp-area{width:100%!important}',
'.inp-wrap{max-width:100%!important}',
// No unexpected horizontal scrolling
'body,html,.app,.mn{overflow-x:hidden!important}',
// Hide horizontal rules in chat
'.chat hr,.bub hr{display:none!important}'
].join('\n');
document.head.appendChild(killSplitCSS);
// ═══════════════════════════════════════════════
// 2. EMOJI INJECTION — Client-side post-processing
// ═══════════════════════════════════════════════
var emojiMap = {
greet: ['👋','🤗','😊','🙌'],
explain: ['💡','🔍','📝','🎯'],
success: ['✅','🎉','🚀','💪'],
warn: ['⚠️','🔔','❗','👀'],
error: ['❌','🚫','💥','😬'],
code: ['💻','🔧','⚙️','🛠️'],
list: ['🔹','📌','▶️','💎'],
data: ['📊','📈','📉','🗂️'],
idea: ['💡','✨','🌟','💎'],
doc: ['📄','📋','📝','📑']
};
function pickEmoji(category) {
var arr = emojiMap[category] || emojiMap.explain;
return arr[Math.floor(Math.random() * arr.length)];
}
function detectCategory(text) {
var t = text.toLowerCase();
if (/^(bonjour|salut|hello|hi|مرحب|اهلا)/.test(t)) return 'greet';
if (/erreur|error|échoué|fail|bug/.test(t)) return 'error';
if (/attention|warning|⚠|prudence/.test(t)) return 'warn';
if (/terminé|succès|fait|success|réussi|done|✓/.test(t)) return 'success';
if (/code|script|function|var |const |let |def |class /.test(t)) return 'code';
if (/document|pdf|rapport|fichier/.test(t)) return 'doc';
if (/données|data|stat|chiffr|nombre/.test(t)) return 'data';
return 'explain';
}
function hasEmoji(text) {
return /[\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}\u{2700}-\u{27BF}]/u.test(text.substring(0, 20));
}
function injectEmojis(text) {
if (!text || text.length < 3) return text;
// Don't double-inject if already has emoji at start
if (hasEmoji(text)) return text;
var cat = detectCategory(text);
var startEmoji = pickEmoji(cat);
// Add emoji at start
text = startEmoji + ' ' + text;
// Replace bullet points with emoji bullets
text = text.replace(/^[\s]*[-•]\s/gm, '🔹 ');
text = text.replace(/^[\s]*(\d+)\.\s/gm, function(m, n) {
var nums = ['0⃣','1⃣','2⃣','3⃣','4⃣','5⃣','6⃣','7⃣','8⃣','9⃣'];
return (nums[parseInt(n)] || n + '.') + ' ';
});
// Add closing emoji if none
var trimmed = text.trim();
if (!hasEmoji(trimmed.substring(trimmed.length - 5))) {
var closers = ['✨','🚀','💡','👍','😊'];
text = text.trimEnd() + ' ' + closers[Math.floor(Math.random() * closers.length)];
}
return text;
}
// ═══════════════════════════════════════════════
// 3. ARABIC VOICE TTS
// ═══════════════════════════════════════════════
var voiceEnabled = false;
var arabicVoice = null;
function initVoice() {
if (!('speechSynthesis' in window)) return;
function loadV() {
var voices = speechSynthesis.getVoices();
arabicVoice = voices.find(function(v){return v.lang.startsWith('ar')})
|| voices.find(function(v){return v.lang.indexOf('ar') >= 0})
|| (voices.length > 0 ? voices[0] : null);
}
loadV();
speechSynthesis.onvoiceschanged = loadV;
}
initVoice();
window.toggleWeviaVoice = function() {
voiceEnabled = !voiceEnabled;
var btns = document.querySelectorAll('.wevia-voice-btn,[id="ttsBtn"],[id="voiceBtn2"]');
btns.forEach(function(b) {
b.textContent = voiceEnabled ? '\u{1F50A}' : '\u{1F507}';
b.style.color = voiceEnabled ? '#22d3ee' : '';
b.title = voiceEnabled ? 'Voix Arabe ON' : 'Voix OFF';
});
if (!voiceEnabled) speechSynthesis.cancel();
};
function speakArabic(text) {
if (!voiceEnabled || !('speechSynthesis' in window)) return;
speechSynthesis.cancel();
// Clean text for speech
var clean = text
.replace(/[\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}]/gu, '')
.replace(/<[^>]*>/g, '')
.replace(/```[\s\S]*?```/g, '')
.replace(/\*\*/g, '').replace(/\*/g, '')
.replace(/#{1,6}\s/g, '')
.replace(/\n+/g, '. ')
.replace(/\s+/g, ' ').trim();
if (!clean || clean.length < 2) return;
var chunks = clean.match(/.{1,200}[.!?\s]|.{1,200}$/g) || [clean];
var i = 0;
(function next() {
if (i >= chunks.length || !voiceEnabled) return;
var utt = new SpeechSynthesisUtterance(chunks[i]);
if (arabicVoice) utt.voice = arabicVoice;
utt.lang = 'ar-SA';
utt.rate = 0.95;
utt.onend = function(){ i++; next(); };
utt.onerror = function(){ i++; next(); };
speechSynthesis.speak(utt);
})();
}
// ═══════════════════════════════════════════════
// 4. MONKEY-PATCH message rendering functions
// ═══════════════════════════════════════════════
// For FULLSCREEN (addMsg)
if (typeof window.addMsg === 'function') {
var origAddMsg = window.addMsg;
window.addMsg = function(role, content, thinking) {
if (role !== 'user' && content) {
content = injectEmojis(content);
}
origAddMsg(role, content, thinking);
if (role !== 'user' && voiceEnabled && content) speakArabic(content);
};
}
// For WIDGET (addMessage)
if (typeof window.addMessage === 'function') {
var origAddMessage = window.addMessage;
window.addMessage = function(content, isUser) {
if (!isUser && content) {
content = injectEmojis(content);
}
origAddMessage(content, isUser);
if (!isUser && voiceEnabled && content) speakArabic(content);
};
}
// Retry patching after DOM load (functions may be defined later)
function retryPatch() {
if (typeof window.addMsg === 'function' && !window._addMsgPatched) {
var orig = window.addMsg;
window.addMsg = function(role, content, thinking) {
if (role !== 'user' && content) content = injectEmojis(content);
orig(role, content, thinking);
if (role !== 'user' && voiceEnabled && content) speakArabic(content);
};
window._addMsgPatched = true;
}
if (typeof window.addMessage === 'function' && !window._addMessagePatched) {
var orig2 = window.addMessage;
window.addMessage = function(content, isUser) {
if (!isUser && content) content = injectEmojis(content);
orig2(content, isUser);
if (!isUser && voiceEnabled && content) speakArabic(content);
};
window._addMessagePatched = true;
}
}
setTimeout(retryPatch, 500);
setTimeout(retryPatch, 1500);
setTimeout(retryPatch, 3000);
// ═══════════════════════════════════════════════
// 5. FORCE ARTIFACTS TO OPEN IN NEW TAB
// ═══════════════════════════════════════════════
if (typeof window.addArtifact === 'function') {
window.addArtifact = function(art) {
if (!art) return;
// Open directly in new window
if (art.url) { window.open(art.url, '_blank'); return; }
if (!art.content) return;
var w = window.open('', '_blank', 'width=900,height=700');
if (!w) { alert('Autorisez les popups pour voir le document'); return; }
var css = 'body{font-family:system-ui,sans-serif;padding:24px;margin:0;background:#0a0f1a;color:#e2e8f0;line-height:1.6}pre{background:#111827;padding:16px;border-radius:8px;overflow-x:auto;font-size:13px;white-space:pre-wrap}h1,h2,h3{color:#22d3ee}';
if (art.type === 'html') {
w.document.write(art.content);
} else if (art.type === 'mermaid') {
w.document.write('<html><head><script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"><\/script><style>' + css + '</style></head><body><div class="mermaid">' + art.content + '</div><script>mermaid.initialize({startOnLoad:true,theme:"dark"})<\/script></body></html>');
} else {
w.document.write('<html><head><title>' + (art.title||'Document') + '</title><style>' + css + '</style></head><body><h2>' + (art.title||'Document') + '</h2><pre>' + art.content.replace(/</g,'&lt;') + '</pre></body></html>');
}
w.document.close();
};
}
// Same retry for addArtifact
function retryArtifact() {
if (typeof window.addArtifact === 'function' && !window._artPatched) {
var origArt = window.addArtifact;
window.addArtifact = function(art) {
if (!art) return;
if (art.url) { window.open(art.url, '_blank'); return; }
if (!art.content) return;
var w = window.open('', '_blank', 'width=900,height=700');
if (!w) return;
var css = 'body{font-family:system-ui,sans-serif;padding:24px;margin:0;background:#0a0f1a;color:#e2e8f0;line-height:1.6}pre{background:#111827;padding:16px;border-radius:8px;overflow-x:auto;white-space:pre-wrap}h1,h2,h3{color:#22d3ee}';
if (art.type === 'html') w.document.write(art.content);
else if (art.type === 'mermaid') w.document.write('<html><head><script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"><\/script><style>'+css+'</style></head><body><div class="mermaid">'+art.content+'</div><script>mermaid.initialize({startOnLoad:true,theme:"dark"})<\/script></body></html>');
else w.document.write('<html><head><title>'+(art.title||'Doc')+'</title><style>'+css+'</style></head><body><h2>'+(art.title||'Doc')+'</h2><pre>'+art.content.replace(/</g,'&lt;')+'</pre></body></html>');
w.document.close();
};
window._artPatched = true;
}
}
setTimeout(retryArtifact, 500);
setTimeout(retryArtifact, 1500);
// ═══════════════════════════════════════════════
// 6. MutationObserver — catch ALL new bot messages
// ═══════════════════════════════════════════════
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(m) {
m.addedNodes.forEach(function(node) {
if (node.nodeType !== 1) return;
// Fullscreen: .msg.ai .bub
var bubs = node.querySelectorAll ? node.querySelectorAll('.msg.ai .bub, .msg:not(.u) .bub') : [];
if (node.classList && (node.classList.contains('msg') && !node.classList.contains('u'))) {
var bub = node.querySelector('.bub');
if (bub && bub.textContent && !hasEmoji(bub.textContent)) {
bub.innerHTML = injectEmojis(bub.innerHTML);
}
}
bubs.forEach(function(bub) {
if (bub.textContent && !hasEmoji(bub.textContent)) {
bub.innerHTML = injectEmojis(bub.innerHTML);
}
});
// Widget: bot messages (not user)
if (node.classList && node.classList.contains('message') && !node.classList.contains('user')) {
var content = node.querySelector('.content, .text, p');
if (content && content.textContent && !hasEmoji(content.textContent)) {
content.innerHTML = injectEmojis(content.innerHTML);
}
}
});
});
});
// Observe both fullscreen chat and widget chat areas
function startObserving() {
var targets = document.querySelectorAll('#chatArea, .chat, .chat-window, .messages, .chat-messages');
targets.forEach(function(t) {
observer.observe(t, { childList: true, subtree: true });
});
// Fallback: observe body
if (targets.length === 0) {
observer.observe(document.body, { childList: true, subtree: true });
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', startObserving);
} else {
startObserving();
}
console.log('✅ WEVIA Enhancement v2 loaded — Emojis + No-Split + Arabic Voice');
})();