Spaces:
Sleeping
Sleeping
| /** | |
| * Vibhu Solutions AI Chat Widget | |
| * Embed on any website with: | |
| * <script src="https://sanjay8013-ai-robot.hf.space/static/widget.js"></script> | |
| */ | |
| (function () { | |
| if (document.getElementById('vs-cb-root')) return; // prevent double-load | |
| const API_URL = 'https://sanjay8013-ai-robot.hf.space/chat'; | |
| // ββ Bot SVG (blinking robot character) βββββββββββββββββββββββββββββββββββββββ | |
| const BOT_SVG = (w, h) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56 64" width="${w}" height="${h}"><line x1="28" y1="6" x2="28" y2="14" stroke="rgba(255,255,255,0.85)" stroke-width="3.5" stroke-linecap="round"/><circle cx="28" cy="4" r="4.5" fill="white" class="vs-bot-ant"/><rect x="4" y="12" width="48" height="44" rx="14" fill="rgba(255,255,255,0.18)" stroke="rgba(255,255,255,0.5)" stroke-width="1.5"/><ellipse cx="19" cy="31" rx="7.5" ry="8.5" fill="white" class="vs-bot-eye"/><ellipse cx="37" cy="31" rx="7.5" ry="8.5" fill="white" class="vs-bot-eye vs-bot-eye-r"/><circle cx="19" cy="32" r="4" fill="#0044CC"/><circle cx="37" cy="32" r="4" fill="#0044CC"/><circle cx="21.5" cy="29" r="1.8" fill="rgba(255,255,255,0.75)"/><circle cx="39.5" cy="29" r="1.8" fill="rgba(255,255,255,0.75)"/><path d="M 14 46 Q 28 57 42 46" stroke="white" stroke-width="2.8" fill="none" stroke-linecap="round"/></svg>`; | |
| // ββ CSS ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // Inject Manrope font | |
| if (!document.getElementById('vs-cb-manrope')) { | |
| const lnk = document.createElement('link'); | |
| lnk.id = 'vs-cb-manrope'; | |
| lnk.rel = 'stylesheet'; | |
| lnk.href = 'https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap'; | |
| document.head.appendChild(lnk); | |
| } | |
| const style = document.createElement('style'); | |
| style.textContent = ` | |
| #vs-cb-overlay { | |
| position:fixed; inset:0; | |
| background:rgba(0,4,12,0.82); backdrop-filter:blur(14px); | |
| display:flex; align-items:center; justify-content:center; | |
| z-index:2147483640; font-family:'Manrope','Segoe UI',Tahoma,sans-serif; | |
| } | |
| #vs-cb-card { | |
| background:rgba(4,14,31,0.93); | |
| backdrop-filter:blur(24px);-webkit-backdrop-filter:blur(24px); | |
| border:1px solid rgba(107,166,255,0.22); | |
| border-radius:24px; | |
| padding:40px 34px 32px; width:100%; max-width:400px; margin:16px; | |
| box-shadow:0 32px 80px rgba(0,0,0,0.8),0 0 60px rgba(0,66,200,0.18); | |
| animation:vsCbSlide 0.32s ease; | |
| } | |
| @keyframes vsCbSlide { | |
| from{opacity:0;transform:translateY(22px);} | |
| to {opacity:1;transform:translateY(0);} | |
| } | |
| .vs-logo { | |
| width:72px;height:72px; | |
| background:linear-gradient(107.8deg, #6BA6FF 3.37%, #0066FF 95.93%); | |
| border-radius:18px;display:flex;align-items:center;justify-content:center; | |
| margin:0 auto 18px; | |
| box-shadow:0 10px 26px rgba(0,102,255,0.45); | |
| } | |
| #vs-cb-card h2 { | |
| text-align:center;color:white;font-size:20px;font-weight:700; | |
| margin-bottom:6px;font-family:'Manrope','Segoe UI',sans-serif; | |
| } | |
| .vs-subtitle { | |
| text-align:center;color:rgba(255,255,255,0.55);font-size:13px; | |
| margin-bottom:22px;line-height:1.6; | |
| } | |
| .vs-field{margin-bottom:13px;} | |
| .vs-field label{ | |
| display:block;font-size:12.5px;font-weight:600; | |
| color:rgba(255,255,255,0.78);margin-bottom:6px;font-family:'Manrope','Segoe UI',sans-serif; | |
| } | |
| .vs-field input{ | |
| width:100%;border:1.5px solid rgba(107,166,255,0.22);border-radius:9px; | |
| padding:11px 14px;font-size:13.5px;color:white;outline:none; | |
| background:rgba(255,255,255,0.07);box-sizing:border-box; | |
| transition:border-color 0.2s,box-shadow 0.2s,background 0.2s; | |
| font-family:'Manrope','Segoe UI',sans-serif; | |
| } | |
| .vs-field input::placeholder{color:rgba(255,255,255,0.3);} | |
| .vs-field input:focus{ | |
| border-color:#6BA6FF; | |
| box-shadow:0 0 0 3px rgba(0,102,255,0.18); | |
| background:rgba(107,166,255,0.1); | |
| } | |
| .vs-field input.vs-err{border-color:#ef4444;} | |
| #vs-cb-login-btn{ | |
| width:100%;padding:13px;margin-top:4px; | |
| background:linear-gradient(107.8deg, #6BA6FF 3.37%, #0066FF 95.93%); | |
| color:white;border:none;border-radius:9px; | |
| font-size:14px;font-weight:600;cursor:pointer; | |
| letter-spacing:0.3px;transition:opacity 0.2s; | |
| font-family:'Manrope','Segoe UI',sans-serif; | |
| box-shadow:0 6px 20px rgba(0,102,255,0.45); | |
| } | |
| #vs-cb-login-btn:hover{opacity:0.9;} | |
| .vs-privacy{text-align:center;font-size:11px;color:rgba(255,255,255,0.35);margin-top:12px;} | |
| #vs-cb-toggle{ | |
| position:fixed;bottom:20px;right:20px; | |
| width:48px;height:48px;border-radius:50%;overflow:visible; | |
| background:linear-gradient(107.8deg, #6BA6FF 3.37%, #0066FF 95.93%); | |
| border:none;cursor:pointer;color:white; | |
| box-shadow:0 4px 18px rgba(0,102,255,0.55),0 0 14px rgba(0,102,255,0.3); | |
| z-index:2147483638; | |
| display:none;align-items:center;justify-content:center; | |
| } | |
| #vs-cb-widget{ | |
| display:none;flex-direction:column; | |
| position:fixed;bottom:78px;right:20px; | |
| width:310px;height:460px; | |
| background:#04111e; | |
| border:1px solid rgba(107,166,255,0.2); | |
| border-radius:16px; | |
| box-shadow:0 12px 48px rgba(0,0,0,0.7),0 0 30px rgba(0,66,200,0.15); | |
| z-index:2147483637;overflow:hidden; | |
| font-family:'Manrope','Segoe UI',Tahoma,sans-serif; | |
| animation:vsCbPop 0.24s ease; | |
| } | |
| @keyframes vsCbPop{ | |
| from{opacity:0;transform:scale(0.95) translateY(10px);} | |
| to {opacity:1;transform:scale(1) translateY(0);} | |
| } | |
| #vs-cb-header{ | |
| background:linear-gradient(107.8deg, #6BA6FF 3.37%, #0066FF 95.93%); | |
| color:white;padding:10px 12px; | |
| display:flex;align-items:center;gap:8px;flex-shrink:0; | |
| } | |
| .vs-avatar{ | |
| width:30px;height:30px;background:rgba(255,255,255,0.22); | |
| border-radius:50%;display:flex;align-items:center; | |
| justify-content:center;flex-shrink:0; | |
| } | |
| .vs-hinfo h3{font-size:12px;font-weight:700;margin:0;} | |
| .vs-hinfo p {font-size:10px;opacity:0.82;margin:1px 0 0;} | |
| #vs-cb-utag{ | |
| font-size:11px;background:rgba(255,255,255,0.2); | |
| border-radius:12px;padding:3px 10px;margin-left:auto; | |
| white-space:nowrap;max-width:105px; | |
| overflow:hidden;text-overflow:ellipsis; | |
| } | |
| #vs-cb-dot{ | |
| width:9px;height:9px;background:#4ade80; | |
| border-radius:50%;flex-shrink:0; | |
| animation:vsPulse 2s infinite; | |
| } | |
| @keyframes vsPulse{ | |
| 0% {box-shadow:0 0 0 0 rgba(74,222,128,0.5);} | |
| 70% {box-shadow:0 0 0 7px rgba(74,222,128,0);} | |
| 100%{box-shadow:0 0 0 0 rgba(74,222,128,0);} | |
| } | |
| #vs-cb-msgs{ | |
| flex:1;overflow-y:auto;padding:10px; | |
| display:flex;flex-direction:column;gap:8px; | |
| background:#030c1a;scroll-behavior:smooth; | |
| } | |
| #vs-cb-msgs::-webkit-scrollbar{width:4px;} | |
| #vs-cb-msgs::-webkit-scrollbar-thumb{background:rgba(107,166,255,0.3);border-radius:2px;} | |
| .vs-wrap{display:flex;flex-direction:column;} | |
| .vs-wrap.user{align-items:flex-end;} | |
| .vs-wrap.bot{flex-direction:row;align-items:flex-end;gap:8px;} | |
| .vs-wrap.bot .vs-msg-col{display:flex;flex-direction:column;align-items:flex-start;} | |
| .vs-bot-mini{ | |
| width:22px;height:22px;flex-shrink:0;border-radius:50%; | |
| background:linear-gradient(107.8deg,#6BA6FF 3.37%,#0066FF 95.93%); | |
| display:flex;align-items:center;justify-content:center;align-self:flex-end; | |
| box-shadow:0 2px 6px rgba(0,102,255,0.4); | |
| } | |
| .vs-msg{ | |
| max-width:86%;padding:8px 11px;border-radius:12px; | |
| font-size:12px;line-height:1.55; | |
| animation:vsFade 0.2s ease; | |
| } | |
| @keyframes vsFade{ | |
| from{opacity:0;transform:translateY(5px);} | |
| to {opacity:1;transform:none;} | |
| } | |
| .vs-msg.bot{ | |
| background:rgba(255,255,255,0.07);color:#d0e8ff; | |
| border:1px solid rgba(107,166,255,0.12); | |
| border-bottom-left-radius:4px; | |
| } | |
| .vs-msg.bot a{color:#6BA6FF;text-decoration:none;font-weight:500;} | |
| .vs-msg.bot a:hover{text-decoration:underline;} | |
| .vs-msg.user{ | |
| background:linear-gradient(107.8deg, #6BA6FF 3.37%, #0066FF 95.93%); | |
| color:white;border-bottom-right-radius:4px; | |
| } | |
| .vs-time{font-size:10.5px;color:rgba(255,255,255,0.3);margin-top:4px;padding:0 4px;} | |
| .vs-msg.typing{ | |
| background:rgba(255,255,255,0.07); | |
| border:1px solid rgba(107,166,255,0.12); | |
| border-bottom-left-radius:4px; | |
| padding:13px 16px; | |
| } | |
| .vs-dots{display:flex;gap:5px;align-items:center;} | |
| .vs-dots span{ | |
| width:7px;height:7px;background:rgba(107,166,255,0.7);border-radius:50%; | |
| animation:vsDot 1.3s infinite ease-in-out; | |
| } | |
| .vs-dots span:nth-child(2){animation-delay:0.18s;} | |
| .vs-dots span:nth-child(3){animation-delay:0.36s;} | |
| @keyframes vsDot{ | |
| 0%,60%,100%{transform:translateY(0);} | |
| 30% {transform:translateY(-8px);} | |
| } | |
| #vs-cb-quick{ | |
| display:flex;flex-wrap:wrap;gap:4px; | |
| padding:0 10px 7px;background:#030c1a;flex-shrink:0; | |
| } | |
| .vs-qbtn{ | |
| background:rgba(0,102,255,0.12);border:1px solid rgba(107,166,255,0.35);color:#6BA6FF; | |
| border-radius:14px;padding:3px 10px;font-size:10.5px; | |
| cursor:pointer;transition:all 0.18s;white-space:nowrap; | |
| font-family:'Manrope','Segoe UI',sans-serif; | |
| } | |
| .vs-qbtn:hover{background:#0066FF;color:white;border-color:#0066FF;} | |
| #vs-cb-inputarea{ | |
| display:flex;padding:7px 9px;gap:6px; | |
| border-top:1px solid rgba(107,166,255,0.15);background:#04111e;flex-shrink:0; | |
| } | |
| #vs-cb-input{ | |
| flex:1;border:1px solid rgba(107,166,255,0.2);border-radius:18px; | |
| padding:7px 12px;font-size:12px;outline:none;color:white; | |
| background:rgba(255,255,255,0.06); | |
| transition:border-color 0.2s,background 0.2s;resize:none;max-height:60px; | |
| font-family:'Manrope','Segoe UI',sans-serif; | |
| } | |
| #vs-cb-input::placeholder{color:rgba(255,255,255,0.3);} | |
| #vs-cb-input:focus{border-color:#6BA6FF;background:rgba(107,166,255,0.08);} | |
| #vs-cb-send{ | |
| width:30px;height:30px;flex-shrink:0; | |
| background:linear-gradient(107.8deg, #6BA6FF 3.37%, #0066FF 95.93%); | |
| border:none;border-radius:50%;cursor:pointer; | |
| color:white;font-size:13px; | |
| display:flex;align-items:center;justify-content:center; | |
| transition:opacity 0.2s; | |
| box-shadow:0 3px 10px rgba(0,102,255,0.4); | |
| } | |
| #vs-cb-send:hover{opacity:0.88;} | |
| #vs-cb-send:disabled{opacity:0.4;cursor:not-allowed;} | |
| /* ββ Bot Animations βββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .vs-bot-eye{ | |
| transform-box:fill-box;transform-origin:50% 50%; | |
| animation:vsBotBlink 4.8s ease-in-out infinite; | |
| } | |
| .vs-bot-eye-r{animation-delay:0.12s;} | |
| @keyframes vsBotBlink{ | |
| 0%,82%,100%{transform:scaleY(1);} | |
| 84%{transform:scaleY(0.18);} | |
| 86%{transform:scaleY(1);} | |
| 88%{transform:scaleY(0.08);} | |
| 90%{transform:scaleY(1);} | |
| } | |
| .vs-bot-ant{ | |
| transform-box:fill-box;transform-origin:50% 50%; | |
| animation:vsAntGlow 2.4s ease-in-out infinite; | |
| } | |
| @keyframes vsAntGlow{ | |
| 0%,100%{opacity:0.4;transform:scale(0.8);filter:drop-shadow(0 0 2px rgba(255,255,255,0.4));} | |
| 45%{opacity:1;transform:scale(1.15);filter:drop-shadow(0 0 5px white);} | |
| 70%{opacity:0.65;transform:scale(0.9);filter:drop-shadow(0 0 3px rgba(255,255,255,0.55));} | |
| } | |
| #vs-cb-toggle{animation:vsBotFloat 2s ease-in-out infinite;} | |
| #vs-cb-toggle:hover{animation:none;transform:scale(1.12);} | |
| @keyframes vsBotFloat{ | |
| 0%,100%{transform:translateY(0);} | |
| 50%{transform:translateY(-8px);} | |
| } | |
| #vs-cb-toggle::after{ | |
| content:'';position:absolute;inset:-4px;border-radius:50%; | |
| border:2px solid rgba(107,166,255,0.6); | |
| animation:vsRingPulse 1.2s ease-out infinite; | |
| } | |
| #vs-cb-toggle::before{ | |
| content:'';position:absolute;inset:-10px;border-radius:50%; | |
| border:1.5px solid rgba(107,166,255,0.25); | |
| animation:vsRingPulse 1.2s ease-out infinite 0.4s; | |
| } | |
| @keyframes vsRingPulse{ | |
| 0%{transform:scale(1);opacity:0.8;} | |
| 100%{transform:scale(1.35);opacity:0;} | |
| } | |
| @media(max-width:480px){ | |
| #vs-cb-widget{ | |
| bottom:0;right:0;left:0; | |
| width:100%;height:100%;border-radius:0; | |
| } | |
| #vs-cb-toggle{bottom:16px;right:16px;} | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| // ββ HTML βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| const root = document.createElement('div'); | |
| root.id = 'vs-cb-root'; | |
| root.innerHTML = ` | |
| <div id="vs-cb-overlay"> | |
| <div id="vs-cb-card"> | |
| <div class="vs-logo">${BOT_SVG(44,50)}</div> | |
| <h2>Vibhu Solutions AI</h2> | |
| <p class="vs-subtitle">Enter your details to chat with our<br>intelligent business AI assistant</p> | |
| <div class="vs-field"> | |
| <label>Full Name <span style="color:#ef4444">*</span></label> | |
| <input id="vs-ln" type="text" placeholder="Your full name" autocomplete="name"/> | |
| </div> | |
| <div class="vs-field"> | |
| <label>Email Address <span style="color:#ef4444">*</span></label> | |
| <input id="vs-le" type="email" placeholder="your@email.com" autocomplete="email"/> | |
| </div> | |
| <div class="vs-field"> | |
| <label>Phone / WhatsApp | |
| <span style="font-weight:400;color:#9ca3af;font-size:11px">(optional)</span> | |
| </label> | |
| <input id="vs-lp" type="tel" placeholder="+91 9XXXXXXXXX" autocomplete="tel"/> | |
| </div> | |
| <button id="vs-cb-login-btn">Start Chatting β</button> | |
| <p class="vs-privacy">π Your information is kept private and secure.</p> | |
| </div> | |
| </div> | |
| <button id="vs-cb-toggle" title="Chat with us">${BOT_SVG(26,29)}</button> | |
| <div id="vs-cb-widget"> | |
| <div id="vs-cb-header"> | |
| <div class="vs-avatar">${BOT_SVG(20,23)}</div> | |
| <div class="vs-hinfo"> | |
| <h3>Vibhu Solutions AI</h3> | |
| <p>Ask me about our services</p> | |
| </div> | |
| <span id="vs-cb-utag"></span> | |
| <div id="vs-cb-dot"></div> | |
| </div> | |
| <div id="vs-cb-msgs"></div> | |
| <div id="vs-cb-quick"> | |
| <button class="vs-qbtn" data-msg="What services do you offer?">Services</button> | |
| <button class="vs-qbtn" data-msg="How do I start a project with you?">Start Project</button> | |
| <button class="vs-qbtn" data-msg="How can I contact your team?">Contact</button> | |
| <button class="vs-qbtn" data-msg="How long does a project take?">Timeline</button> | |
| </div> | |
| <div id="vs-cb-inputarea"> | |
| <textarea id="vs-cb-input" rows="1" | |
| placeholder="Ask anything about our servicesβ¦"></textarea> | |
| <button id="vs-cb-send">β€</button> | |
| </div> | |
| </div> | |
| `; | |
| document.body.appendChild(root); | |
| // ββ State ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| let cbOpen = false, cbTypingEl = null, cbUser = null; | |
| // ββ Format bot message (clickable links / emails / phones) βββββββββββββββββββ | |
| function formatMsg(text) { | |
| let h = text | |
| .replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); | |
| h = h.replace(/\*\*([^*\n]+)\*\*/g, '<strong>$1</strong>'); | |
| h = h.replace(/(https?:\/\/[^\s&<]+)/g, | |
| '<a href="$1" target="_blank" rel="noopener">$1</a>'); | |
| h = h.replace(/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g, | |
| '<a href="mailto:$1">$1</a>'); | |
| h = h.replace(/(\+91[\s]?[0-9]{10})/g, | |
| '<a href="tel:$1">$1</a>'); | |
| h = h.replace(/\n/g,'<br>'); | |
| return h; | |
| } | |
| // ββ Add message ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function addMsg(content, type, isHTML) { | |
| const msgs = document.getElementById('vs-cb-msgs'); | |
| const wrap = document.createElement('div'); | |
| wrap.className = 'vs-wrap ' + type; | |
| if (type === 'bot') { | |
| const mini = document.createElement('div'); | |
| mini.className = 'vs-bot-mini'; | |
| mini.innerHTML = BOT_SVG(14, 16); | |
| wrap.appendChild(mini); | |
| const col = document.createElement('div'); | |
| col.className = 'vs-msg-col'; | |
| const div = document.createElement('div'); | |
| div.className = 'vs-msg bot'; | |
| if (isHTML) div.innerHTML = content; | |
| else div.textContent = content; | |
| col.appendChild(div); | |
| const t = document.createElement('span'); | |
| t.className = 'vs-time'; | |
| t.textContent = new Date().toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}); | |
| col.appendChild(t); | |
| wrap.appendChild(col); | |
| } else { | |
| const div = document.createElement('div'); | |
| div.className = 'vs-msg ' + type; | |
| if (isHTML) div.innerHTML = content; | |
| else div.textContent = content; | |
| wrap.appendChild(div); | |
| const t = document.createElement('span'); | |
| t.className = 'vs-time'; | |
| t.textContent = new Date().toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}); | |
| wrap.appendChild(t); | |
| } | |
| msgs.appendChild(wrap); | |
| msgs.scrollTop = msgs.scrollHeight; | |
| return wrap; | |
| } | |
| // ββ Animated typing dots βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function showTyping() { | |
| const msgs = document.getElementById('vs-cb-msgs'); | |
| const wrap = document.createElement('div'); | |
| wrap.className = 'vs-wrap bot'; | |
| const mini = document.createElement('div'); | |
| mini.className = 'vs-bot-mini'; | |
| mini.innerHTML = BOT_SVG(18, 20); | |
| wrap.appendChild(mini); | |
| const col = document.createElement('div'); | |
| col.className = 'vs-msg-col'; | |
| const div = document.createElement('div'); | |
| div.className = 'vs-msg typing'; | |
| div.innerHTML = '<div class="vs-dots"><span></span><span></span><span></span></div>'; | |
| col.appendChild(div); | |
| wrap.appendChild(col); | |
| msgs.appendChild(wrap); | |
| msgs.scrollTop = msgs.scrollHeight; | |
| cbTypingEl = wrap; | |
| } | |
| function hideTyping() { | |
| if (cbTypingEl) { cbTypingEl.remove(); cbTypingEl = null; } | |
| } | |
| // ββ Login ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function doLogin() { | |
| const nameEl = document.getElementById('vs-ln'); | |
| const emailEl = document.getElementById('vs-le'); | |
| const name = nameEl.value.trim(); | |
| const email = emailEl.value.trim(); | |
| const phone = document.getElementById('vs-lp').value.trim(); | |
| nameEl.classList.remove('vs-err'); | |
| emailEl.classList.remove('vs-err'); | |
| let ok = true; | |
| if (!name) { nameEl.classList.add('vs-err'); nameEl.focus(); ok = false; } | |
| if (!email || !email.includes('@')) { | |
| emailEl.classList.add('vs-err'); | |
| if (ok) emailEl.focus(); | |
| ok = false; | |
| } | |
| if (!ok) return; | |
| cbUser = { name, email, phone, | |
| session_id: 'vs_' + Date.now() + '_' + Math.random().toString(36).slice(2,8) }; | |
| try { localStorage.setItem('vs_cb_user', JSON.stringify(cbUser)); } catch(_){} | |
| document.getElementById('vs-cb-overlay').style.display = 'none'; | |
| document.getElementById('vs-cb-toggle').style.display = 'flex'; | |
| cbToggle(); | |
| } | |
| // ββ Restore session ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| try { | |
| const saved = localStorage.getItem('vs_cb_user'); | |
| if (saved) { | |
| cbUser = JSON.parse(saved); | |
| document.getElementById('vs-cb-overlay').style.display = 'none'; | |
| document.getElementById('vs-cb-toggle').style.display = 'flex'; | |
| } | |
| } catch(_) {} | |
| // ββ Toggle widget ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function cbToggle() { | |
| cbOpen = !cbOpen; | |
| const w = document.getElementById('vs-cb-widget'); | |
| const btn = document.getElementById('vs-cb-toggle'); | |
| w.style.display = cbOpen ? 'flex' : 'none'; | |
| btn.innerHTML = cbOpen ? 'β' : BOT_SVG(26, 29); | |
| if (cbUser) | |
| document.getElementById('vs-cb-utag').textContent = | |
| 'π€ ' + cbUser.name.split(' ')[0]; | |
| if (cbOpen && document.getElementById('vs-cb-msgs').children.length === 0) { | |
| const fn = cbUser ? cbUser.name.split(' ')[0] : ''; | |
| const greeting = fn | |
| ? `Hi ${fn}! π Welcome to Vibhu Solutions.\n\nI'm your AI assistant. I can help you with:\nβ’ Our services & technologies\nβ’ How to start a project\nβ’ Our process & timelines\nβ’ How to contact our team\n\nWhat can I help you with today?` | |
| : `Hello! π Welcome to Vibhu Solutions.\n\nAsk me about our services or how to get started!`; | |
| addMsg(greeting, 'bot', false); | |
| } | |
| if (cbOpen) document.getElementById('vs-cb-input').focus(); | |
| } | |
| // ββ API call with timeout ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async function callAPI(payload, ms) { | |
| const ctrl = new AbortController(); | |
| const timer = setTimeout(() => ctrl.abort(), ms); | |
| try { | |
| const r = await fetch(API_URL, { | |
| method:'POST', signal:ctrl.signal, | |
| headers:{'Content-Type':'application/json'}, | |
| body: JSON.stringify(payload), | |
| }); | |
| return await r.json(); | |
| } finally { clearTimeout(timer); } | |
| } | |
| // ββ Send message βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async function cbSend() { | |
| const input = document.getElementById('vs-cb-input'); | |
| const send = document.getElementById('vs-cb-send'); | |
| const msg = input.value.trim(); | |
| if (!msg) return; | |
| addMsg(msg, 'user', false); | |
| input.value = ''; input.style.height = ''; | |
| input.disabled = true; send.disabled = true; | |
| showTyping(); | |
| document.getElementById('vs-cb-quick').style.display = 'none'; | |
| const payload = { | |
| message: msg, | |
| session_id: cbUser ? cbUser.session_id : 'guest_' + Date.now(), | |
| user_name: cbUser ? cbUser.name : '', | |
| user_email: cbUser ? cbUser.email : '', | |
| user_phone: cbUser ? cbUser.phone : '', | |
| }; | |
| try { | |
| const data = await callAPI(payload, 30000); | |
| hideTyping(); | |
| addMsg(formatMsg(data.reply || 'Sorry, something went wrong.'), 'bot', true); | |
| } catch(_) { | |
| hideTyping(); | |
| cbTypingEl = addMsg('Please wait, connectingβ¦', 'bot', false); | |
| await new Promise(r => setTimeout(r, 3000)); | |
| hideTyping(); | |
| try { | |
| const data = await callAPI(payload, 60000); | |
| hideTyping(); | |
| addMsg(formatMsg(data.reply || 'Sorry, something went wrong.'), 'bot', true); | |
| } catch(_) { | |
| hideTyping(); | |
| addMsg('Unable to reach assistant.\n\nπ§ contact@vibhusolutions.com\nπ +91 9380345108', | |
| 'bot', false); | |
| } | |
| } finally { | |
| input.disabled = false; send.disabled = false; input.focus(); | |
| } | |
| } | |
| // ββ Event listeners ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| document.getElementById('vs-cb-login-btn').addEventListener('click', doLogin); | |
| document.getElementById('vs-ln').addEventListener('keypress', | |
| e => { if (e.key==='Enter') doLogin(); }); | |
| document.getElementById('vs-cb-toggle').addEventListener('click', cbToggle); | |
| document.getElementById('vs-cb-send').addEventListener('click', cbSend); | |
| document.getElementById('vs-cb-input').addEventListener('keydown', | |
| e => { if (e.key==='Enter' && !e.shiftKey) { e.preventDefault(); cbSend(); } }); | |
| document.getElementById('vs-cb-input').addEventListener('input', function() { | |
| this.style.height = ''; | |
| this.style.height = Math.min(this.scrollHeight, 72) + 'px'; | |
| }); | |
| document.querySelectorAll('.vs-qbtn').forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| document.getElementById('vs-cb-input').value = btn.dataset.msg; | |
| cbSend(); | |
| }); | |
| }); | |
| })(); | |