Spaces:
Sleeping
Sleeping
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>TAJ HOTEL CHATBOT</title> | |
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet"> | |
<script src="https://code.responsivevoice.org/responsivevoice.js?key=q1DbMp6Z"></script> | |
<style> | |
:root { | |
--primary-color: #007bff; /* Default blue */ | |
--bot-message-bg: #f0f2f5; /* Light Gray */ | |
--user-message-bg: #007bff; /* User Blue */ | |
--user-message-text: #fff; /* User Message White */ | |
--accent-color: #6a0dad; /* Default Purple */ | |
--background-color: #fff; /* Default Background White */ | |
--shadow-color: rgba(0, 0, 0, 0.2); /* Default Shadow */ | |
--input-bg: #f0f2f5; /* Default Input Background */ | |
--input-border: #ccc; /* Default Input Border */ | |
} | |
/* Themes */ | |
.theme-calm-azure { | |
--background-color: #E3F2FD; | |
--bot-message-bg: #BBDEFB; | |
--user-message-bg: #2196F3; | |
--user-message-text: #FFFFFF; | |
--input-bg: #FFFFFF; | |
--input-border: #BDBDBD; | |
--accent-color: #1976D2; | |
} | |
.theme-elegant-charcoal { | |
--background-color: #263238; | |
--bot-message-bg: #37474F; | |
--user-message-bg: #FF5722; | |
--user-message-text: #FFFFFF; | |
--input-bg: #455A64; | |
--input-border: #CFD8DC; | |
--accent-color: #FF9800; | |
} | |
.theme-fresh-greenery { | |
--background-color: #E8F5E9; | |
--bot-message-bg: #C8E6C9; | |
--user-message-bg: #4CAF50; | |
--user-message-text: #FFFFFF; | |
--input-bg: #FFFFFF; | |
--input-border: #A5D6A7; | |
--accent-color: #388E3C; | |
} | |
.theme-soft-lavender { | |
--background-color: #F3E5F5; | |
--bot-message-bg: #E1BEE7; | |
--user-message-bg: #9C27B0; | |
--user-message-text: #FFFFFF; | |
--input-bg: #FFFFFF; | |
--input-border: #D1C4E9; | |
--accent-color: #7B1FA2; | |
} | |
.theme-bright-summer { | |
--background-color: #FFEB3B; | |
--bot-message-bg: #FFF9C4; | |
--user-message-bg: #F44336; | |
--user-message-text: #FFFFFF; | |
--input-bg: #FFFFFF; | |
--input-border: #FBC02D; | |
--accent-color: #C62828; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
body { | |
font-family: 'Roboto', sans-serif; | |
background-color: var(--background-color); | |
transition: background 0.5s ease; | |
overflow: hidden; /* Prevent scroll on body */ | |
} | |
.container { | |
display: flex; | |
flex-direction: column; | |
height: 100vh; | |
width: 100%; | |
overflow: hidden; /* Prevent scroll on container */ | |
} | |
/* Header */ | |
.header { | |
background: var(--accent-color); | |
color: #fff; | |
font-size: 1.5rem; | |
font-weight: 700; | |
text-align: center; | |
padding: 20px; | |
box-shadow: 0 4px 8px var(--shadow-color); | |
position: relative; | |
z-index: 1000; | |
} | |
/* Chatbox */ | |
.chat-box { | |
flex: 1; | |
display: flex; | |
flex-direction: column; | |
overflow-y: auto; | |
padding: 20px; | |
background: linear-gradient(to bottom right, #f5f7fa, #c3cfe2); | |
border-radius: 10px; | |
margin: 20px; | |
box-shadow: 0 4px 8px var(--shadow-color); | |
position: relative; | |
z-index: 10; | |
} | |
.message { | |
max-width: 75%; | |
padding: 12px 18px; | |
border-radius: 20px; | |
box-shadow: 0 3px 6px var(--shadow-color); | |
margin-bottom: 10px; | |
opacity: 0; | |
animation: fadeIn 0.3s forwards; /* Changed to forwards for delay effect */ | |
} | |
.user-message { | |
align-self: flex-end; | |
background: var(--user-message-bg); | |
color: var(--user-message-text); | |
border-radius: 15px 20px 20px 20px; | |
animation: slideInRight 0.5s forwards; /* Sliding effect on user message */ | |
} | |
.bot-message { | |
align-self: flex-start; | |
background: var(--bot-message-bg); | |
color: #333; | |
border-radius: 20px 15px 20px 20px; | |
animation: slideInLeft 0.5s forwards; /* Sliding effect on bot message */ | |
} | |
/* Footer */ | |
.footer { | |
background: #ffffff; | |
padding: 15px; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
box-shadow: 0 -4px 8px var(--shadow-color); | |
position: relative; | |
z-index: 1000; | |
} | |
.footer input[type="text"] { | |
width: 75%; | |
padding: 15px; | |
border: 1px solid var(--input-border); | |
border-radius: 20px; | |
margin-right: 10px; | |
box-shadow: 0 2px 4px var(--shadow-color); | |
transition: border 0.3s, box-shadow 0.3s; /* Added shadow transition */ | |
background-color: var(--input-bg); | |
outline: none; | |
} | |
.footer input[type="text"]:focus { | |
border-color: var(--accent-color); | |
box-shadow: 0 0 10px var(--accent-color); | |
} | |
button { | |
background: var(--accent-color); | |
color: #fff; | |
border: none; | |
padding: 10px 20px; | |
border-radius: 20px; | |
font-size: 1rem; | |
cursor: pointer; | |
box-shadow: 0 4px 10px var(--shadow-color); | |
transition: background 0.3s ease, transform 0.2s ease, box-shadow 0.2s ease; | |
} | |
button:hover { | |
background: #4b0082; | |
transform: scale(1.05); | |
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); /* Shadow effect on hover */ | |
} | |
/* Settings */ | |
.settings { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
padding: 10px; | |
background: #f0f2f5; | |
box-shadow: 0 2px 5px var(--shadow-color); | |
position: relative; | |
z-index: 1000; | |
} | |
.color-picker, | |
.theme-toggle { | |
display: flex; | |
align-items: center; | |
position:relative; | |
} | |
.color-circle { | |
width: 20px; | |
height: 20px; | |
border-radius: 50%; | |
margin: 0 5px; | |
cursor: pointer; | |
box-shadow: 0 2px 5px var(--shadow-color); | |
transition: transform 0.3s; /* Adding circle hover effect */ | |
} | |
.color-circle:hover { | |
transform: scale(1.2); /* Scale up on hover */ | |
} | |
/* Animations */ | |
@keyframes fadeIn { | |
from { | |
opacity: 0; | |
transform: translateY(20px); | |
} | |
to { | |
opacity: 1; | |
transform: translateY(0); | |
} | |
} | |
@keyframes slideInRight { | |
from { | |
opacity: 0; | |
transform: translateX(100%); | |
} | |
to { | |
opacity: 1; | |
transform: translateX(0); | |
} | |
} | |
@keyframes slideInLeft { | |
from { | |
opacity: 0; | |
transform: translateX(-100%); | |
} | |
to { | |
opacity: 1; | |
transform: translateX(0); | |
} | |
} | |
/* Background animation */ | |
@keyframes backgroundAnimate { | |
0% { | |
background-color: rgba(255, 255, 255, 0.05); | |
} | |
50% { | |
background-color: rgba(255, 255, 255, 0.1); | |
} | |
100% { | |
background-color: rgba(255, 255, 255, 0.05); | |
} | |
} | |
/* VFX related styles */ | |
.vfx { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
pointer-events: none; | |
animation: backgroundAnimate 5s infinite; /* Continuously animate background */ | |
z-index: 0; /* Background layer */ | |
} | |
</style> | |
</head> | |
<body> | |
<div class="vfx"></div> <!-- Background effects --> | |
<div class="container"> | |
<!-- Settings --> | |
<div class="settings"> | |
<div class="theme-toggle"> | |
<label for="theme-select">Select Theme:</label> | |
<select id="theme-select"> | |
<option value="default">Default</option> | |
<option value="calm-azure">Calm Azure</option> | |
<option value="elegant-charcoal">Elegant Charcoal</option> | |
<option value="fresh-greenery">Fresh Greenery</option> | |
<option value="soft-lavender">Soft Lavender</option> | |
<option value="bright-summer">Bright Summer</option> | |
</select> | |
</div> | |
<div> | |
<!-- Language dropdown --> | |
<label for="language-select">Select Language:</label> | |
<select id="language-select"> | |
<option value="english">English</option> | |
<option value="hindi">Hindi</option> | |
<option value="bengali">Bengali</option> | |
<option value="telugu">Telugu</option> | |
<option value="marathi">Marathi</option> | |
<option value="tamil">Tamil</option> | |
<option value="gujarati">Gujarati</option> | |
<option value="kannada">Kannada</option> | |
<option value="malayalam">Malayalam</option> | |
<option value="punjabi">Punjabi</option> | |
<option value="odia">Odia</option> | |
<option value="urdu">Urdu</option> | |
<option value="assamese">Assamese</option> | |
<option value="sanskrit">Sanskrit</option> | |
<option value="arabic">Arabic</option> | |
<option value="chinese">Chinese</option> | |
<option value="dutch">Dutch</option> | |
<option value="french">French</option> | |
<option value="filipino">Filipino</option> | |
<option value="greek">Greek</option> | |
<option value="indonesian">Indonesian</option> | |
<option value="italian">Italian</option> | |
<option value="japanese">Japanese</option> | |
<option value="korean">Korean</option> | |
<option value="latin">Latin</option> | |
<option value="nepali">Nepali</option> | |
<option value="portuguese">Portuguese</option> | |
<option value="romanian">Romanian</option> | |
<option value="russian">Russian</option> | |
<option value="spanish">Spanish</option> | |
<option value="swedish">Swedish</option> | |
<option value="thai">Thai</option> | |
<option value="ukrainian">Ukrainian</option> | |
<option value="turkish">Turkish</option> | |
</select> | |
</div> | |
<div class="color-picker"> | |
<label>Accent Color:</label> | |
<div class="color-circle" style="background-color: #6a0dad;" onclick="changeColor('#6a0dad')"></div> | |
<div class="color-circle" style="background-color: #ff4500;" onclick="changeColor('#ff4500')"></div> | |
<div class="color-circle" style="background-color: #007bff;" onclick="changeColor('#007bff')"></div> | |
<div class="color-circle" style="background-color: #28a745;" onclick="changeColor('#28a745')"></div> | |
</div> | |
</div> | |
<!-- Header --> | |
<div class="header">TAJ HOTEL CHATBOT</div> | |
<!-- Chatbox --> | |
<div class="chat-box" id="chat-box"></div> | |
<!-- Footer --> | |
<div class="footer"> | |
<input type="text" id="user-input" placeholder="Type your message..." /> | |
<button id="send-btn">Send</button> | |
<button id="voice-btn">🎤 Start Voice Input</button> | |
</div> | |
</div> | |
<script> | |
const chatBox = document.getElementById('chat-box'); | |
const voiceBtn = document.getElementById('voice-btn'); | |
const sendBtn = document.getElementById('send-btn'); | |
const userInput = document.getElementById('user-input'); | |
const themeSelect = document.getElementById('theme-select'); | |
const languageSelect = document.getElementById('language-select'); | |
// Add message to chatbox | |
function addMessage(sender, text) { | |
const msgDiv = document.createElement('div'); | |
msgDiv.classList.add('message', sender); | |
msgDiv.textContent = text; | |
chatBox.appendChild(msgDiv); | |
chatBox.scrollTop = chatBox.scrollHeight; // Scroll to the bottom of the chat | |
} | |
// Initialize speech recognition | |
const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)(); | |
function setRecognitionLanguage() { | |
const selectedLanguage = languageSelect.value; | |
switch (selectedLanguage) { | |
case 'telugu': recognition.lang = 'te-IN'; break; | |
case 'hindi': recognition.lang = 'hi-IN'; break; | |
case 'bengali': recognition.lang = 'bn-IN'; break; | |
case 'marathi': recognition.lang = 'mr-IN'; break; | |
case 'tamil': recognition.lang = 'ta-IN'; break; | |
case 'gujarati': recognition.lang = 'gu-IN'; break; | |
case 'kannada': recognition.lang = 'kn-IN'; break; | |
case 'malayalam': recognition.lang = 'ml-IN'; break; | |
case 'punjabi': recognition.lang = 'pa-IN'; break; | |
case 'odia': recognition.lang = 'or-IN'; break; | |
case 'urdu': recognition.lang = 'ur-IN'; break; | |
case 'assamese': recognition.lang = 'as-IN'; break; | |
case 'sanskrit': recognition.lang = 'sa-IN'; break; | |
case 'arabic': recognition.lang = 'ar-SA'; break; | |
case 'chinese': recognition.lang = 'zh-CN'; break; | |
case 'dutch': recognition.lang = 'nl-NL'; break; | |
case 'french': recognition.lang = 'fr-FR'; break; | |
case 'filipino': recognition.lang = 'fil-PH'; break; | |
case 'greek': recognition.lang = 'el-GR'; break; | |
case 'indonesian': recognition.lang = 'id-ID'; break; | |
case 'italian': recognition.lang = 'it-IT'; break; | |
case 'japanese': recognition.lang = 'ja-JP'; break; | |
case 'korean': recognition.lang = 'ko-KR'; break; | |
case 'latin': recognition.lang = 'la'; break; | |
case 'nepali': recognition.lang = 'ne-NP'; break; | |
case 'portuguese': recognition.lang = 'pt-PT'; break; | |
case 'romanian': recognition.lang = 'ro-RO'; break; | |
case 'russian': recognition.lang = 'ru-RU'; break; | |
case 'spanish': recognition.lang = 'es-ES'; break; | |
case 'swedish': recognition.lang = 'sv-SE'; break; | |
case 'thai': recognition.lang = 'th-TH'; break; | |
case 'ukrainian': recognition.lang = 'uk-UA'; break; | |
case 'turkish': recognition.lang = 'tr-TR'; break; | |
case 'english': | |
default: recognition.lang = 'en-US'; break; // Default to English | |
} | |
} | |
// Event listener for voice input button | |
voiceBtn.addEventListener('click', () => { | |
setRecognitionLanguage(); // Set language | |
recognition.start(); // Start recognition | |
}); | |
// Handle results from speech recognition | |
recognition.addEventListener('result', (e) => { | |
const transcript = e.results[0][0].transcript; | |
addMessage('user-message', transcript); | |
sendUserMessage(transcript); | |
}); | |
// Handle errors in speech recognition | |
recognition.addEventListener('error', (event) => { | |
console.error("Speech recognition error", event); | |
}); | |
// Change the accent color | |
function changeColor(color) { | |
document.documentElement.style.setProperty('--accent-color', color); | |
} | |
// Change the theme | |
function changeTheme(theme) { | |
document.documentElement.classList.remove('theme-calm-azure', 'theme-elegant-charcoal', 'theme-fresh-greenery', 'theme-soft-lavender', 'theme-bright-summer'); | |
if (theme !== 'default') { | |
document.documentElement.classList.add('theme-' + theme); | |
} | |
} | |
// Function to send user input and selected language to backend | |
function sendUserMessage(message) { | |
const selectedLanguage = languageSelect.value; // Get the selected language | |
// Send the message and selected language to the backend | |
fetch('/chat', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
message, | |
language: selectedLanguage, // Include the selected language in the request body | |
}), | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
const botResponse = data.response; | |
addMessage('bot-message', botResponse); | |
speakResponse(botResponse, selectedLanguage); | |
}) | |
.catch(error => { | |
console.error("Error:", error); | |
addMessage('bot-message', "Sorry, I couldn't process that."); | |
}); | |
} | |
// // Function to get the voice list and match the language | |
// function getVoiceForLanguage(lang) { | |
// const voices = window.speechSynthesis.getVoices(); | |
// const matchingVoice = voices.find(voice => voice.lang === lang); // Match exact language code | |
// return matchingVoice || null; // Return first match or null if not found | |
// } | |
// // Text-to-Speech function | |
// function speak(text, lang) { | |
// const utterance = new SpeechSynthesisUtterance(text); | |
// const selectedVoice = getVoiceForLanguage(lang); | |
// if (selectedVoice) { | |
// utterance.voice = selectedVoice; // Set the matching voice | |
// utterance.lang = lang; // Set the language | |
// } else { | |
// console.warn(`No voice found for language: ${lang}. Falling back to default.`); | |
// utterance.lang = 'en-US'; // Fallback to English | |
// } | |
// utterance.pitch = 1; // Set pitch | |
// utterance.rate = 1; // Set rate | |
// window.speechSynthesis.speak(utterance); // Speak the text | |
// } | |
// // Language Handling Function | |
// function speakResponse(text, selectedLanguage) { | |
// let lang; | |
// switch (selectedLanguage) { | |
// case 'hindi': lang = 'hi-IN'; break; | |
// case 'bengali': lang = 'bn-IN'; break; | |
// case 'telugu': lang = 'te-IN'; break; | |
// case 'marathi': lang = 'mr-IN'; break; | |
// case 'tamil': lang = 'ta-IN'; break; | |
// case 'gujarati': lang = 'gu-IN'; break; | |
// case 'kannada': lang = 'kn-IN'; break; | |
// case 'malayalam': lang = 'ml-IN'; break; | |
// case 'punjabi': lang = 'pa-IN'; break; | |
// case 'odia': lang = 'or-IN'; break; | |
// case 'urdu': lang = 'ur-IN'; break; | |
// case 'assamese': lang = 'as-IN'; break; | |
// case 'sanskrit': lang = 'sa-IN'; break; | |
// default: lang = 'en-US'; break; // English (default) | |
// } | |
// speak(text, lang); // Call the speak function with the determined language | |
// } | |
// // Ensure voices are loaded before running the TTS | |
// window.speechSynthesis.onvoiceschanged = () => { | |
// const voices = window.speechSynthesis.getVoices(); | |
// voices.forEach(voice => { | |
// console.log(`Voice: ${voice.name}, Language: ${voice.lang}`); | |
// }); | |
// }; | |
// // Function to initialize and fetch voices | |
// function initializeVoices() { | |
// return new Promise((resolve) => { | |
// const voices = window.speechSynthesis.getVoices(); | |
// if (voices.length) { | |
// resolve(voices); | |
// } else { | |
// window.speechSynthesis.onvoiceschanged = () => { | |
// resolve(window.speechSynthesis.getVoices()); | |
// }; | |
// } | |
// }); | |
// } | |
// // Function to get the voice for a given language | |
// function getVoiceForLanguage(lang, voices) { | |
// const voice = voices.find(voice => voice.lang === lang); | |
// if (voice) { | |
// return voice; | |
// } | |
// console.warn(`No voice found for language: ${lang}.`); | |
// return null; | |
// } | |
// // Text-to-Speech function | |
// async function speak(text, lang) { | |
// const voices = await initializeVoices(); | |
// const selectedVoice = getVoiceForLanguage(lang, voices); | |
// const utterance = new SpeechSynthesisUtterance(text); | |
// if (selectedVoice) { | |
// utterance.voice = selectedVoice; | |
// utterance.lang = selectedVoice.lang; | |
// } else { | |
// console.warn(`Falling back to default language.`); | |
// utterance.lang = 'en-US'; | |
// } | |
// utterance.pitch = 1; // Set pitch | |
// utterance.rate = 1; // Set rate | |
// window.speechSynthesis.speak(utterance); // Speak the text | |
// } | |
// Language Handling Function | |
function speakResponse(text, selectedLanguage) { | |
// Dictionary mapping specified languages to their respective voices | |
const languageVoiceMap = { | |
hindi: 'Hindi Female', | |
tamil: 'Tamil Female', | |
arabic: 'Arabic Female', | |
chinese: 'Chinese Female', | |
dutch: 'Dutch Female', | |
french: 'French Female', | |
filipino: 'Filipino Female', | |
greek: 'Greek Female', | |
indonesian: 'Indonesian Female', | |
italian: 'Italian Female', | |
japanese: 'Japanese Female', | |
korean: 'Korean Female', | |
portuguese: 'Portuguese Female', | |
romanian: 'Romanian Female', | |
russian: 'Russian Female', | |
spanish: 'Spanish Female', | |
swedish: 'Swedish Female', | |
thai: 'Thai Female', | |
ukrainian: 'Ukrainian Female', | |
turkish: 'Turkish Female' | |
}; | |
// Get the voice for the selected language | |
const voice = languageVoiceMap[selectedLanguage.toLowerCase()]; | |
// Check if the language has a specified voice | |
if (voice) { | |
responsiveVoice.speak(text, voice); | |
} else { | |
// Use default behavior for unspecified languages | |
responsiveVoice.speak(text); | |
} | |
} | |
// // Test voices and log them | |
// initializeVoices().then(voices => { | |
// console.log("Available voices:"); | |
// voices.forEach(voice => console.log(`Voice: ${voice.name}, Language: ${voice.lang}`)); | |
// }); | |
// Event listeners for buttons | |
sendBtn.addEventListener('click', () => { | |
const message = userInput.value.trim(); | |
if (message) { | |
addMessage('user-message', message); | |
sendUserMessage(message); | |
userInput.value = ''; // Clear input field after sending | |
} | |
}); | |
// Handle pressing 'Enter' key for sending messages | |
userInput.addEventListener('keypress', (e) => { | |
if (e.key === 'Enter') { | |
sendBtn.click(); // Trigger button click | |
} | |
}); | |
// Update theme when selected from dropdown | |
themeSelect.addEventListener('change', (e) => { | |
changeTheme(e.target.value); | |
}); | |
</script> | |
</body> | |
</html> |