Spaces:
Runtime error
Runtime error
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>LA Festival Guide AI</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| .typing-dot { | |
| animation: typing 1.4s infinite ease-in-out both; | |
| } | |
| .typing-dot:nth-child(1) { animation-delay: -0.32s; } | |
| .typing-dot:nth-child(2) { animation-delay: -0.16s; } | |
| @keyframes typing { | |
| 0%, 80%, 100% { transform: scale(0); } | |
| 40% { transform: scale(1); } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 h-screen flex flex-col items-center justify-center p-4"> | |
| <!-- Main Card --> | |
| <div class="w-full max-w-2xl bg-white rounded-2xl shadow-xl overflow-hidden flex flex-col h-[80vh]"> | |
| <!-- Header --> | |
| <div class="bg-gradient-to-r from-blue-600 to-purple-600 p-6 text-white"> | |
| <h1 class="text-2xl font-bold">🌴 LA Festival Guide</h1> | |
| <p class="text-blue-100 text-sm">Ask about events, dates, and festivals in LA</p> | |
| </div> | |
| <!-- Chat Area --> | |
| <div id="chat-box" class="flex-1 overflow-y-auto p-6 space-y-4 bg-gray-50"> | |
| <!-- Bot Welcome Message --> | |
| <div class="flex items-start"> | |
| <div class="bg-blue-100 p-3 rounded-lg rounded-tl-none max-w-[80%] text-gray-800"> | |
| Hello! I'm your LA events concierge. What are you looking for today? | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Input Area --> | |
| <div class="p-4 bg-white border-t border-gray-200"> | |
| <form id="chat-form" class="flex gap-2"> | |
| <input type="text" id="user-input" | |
| class="flex-1 px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" | |
| placeholder="e.g., Music festivals in August..." autocomplete="off"> | |
| <button type="submit" | |
| class="bg-blue-600 text-white px-6 py-3 rounded-lg font-semibold hover:bg-blue-700 transition-colors"> | |
| Send | |
| </button> | |
| </form> | |
| </div> | |
| </div> | |
| <script> | |
| const chatBox = document.getElementById('chat-box'); | |
| const chatForm = document.getElementById('chat-form'); | |
| const userInput = document.getElementById('user-input'); | |
| function appendMessage(text, isUser) { | |
| const div = document.createElement('div'); | |
| div.className = `flex ${isUser ? 'justify-end' : 'items-start'}`; | |
| const bubble = document.createElement('div'); | |
| bubble.className = isUser | |
| ? 'bg-blue-600 text-white p-3 rounded-lg rounded-tr-none max-w-[80%]' | |
| : 'bg-white border border-gray-200 p-3 rounded-lg rounded-tl-none max-w-[80%] text-gray-800 shadow-sm'; | |
| // Allow basic markdown-like formatting for bot | |
| bubble.innerHTML = isUser ? text : text.replace(/\n/g, '<br>'); | |
| div.appendChild(bubble); | |
| chatBox.appendChild(div); | |
| chatBox.scrollTop = chatBox.scrollHeight; | |
| } | |
| function showTyping() { | |
| const div = document.createElement('div'); | |
| div.id = 'typing-indicator'; | |
| div.className = 'flex items-start'; | |
| div.innerHTML = ` | |
| <div class="bg-gray-200 p-3 rounded-lg rounded-tl-none flex space-x-1"> | |
| <div class="w-2 h-2 bg-gray-500 rounded-full typing-dot"></div> | |
| <div class="w-2 h-2 bg-gray-500 rounded-full typing-dot"></div> | |
| <div class="w-2 h-2 bg-gray-500 rounded-full typing-dot"></div> | |
| </div> | |
| `; | |
| chatBox.appendChild(div); | |
| chatBox.scrollTop = chatBox.scrollHeight; | |
| } | |
| function removeTyping() { | |
| const el = document.getElementById('typing-indicator'); | |
| if (el) el.remove(); | |
| } | |
| chatForm.addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| const message = userInput.value.trim(); | |
| if (!message) return; | |
| // 1. Show User Message | |
| appendMessage(message, true); | |
| userInput.value = ''; | |
| showTyping(); | |
| try { | |
| // 2. Call Python Backend | |
| const response = await fetch('/api/chat', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ message: message }) | |
| }); | |
| const data = await response.json(); | |
| // 3. Show Bot Response | |
| removeTyping(); | |
| if (response.ok) { | |
| appendMessage(data.response, false); | |
| } else { | |
| appendMessage("⚠️ Error: " + (data.detail || "Failed to fetch"), false); | |
| } | |
| } catch (err) { | |
| removeTyping(); | |
| appendMessage("⚠️ Network error. Please try again.", false); | |
| console.error(err); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |