jaysx / index.html
jjmandog's picture
I want you to click every button and make sure it works. I want all the coded information given to work properly . Fix any errors. Every button that I click doesn’t work and it needs to work - Follow Up Deployment
33ad90f verified
<!DOCTYPE html>
<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(showNotification = true) {
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>
<!-- Text 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)">
<div class="flex gap-2">
<button class="w-12 h-12 rounded-xl bg-blue-500 flex items-center justify-center text-white" onclick="submitTextTraining()">
<i class="fas fa-keyboard"></i>
</button>
<button class="w-12 h-12 rounded-xl bg-purple-500 flex items-center justify-center text-white" onclick="showScreen('voiceTrainingScreen')">
<i class="fas fa-microphone"></i>
</button>
</div>
</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>
<!-- Enhanced Navigation Tab Bar -->
<div class="tab-bar fixed inset-x-0 bottom-0 bg-white dark:bg-gray-800 shadow-lg p-2 flex justify-around items-center border-t border-gray-200 dark:border-gray-700">
<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>
<!-- Voice Training Screen -->
<div id="voiceTrainingScreen" 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('trainingScreen')">
<i class="fas fa-arrow-left"></i>
</button>
<div class="ml-2">
<h2 class="text-xl font-bold">Voice Training</h2>
<p class="text-gray-500 dark:text-gray-400 text-sm -mt-1">Train vocal responses</p>
</div>
</div>
</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 id="voiceFeedback" class="flex-1 overflow-y-auto pb-4">
<div class="ai-bubble">
<p>Let's train your AI's verbal responses. Start by saying sample phrases you'd like it to use.</p>
</div>
</div>
<div class="mt-auto pt-4 border-t border-gray-200 dark:border-gray-700">
<div class="flex flex-col gap-3">
<div class="flex gap-2">
<button id="startRecording" class="flex-1 h-12 rounded-xl bg-red-500 text-white" onclick="startVoiceTraining()">
<i class="fas fa-microphone mr-2"></i> Record Response
</button>
<button class="w-12 h-12 rounded-xl bg-gray-200 flex items-center justify-center" onclick="playLastResponse()">
<i class="fas fa-play"></i>
</button>
</div>
<div class="text-center">
<p class="text-xs text-gray-500 dark:text-gray-400">Analyzing: Tone, Clarity, Pace</p>
</div>
</div>
</div>
</div>
</div>
</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>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="saveCallTimings()" class="mt-6 w-full bg-green-500 text-white py-2 rounded-lg font-medium">Save Call Timing Settings</button>
<button onclick="document.getElementById('directPhoneLink').click()" class="mt-4 w-full bg-blue-500 text-white py-2 rounded-lg font-medium flex items-center justify-center">
<i class="fas fa-phone mr-2"></i> Test Phone Connection
</button>
</div>
</div>
</div>
<!-- Floating Action Button -->
<div class="fab" onclick="answerCall()">
<i class="fas fa-phone"></i>
</div>
</div>
<script>
// Enhanced Training Data Structure
let trainingData = {
// Text-based training
textTraining: {
responseTemplates: {},
patternMatching: {},
contextRules: {},
learningMetrics: {
responseAccuracy: 0.85,
confidenceScores: {}
}
},
// Voice-based training
voiceTraining: {
speechProfiles: {},
toneAnalysis: {},
voiceResponses: [],
pronunciation: {}
},
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));
}
// Navigation System
function showScreen(screenId) {
const screens = document.querySelectorAll('.screen');
screens.forEach(screen => {
screen.classList.remove('active');
});
const targetScreen = document.getElementById(screenId);
if (targetScreen) {
targetScreen.classList.add('active');
if (screenId === 'settingsScreen') {
loadSettings();
} else if (screenId === 'trainingScreen') {
populateTrainingHistory();
document.getElementById('trainingInput').focus();
}
}
// Update tab bar styling
const tabLabels = {
'homeScreen': 0,
'repliesScreen': 1,
'trainingScreen': 2,
'settingsScreen': 3
};
const tabs = document.querySelectorAll('.tab-bar button');
const tabIndex = tabLabels[screenId] || 0;
tabs.forEach((tab, index) => {
tab.classList.toggle('text-accent', index === tabIndex);
tab.classList.toggle('text-gray-500', index !== tabIndex);
tab.classList.toggle('font-medium', index === tabIndex);
});
// Screen-specific initialization
switch(screenId) {
case 'settingsScreen':
loadSettings();
break;
case 'trainingScreen':
initTraining();
break;
case 'voiceTrainingScreen':
initVoiceTraining();
break;
}
// Save last viewed screen
localStorage.setItem('lastScreen', screenId);
}
// Save call timing settings to localStorage
function saveCallTimings() {
businessSettings.maxRingTime = parseInt(document.getElementById('maxRingTime').value);
businessSettings.smsResponseTime = parseInt(document.getElementById('smsResponseTime').value);
businessSettings.businessHours = {
open: document.getElementById('openTime').value,
close: document.getElementById('closeTime').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 = 'Call timings saved successfully!';
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
}
// 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)';
showResponseMessage(`Call ringing (will answer in ${businessSettings.maxRingTime} seconds if no reply)...`);
setTimeout(() => {
if (icon.classList.contains('fa-stop')) {
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 {
icon.classList.remove('fa-stop');
icon.classList.add('fa-phone');
fab.style.background = 'linear-gradient(135deg, #0a84ff, #5e5ce6)';
}
// Log this interaction for learning
const callLog = {
timestamp: new Date().toISOString(),
number: customNumber || (isTest ? 'Test Caller' : 'Unknown'),
scenario,
duration: businessSettings.maxRingTime,
response: businessSettings.personalGreeting,
outcome: 'answered'
};
trainingData.callHistory = trainingData.callHistory || [];
trainingData.callHistory.push(callLog);
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') {
submitTextTraining();
}
}
function submitTextTraining() {
const input = document.getElementById('trainingInput');
if (input.value.trim()) {
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);
setTimeout(() => {
const aiBubble = document.createElement('div');
aiBubble.className = 'ai-bubble mt-4 animate-fadeIn';
aiBubble.innerHTML = `<p>Understood! I'll handle calls with: "${input.value}"</p>`;
chatContainer.appendChild(aiBubble);
chatContainer.scrollTop = chatContainer.scrollHeight;
trainingData.textTraining.responseTemplates[Date.now()] = input.value;
localStorage.setItem('AI_Training', JSON.stringify(trainingData));
}, 500);
input.value = '';
}
}
// Advanced Reasoning Engine
function processTrainingInput(inputText) {
// Use NLP to analyze input
const tokens = inputText.toLowerCase().split(/\s+/);
const intent = detectIntent(inputText);
const context = buildContext(inputText);
// Apply reasoning rules
const reasoningChain = buildReasoningChain(intent, context);
// Generate response variants
const responseOptions = generateResponseVariants(intent, context);
return {
success: true,
intent: intent,
reasoning: reasoningChain,
responseVariants: responseOptions,
confidence: 0.92, // AI's confidence in this solution
suggestedActions: generateFollowUpQuestions(intent)
};
}
function detectIntent(text) {
// Enhanced intent detection with fuzzy matching
const normalized = text.toLowerCase();
// Business vs personal detection
if (/business|client|customer|service/i.test(normalized)) {
return 'business_call';
} else if (/family|friend|personal/i.test(normalized)) {
return 'personal_call';
}
// Action detection
if (/transfer|connect|put through/i.test(normalized)) {
return 'call_transfer';
} else if (/message|text|notify/i.test(normalized)) {
return 'message_relay';
}
// Default to learning new response
return 'new_response_pattern';
}
function buildReasoningChain(intent, context) {
// Build logical reasoning steps
const chains = {
'business_call': [
"Detected business context → Using formal tone",
"Verified working hours → Will mention availability",
"Analyzed keywords → Focus on professional responses"
],
'personal_call': [
"Identified personal connection → Using friendly tone",
"Checked relationship markers → Adjusting familiarity level",
"Assessed urgency → Determining response priority"
]
};
return chains[intent] || [
"No specific pattern found → Learning new behavior",
"Analyzing word frequency → Building response map",
"Cross-referencing with existing knowledge → Creating adaptive response"
];
}
// 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
// Voice Training System
let voiceRecording = false;
let mediaRecorder;
let audioChunks = [];
function startVoiceTraining() {
const button = document.getElementById('startRecording');
if (!voiceRecording) {
button.innerHTML = '<i class="fas fa-stop mr-2"></i> Stop Recording';
button.classList.add('bg-red-600');
voiceRecording = true;
// Simulate recording (in a real app would use MediaRecorder API)
setTimeout(() => {
button.innerHTML = '<i class="fas fa-microphone mr-2"></i> Record Response';
button.classList.remove('bg-red-600');
voiceRecording = false;
processVoiceRecording();
}, 2000);
}
const button = document.getElementById('startRecording');
if (!voiceRecording) {
// Start recording
button.innerHTML = '<i class="fas fa-stop mr-2"></i> Stop Recording';
button.classList.add('bg-red-600');
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start();
voiceRecording = true;
mediaRecorder.ondataavailable = e => {
audioChunks.push(e.data);
};
mediaRecorder.onstop = () => {
processVoiceRecording();
};
});
} else {
// Stop recording
button.innerHTML = '<i class="fas fa-microphone mr-2"></i> Record Response';
button.classList.remove('bg-red-600');
mediaRecorder.stop();
voiceRecording = false;
}
}
function processVoiceRecording() {
const audioBlob = new Blob(audioChunks);
audioChunks = [];
// In a real implementation, you would send this to a voice processing API
const feedback = document.getElementById('voiceFeedback');
const bubble = document.createElement('div');
bubble.className = 'ai-bubble mt-4 animate-fadeIn';
bubble.innerHTML = `
<p>Recording received! Analysis:</p>
<ul class="ml-5 mt-2 list-disc">
<li>Tone: Professional</li>
<li>Clarity: 85%</li>
<li>Recommended pacing adjustment: Slightly slower</li>
</ul>
<p class="mt-2">Would you like to save this as a standard response?</p>
`;
feedback.appendChild(bubble);
// Save to training data
trainingData.voiceTraining.voiceResponses.push({
timestamp: new Date().toISOString(),
blob: URL.createObjectURL(audioBlob),
analysis: {
tone: 'professional',
clarity: 0.85,
pace: 0.72
}
});
localStorage.setItem('AI_Training', JSON.stringify(trainingData));
}
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', () => {
// Load settings immediately when page loads
if (localStorage.getItem('JMW_Settings')) {
businessSettings = JSON.parse(localStorage.getItem('JMW_Settings'));
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();
// Initialize with home screen
showScreen('homeScreen');
// Load settings when settings screen is shown
// Initialize tab buttons
document.querySelectorAll('.tab-bar button').forEach((tab, index) => {
tab.addEventListener('click', function() {
const screens = ['homeScreen', 'repliesScreen', 'trainingScreen', 'settingsScreen'];
showScreen(screens[index]);
});
});
// Initialize other interactive elements
document.querySelector('.fab').addEventListener('click', function() {
answerCall();
});
document.getElementById('saveTraining').addEventListener('click', saveTraining);
// Direct phone link initialization
const phoneLink = document.createElement('a');
phoneLink.href = 'tel:5622289429';
phoneLink.id = 'directPhoneLink';
document.body.appendChild(phoneLink);
});
// Save settings function
function saveSettings() {
businessSettings = {
maxRingTime: parseInt(document.getElementById('maxRingTime').value) || 30,
smsResponseTime: parseInt(document.getElementById('smsResponseTime').value) || 15,
responseLanguage: document.getElementById('responseLanguage').value || 'en',
personalGreeting: document.getElementById('personalGreeting').value || '',
businessHours: {
open: document.getElementById('openTime').value || '08:00',
close: document.getElementById('closeTime').value || '18:00'
},
responses: {
missedCall: {
en: document.getElementById('missedCallResponse').value || "Hello, this is Jay's Mobile Wash...",
es: document.getElementById('missedCallResponseEs').value || "Hola, es el lavado móvil de Jay..."
},
afterHours: {
en: document.getElementById('afterHoursResponse').value || "Thank you for contacting...",
es: document.getElementById('afterHoursResponseEs').value || "Gracias por contactar..."
}
}
};
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 = '<i class="fas fa-check-circle mr-2"></i> Settings saved successfully!';
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
// Test phone connection
document.getElementById('directPhoneLink').click();
}
// Initialize default data if empty
if (!trainingData) {
trainingData = {
textTraining: {},
voiceTraining: {},
customResponses: {},
detailingKnowledge: {
website: "https://www.jaysmobilewash.com",
pricing: {
basic: { car: 60, suv: 70 },
luxury: { car: 130, suv: 140 },
max: { car: 200, suv: 210 }
}
}
};
}
// 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>