Please fix the settingss tab it doesn’t work. I want to be able to set duration times . For example if I don’t answer a test after a certain amount of minutes or if I don’t answer a call after a certain amount of time then the ai answers the call or responds via text - Initial Deployment
80c49f5
verified
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AI Phone Assistant</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<script> | |
// Business settings data | |
let businessSettings = { | |
maxRingTime: 30, | |
smsResponseTime: 15, | |
responseLanguage: "en", | |
personalGreeting: "", | |
businessHours: { | |
open: "08:00", | |
close: "18:00" | |
}, | |
responses: { | |
missedCall: { | |
en: "Hello, this is Jay's Mobile Wash. We missed your call. Please leave a message and we'll return your call as soon as possible.", | |
es: "Hola, es el lavado móvil de Jay. Perdimos su llamada. Por favor deje un mensaje y le devolveremos la llamada lo antes posible." | |
}, | |
afterHours: { | |
en: "Thank you for contacting Jay's Mobile Wash. Our business hours are [hours]. We will respond when we reopen.", | |
es: "Gracias por contactar el lavado móvil de Jay. Nuestro horario es de [hours]. Responderemos cuando volvamos a abrir." | |
} | |
} | |
}; | |
function loadSettings() { | |
const saved = localStorage.getItem('JMW_Settings'); | |
if (saved) { | |
businessSettings = JSON.parse(saved); | |
// Set default values if they don't exist | |
if (!businessSettings.maxRingTime) businessSettings.maxRingTime = 30; | |
if (!businessSettings.smsResponseTime) businessSettings.smsResponseTime = 15; | |
document.getElementById('maxRingTime').value = businessSettings.maxRingTime; | |
document.getElementById('smsResponseTime').value = businessSettings.smsResponseTime; | |
document.getElementById('openTime').value = businessSettings.businessHours.open; | |
document.getElementById('closeTime').value = businessSettings.businessHours.close; | |
document.getElementById('responseLanguage').value = businessSettings.responseLanguage; | |
document.getElementById('personalGreeting').value = businessSettings.personalGreeting; | |
document.getElementById('missedCallResponse').value = businessSettings.responses.missedCall.en; | |
document.getElementById('missedCallResponseEs').value = businessSettings.responses.missedCall.es; | |
document.getElementById('afterHoursResponse').value = businessSettings.responses.afterHours.en; | |
document.getElementById('afterHoursResponseEs').value = businessSettings.responses.afterHours.es; | |
} | |
} | |
function saveSettings() { | |
businessSettings = { | |
maxRingTime: parseInt(document.getElementById('maxRingTime').value), | |
smsResponseTime: parseInt(document.getElementById('smsResponseTime').value), | |
responseLanguage: document.getElementById('responseLanguage').value, | |
personalGreeting: document.getElementById('personalGreeting').value, | |
businessHours: { | |
open: document.getElementById('openTime').value, | |
close: document.getElementById('closeTime').value | |
}, | |
responses: { | |
missedCall: { | |
en: document.getElementById('missedCallResponse').value, | |
es: document.getElementById('missedCallResponseEs').value | |
}, | |
afterHours: { | |
en: document.getElementById('afterHoursResponse').value, | |
es: document.getElementById('afterHoursResponseEs').value | |
} | |
} | |
}; | |
localStorage.setItem('JMW_Settings', JSON.stringify(businessSettings)); | |
// Show success message | |
const notification = document.createElement('div'); | |
notification.className = 'fixed top-40 left-1/2 transform -translate-x-1/2 bg-green-500 text-white px-6 py-3 rounded-xl animate-fadeIn z-50 shadow-lg'; | |
notification.innerHTML = 'Settings saved successfully!'; | |
document.body.appendChild(notification); | |
setTimeout(() => notification.remove(), 3000); | |
} | |
// Enhanced answerCall with time-based response | |
function answerCall() { | |
const currentTime = new Date(); | |
const openTime = new Date(); | |
const closeTime = new Date(); | |
const [openHours, openMins] = businessSettings.businessHours.open.split(':'); | |
const [closeHours, closeMins] = businessSettings.businessHours.close.split(':'); | |
openTime.setHours(openHours, openMins); | |
closeTime.setHours(closeHours, closeMins); | |
if (currentTime < openTime || currentTime > closeTime) { | |
const fab = document.querySelector('.fab'); | |
const icon = fab.querySelector('i'); | |
icon.classList.remove('fa-phone'); | |
icon.classList.add('fa-clock'); | |
showResponseMessage(businessSettings.responses.afterHours.replace('[hours]', | |
`${businessSettings.businessHours.open} - ${businessSettings.businessHours.close}`)); | |
setTimeout(() => { | |
icon.classList.remove('fa-clock'); | |
icon.classList.add('fa-phone'); | |
}, 1000); | |
return; | |
} | |
// Original answerCall functionality... | |
} | |
function showResponseMessage(message) { | |
const responseContainer = document.querySelector('#callResponseContainer'); | |
if (!responseContainer) { | |
const container = document.createElement('div'); | |
container.id = 'callResponseContainer'; | |
container.className = 'fixed top-16 left-1/2 transform -translate-x-1/2 bg-black bg-opacity-80 text-white px-4 py-2 rounded-lg z-50'; | |
container.textContent = message; | |
document.body.appendChild(container); | |
setTimeout(() => container.remove(), 3000); | |
} | |
} | |
function exportConfiguration() { | |
const data = { | |
trainingData: trainingData, | |
timestamp: new Date().toISOString(), | |
version: "1.0", | |
aiProfile: "Grok-Style Learning Assistant" | |
}; | |
const blob = new Blob([JSON.stringify(data, null, 2)], {type: 'application/json'}); | |
const url = URL.createObjectURL(blob); | |
const a = document.createElement('a'); | |
a.href = url; | |
a.download = `AI-Call-Assistant-${new Date().toISOString().split('T')[0]}.json`; | |
document.body.appendChild(a); | |
a.click(); | |
document.body.removeChild(a); | |
URL.revokeObjectURL(url); | |
alert("Configuration exported successfully!"); | |
} | |
// Tailwind config | |
tailwind.config = { | |
theme: { | |
extend: { | |
colors: { | |
iosbg: '#f2f2f7', | |
iosdark: '#1c1c1e', | |
accent: '#0a84ff', | |
accent2: '#5e5ce6', | |
} | |
} | |
} | |
} | |
// SMS/iMessage Handling | |
function handleSMS(message, sender, isiMessage) { | |
const responseLanguage = businessSettings.responseLanguage; | |
const greeting = businessSettings.personalGreeting; | |
let response; | |
// Check for Spanish keywords | |
const spanishKeywords = ['hola', 'gracias', 'servicio', 'lavado']; | |
const isSpanish = spanishKeywords.some(word => | |
message.toLowerCase().includes(word)); | |
// Determine best language to respond in | |
const useSpanish = responseLanguage === 'es' || isSpanish; | |
if (message.toLowerCase().includes('appointment') || | |
message.toLowerCase().includes('cita')) { | |
response = useSpanish ? | |
`Gracias por su mensaje. Nuestros horarios para citas son ${businessSettings.businessHours.open} a ${businessSettings.businessHours.close}.` : | |
`Thanks for your message. Our appointment hours are ${businessSettings.businessHours.open} to ${businessSettings.businessHours.close}.`; | |
} else if (greeting && !isiMessage) { | |
// Use personal greeting for SMS (not iMessage) | |
response = greeting; | |
} else { | |
response = useSpanish ? | |
"Gracias por su mensaje. ¿En qué puedo ayudarle hoy?" : | |
"Thanks for your message. How can I help you today?"; | |
} | |
return response; | |
} | |
// Call Answering with Speech Synthesis | |
function answerCallWithSpeech(callerNumber) { | |
const synth = window.speechSynthesis; | |
const utterance = new SpeechSynthesisUtterance(); | |
const greeting = businessSettings.personalGreeting || | |
(businessSettings.responseLanguage === 'es' ? | |
"Buenos días, habla el asistente de Jay's Mobile Wash. ¿En qué puedo ayudarle?" : | |
"Hello, this is Jay's Mobile Wash assistant. How can I help you?"); | |
utterance.text = greeting; | |
utterance.lang = businessSettings.responseLanguage === 'es' ? 'es-ES' : 'en-US'; | |
// Speak the greeting | |
synth.speak(utterance); | |
// Set up voice recognition for caller response | |
if ('webkitSpeechRecognition' in window) { | |
const recognition = new webkitSpeechRecognition(); | |
recognition.lang = businessSettings.responseLanguage === 'es' ? 'es-ES' : 'en-US'; | |
recognition.interimResults = false; | |
recognition.onresult = function(event) { | |
const transcript = event.results[0][0].transcript; | |
// Process caller's speech and respond | |
processCallerSpeech(transcript, recognition); | |
}; | |
recognition.start(); | |
} | |
} | |
function processCallerSpeech(transcript, recognition) { | |
const synth = window.speechSynthesis; | |
const utterance = new SpeechSynthesisUtterance(); | |
utterance.lang = businessSettings.responseLanguage === 'es' ? 'es-ES' : 'en-US'; | |
// Simple response logic - would be enhanced with AI in production | |
if (transcript.toLowerCase().includes('appointment') || | |
transcript.toLowerCase().includes('cita')) { | |
utterance.text = businessSettings.responseLanguage === 'es' ? | |
`Las citas están disponibles de ${businessSettings.businessHours.open} a ${businessSettings.businessHours.close}.` : | |
`Appointments are available from ${businessSettings.businessHours.open} to ${businessSettings.businessHours.close}.`; | |
} else { | |
utterance.text = businessSettings.responseLanguage === 'es' ? | |
"Por favor visite nuestro sitio web jaysmobilewash.com para más información. ¿Algo más en lo que pueda ayudarle?" : | |
"Please visit our website jaysmobilewash.com for more information. Is there anything else I can help with?"; | |
} | |
synth.speak(utterance); | |
// Continue listening for next input | |
setTimeout(() => recognition.start(), 2000); | |
} | |
</script> | |
<style> | |
body { | |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; | |
} | |
.screen { | |
display: none; | |
} | |
.screen.active { | |
display: block; | |
} | |
/* Simple switch */ | |
.toggle-switch { | |
position: relative; | |
display: inline-block; | |
width: 60px; | |
height: 34px; | |
} | |
.toggle-switch input { | |
opacity: 0; | |
width: 0; | |
height: 0; | |
} | |
.slider { | |
position: absolute; | |
cursor: pointer; | |
top: 0; | |
left: 0; | |
right: 0; | |
bottom: 0; | |
background-color: #ccc; | |
transition: .4s; | |
border-radius: 34px; | |
} | |
.slider:before { | |
position: absolute; | |
content: ""; | |
height: 26px; | |
width: 26px; | |
left: 4px; | |
bottom: 4px; | |
background-color: white; | |
transition: .4s; | |
border-radius: 50%; | |
} | |
input:checked + .slider { | |
background-color: #2196F3; | |
} | |
input:checked + .slider:before { | |
transform: translateX(26px); | |
} | |
/* Chat bubbles */ | |
.ai-bubble { | |
background: #f1f1f1; | |
border-radius: 5px 15px 15px 5px; | |
padding: 10px 15px; | |
max-width: 85%; | |
margin: 5px 0; | |
} | |
.user-bubble { | |
background: #2196F3; | |
color: white; | |
border-radius: 15px 5px 5px 15px; | |
padding: 10px 15px; | |
max-width: 85%; | |
margin: 5px 0 5px auto; | |
} | |
/* Simple buttons */ | |
.simple-btn { | |
background: #2196F3; | |
color: white; | |
border: none; | |
padding: 10px 15px; | |
border-radius: 5px; | |
cursor: pointer; | |
margin: 5px; | |
} | |
/* Function buttons */ | |
.action-btn { | |
background: #4CAF50; | |
color: white; | |
border: none; | |
padding: 10px 15px; | |
border-radius: 5px; | |
cursor: pointer; | |
margin: 5px; | |
} | |
</style> | |
</head> | |
<body class="bg-iosbg dark:bg-iosdark text-gray-900 dark:text-gray-200 min-h-screen"> | |
<!-- Status Bar --> | |
<div class="fixed top-0 left-0 right-0 h-12 flex items-center px-4 z-50 bg-iosbg dark:bg-iosdark"> | |
<div class="text-left text-sm w-20">9:41</div> | |
<div class="flex-1 flex justify-center"> | |
<i class="fas fa-signal mr-2"></i> | |
<i class="fas fa-wifi mr-2"></i> | |
<i class="fas fa-battery-three-quarters"></i> | |
</div> | |
<div class="w-20 text-right text-xs">100%</div> | |
</div> | |
<!-- Main App Container --> | |
<div class="relative pt-12 max-w-md mx-auto h-screen overflow-hidden"> | |
<!-- Home Screen --> | |
<div id="homeScreen" class="screen active px-4 pt-4 h-full flex flex-col"> | |
<div class="mt-2"> | |
<h1 class="text-3xl font-bold">Jay's Mobile Wash</h1> | |
<p class="text-gray-500 dark:text-gray-400 mt-1">AI Call Assistant Dashboard</p> | |
</div> | |
<!-- Quick Action Buttons --> | |
<div class="mt-8 grid grid-cols-2 gap-4"> | |
<button onclick="showScreen('repliesScreen')" class="bg-white dark:bg-gray-800 rounded-2xl p-5 flex flex-col items-center shadow-sm"> | |
<div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center mb-3"> | |
<i class="fas fa-comments text-blue-500 text-xl"></i> | |
</div> | |
<h3 class="font-medium">Response Templates</h3> | |
<p class="text-xs text-gray-500 mt-1 text-center">Pre-set replies for common calls</p> | |
</button> | |
<button onclick="showScreen('trainingScreen')" class="bg-white dark:bg-gray-800 rounded-2xl p-5 flex flex-col items-center shadow-sm"> | |
<div class="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center mb-3"> | |
<i class="fas fa-graduation-cap text-purple-500 text-xl"></i> | |
</div> | |
<h3 class="font-medium">Train AI</h3> | |
<p class="text-xs text-gray-500 mt-1 text-center">Improve call responses</p> | |
</button> | |
<button onclick="showScreen('settingsScreen')" class="bg-white dark:bg-gray-800 rounded-2xl p-5 flex flex-col items-center shadow-sm"> | |
<div class="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center mb-3"> | |
<i class="fas fa-cog text-green-500 text-xl"></i> | |
</div> | |
<h3 class="font-medium">Settings</h3> | |
<p class="text-xs text-gray-500 mt-1 text-center">Configure call handling</p> | |
</button> | |
<button onclick="answerCall(true)" class="bg-white dark:bg-gray-800 rounded-2xl p-5 flex flex-col items-center shadow-sm"> | |
<div class="w-12 h-12 rounded-full bg-red-100 flex items-center justify-center mb-3"> | |
<i class="fas fa-phone text-red-500 text-xl"></i> | |
</div> | |
<h3 class="font-medium">Test Call</h3> | |
<p class="text-xs text-gray-500 mt-1 text-center">Practice AI responses</p> | |
</button> | |
</div> | |
<!-- Today's Summary --> | |
<div class="mt-8 bg-white dark:bg-gray-800 rounded-2xl p-5"> | |
<h2 class="font-bold text-lg mb-3">Today's Summary</h2> | |
<div class="grid grid-cols-3 gap-4 text-center"> | |
<div class="bg-blue-50 dark:bg-blue-900/30 p-3 rounded-xl"> | |
<div class="text-2xl font-bold">12</div> | |
<div class="text-xs">Calls</div> | |
</div> | |
<div class="bg-green-50 dark:bg-green-900/30 p-3 rounded-xl"> | |
<div class="text-2xl font-bold">8</div> | |
<div class="text-xs">Answered</div> | |
</div> | |
<div class="bg-yellow-50 dark:bg-yellow-900/30 p-3 rounded-xl"> | |
<div class="text-2xl font-bold">4</div> | |
<div class="text-xs">Missed</div> | |
</div> | |
</div> | |
</div> | |
<!-- Recent Activity --> | |
<div class="mt-4"> | |
<div class="flex justify-between items-center mb-2"> | |
<h3 class="font-medium">Recent Calls</h3> | |
<button class="text-sm text-blue-500">See All</button> | |
</div> | |
<div class="space-y-2"> | |
<div class="flex items-center justify-between p-3 bg-white dark:bg-gray-800 rounded-xl"> | |
<div class="flex items-center"> | |
<div class="w-8 h-8 rounded-full bg-green-100 flex items-center justify-center mr-3"> | |
<i class="fas fa-check text-green-500 text-xs"></i> | |
</div> | |
<div> | |
<p class="text-sm font-medium">(562) 228-9429</p> | |
<p class="text-xs text-gray-500">AI Answered - 2:15 PM</p> | |
</div> | |
</div> | |
<i class="fas fa-chevron-right text-gray-400"></i> | |
</div> | |
<div class="flex items-center justify-between p-3 bg-white dark:bg-gray-800 rounded-xl"> | |
<div class="flex items-center"> | |
<div class="w-8 h-8 rounded-full bg-red-100 flex items-center justify-center mr-3"> | |
<i class="fas fa-times text-red-500 text-xs"></i> | |
</div> | |
<div> | |
<p class="text-sm font-medium">Unknown Caller</p> | |
<p class="text-xs text-gray-500">Missed - 10:45 AM</p> | |
</div> | |
</div> | |
<i class="fas fa-chevron-right text-gray-400"></i> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Configure Replies Screen --> | |
<div id="repliesScreen" class="screen h-full flex flex-col"> | |
<div class="px-4 pt-4"> | |
<div class="flex items-center"> | |
<button class="p-2 rounded-full" onclick="showScreen('homeScreen')"> | |
<i class="fas fa-arrow-left"></i> | |
</button> | |
<h2 class="text-xl font-bold ml-2">Smart Replies</h2> | |
</div> | |
<p class="text-gray-500 dark:text-gray-400 mt-1 ml-12">Customize how AI answers calls</p> | |
</div> | |
<div class="mt-4 px-4 flex-1 overflow-y-auto"> | |
<div class="bg-white dark:bg-gray-800 rounded-2xl p-5 mb-4"> | |
<div class="flex items-center"> | |
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-accent to-accent2 flex items-center justify-center"> | |
<i class="fas fa-brain text-white text-xl"></i> | |
</div> | |
<div class="ml-3"> | |
<h3 class="font-medium">AI Learning Mode</h3> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">Improves responses over time</p> | |
</div> | |
</div> | |
<div class="mt-4 flex items-center justify-between"> | |
<span>Learning from interactions</span> | |
<label class="ios-switch"> | |
<input type="checkbox" checked> | |
<span class="ios-slider"></span> | |
</label> | |
</div> | |
</div> | |
<div class="bg-white dark:bg-gray-800 rounded-2xl overflow-hidden"> | |
<div class="px-5 pt-4"> | |
<h3 class="font-medium">Custom Response Templates</h3> | |
<p class="text-gray-500 dark:text-gray-400 text-sm mt-1">Set predefined responses</p> | |
</div> | |
<div class="mt-4 space-y-2"> | |
<div class="flex items-center justify-between p-4 hover:bg-gray-100 dark:hover:bg-gray-750 cursor-pointer"> | |
<div> | |
<h4 class="font-medium">Business Calls</h4> | |
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">"Hello, this is [Your Name]'s assistant..."</p> | |
</div> | |
<i class="fas fa-chevron-right text-gray-400"></i> | |
</div> | |
<div class="flex items-center justify-between p-4 hover:bg-gray-100 dark:hover:bg-gray-750 cursor-pointer"> | |
<div> | |
<h4 class="font-medium">Personal Calls</h4> | |
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">"Hi, this is [Name]'s phone..."</p> | |
</div> | |
<i class="fas fa-chevron-right text-gray-400"></i> | |
</div> | |
<div class="flex items-center justify-between p-4 hover:bg-gray-100 dark:hover:bg-gray-750 cursor-pointer"> | |
<div> | |
<h4 class="font-medium">Spam Protection</h4> | |
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">"Sorry, this number is not accepting calls..."</p> | |
</div> | |
<i class="fas fa-chevron-right text-gray-400"></i> | |
</div> | |
</div> | |
</div> | |
<div class="bg-white dark:bg-gray-800 rounded-2xl mt-4 p-5"> | |
<h3 class="font-medium">Response Style</h3> | |
<div class="mt-4 space-y-4"> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h4 class="font-medium">Formal Tone</h4> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">Professional business language</p> | |
</div> | |
<label class="ios-switch"> | |
<input type="checkbox" checked> | |
<span class="ios-slider"></span> | |
</label> | |
</div> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h4 class="font-medium">Friendly Tone</h4> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">Casual conversation style</p> | |
</div> | |
<label class="ios-switch"> | |
<input type="checkbox"> | |
<span class="ios-slider"></span> | |
</label> | |
</div> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h4 class="font-medium">Use My Name</h4> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">"This is [Your Name]'s phone"</p> | |
</div> | |
<label class="ios-switch"> | |
<input type="checkbox" checked> | |
<span class="ios-slider"></span> | |
</label> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Call Training Screen --> | |
<div id="trainingScreen" class="screen h-full flex flex-col"> | |
<div class="px-4 pt-4"> | |
<div class="flex items-center justify-between"> | |
<div class="flex items-center"> | |
<button class="p-2 rounded-full" onclick="showScreen('homeScreen')"> | |
<i class="fas fa-arrow-left"></i> | |
</button> | |
<div class="ml-2"> | |
<h2 class="text-xl font-bold">Train AI</h2> | |
<p class="text-gray-500 dark:text-gray-400 text-sm -mt-1">Linked to (562) 228-9429</p> | |
</div> | |
</div> | |
<button class="text-accent" id="saveTraining">Save</button> | |
</div> | |
</div> | |
<div class="mt-4 px-4 flex-1 overflow-hidden flex flex-col"> | |
<div class="bg-white dark:bg-gray-800 rounded-2xl p-5 flex-1 overflow-hidden flex flex-col"> | |
<div class="flex-1 overflow-y-auto pb-4"> | |
<div class="ai-bubble"> | |
<p>How would you like me to respond to calls from your family?</p> | |
</div> | |
<div class="user-bubble mt-4"> | |
<p>Always transfer calls from Mom and Dad to me</p> | |
</div> | |
<div class="ai-bubble mt-4"> | |
<p>Noted! I'll transfer calls from Mom and Dad immediately.</p> | |
<p class="mt-2">For other family members, how should I respond?</p> | |
</div> | |
<div class="user-bubble mt-4"> | |
<p>Ask them for the reason of calling and text me if it's important</p> | |
</div> | |
<div class="ai-bubble mt-4"> | |
<p>Got it. Here's the response I created based on your feedback:</p> | |
<div class="mt-2 bg-blue-50 dark:bg-blue-900 rounded-lg p-3"> | |
<p>"Hello, this is Alex's assistant. Could you let me know what you're calling about? I'll make sure they get your message."</p> | |
</div> | |
<p class="mt-2">Does this work?</p> | |
</div> | |
</div> | |
<div class="mt-auto pt-4 border-t border-gray-200 dark:border-gray-700"> | |
<div class="flex gap-2"> | |
<input id="trainingInput" type="text" class="ios-input flex-1" placeholder="Teach your assistant..." onkeypress="handleTrainingKeyPress(event)"> | |
<button class="w-12 h-12 rounded-xl bg-accent flex items-center justify-center text-white" onclick="submitTraining()"> | |
<i class="fas fa-paper-plane"></i> | |
</button> | |
</div> | |
<p class="text-xs text-gray-500 dark:text-gray-400 mt-2 text-center">The AI learns from every interaction</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Simplified Navigation --> | |
<div class="fixed bottom-0 left-0 right-0 bg-white shadow-lg p-2 flex justify-around"> | |
<button class="flex flex-col items-center text-xs" onclick="showScreen('homeScreen')"> | |
<i class="fas fa-home mb-1"></i> | |
<span>Home</span> | |
</button> | |
<button class="flex flex-col items-center text-xs" onclick="showScreen('repliesScreen')"> | |
<i class="fas fa-comments mb-1"></i> | |
<span>Replies</span> | |
</button> | |
<button class="flex flex-col items-center text-xs" onclick="showScreen('trainingScreen')"> | |
<i class="fas fa-graduation-cap mb-1"></i> | |
<span>Train</span> | |
</button> | |
<button class="flex flex-col items-center text-xs" onclick="showScreen('settingsScreen')"> | |
<i class="fas fa-cog mb-1"></i> | |
<span>Settings</span> | |
</button> | |
</div> | |
<!-- AI Chat Test Screen --> | |
<div id="chatScreen" class="screen h-full flex flex-col"> | |
<div class="px-4 pt-4"> | |
<div class="flex items-center"> | |
<button class="p-2 rounded-full" onclick="showScreen('homeScreen')"> | |
<i class="fas fa-arrow-left"></i> | |
</button> | |
<h2 class="text-xl font-bold ml-2">AI Chat Test</h2> | |
</div> | |
<p class="text-gray-500 dark:text-gray-400 mt-1 ml-12">Test and train the AI assistant</p> | |
</div> | |
<div class="mt-4 px-4 flex-1 overflow-hidden flex flex-col"> | |
<div class="bg-white dark:bg-gray-800 rounded-2xl p-5 flex-1 overflow-hidden flex flex-col"> | |
<div id="chatMessages" class="flex-1 overflow-y-auto pb-4 space-y-4"> | |
<div class="ai-bubble animate-fadeIn"> | |
<p>Hi! I'm your AI assistant for Jay's Mobile Wash. I can answer questions about our detailing services and learn from our conversations.</p> | |
<p class="mt-2">Would you like to test my knowledge or teach me something new?</p> | |
</div> | |
</div> | |
<div class="mt-auto pt-4 border-t border-gray-200 dark:border-gray-700"> | |
<div class="flex gap-2"> | |
<input id="chatInput" type="text" class="ios-input flex-1" placeholder="Ask or teach me..." onkeypress="handleChatKeyPress(event)"> | |
<button class="w-12 h-12 rounded-xl bg-accent flex items-center justify-center text-white" onclick="submitChatMessage()"> | |
<i class="fas fa-paper-plane"></i> | |
</button> | |
</div> | |
<p class="text-xs text-gray-500 dark:text-gray-400 mt-2 text-center">I'll learn from every interaction</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Settings Screen --> | |
<div id="settingsScreen" class="screen h-full flex flex-col"> | |
<div class="px-4 pt-4"> | |
<div class="flex items-center"> | |
<button class="p-2 rounded-full" onclick="showScreen('homeScreen')"> | |
<i class="fas fa-arrow-left"></i> | |
</button> | |
<h2 class="text-xl font-bold ml-2">Jay's Mobile Wash Settings</h2> | |
</div> | |
<p class="text-gray-500 dark:text-gray-400 mt-1 ml-12">Configure AI response behavior</p> | |
</div> | |
<div class="mt-4 px-4 flex-1 overflow-y-auto"> | |
<div class="bg-white dark:bg-gray-800 rounded-2xl p-5 mb-4"> | |
<h3 class="font-medium mb-4">Call Response Timing</h3> | |
<div class="space-y-4"> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h4>Max Ring Time (seconds)</h4> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">If you don't answer by this time, AI will answer</p> | |
</div> | |
<input type="number" id="maxRingTime" value="30" min="5" max="60" class="w-20 px-2 py-1 rounded-lg border border-gray-300"> | |
</div> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h4>Max Ring Time (seconds)</h4> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">How long to ring before AI answers</p> | |
</div> | |
<input type="number" id="maxRingTime" value="30" min="5" max="60" class="w-20 px-2 py-1 rounded-lg border border-gray-300"> | |
</div> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h4>SMS Auto-Reply Time (minutes)</h4> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">If no reply to SMS by this time</p> | |
</div> | |
<input type="number" id="smsResponseTime" value="15" min="1" max="120" class="w-20 px-2 py-1 rounded-lg border border-gray-300"> | |
</div> | |
<div class="border-t border-gray-200 dark:border-gray-700 pt-4"> | |
<h3 class="font-medium mb-2">Business Hours</h3> | |
<div class="grid grid-cols-2 gap-3"> | |
<div> | |
<label class="block text-sm text-gray-500 dark:text-gray-400 mb-1">Open Time</label> | |
<input type="time" id="openTime" value="08:00" class="w-full px-2 py-1 rounded-lg border border-gray-300"> | |
</div> | |
<div> | |
<label class="block text-sm text-gray-500 dark:text-gray-400 mb-1">Close Time</label> | |
<input type="time" id="closeTime" value="18:00" class="w-full px-2 py-1 rounded-lg border border-gray-300"> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="bg-white dark:bg-gray-800 rounded-2xl p-5"> | |
<h3 class="font-medium mb-4">Call Handling Configuration</h3> | |
<div class="flex items-center justify-between mb-4"> | |
<div> | |
<h4>Answer Incoming Calls</h4> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">Enable AI to answer phone calls</p> | |
</div> | |
<label class="ios-switch"> | |
<input type="checkbox" id="answerCallsToggle" checked> | |
<span class="ios-slider"></span> | |
</label> | |
</div> | |
<div class="flex items-center justify-between mb-4"> | |
<div> | |
<h4>Live Call Training Mode</h4> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">Ask me questions during calls to learn</p> | |
</div> | |
<label class="ios-switch"> | |
<input type="checkbox" id="callTrainingToggle"> | |
<span class="ios-slider"></span> | |
</label> | |
</div> | |
<h3 class="font-medium mb-4 mt-6">Response Messages</h3> | |
<div class="space-y-4"> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h4>Language</h4> | |
<p class="text-gray-500 dark:text-gray-400 text-sm">Default response language</p> | |
</div> | |
<select id="responseLanguage" class="px-2 py-1 rounded-lg border border-gray-300"> | |
<option value="en">English</option> | |
<option value="es">Español</option> | |
</select> | |
</div> | |
<div> | |
<label class="block text-sm mb-1">Personal Greeting</label> | |
<textarea id="personalGreeting" rows="2" class="w-full px-3 py-2 rounded-lg border border-gray-300" placeholder="Custom greeting when answering calls..."></textarea> | |
</div> | |
<div> | |
<label class="block text-sm mb-1">Missed Call Response (English)</label> | |
<textarea id="missedCallResponse" rows="2" class="w-full px-3 py-2 rounded-lg border border-gray-300">Hello, this is Jay's Mobile Wash. We missed your call. Please leave a message and we'll return your call as soon as possible.</textarea> | |
</div> | |
<div> | |
<label class="block text-sm mb-1">Respuesta Llamada Perdida (Español)</label> | |
<textarea id="missedCallResponseEs" rows="2" class="w-full px-3 py-2 rounded-lg border border-gray-300">Hola, es el lavado móvil de Jay. Perdimos su llamada. Por favor deje un mensaje y le devolveremos la llamada lo antes posible.</textarea> | |
</div> | |
<div> | |
<label class="block text-sm mb-1">After Hours Response (English)</label> | |
<textarea id="afterHoursResponse" rows="2" class="w-full px-3 py-2 rounded-lg border border-gray-300">Thank you for contacting Jay's Mobile Wash. Our business hours are [hours]. We will respond when we reopen.</textarea> | |
</div> | |
<div> | |
<label class="block text-sm mb-1">Respuesta Fuera Horario (Español)</label> | |
<textarea id="afterHoursResponseEs" rows="2" class="w-full px-3 py-2 rounded-lg border border-gray-300">Gracias por contactar el lavado móvil de Jay. Nuestro horario es de [hours]. Responderemos cuando volvamos a abrir.</textarea> | |
</div> | |
</div> | |
<button onclick="saveSettings()" class="mt-6 w-full bg-green-500 text-white py-2 rounded-lg font-medium">Save Settings</button> | |
</div> | |
</div> | |
</div> | |
<!-- Floating Action Button --> | |
<div class="fab" onclick="answerCall()"> | |
<i class="fas fa-phone"></i> | |
</div> | |
</div> | |
<script> | |
// Grok-Style AI Training Data | |
let trainingData = { | |
responses: [], | |
trainedPatterns: {}, | |
dictionProfiles: {}, | |
learningRates: {}, | |
contextMemory: {}, | |
customResponses: { | |
business: '"Hello, this is [Your Name]\'s assistant. How can I help you today?"', | |
personal: '"Hi, this is [Name] calling. How can I help you?"', | |
spam: '"Sorry, this number is not accepting unsolicited calls at this time."', | |
urgent: '"This is urgent, please connect me immediately"' | |
}, | |
// Grok-specific additions | |
humorProfiles: {}, | |
sarcasmDetection: {}, | |
emotionalContext: {}, | |
savedTemplates: [] | |
}; | |
// Enhanced training function storage | |
function storeTrainingPattern(pattern, response) { | |
trainingData.trainedPatterns[pattern.toLowerCase()] = response; | |
localStorage.setItem('AI_Training', JSON.stringify(trainingData)); | |
} | |
// Screen navigation | |
function showScreen(screenId) { | |
document.querySelectorAll('.screen').forEach(screen => { | |
screen.classList.remove('active'); | |
}); | |
document.getElementById(screenId).classList.add('active'); | |
// Update tab bar active state | |
const tabs = document.querySelectorAll('.fixed.bottom-0 button'); | |
tabs.forEach(tab => { | |
tab.classList.remove('text-accent'); | |
tab.classList.add('text-gray-500'); | |
}); | |
// Highlight active tab | |
const activeTab = Array.from(tabs).find(tab => { | |
return tab.getAttribute('onclick').includes(screenId); | |
}); | |
if (activeTab) { | |
activeTab.classList.remove('text-gray-500'); | |
activeTab.classList.add('text-accent'); | |
} | |
} | |
// Simulate AI learning progress | |
function simulateAIProgress() { | |
const progressBars = document.querySelectorAll('.progress'); | |
progressBars.forEach(bar => { | |
const width = 70 + Math.floor(Math.random() * 30); | |
bar.style.width = `${width}%`; | |
}); | |
} | |
// Toggle call recording function | |
function toggleRecording() { | |
const fab = document.querySelector('.fab'); | |
const icon = fab.querySelector('i'); | |
if (icon.classList.contains('fa-microphone')) { | |
icon.classList.remove('fa-microphone'); | |
icon.classList.add('fa-stop'); | |
fab.style.background = 'linear-gradient(135deg, #ff375f, #ff2d55)'; | |
// Show a notification | |
const notification = document.createElement('div'); | |
notification.innerHTML = ` | |
<div class="fixed top-16 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white px-4 py-2 rounded-full animate-fadeIn"> | |
Recording started | |
</div> | |
`; | |
document.body.appendChild(notification); | |
setTimeout(() => { | |
notification.remove(); | |
}, 2000); | |
} else { | |
icon.classList.remove('fa-stop'); | |
icon.classList.add('fa-microphone'); | |
fab.style.background = 'linear-gradient(135deg, #0a84ff, #5e5ce6)'; | |
// Simulate AI learning after recording | |
simulateAIProgress(); | |
} | |
} | |
// Answer call function | |
function answerCall(isTest = false) { | |
const fab = document.querySelector('.fab'); | |
const icon = fab.querySelector('i'); | |
if (icon.classList.contains('fa-phone')) { | |
icon.classList.remove('fa-phone'); | |
icon.classList.add('fa-stop'); | |
fab.style.background = 'linear-gradient(135deg, #32d74b, #30d158)'; | |
// Show call is ringing | |
showResponseMessage(`Call ringing (will answer in ${businessSettings.maxRingTime} seconds if no reply)...`); | |
// Set timeout to answer call after maxRingTime | |
setTimeout(() => { | |
if (icon.classList.contains('fa-stop')) { // If still not answered | |
// Create a new call card | |
const homeScreen = document.getElementById('homeScreen'); | |
const callCard = document.createElement('div'); | |
callCard.className = 'bg-white dark:bg-gray-800 rounded-2xl p-4 mt-4 animate-fadeIn'; | |
const caller = isTest ? 'Test Caller' : 'Unknown (New number)'; | |
callCard.innerHTML = ` | |
<div class="flex items-center justify-between"> | |
<div> | |
<h3 class="font-medium">AI answered call</h3> | |
<p class="text-sm text-gray-500 dark:text-gray-400">From: ${caller}</p> | |
</div> | |
<div class="text-green-500"> | |
<i class="fas fa-check-circle text-xl"></i> | |
</div> | |
</div> | |
<div class="mt-3 text-sm"> | |
<p>AI answered after ${businessSettings.maxRingTime} seconds</p> | |
</div> | |
`; | |
homeScreen.insertBefore(callCard, homeScreen.children[3]); | |
showResponseMessage(businessSettings.personalGreeting || | |
(businessSettings.responseLanguage === 'es' ? | |
"Hola, habla el asistente de Jay's Mobile Wash" : | |
"Hello, this is Jay's Mobile Wash assistant")); | |
} | |
}, businessSettings.maxRingTime * 1000); | |
} else { | |
// End call | |
icon.classList.remove('fa-stop'); | |
icon.classList.add('fa-phone'); | |
fab.style.background = 'linear-gradient(135deg, #0a84ff, #5e5ce6)'; | |
} | |
} | |
function handleSMS(message, sender, isiMessage) { | |
const responseLanguage = businessSettings.responseLanguage; | |
const greeting = businessSettings.personalGreeting; | |
// Set timeout for auto-response | |
setTimeout(() => { | |
if (!message.includes('RE:')) { // If no reply was sent | |
const response = greeting || | |
(responseLanguage === 'es' ? | |
"Gracias por su mensaje. ¿En qué puedo ayudarle hoy?" : | |
"Thanks for your message. How can I help you today?"); | |
showResponseMessage(`Auto-reply sent after ${businessSettings.smsResponseTime} mins: ${response}`); | |
} | |
}, businessSettings.smsResponseTime * 60 * 1000); | |
return handleSMSResponse(message, sender, isiMessage); | |
} | |
// Enhanced training functions | |
function saveTraining() { | |
localStorage.setItem('AI_Training', JSON.stringify(trainingData)); | |
// Show persistent notification | |
const notification = document.createElement('div'); | |
notification.className = 'fixed top-40 left-1/2 transform -translate-x-1/2 bg-gradient-to-r from-green-400 to-blue-500 text-white px-6 py-3 rounded-xl animate-fadeIn z-50 shadow-lg'; | |
notification.innerHTML = ` | |
<div class="flex items-center"> | |
<i class="fas fa-check-circle mr-2"></i> | |
<span>AI training saved! New responses will be active immediately.</span> | |
</div> | |
`; | |
document.body.appendChild(notification); | |
setTimeout(() => { | |
notification.remove(); | |
showScreen('homeScreen'); | |
}, 3000); | |
// Update home screen with new training count | |
const statsElement = document.querySelector('#homeScreen .w-10.h-10 + div p'); | |
statsElement.textContent = `Trained on ${Object.keys(trainingData.trainedPatterns).length} patterns`; | |
} | |
// Add animation to elements when they appear | |
function addAppearAnimations() { | |
document.querySelectorAll('.animate-fadeIn').forEach((el, index) => { | |
el.style.animationDelay = `${index * 0.1}s`; | |
}); | |
} | |
// Smart Training Functions | |
function submitTraining() { | |
const input = document.getElementById('trainingInput'); | |
if (input.value.trim() !== '') { | |
trainingData.responses.push(input.value); | |
// Add the user's message to the chat | |
const chatContainer = document.querySelector('#trainingScreen .flex-1.overflow-y-auto'); | |
const userBubble = document.createElement('div'); | |
userBubble.className = 'user-bubble mt-4 animate-fadeIn'; | |
userBubble.innerHTML = `<p>${input.value}</p>`; | |
chatContainer.appendChild(userBubble); | |
// Process training input with smart logic | |
const processed = processTrainingInput(input.value); | |
// Generate and add AI response | |
setTimeout(() => { | |
const aiBubble = document.createElement('div'); | |
aiBubble.className = 'ai-bubble mt-4 animate-fadeIn'; | |
if (processed.success) { | |
aiBubble.innerHTML = ` | |
<p>Understood! I'll handle calls that way now.</p> | |
<div class="mt-2 bg-green-50 dark:bg-green-900 rounded-lg p-3"> | |
<h4 class="font-medium">New Response Pattern:</h4> | |
<p class="mt-1"><strong>When caller says:</strong> ${processed.triggerPhrases.join(' OR ')}</p> | |
<p class="mt-1"><strong>I will:</strong> ${processed.response}</p> | |
</div> | |
<p class="mt-2">Would you like to review any other scenarios?</p> | |
`; | |
storeTrainingPattern(processed.triggerPhrases[0], processed.response); | |
} else { | |
aiBubble.innerHTML = ` | |
<p>I think you want me to handle calls differently when:</p> | |
<div class="mt-2 bg-blue-50 dark:bg-blue-900 rounded-lg p-3"> | |
<p>${processed.response}</p> | |
</div> | |
<p class="mt-2">Can you confirm or clarify how you'd like me to respond?</p> | |
`; | |
} | |
chatContainer.appendChild(aiBubble); | |
chatContainer.scrollTop = chatContainer.scrollHeight; | |
}, 800); | |
input.value = ''; | |
} | |
} | |
function handleTrainingKeyPress(e) { | |
if (e.key === 'Enter') { | |
submitTraining(); | |
} | |
} | |
// Grok-Style Learning Processor | |
function processTrainingInput(inputText) { | |
// First analyze diction and emotional context | |
analyzeDiction(inputText); | |
// Grok-style pattern matching with contextual learning | |
const context = getCurrentContext(); | |
const patterns = [ | |
// Direct instructions | |
/(when|if) (.+?) (then|do|respond with) (.+)/i, | |
// Examples | |
/(for|when) (\w+) calls?,? (say|respond) "(.+?)"/i, | |
// Behavioral patterns | |
/(treat|handle) (.+?) (as|like) (\w+)/i, | |
// Tone adjustments | |
/(make|be) (more|less) (\w+) (when|for) (\w+)/i | |
]; | |
for (const pattern of patterns) { | |
const match = inputText.match(pattern); | |
if (match) { | |
const [, triggerType, trigger, action, response] = match; | |
storeBehaviorPattern(trigger, response, context); | |
return { | |
success: true, | |
triggerPhrases: [trigger], | |
response: enhanceResponse(response, context), | |
context: context | |
}; | |
} | |
} | |
// Fallback to Grok's adaptive learning | |
return adaptiveLearning(inputText); | |
} | |
// Grok-style diction analysis | |
function analyzeDiction(text) { | |
const words = text.toLowerCase().split(/\s+/); | |
const contractions = text.match(/\w+'?\w*/g) || []; | |
// Update diction profile | |
if (!trainingData.dictionProfiles.user) { | |
trainingData.dictionProfiles.user = { | |
wordUsage: {}, | |
contractionRate: 0, | |
formalityScore: 0, | |
complexityScore: 0 | |
}; | |
} | |
contractions.forEach(word => { | |
if (word.includes("'")) { | |
trainingData.dictionProfiles.user.contractionRate++; | |
} | |
}); | |
// Word usage stats | |
words.forEach(word => { | |
trainingData.dictionProfiles.user.wordUsage[word] = | |
(trainingData.dictionProfiles.user.wordUsage[word] || 0) + 1; | |
}); | |
// Save updated profile | |
localStorage.setItem('AI_DictionProfile', JSON.stringify(trainingData.dictionProfiles)); | |
} | |
function interpretTrainingIntent(text) { | |
const lower = text.toLowerCase(); | |
if (lower.includes('family') || lower.includes('mom') || lower.includes('dad')) { | |
return trainingData.customResponses.personal; | |
} | |
else if (lower.includes('work') || lower.includes('business') || lower.includes('colleague')) { | |
return trainingData.customResponses.business; | |
} | |
else if (lower.includes('appointment') || lower.includes('schedule')) { | |
return trainingData.customResponses.appointments; | |
} | |
else if (lower.includes('urgent') || lower.includes('emergency')) { | |
return trainingData.customResponses.urgent; | |
} | |
else if (lower.includes('callback') || lower.includes('call back')) { | |
return trainingData.customResponses.callbacks; | |
} | |
else if (lower.includes('spam') || lower.includes('scam') || lower.includes('block')) { | |
return trainingData.customResponses.spam; | |
} | |
else { | |
return detectNewPattern(text); | |
} | |
} | |
function detectNewPattern(text) { | |
// Use simple NLP to extract key phrases | |
const keywords = text.match(/\b(\w{4,})\b/g) || []; | |
const commands = ['transfer', 'ask', 'tell', 'say', 'respond', 'record']; | |
const action = commands.find(cmd => text.toLowerCase().includes(cmd)) || 'handle'; | |
const context = keywords.filter(w => | |
!commands.includes(w.toLowerCase()) && | |
w.length > 3 | |
).join(', '); | |
return `When call relates to ${context || "this situation"}, I will ${action} accordingly.`; | |
} | |
// Initialize when page loads | |
document.addEventListener('DOMContentLoaded', () => { | |
loadSettings(); | |
// Load saved training data | |
const savedData = localStorage.getItem('AI_Training'); | |
if (savedData) { | |
trainingData = JSON.parse(savedData); | |
} | |
document.getElementById('saveTraining').addEventListener('click', saveTraining); | |
addAppearAnimations(); | |
simulateAIProgress(); | |
// Enhanced screen initialization | |
document.querySelectorAll('[onclick^="showScreen"]').forEach(btn => { | |
btn.addEventListener('click', function() { | |
const screenName = this.getAttribute('onclick').match(/'(.*?)'/)[1]; | |
setTimeout(() => { | |
if (screenName === 'trainingScreen') { | |
document.getElementById('trainingInput').focus(); | |
populateTrainingHistory(); | |
} | |
}, 300); | |
}); | |
}); | |
}); | |
// Mobile detailing knowledge base | |
const detailingKnowledge = { | |
website: "https://www.jaysmobilewash.com", | |
pricing: { | |
basic: { car: 60, suv: 70 }, | |
luxury: { car: 130, suv: 140 }, | |
max: { car: 200, suv: 210 } | |
}, | |
packages: { | |
basic: "2-Step Hand Wash, Tornador Blast, Rim Cleaning, Interior Wipe-Down", | |
luxury: "Basic + Ceramic Wax, Dust Repellent, Vinyl Restoration", | |
max: "Luxury + Graphene Wax, Steam Sanitization, Leather Conditioning" | |
}, | |
features: [ | |
"Eco-Friendly Self-Sufficient Service", | |
"Deionized Spot-Free Water", | |
"Tornador Z-007 Compressed Air Cleaning", | |
"Customizable Packages" | |
] | |
}; | |
function handleChatKeyPress(e) { | |
if (e.key === 'Enter') { | |
submitChatMessage(); | |
} | |
} | |
function submitChatMessage() { | |
const input = document.getElementById('chatInput'); | |
if (input.value.trim() !== '') { | |
// Add user message | |
const chatContainer = document.getElementById('chatMessages'); | |
const userBubble = document.createElement('div'); | |
userBubble.className = 'user-bubble mt-4 animate-fadeIn'; | |
userBubble.innerHTML = `<p>${input.value}</p>`; | |
chatContainer.appendChild(userBubble); | |
// Process and generate AI response | |
setTimeout(() => { | |
const aiResponse = generateAIResponse(input.value); | |
const aiBubble = document.createElement('div'); | |
aiBubble.className = 'ai-bubble mt-4 animate-fadeIn'; | |
aiBubble.innerHTML = `<p>${aiResponse}</p>`; | |
chatContainer.appendChild(aiBubble); | |
chatContainer.scrollTop = chatContainer.scrollHeight; | |
// Learn from the interaction | |
learnFromChat(input.value, aiResponse); | |
}, 500); | |
input.value = ''; | |
} | |
} | |
function generateAIResponse(message) { | |
const lowerMsg = message.toLowerCase(); | |
// Check for pricing questions | |
if (lowerMsg.includes('price') || lowerMsg.includes('cost') || lowerMsg.includes('how much')) { | |
if (lowerMsg.includes('basic')) { | |
return `Our Basic package is ${detailingKnowledge.pricing.basic.car} for cars and ${detailingKnowledge.pricing.basic.suv} for SUVs. It includes: ${detailingKnowledge.packages.basic}`; | |
} else if (lowerMsg.includes('luxury')) { | |
return `Our Luxury package is ${detailingKnowledge.pricing.luxury.car} for cars and ${detailingKnowledge.pricing.luxury.suv} for SUVs. Includes: ${detailingKnowledge.packages.luxury}`; | |
} else if (lowerMsg.includes('max')) { | |
return `Our Max package is ${detailingKnowledge.pricing.max.car} for cars and ${detailingKnowledge.pricing.max.suv} for SUVs. Everything in: ${detailingKnowledge.packages.max}`; | |
} | |
return `We offer three main packages:\nBasic: ${detailingKnowledge.pricing.basic.car}-${detailingKnowledge.pricing.basic.suv}\nLuxury: ${detailingKnowledge.pricing.luxury.car}-${detailingKnowledge.pricing.luxury.suv}\nMax: ${detailingKnowledge.pricing.max.car}-${detailingKnowledge.pricing.max.suv}`; | |
} | |
// Check for service questions | |
if (lowerMsg.includes('service') || lowerMsg.includes('include') || lowerMsg.includes('wash')) { | |
return `Our services include:\n- ${detailingKnowledge.features.join('\n- ')}\n\nWould you like details on a specific package?`; | |
} | |
// Check for appointment scheduling | |
if (lowerMsg.includes('book') || lowerMsg.includes('schedule') || lowerMsg.includes('appointment')) { | |
return `To schedule an appointment, please call or text us at (562) 228-9429 with your preferred date, time, and package selection.`; | |
} | |
// Check for website questions | |
if (lowerMsg.includes('website') || lowerMsg.includes('online')) { | |
return `You can find more information on our website: ${detailingKnowledge.website}`; | |
} | |
// Default response if no matches | |
return `I'm still learning about Jay's Mobile Wash. Could you clarify your question or teach me the correct response? For example:\n- "For basic washes, say 'Our Basic package starts at $60'"\n\nYou can also visit our website: ${detailingKnowledge.website}`; | |
} | |
function learnFromChat(message, response) { | |
// Save new knowledge | |
if (!trainingData.detailingKnowledge) { | |
trainingData.detailingKnowledge = []; | |
} | |
trainingData.detailingKnowledge.push({ | |
question: message, | |
answer: response, | |
timestamp: new Date().toISOString() | |
}); | |
localStorage.setItem('AI_Training', JSON.stringify(trainingData)); | |
} | |
function populateTrainingHistory() { | |
const chatContainer = document.querySelector('#trainingScreen .flex-1.overflow-y-auto'); | |
chatContainer.innerHTML = ''; | |
if (trainingData.responses.length === 0) { | |
const welcomeBubble = document.createElement('div'); | |
welcomeBubble.className = 'ai-bubble animate-fadeIn'; | |
welcomeBubble.innerHTML = ` | |
<p>Hi! I'm your call assistant. Teach me how to handle calls by:</p> | |
<ol class="list-decimal pl-5 mt-2 space-y-1"> | |
<li>Setting response templates</li> | |
<li>Training me on specific call types</li> | |
<li>Testing responses in real calls</li> | |
</ol> | |
<p class="mt-2">Try saying something like: "If caller says 'urgent', mark as important"</p> | |
`; | |
chatContainer.appendChild(welcomeBubble); | |
} else { | |
trainingData.responses.forEach(item => { | |
const userBubble = document.createElement('div'); | |
userBubble.className = 'user-bubble mt-4 animate-fadeIn'; | |
userBubble.innerHTML = `<p>${item}</p>`; | |
chatContainer.appendChild(userBubble); | |
}); | |
} | |
} | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=jjmandog/jaysx" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |