AI_Robot / static /index.html
Sanjay kumar K
Slow bot eye and antenna animations
00fc62e
Raw
History Blame Contribute Delete
26.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Vibhu Solutions AI Agent</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 40 40%22><polygon points=%2220,2 38,20 20,38 2,20%22 fill=%22%230066FF%22/><text x=%2250%25%22 y=%2257%25%22 dominant-baseline=%22middle%22 text-anchor=%22middle%22 fill=%22white%22 font-size=%2213%22 font-weight=%22700%22 font-family=%22sans-serif%22>VS</text></svg>">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Manrope', 'Segoe UI', Tahoma, sans-serif;
min-height: 100vh;
color: white;
background: #000810;
}
/* Vibhu-style hero background */
body::before {
content: '';
position: fixed; inset: 0; z-index: 0; pointer-events: none;
background:
radial-gradient(ellipse 65% 60% at 72% 50%, rgba(0,66,200,0.22) 0%, transparent 70%),
radial-gradient(ellipse 30% 40% at 12% 75%, rgba(0,30,130,0.1) 0%, transparent 60%),
linear-gradient(160deg, #000810 0%, #040e22 100%);
}
/* Circuit board grid overlay */
body::after {
content: '';
position: fixed; inset: 0; z-index: 0; pointer-events: none;
background-image:
linear-gradient(rgba(0,100,255,0.055) 1px, transparent 1px),
linear-gradient(90deg, rgba(0,100,255,0.055) 1px, transparent 1px);
background-size: 52px 52px;
mask-image: radial-gradient(ellipse 80% 80% at 65% 50%, black 0%, transparent 80%);
-webkit-mask-image: radial-gradient(ellipse 80% 80% at 65% 50%, black 0%, transparent 80%);
}
/* ── Login Overlay ───────────────────────────────────────────── */
#cb-login-overlay {
position: fixed; inset: 0;
background: rgba(0,4,12,0.45);
backdrop-filter: blur(2px);
display: flex; align-items: center; justify-content: center;
z-index: 99999;
}
#cb-login-card {
background: rgba(4,14,31,0.92);
backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px);
border: 1px solid rgba(107,166,255,0.22);
border-radius: 24px;
padding: 44px 38px 36px;
width: 100%; max-width: 420px; margin: 16px;
box-shadow: 0 32px 80px rgba(0,0,0,0.8), 0 0 60px rgba(0,66,200,0.18);
animation: loginSlide 0.35s ease;
position: relative; z-index: 1;
}
@keyframes loginSlide {
from { opacity:0; transform:translateY(28px); }
to { opacity:1; transform:translateY(0); }
}
.login-logo {
width:80px; height:80px;
background: linear-gradient(107.8deg, #6BA6FF 3.37%, #0066FF 95.93%);
border-radius:20px; display:flex; align-items:center; justify-content:center;
margin:0 auto 20px;
box-shadow:0 10px 28px rgba(0,102,255,0.5), 0 0 40px rgba(0,102,255,0.2);
}
#cb-login-card h2 {
text-align:center; color:white; font-size:22px; font-weight:700;
margin-bottom:6px;
}
.login-subtitle {
text-align:center; color:rgba(255,255,255,0.55); font-size:13.5px;
margin-bottom:26px; line-height:1.6;
}
.login-field { margin-bottom:15px; }
.login-field label {
display:block; font-size:13px; font-weight:600;
color:rgba(255,255,255,0.78); margin-bottom:7px;
}
.login-field input {
width:100%; border:1.5px solid rgba(107,166,255,0.22); border-radius:10px;
padding:12px 15px; font-size:14px; color:white; outline:none;
background:rgba(255,255,255,0.07);
transition:border-color 0.2s, box-shadow 0.2s, background 0.2s;
}
.login-field input::placeholder { color:rgba(255,255,255,0.3); }
.login-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);
}
.login-field input.error { border-color:#ef4444; }
#cb-login-btn {
width:100%; padding:14px;
background:linear-gradient(107.8deg, #6BA6FF 3.37%, #0066FF 95.93%);
color:white; border:none; border-radius:10px;
font-size:15px; font-weight:600; cursor:pointer;
margin-top:6px; letter-spacing:0.3px;
transition:opacity 0.2s, transform 0.1s;
box-shadow:0 6px 20px rgba(0,102,255,0.45);
font-family:'Manrope','Segoe UI',sans-serif;
}
#cb-login-btn:hover { opacity:0.91; }
#cb-login-btn:active { transform:scale(0.98); }
.login-privacy {
text-align:center; font-size:11.5px; color:rgba(255,255,255,0.35); margin-top:14px;
}
/* ── Chat Toggle Button ──────────────────────────────────────── */
#cb-toggle-btn {
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:9999;
display:none; align-items:center; justify-content:center;
}
/* ── Chat Widget ─────────────────────────────────────────────── */
#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:9998; overflow:hidden;
animation:widgetPop 0.25s ease;
}
@keyframes widgetPop {
from { opacity:0; transform:scale(0.95) translateY(10px); }
to { opacity:1; transform:scale(1) translateY(0); }
}
/* Header */
#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;
}
#cb-header .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;
}
#cb-header .info h3 { font-size:12px; font-weight:700; }
#cb-header .info p { font-size:10px; opacity:0.82; margin-top:1px; }
#cb-user-tag {
font-size:11px; background:rgba(255,255,255,0.2);
border-radius:12px; padding:3px 10px; margin-left:auto;
white-space:nowrap; max-width:115px;
overflow:hidden; text-overflow:ellipsis;
}
#cb-status-dot {
width:9px; height:9px; background:#4ade80;
border-radius:50%; flex-shrink:0;
box-shadow:0 0 0 0 rgba(74,222,128,0.5);
animation:pulse 2s infinite;
}
@keyframes pulse {
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); }
}
/* Messages */
#cb-messages {
flex:1; overflow-y:auto; padding:10px;
display:flex; flex-direction:column; gap:8px;
background:#030c1a;
scroll-behavior:smooth;
}
#cb-messages::-webkit-scrollbar { width:4px; }
#cb-messages::-webkit-scrollbar-track { background:transparent; }
#cb-messages::-webkit-scrollbar-thumb { background:rgba(107,166,255,0.3); border-radius:2px; }
.cb-msg-wrap { display:flex; flex-direction:column; }
.cb-msg-wrap.user { align-items:flex-end; }
.cb-msg-wrap.bot { flex-direction:row; align-items:flex-end; gap:8px; }
.cb-msg-wrap.bot .cb-msg-col { display:flex; flex-direction:column; align-items:flex-start; }
.cb-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);
}
/* Bot Animations */
.vs-bot-eye {
transform-box:fill-box; transform-origin:50% 50%;
animation:cbBotBlink 4.8s ease-in-out infinite;
}
.vs-bot-eye-r { animation-delay:0.12s; }
@keyframes cbBotBlink {
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:cbAntGlow 2.4s ease-in-out infinite;
}
@keyframes cbAntGlow {
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)); }
}
#cb-toggle-btn { animation:cbBotFloat 2s ease-in-out infinite; }
#cb-toggle-btn:hover { animation:none; transform:scale(1.12); }
@keyframes cbBotFloat {
0%,100% { transform:translateY(0); }
50% { transform:translateY(-8px); }
}
#cb-toggle-btn::after {
content:''; position:absolute; inset:-4px; border-radius:50%;
border:2px solid rgba(107,166,255,0.6);
animation:cbRingPulse 1.2s ease-out infinite;
}
#cb-toggle-btn::before {
content:''; position:absolute; inset:-10px; border-radius:50%;
border:1.5px solid rgba(107,166,255,0.25);
animation:cbRingPulse 1.2s ease-out infinite 0.4s;
}
@keyframes cbRingPulse {
0% { transform:scale(1); opacity:0.8; }
100% { transform:scale(1.35); opacity:0; }
}
.cb-msg {
max-width:86%; padding:8px 11px; border-radius:12px;
font-size:12px; line-height:1.55;
animation:fadeIn 0.22s ease;
}
@keyframes fadeIn {
from { opacity:0; transform:translateY(6px); }
to { opacity:1; transform:none; }
}
.cb-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;
}
.cb-msg.bot a {
color:#6BA6FF; text-decoration:none; font-weight:500;
}
.cb-msg.bot a:hover { text-decoration:underline; }
.cb-msg.user {
background:linear-gradient(107.8deg, #6BA6FF 3.37%, #0066FF 95.93%);
color:white; border-bottom-right-radius:4px;
}
.cb-time {
font-size:10.5px; color:rgba(255,255,255,0.3); margin-top:4px; padding:0 4px;
}
/* Animated typing dots */
.cb-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;
}
.typing-dots { display:flex; gap:5px; align-items:center; }
.typing-dots span {
width:7px; height:7px; background:rgba(107,166,255,0.7);
border-radius:50%; display:inline-block;
animation:dotBounce 1.3s infinite ease-in-out;
}
.typing-dots span:nth-child(2) { animation-delay:0.18s; }
.typing-dots span:nth-child(3) { animation-delay:0.36s; }
@keyframes dotBounce {
0%,60%,100% { transform:translateY(0); }
30% { transform:translateY(-8px); }
}
/* Quick replies */
#cb-quick-replies {
display:flex; flex-wrap:wrap; gap:4px;
padding:0 10px 7px; background:#030c1a; flex-shrink:0;
}
.cb-quick-btn {
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;
}
.cb-quick-btn:hover { background:#0066FF; color:white; border-color:#0066FF; }
/* Input area */
#cb-input-area {
display:flex; padding:7px 9px; gap:6px;
border-top:1px solid rgba(107,166,255,0.15); background:#04111e; flex-shrink:0;
}
#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;
}
#cb-input::placeholder { color:rgba(255,255,255,0.3); }
#cb-input:focus { border-color:#6BA6FF; background:rgba(107,166,255,0.08); }
#cb-send-btn {
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, transform 0.1s;
}
#cb-send-btn:hover { opacity:0.88; }
#cb-send-btn:active { transform:scale(0.94); }
#cb-send-btn:disabled { opacity:0.45; cursor:not-allowed; }
/* Mobile — full screen widget */
@media (max-width: 480px) {
#cb-widget {
bottom:0; right:0; left:0;
width:100%; height:100%;
border-radius:0;
}
#cb-toggle-btn { bottom:16px; right:16px; }
}
</style>
</head>
<body>
<!-- ════════════ LOGIN OVERLAY ════════════ -->
<div id="cb-login-overlay">
<div id="cb-login-card">
<div class="login-logo" id="cb-logo-bot"></div>
<h2>Vibhu Solutions AI</h2>
<p class="login-subtitle">
Enter your details to chat with our<br>intelligent business AI assistant
</p>
<form id="cb-login-form" onsubmit="cbLogin(event)" novalidate>
<div class="login-field">
<label>Full Name <span style="color:#ef4444">*</span></label>
<input id="cb-ln" type="text" placeholder="Your full name"
autocomplete="name" required />
</div>
<div class="login-field">
<label>Email Address <span style="color:#ef4444">*</span></label>
<input id="cb-le" type="email" placeholder="your@email.com"
autocomplete="email" required />
</div>
<div class="login-field">
<label>Phone / WhatsApp
<span style="font-weight:400;color:#9ca3af;font-size:11.5px">(optional)</span>
</label>
<input id="cb-lp" type="tel" placeholder="+91 9XXXXXXXXX"
autocomplete="tel" />
</div>
<button type="submit" id="cb-login-btn">Start Chatting →</button>
</form>
<p class="login-privacy">🔒 Your information is kept private and secure.</p>
</div>
</div>
<!-- ════════════ CHAT TOGGLE BUTTON ════════════ -->
<button id="cb-toggle-btn" title="Chat with us"></button>
<!-- ════════════ CHAT WIDGET ════════════ -->
<div id="cb-widget">
<div id="cb-header">
<div class="avatar" id="cb-header-bot"></div>
<div class="info">
<h3>Vibhu Solutions AI</h3>
<p>Ask me anything about our services</p>
</div>
<span id="cb-user-tag"></span>
<div id="cb-status-dot"></div>
</div>
<div id="cb-messages"></div>
<div id="cb-quick-replies">
<button class="cb-quick-btn"
onclick="cbSendQuick('What services do you offer?')">Services</button>
<button class="cb-quick-btn"
onclick="cbSendQuick('How do I start a project with you?')">Start Project</button>
<button class="cb-quick-btn"
onclick="cbSendQuick('How can I contact your team?')">Contact</button>
<button class="cb-quick-btn"
onclick="cbSendQuick('How long does a project take?')">Timeline</button>
</div>
<div id="cb-input-area">
<textarea id="cb-input" rows="1"
placeholder="Ask anything about our services…"></textarea>
<button id="cb-send-btn" onclick="cbSend()"></button>
</div>
</div>
<!-- SCRIPTS -->
<script>
const CB_API_URL = '/chat';
let cbOpen = false, cbTypingEl = null, cbUser = null;
/* Bot SVG generator */
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>`;
/* Inject bot into static placeholders */
document.getElementById('cb-logo-bot').innerHTML = BOT_SVG(50, 56);
document.getElementById('cb-header-bot').innerHTML = BOT_SVG(20, 23);
document.getElementById('cb-toggle-btn').innerHTML = BOT_SVG(26, 29);
/* Format bot message: make links / emails / phones clickable */
function formatBotMsg(text) {
// Escape HTML to prevent injection
let h = text
.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
// Bold **text**
h = h.replace(/\*\*([^*\n]+)\*\*/g, '<strong>$1</strong>');
// URLs
h = h.replace(/(https?:\/\/[^\s&<]+)/g,
'<a href="$1" target="_blank" rel="noopener">$1</a>');
// Emails
h = h.replace(/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g,
'<a href="mailto:$1">$1</a>');
// Indian phone numbers
h = h.replace(/(\+91[\s]?[0-9]{10})/g,
'<a href="tel:$1">$1</a>');
// Line breaks
h = h.replace(/\n/g, '<br>');
return h;
}
/* Add message bubble */
function cbAddMsg(text, type, isHTML) {
const msgs = document.getElementById('cb-messages');
const wrap = document.createElement('div');
wrap.className = 'cb-msg-wrap ' + type;
if (type === 'bot') {
const mini = document.createElement('div');
mini.className = 'cb-bot-mini';
mini.innerHTML = BOT_SVG(14, 16);
wrap.appendChild(mini);
const col = document.createElement('div');
col.className = 'cb-msg-col';
const div = document.createElement('div');
div.className = 'cb-msg bot';
if (isHTML) div.innerHTML = text;
else div.textContent = text;
col.appendChild(div);
const t = document.createElement('span');
t.className = 'cb-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 = 'cb-msg ' + type;
if (isHTML) div.innerHTML = text;
else div.textContent = text;
wrap.appendChild(div);
const t = document.createElement('span');
t.className = 'cb-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 indicator */
function cbShowTyping() {
const msgs = document.getElementById('cb-messages');
const wrap = document.createElement('div');
wrap.className = 'cb-msg-wrap bot';
const mini = document.createElement('div');
mini.className = 'cb-bot-mini';
mini.innerHTML = BOT_SVG(14, 16);
wrap.appendChild(mini);
const col = document.createElement('div');
col.className = 'cb-msg-col';
const div = document.createElement('div');
div.className = 'cb-msg typing';
div.innerHTML = '<div class="typing-dots"><span></span><span></span><span></span></div>';
col.appendChild(div);
wrap.appendChild(col);
msgs.appendChild(wrap);
msgs.scrollTop = msgs.scrollHeight;
cbTypingEl = wrap;
}
function cbHideTyping() {
if (cbTypingEl) { cbTypingEl.remove(); cbTypingEl = null; }
}
/* Login */
function cbLogin(e) {
e.preventDefault();
const nameEl = document.getElementById('cb-ln');
const emailEl = document.getElementById('cb-le');
const name = nameEl.value.trim();
const email = emailEl.value.trim();
const phone = document.getElementById('cb-lp').value.trim();
nameEl.classList.remove('error');
emailEl.classList.remove('error');
let ok = true;
if (!name) { nameEl.classList.add('error'); nameEl.focus(); ok = false; }
if (!email || !email.includes('@')) {
emailEl.classList.add('error');
if (ok) emailEl.focus();
ok = false;
}
if (!ok) return;
cbUser = {
name, email, phone,
session_id: 'vs_' + Date.now() + '_' + Math.random().toString(36).slice(2,9)
};
try { localStorage.setItem('cb_user', JSON.stringify(cbUser)); } catch(_){}
document.getElementById('cb-login-overlay').style.display = 'none';
const btn = document.getElementById('cb-toggle-btn');
btn.style.display = 'flex';
cbToggle();
}
/* Restore existing session */
(function restoreSession() {
try {
const saved = localStorage.getItem('cb_user');
if (!saved) return;
cbUser = JSON.parse(saved);
document.getElementById('cb-login-overlay').style.display = 'none';
document.getElementById('cb-toggle-btn').style.display = 'flex';
} catch(_) { localStorage.removeItem('cb_user'); }
})();
/* Toggle widget */
function cbToggle() {
cbOpen = !cbOpen;
const w = document.getElementById('cb-widget');
const btn = document.getElementById('cb-toggle-btn');
w.style.display = cbOpen ? 'flex' : 'none';
btn.innerHTML = cbOpen ? '✕' : BOT_SVG(26, 29);
btn.classList.toggle('open', cbOpen);
if (cbUser && cbUser.name)
document.getElementById('cb-user-tag').textContent =
'👤 ' + cbUser.name.split(' ')[0];
if (cbOpen && document.getElementById('cb-messages').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, how to get started, or how to contact our team!`;
cbAddMsg(greeting, 'bot', false);
}
if (cbOpen) document.getElementById('cb-input').focus();
}
document.getElementById('cb-toggle-btn').addEventListener('click', cbToggle);
/* Quick reply */
function cbSendQuick(msg) {
document.getElementById('cb-input').value = msg;
cbSend();
}
/* API call with timeout */
async function cbCallAPI(payload, ms) {
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), ms);
try {
const r = await fetch(CB_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('cb-input');
const sendBtn = document.getElementById('cb-send-btn');
const msg = input.value.trim();
if (!msg) return;
cbAddMsg(msg, 'user', false);
input.value = '';
input.style.height = '';
input.disabled = true;
sendBtn.disabled = true;
cbShowTyping();
document.getElementById('cb-quick-replies').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 cbCallAPI(payload, 30000);
cbHideTyping();
cbAddMsg(formatBotMsg(data.reply || 'Sorry, something went wrong.'), 'bot', true);
} catch(_) {
cbHideTyping();
cbTypingEl = cbAddMsg('Please wait, connecting…', 'bot', false);
await new Promise(r => setTimeout(r, 3000));
cbHideTyping();
try {
const data = await cbCallAPI(payload, 60000);
cbHideTyping();
cbAddMsg(formatBotMsg(data.reply || 'Sorry, something went wrong.'), 'bot', true);
} catch(_) {
cbHideTyping();
cbAddMsg(
'Unable to reach the assistant right now. Please try again.\n\n' +
'📧 contact@vibhusolutions.com\n📞 +91 9380345108',
'bot', false
);
}
} finally {
input.disabled = false;
sendBtn.disabled = false;
input.focus();
}
}
/* Auto-grow textarea */
document.getElementById('cb-input').addEventListener('input', function() {
this.style.height = '';
this.style.height = Math.min(this.scrollHeight, 80) + 'px';
});
/* Enter to send (Shift+Enter for newline) */
document.getElementById('cb-input').addEventListener('keydown', function(e) {
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); cbSend(); }
});
</script>
</body>
</html>