# AN HTML CODE WHICH COULD BE RAN WITH A PYTHIN BACKENED AND THS IS THE FRONTEND

> Source: <https://gist.github.com/LegedsDaD/02b9fe2e71d3daf4af00d5ff9f76b104>
> Published: 2026-06-29 03:44:57+00:00

| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Local AI Chatbot</title> | |
| <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap"> | |
| <style> | |
| /* CSS Variables for easy theme adjustments */ | |
| :root { | |
| --primary-color: #007bff; /* Bright blue for actions/user messages */ | |
| --primary-hover: #0056b3; | |
| --background-color: #f0f2f5; /* Light gray background */ | |
| --container-bg: #fff; | |
| --bot-bg: #e9e9eb; /* Light gray for bot message background */ | |
| --text-color: #333; | |
| --border-color: #e0e0e0; | |
| --input-bg: #f7f7f7; | |
| --shadow-light: 0 4px 12px rgba(0, 0, 0, 0.1); | |
| } | |
| /* General Body Styling & Accessibility Enhancements */ | |
| body { | |
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | |
| background-color: var(--background-color); | |
| color: var(--text-color); | |
| margin: 0; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| min-height: 100vh; | |
| padding: 0; /* Let the container handle padding */ | |
| } | |
| /* Chat Container (Main Layout) */ | |
| .chat-container { | |
| width: 90%; /* More responsive width */ | |
| max-width: 650px; /* Slightly wider max-width */ | |
| height: 90vh; /* Taller on large screens */ | |
| display: flex; | |
| flex-direction: column; | |
| background-color: var(--container-bg); | |
| border-radius: 12px; | |
| box-shadow: var(--shadow-light); | |
| overflow: hidden; | |
| transition: all 0.3s ease; /* Smooth transition for resizing/theme changes */ | |
| } | |
| /* Chat Box (Messages Area) */ | |
| .chat-box { | |
| flex: 1; | |
| padding: 20px; | |
| overflow-y: auto; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; /* Slightly smaller gap */ | |
| scroll-behavior: smooth; /* Smooth scrolling when new messages appear */ | |
| } | |
| /* Heading for better semantic structure */ | |
| .chat-header { | |
| padding: 15px 20px; | |
| text-align: center; | |
| font-size: 1.2em; | |
| font-weight: 600; | |
| color: var(--primary-color); | |
| border-bottom: 1px solid var(--border-color); | |
| background-color: var(--input-bg); | |
| } | |
| /* Individual Message Styling */ | |
| .message-wrapper { | |
| display: flex; | |
| /* Use flex for alignment */ | |
| } | |
| .message { | |
| max-width: 85%; /* Give bot slightly more space */ | |
| padding: 12px 16px; | |
| border-radius: 18px; /* Slightly smaller radius for a modern feel */ | |
| word-wrap: break-word; | |
| line-height: 1.45; | |
| box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); /* Lighter shadow */ | |
| } | |
| .user-message-wrapper { | |
| justify-content: flex-end; /* Align user messages to the right */ | |
| } | |
| .user-message { | |
| background-color: var(--primary-color); | |
| color: #fff; | |
| border-bottom-right-radius: 6px; | |
| } | |
| .bot-message-wrapper { | |
| justify-content: flex-start; /* Align bot messages to the left */ | |
| } | |
| .bot-message { | |
| background-color: var(--bot-bg); | |
| color: var(--text-color); | |
| border-bottom-left-radius: 6px; | |
| } | |
| /* Loading Indicator */ | |
| .loading-indicator { | |
| background-color: var(--bot-bg); | |
| color: var(--text-color); | |
| animation: pulse 1.5s infinite ease-in-out; | |
| /* Ensure it has the same padding/border as a message */ | |
| padding: 12px 16px; | |
| border-radius: 18px; | |
| border-bottom-left-radius: 6px; | |
| } | |
| .loading-wrapper { | |
| justify-content: flex-start; | |
| } | |
| @keyframes pulse { | |
| 0% { opacity: 0.7; } | |
| 50% { opacity: 1; } | |
| 100% { opacity: 0.7; } | |
| } | |
| /* Input Area */ | |
| .input-area { | |
| display: flex; | |
| padding: 15px 20px; | |
| border-top: 1px solid var(--border-color); | |
| background-color: var(--input-bg); | |
| } | |
| .input-area input { | |
| flex: 1; | |
| border: 1px solid var(--border-color); | |
| border-radius: 20px; | |
| padding: 10px 15px; | |
| font-size: 16px; | |
| outline: none; | |
| transition: border-color 0.2s, box-shadow 0.2s; | |
| line-height: 1.3; | |
| } | |
| .input-area input:focus { | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25); /* Focus ring for accessibility */ | |
| } | |
| .input-area button { | |
| margin-left: 10px; | |
| background-color: var(--primary-color); | |
| color: #fff; | |
| border: none; | |
| border-radius: 20px; | |
| padding: 10px 20px; | |
| font-size: 16px; | |
| cursor: pointer; | |
| transition: background-color 0.2s, opacity 0.2s; | |
| font-weight: 600; /* Bolder button text */ | |
| } | |
| .input-area button:hover:not(:disabled) { | |
| background-color: var(--primary-hover); | |
| } | |
| .input-area button:focus { | |
| outline: none; | |
| box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.5); /* Focus ring */ | |
| } | |
| .input-area button:disabled { | |
| background-color: #a0c3e7; | |
| opacity: 0.8; | |
| cursor: not-allowed; | |
| } | |
| /* Media Query for Mobile Responsiveness */ | |
| @media (max-width: 600px) { | |
| body { | |
| padding: 0; | |
| } | |
| .chat-container { | |
| width: 100%; | |
| height: 100vh; | |
| border-radius: 0; | |
| box-shadow: none; | |
| } | |
| .input-area { | |
| padding: 10px 15px; | |
| } | |
| .input-area input { | |
| padding: 8px 12px; | |
| } | |
| .input-area button { | |
| padding: 8px 15px; | |
| font-size: 14px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="chat-container"> | |
| <header class="chat-header"> | |
| Local AI Chatbot | |
| </header> | |
| <main class="chat-box" id="chat-box" aria-live="polite"> | |
| <div class="message-wrapper bot-message-wrapper"> | |
| <div class="message bot-message">Hello! I'm a local AI. How can I help you?</div> | |
| </div> | |
| </main> | |
| <div class="input-area"> | |
| <form id="chat-form" style="display: flex; width: 100%;"> | |
| <label for="user-input" class="visually-hidden">Type your message</label> | |
| <input type="text" id="user-input" placeholder="Type your message..." autofocus aria-label="Chat input field"> | |
| <button type="submit" id="send-button">Send</button> | |
| </form> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const chatBox = document.getElementById('chat-box'); | |
| const userInput = document.getElementById('user-input'); | |
| const sendButton = document.getElementById('send-button'); | |
| const chatForm = document.getElementById('chat-form'); // Reference the new form element | |
| // Helper function to create a message element | |
| const createMessageElement = (content, sender) => { | |
| const wrapperDiv = document.createElement('div'); | |
| wrapperDiv.classList.add('message-wrapper', `${sender}-message-wrapper`); | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.classList.add('message', `${sender}-message`); | |
| messageDiv.textContent = content; | |
| wrapperDiv.appendChild(messageDiv); | |
| return wrapperDiv; | |
| }; | |
| const addMessage = (content, sender) => { | |
| const messageElement = createMessageElement(content, sender); | |
| chatBox.appendChild(messageElement); | |
| // Ensure chat scrolls to the bottom smoothly | |
| chatBox.scrollTop = chatBox.scrollHeight; | |
| }; | |
| const showLoadingIndicator = () => { | |
| // Using the same structure as a message for consistency | |
| const loadingWrapper = document.createElement('div'); | |
| loadingWrapper.classList.add('message-wrapper', 'loading-wrapper'); | |
| loadingWrapper.id = 'loading-indicator-wrapper'; | |
| const loadingDiv = document.createElement('div'); | |
| loadingDiv.classList.add('message', 'loading-indicator'); | |
| loadingDiv.textContent = 'Bot is thinking...'; | |
| loadingWrapper.appendChild(loadingDiv); | |
| chatBox.appendChild(loadingWrapper); | |
| chatBox.scrollTop = chatBox.scrollHeight; | |
| }; | |
| const removeLoadingIndicator = () => { | |
| const loadingWrapper = document.getElementById('loading-indicator-wrapper'); | |
| if (loadingWrapper) { | |
| loadingWrapper.remove(); | |
| } | |
| }; | |
| const disableInput = (disabled) => { | |
| userInput.disabled = disabled; | |
| sendButton.disabled = disabled; | |
| }; | |
| const sendMessage = async (event) => { | |
| event.preventDefault(); // Prevent default form submission/page reload | |
| const message = userInput.value.trim(); | |
| if (message === '') return; | |
| addMessage(message, 'user'); | |
| userInput.value = ''; | |
| disableInput(true); // Disable input while waiting for response | |
| showLoadingIndicator(); | |
| try { | |
| // Simulating network delay for local testing | |
| // await new Promise(resolve => setTimeout(resolve, 1000)); | |
| const response = await fetch('http://127.0.0.1:5000/chatbot', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ message: message }), | |
| }); | |
| const data = await response.json(); | |
| removeLoadingIndicator(); | |
| if (data.response) { | |
| addMessage(data.response, 'bot'); | |
| } else { | |
| addMessage('Sorry, an empty response was received.', 'bot'); | |
| } | |
| } catch (error) { | |
| removeLoadingIndicator(); | |
| addMessage('Sorry, I could not connect to the server (Error: ' + error.message + ').', 'bot'); | |
| console.error('Error:', error); | |
| } finally { | |
| disableInput(false); | |
| userInput.focus(); // Return focus to input for quick typing | |
| } | |
| }; | |
| // Use the form's submit event for both button click and Enter key | |
| chatForm.addEventListener('submit', sendMessage); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
