Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>LLM Chat | Swiss Army Web Tools</title> | |
| <link rel="icon" type="image/x-icon" href="favicon.ico"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <style> | |
| .message { | |
| max-width: 80%; | |
| animation: fadeIn 0.3s ease; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| #thinkingIndicator { | |
| display: none; | |
| } | |
| #thinkingIndicator.visible { | |
| display: flex; | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen bg-gradient-to-br from-gray-900 to-gray-800"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <header class="text-center mb-8"> | |
| <h1 class="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-cyan-400 to-blue-500"> | |
| LLM Chat Assistant | |
| </h1> | |
| <p class="text-gray-300 mt-2">Chat with our AI assistant powered by OpenAI</p> | |
| </header> | |
| <div class="bg-gray-800 rounded-2xl shadow-xl overflow-hidden max-w-4xl mx-auto border border-gray-700 backdrop-blur-sm bg-opacity-50"> | |
| <div class="p-6 h-[70vh] overflow-y-auto" id="chatContainer"> | |
| <div class="message bg-gray-700 p-4 rounded-2xl mb-4 ml-auto"> | |
| <p>Hello! I'm your AI assistant. How can I help you today?</p> | |
| </div> | |
| </div> | |
| <div class="p-4 border-t border-gray-700 relative"> | |
| <div id="thinkingIndicator" class="absolute -top-4 left-0 right-0 justify-center items-center gap-2 text-gray-400"> | |
| <div class="flex space-x-1"> | |
| <div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce"></div> | |
| <div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style="animation-delay: 0.2s"></div> | |
| <div class="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style="animation-delay: 0.4s"></div> | |
| </div> | |
| <span>Thinking...</span> | |
| </div> | |
| <div class="flex gap-2"> | |
| <textarea id="userInput" class="flex-1 px-4 py-3 bg-gray-700 border border-gray-600 rounded-xl focus:outline-none focus:ring-2 focus:ring-cyan-500 text-white placeholder-gray-400 resize-none" | |
| rows="1" placeholder="Type your message here..." autocomplete="off"></textarea> | |
| <button id="sendBtn" class="bg-gradient-to-r from-cyan-500 to-blue-600 hover:from-cyan-600 hover:to-blue-700 text-white px-5 py-3 rounded-xl flex items-center gap-2 shadow-lg hover:shadow-cyan-500/20 transition-all"> | |
| <i data-feather="send"></i> | |
| </button> | |
| </div> | |
| <p class="text-xs text-gray-500 mt-2">Note: This is a demo using mock responses. In a real implementation, you would connect to an LLM API.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| feather.replace(); | |
| const chatContainer = document.getElementById('chatContainer'); | |
| const userInput = document.getElementById('userInput'); | |
| const sendBtn = document.getElementById('sendBtn'); | |
| const thinkingIndicator = document.getElementById('thinkingIndicator'); | |
| // Auto-resize textarea | |
| userInput.addEventListener('input', function() { | |
| this.style.height = 'auto'; | |
| this.style.height = (this.scrollHeight) + 'px'; | |
| }); | |
| // Send message on Enter (Shift+Enter for new line) | |
| userInput.addEventListener('keydown', function(e) { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| sendBtn.addEventListener('click', sendMessage); | |
| function sendMessage() { | |
| const message = userInput.value.trim(); | |
| if (!message) return; | |
| // Add user message to chat | |
| addMessage(message, 'user'); | |
| userInput.value = ''; | |
| userInput.style.height = 'auto'; | |
| // Show thinking indicator | |
| thinkingIndicator.classList.add('visible'); | |
| // Mock AI response (in a real app, you'd call an API here) | |
| setTimeout(() => { | |
| thinkingIndicator.classList.remove('visible'); | |
| const mockResponses = [ | |
| "Interesting question! Based on my knowledge, I'd say...", | |
| "Thanks for asking. Here's what I know about that...", | |
| "I'm glad you asked! The answer is...", | |
| "That's a great question. Let me think about that...", | |
| "I don't have all the answers, but here's what I can tell you..." | |
| ]; | |
| const randomResponse = mockResponses[Math.floor(Math.random() * mockResponses.length)]; | |
| addMessage(randomResponse, 'ai'); | |
| }, 1500 + Math.random() * 2000); | |
| } | |
| function addMessage(text, sender) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `message p-4 rounded-2xl mb-4 ${sender === 'user' ? 'bg-cyan-600 ml-auto' : 'bg-gray-700 mr-auto'}`; | |
| messageDiv.innerHTML = `<p>${text.replace(/\n/g, '<br>')}</p>`; | |
| chatContainer.appendChild(messageDiv); | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |