Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Hotel Arcane 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> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| 'hotel-primary': '#1F2937', | |
| 'hotel-secondary': '#4B5563', | |
| 'hotel-accent': '#1D4ED8', | |
| }, | |
| spacing: { | |
| 'chat-height': '32rem', | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(4px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .message { | |
| animation: fadeIn 0.2s ease-out forwards; | |
| } | |
| .chat-log::-webkit-scrollbar { | |
| width: 4px; | |
| } | |
| .chat-log::-webkit-scrollbar-thumb { | |
| background: #E5E7EB; | |
| border-radius: 2px; | |
| } | |
| .input-focus { | |
| transition: all 0.2s ease; | |
| box-shadow: 0 0 0 2px rgba(29, 78, 216, 0.1); | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen flex items-center justify-center p-4"> | |
| <div id="chat-container" class="w-full max-w-md bg-white rounded-lg shadow-sm overflow-hidden border border-gray-200"> | |
| <!-- Header --> | |
| <div class="border-b border-gray-200 p-5 bg-white"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-9 h-9 rounded-full bg-blue-50 flex items-center justify-center text-hotel-accent"> | |
| <i class="fas fa-hotel text-sm"></i> | |
| </div> | |
| <div> | |
| <h2 class="font-medium text-gray-900">Hotel Arcane</h2> | |
| <p class="text-xs text-gray-500">Digital Concierge</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Chat Area --> | |
| <div class="chat-log h-chat-height p-5 overflow-y-auto bg-white" id="chatLog"> | |
| <div class="flex mb-4 message"> | |
| <div class="w-8 h-8 rounded-full bg-blue-50 flex items-center justify-center text-hotel-accent flex-shrink-0"> | |
| <i class="fas fa-hotel text-xs"></i> | |
| </div> | |
| <div class="ml-3 max-w-[85%]"> | |
| <div class="bg-gray-50 px-4 py-3 rounded-lg"> | |
| <p class="text-sm text-gray-800 leading-relaxed">Welcome to Hotel Arcane. I'm here to assist with your stay. How may I help you today?</p> | |
| </div> | |
| <p class="text-xs text-gray-400 mt-1">Today at <span id="current-time"></span></p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Input Area --> | |
| <div class="border-t border-gray-200 p-4 bg-white"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="flex-grow relative"> | |
| <input | |
| type="text" | |
| id="userInput" | |
| placeholder="Message Hotel Arcane..." | |
| class="w-full px-4 py-3 rounded-lg border border-gray-200 focus:outline-none focus:border-hotel-accent input-focus text-sm text-gray-800 placeholder-gray-400" | |
| onkeypress="if(event.keyCode==13) sendMessage()" | |
| > | |
| </div> | |
| <button | |
| onclick="sendMessage()" | |
| class="w-10 h-10 bg-hotel-accent text-white rounded-lg flex items-center justify-center hover:bg-blue-700 transition" | |
| aria-label="Send message" | |
| > | |
| <i class="fas fa-paper-plane text-xs"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Display current time | |
| const updateTime = () => { | |
| const now = new Date(); | |
| document.getElementById('current-time').textContent = now.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); | |
| } | |
| setInterval(updateTime, 1000); | |
| updateTime(); | |
| // Chat functions | |
| const chatLog = document.getElementById('chatLog'); | |
| const userInput = document.getElementById('userInput'); | |
| function appendMessage(sender, text) { | |
| const now = new Date(); | |
| const timeString = now.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `flex mb-4 message`; | |
| if (sender === 'user') { | |
| messageDiv.innerHTML = ` | |
| <div class="ml-auto max-w-[85%]"> | |
| <div class="bg-hotel-accent text-white px-4 py-3 rounded-lg"> | |
| <p class="text-sm leading-relaxed">${text}</p> | |
| </div> | |
| <p class="text-xs text-gray-400 mt-1 text-right">${timeString}</p> | |
| </div> | |
| `; | |
| } else { | |
| messageDiv.innerHTML = ` | |
| <div class="w-8 h-8 rounded-full bg-blue-50 flex items-center justify-center text-hotel-accent flex-shrink-0"> | |
| <i class="fas fa-hotel text-xs"></i> | |
| </div> | |
| <div class="ml-3 max-w-[85%]"> | |
| <div class="bg-gray-50 px-4 py-3 rounded-lg"> | |
| <p class="text-sm text-gray-800 leading-relaxed">${text}</p> | |
| </div> | |
| <p class="text-xs text-gray-400 mt-1">${timeString}</p> | |
| </div> | |
| `; | |
| } | |
| chatLog.appendChild(messageDiv); | |
| chatLog.scrollTop = chatLog.scrollHeight; | |
| return messageDiv; | |
| } | |
| // Enhanced responses for hotel context | |
| const hotelResponses = { | |
| greetings: ["Hello! How may I assist you today?", "Welcome back! How can we make your stay better?", "Good day! What can I help you with?"], | |
| checkIn: ["Would you like help with check-in procedures?", "Our check-in time is at 3:00 PM. Need any assistance?", "I can prepare your check-in details. May I have your name?"], | |
| amenities: ["We offer spa services, fine dining, and a rooftop pool. What interests you?", "Our amenities include 24/7 room service, fitness center, and valet parking.", "Would you like recommendations for our on-site facilities?"], | |
| dining: ["Our restaurant serves breakfast from 7-11AM and dinner from 6-10PM. Shall I make a reservation?", "We have both room service and our signature restaurant. Which would you prefer?", "Our chef's special tonight is pan-seared salmon. Would you like to book a table?"], | |
| checkout: ["Check-out is at 11AM. Would you like to request a late check-out?", "I can arrange your bill and transportation. When are you departing?", "Would you like your receipt emailed or printed?"] | |
| }; | |
| function getRandomResponse(responses) { | |
| return responses[Math.floor(Math.random() * responses.length)]; | |
| } | |
| function sendMessage() { | |
| const userText = userInput.value.trim(); | |
| if (!userText) return; | |
| appendMessage('user', userText); | |
| userInput.value = ''; | |
| // Simulate typing delay for more natural interaction | |
| setTimeout(() => { | |
| const typingIndicator = appendMessage('hotel', '...'); | |
| setTimeout(() => { | |
| chatLog.removeChild(typingIndicator); | |
| let reply = ""; | |
| const lowerText = userText.toLowerCase(); | |
| if (lowerText.includes('hello') || lowerText.includes('hi') || lowerText.includes('hey')) { | |
| reply = getRandomResponse(hotelResponses.greetings); | |
| } | |
| else if (lowerText.includes('check in') || lowerText.includes('arrival')) { | |
| reply = getRandomResponse(hotelResponses.checkIn); | |
| } | |
| else if (lowerText.includes('room') || lowerText.includes('available') || lowerText.includes('book')) { | |
| reply = "We have Deluxe, Executive, and Suite rooms available. Would you like details on a specific type?"; | |
| } | |
| else if (lowerText.includes('amen') || lowerText.includes('facility') || lowerText.includes('service')) { | |
| reply = getRandomResponse(hotelResponses.amenities); | |
| } | |
| else if (lowerText.includes('food') || lowerText.includes('dinner') || lowerText.includes('breakfast')) { | |
| reply = getRandomResponse(hotelResponses.dining); | |
| } | |
| else if (lowerText.includes('check out') || lowerText.includes('depart') || lowerText.includes('leave')) { | |
| reply = getRandomResponse(hotelResponses.checkout); | |
| } | |
| else if (lowerText.includes('thank') || lowerText.includes('thanks')) { | |
| reply = "You're most welcome! Is there anything else I can assist you with?"; | |
| } | |
| else { | |
| reply = "I'd be happy to assist with your request at Hotel Arcane. Could you share more details?"; | |
| } | |
| appendMessage('hotel', reply); | |
| }, 800 + Math.random() * 500); // Random delay for more natural feel | |
| }, 300); | |
| } | |
| // Focus input on load | |
| window.onload = function() { | |
| userInput.focus(); | |
| }; | |
| </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=chipmonktalent/rimi" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |