// ── Auto-detect website primary colour and apply to chatbot theme ── function _cbParseRgb(str) { if (!str) return null; str = str.trim(); if (str[0] === '#') { let h = str.slice(1); if (h.length === 3) h = h.split('').map(c => c + c).join(''); const n = parseInt(h, 16); if (isNaN(n)) return null; return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 }; } const m = str.match(/rgba?\(\s*(\d+)[,\s]+(\d+)[,\s]+(\d+)/); if (m) return { r: +m[1], g: +m[2], b: +m[3] }; return null; } function _cbToHex(rgb) { return '#' + [rgb.r, rgb.g, rgb.b].map(v => v.toString(16).padStart(2, '0')).join(''); } function _cbDarken(rgb, pct) { const f = 1 - pct / 100; return _cbToHex({ r: Math.max(0, Math.round(rgb.r * f)), g: Math.max(0, Math.round(rgb.g * f)), b: Math.max(0, Math.round(rgb.b * f)) }); } function _cbIsUsable(rgb) { if (!rgb) return false; const { r, g, b } = rgb; const lum = (r * 299 + g * 587 + b * 114) / 1000; return lum > 20 && lum < 230 && !(r > 240 && g > 240 && b > 240); } function detectAndApplyChatbotTheme() { const widget = document.getElementById('chatbot-widget'); if (!widget) return; let primary = null; const rootStyle = getComputedStyle(document.documentElement); const cssVars = ['--primary', '--primary-color', '--bs-primary', '--color-primary', '--brand-color', '--theme-color', '--accent-color', '--main-color', '--site-color']; for (const v of cssVars) { const val = rootStyle.getPropertyValue(v).trim(); if (val) { primary = _cbParseRgb(val); if (_cbIsUsable(primary)) break; primary = null; } } if (!primary) { const probes = [ { sel: '.back-to-top', prop: 'backgroundColor' }, { sel: '.btn-primary', prop: 'backgroundColor' }, { sel: 'nav.navbar', prop: 'backgroundColor' }, { sel: '#header', prop: 'backgroundColor' }, { sel: 'header', prop: 'backgroundColor' }, { sel: '.navbar-brand', prop: 'color' }, { sel: 'a', prop: 'color' }, ]; for (const { sel, prop } of probes) { const el = document.querySelector(sel); if (!el) continue; const rgb = _cbParseRgb(getComputedStyle(el)[prop]); if (_cbIsUsable(rgb)) { primary = rgb; break; } } } if (!primary) return; const hex = _cbToHex(primary); const hexDark = _cbDarken(primary, 22); const shadow = 'rgba(' + primary.r + ',' + primary.g + ',' + primary.b + ',0.25)'; widget.style.setProperty('--cb-primary', hex); widget.style.setProperty('--cb-primary-dark', hexDark); widget.style.setProperty('--cb-shadow', shadow); const micBtn = document.getElementById('micBtn'); if (micBtn) micBtn.style.background = 'linear-gradient(135deg, ' + hex + ' 0%, ' + hexDark + ' 100%)'; } // ── End auto-detect ──────────────────────────────────────────────── // Universal AI Chatbot Script const chatbotToggle = document.getElementById('chatbot-toggle'); const chatbotWindow = document.getElementById('chatbot-window'); const chatbotSend = document.getElementById('chatbot-send'); const chatbotInput = document.getElementById('chatbot-input'); const chatbotMessages = document.getElementById('chatbot-messages'); const API_ENDPOINT = 'https://kcom.mukesoft.com/Chatbot/chatbot-answer.php'; const API_ENDPOINT_PREDEFINED_QUESTION = 'https://kcom.mukesoft.com/Chatbot/predfined_questions.php'; let isLoading = false; let chatInitialized = false; let chatSessionId = null; document.addEventListener('DOMContentLoaded', () => { detectAndApplyChatbotTheme(); chatSessionId = getCookie('chat_session_id') || generateChatSessionId(); setCookie('chat_session_id', chatSessionId, 1); setTimeout(() => { if (!chatInitialized) { getPredfinedQuestion(); chatInitialized = true; } }, 1000); }); function getPredfinedQuestion() { const IdData = { client_id: 'NDY=' }; fetch(API_ENDPOINT_PREDEFINED_QUESTION, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(IdData) }) .then(res => res.json()) .then(data => { if (data.code == 200) { appendMessage('Bot', 'Hello! How may I assist you today?', 'bot', true, data.answer); } else { appendMessage('Bot', 'Hello! How may I assist you today?', 'bot'); } }) .catch((error) => { console.log('Error:', error); appendMessage('Bot', 'Sorry, there was an error getting the answer.', 'bot'); addMessageToTranscript('Bot', 'Sorry, there was an error getting the answer.'); }); } function generateChatSessionId() { return 'chat_' + Math.random().toString(36).substr(2, 9) + '_' + Date.now(); } function setCookie(name, value, days = 1) { const expires = new Date(Date.now() + days * 864e5).toUTCString(); document.cookie = name + '=' + encodeURIComponent(value) + '; expires=' + expires + '; path=/'; } function getCookie(name) { return document.cookie.split('; ').reduce((r, v) => { const parts = v.split('='); return parts[0] === name ? decodeURIComponent(parts[1]) : r; }, ''); } chatbotToggle.onclick = () => { chatbotWindow.style.display = chatbotWindow.style.display === 'block' ? 'none' : 'block'; }; chatbotSend.onclick = sendMessage; chatbotInput.addEventListener('keydown', function(e) { if (e.key === 'Enter') sendMessage(); }); let previousUserMessage = ''; let answerdata = ''; function sendMessage() { const msg = chatbotInput.value.trim(); if (!msg) return; appendMessage('You', msg, 'user'); chatbotInput.value = ''; if (/next slot/i.test(msg)) { let page = parseInt(getCookie('slot_page') || '0', 10); setCookie('slot_page', page + 1); } else if (/(book|schedule|want|arrange|need|require|organize|plan|set|line up|organize).*demo/i.test(msg)) { setCookie('slot_page', 0); } appendMessage('Bot', 'Writing...', 'bot'); addMessageToTranscript('user', msg); resetInactivityTimer(); const requestData = { question: msg, lastUserMsg: previousUserMessage, slot_page: getCookie('slot_page'), slot_data: getCookie('slot_data'), chat_session_id: chatSessionId, client_id: 'NDY=', booking_session_id: getCookie('booking_session_id') || '' }; if (/^\d{1,4}$/.test(msg.trim())) { try { console.log('=== Slot Selection Debug ==='); const lastResponse = JSON.parse(localStorage.getItem('last_slot_response') || '{}'); if (lastResponse && lastResponse.slots && Array.isArray(lastResponse.slots)) { console.log('Sending slots to server:', lastResponse.slots); requestData.slot_number = parseInt(msg.trim(), 10); requestData.displayedSlots = JSON.stringify(lastResponse.slots); if (lastResponse.selected_date) { requestData.selected_date = lastResponse.selected_date; } if (lastResponse.slot_page !== undefined) { requestData.slot_page = lastResponse.slot_page; } console.log('Slot data prepared:', { slot_number: requestData.slot_number, slots: lastResponse.slots.length, selected_date: requestData.selected_date, slot_page: requestData.slot_page, chat_session_id: requestData.chat_session_id, booking_session_id: requestData.booking_session_id, client_id: 'NDY=' }); } else { console.warn('No valid slots found in last response'); } } catch (e) { console.error('Error handling slot selection:', e); } } fetch(API_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }) .then(res => res.json()) .then(data => { chatbotMessages.removeChild(chatbotMessages.lastChild); appendMessage('Bot', data.answer ? data.answer : 'No answer found.', 'bot'); addMessageToTranscript('Bot', data.answer ? data.answer : 'No answer found.'); answerdata += '+' + data.answer; if (data.booking_session_id) { setCookie('booking_session_id', data.booking_session_id, 1); } if (data.slot_data) { setCookie('slot_data', data.slot_data); } if (data.slots && Array.isArray(data.slots)) { console.log('=== Storing Slots Data ==='); const responseData = { slots: data.slots, timestamp: new Date().toISOString() }; if (data.selected_date !== undefined) { responseData.selected_date = data.selected_date; } if (data.slot_page !== undefined) { responseData.slot_page = data.slot_page; } try { localStorage.setItem('last_slot_response', JSON.stringify(responseData)); console.log('Stored slot data:', { slots: responseData.slots.length, selected_date: responseData.selected_date, slot_page: responseData.slot_page }); } catch (e) { console.error('Error storing slot data:', e); } } }) .catch(() => { chatbotMessages.removeChild(chatbotMessages.lastChild); appendMessage('Bot', 'Sorry, there was an error getting the answer.', 'bot'); addMessageToTranscript('Bot', 'Sorry, there was an error getting the answer.'); }); previousUserMessage += '+' + msg; if (/(bye|goodbye|thank you|thanks|see you)/i.test(msg)) { endChat(); } resetInactivityTimer(); } let chatTranscript = []; let inactivityTimer = null; const INACTIVITY_LIMIT = 10 * 60 * 1000; function addMessageToTranscript(sender, message) { chatTranscript.push({ sender, message }); } function resetInactivityTimer() { if (inactivityTimer) clearTimeout(inactivityTimer); inactivityTimer = setTimeout(() => { console.log("Inactivity timeout"); endChat(); }, INACTIVITY_LIMIT); } function endChat() { if (chatTranscript.length === 0) return; const payload = JSON.stringify({ action: 'end_chat', transcript: chatTranscript, chat_session_id: chatSessionId, client_id: 'NDY=', booking_session_id: getCookie('booking_session_id') || '' }); if (navigator.sendBeacon) { const blob = new Blob([payload], { type: 'application/json' }); navigator.sendBeacon(API_ENDPOINT, blob); } else { fetch(API_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: payload }); } chatTranscript = []; if (inactivityTimer) clearTimeout(inactivityTimer); setCookie('booking_session_id', '', -1); } window.addEventListener('beforeunload', function() { endChat(); }); function linkify(text) { return text.replace(/(https?:\/\/[^\s]+)/g, '$1'); } let messageCounter = 0; function appendMessage(sender, text, type, predfined = false, predefinedQA = [], is_link = false, link = null) { const msgDiv = document.createElement('div'); const uniqueId = 'buttonsContainer-' + Date.now() + '-' + messageCounter++; msgDiv.className = 'chatbot-msg' + (type === 'user' ? ' user' : ''); msgDiv.innerHTML = '' + sender + ': ' + ((type === 'bot') ? linkify(text) : text) + "
"; chatbotMessages.appendChild(msgDiv); if (predfined) { if (predefinedQA.length < 0) return; if (predefinedQA.length > 0) console.log("here get predefinedQA"); const buttonsContainer = document.getElementById(uniqueId); for (let i = 0; i < predefinedQA.length; i++) { const qa = predefinedQA[i]; if (qa && qa.question) { const btn = document.createElement("button"); btn.className = "predef-btn"; btn.dataset.index = i; btn.textContent = qa.question; btn.addEventListener("click", () => { document.getElementById(uniqueId).remove(); if (qa.link == 0) { appendMessage("You", qa.question, "user"); appendMessage("Bot", qa.answer, "bot"); } else { appendMessage("You", qa.question, "user"); appendMessage("Bot", qa.answer, "bot", false, null, true, qa.link); } }); buttonsContainer.appendChild(btn); } } const bookdemo = document.createElement("button"); bookdemo.className = "book-predef-btn"; bookdemo.id = 'book-btn'; bookdemo.dataset.index = 0; bookdemo.textContent = "Book Demo"; buttonsContainer.appendChild(bookdemo); const bookBtn = document.getElementById('book-btn'); const input = document.getElementById('chatbot-input'); if (bookBtn && input) { bookBtn.addEventListener('click', function () { input.value = this.innerText; sendMessage(); }); } } if (is_link) { const buttonsContainer = document.getElementById(uniqueId); buttonsContainer.innerHTML = 'Go To page'; } chatbotMessages.scrollTop = chatbotMessages.scrollHeight; }