| script = """ |
| // Generate a new session ID on every page load |
| let sessionId = Math.random().toString(36).substring(2); |
| |
| // Handle page load |
| window.onload = function() { |
| autoResizeTextarea(); // Handle the initial state of the textarea |
| renderHomeText(); // Render the home text (markdown content) |
| }; |
| |
| // Function to handle sending a message |
| async function sendMessage() { |
| const messageElem = document.getElementById('message'); |
| const sendButton = document.querySelector('.send-button'); |
| const message = messageElem.value.trim(); |
| |
| // Return early if the message is empty |
| if (!message) return; |
| |
| const output = document.getElementById('output'); |
| |
| // Disable textarea and button while processing |
| messageElem.disabled = true; |
| sendButton.disabled = true; |
| sendButton.classList.add('disabled'); // Visual indication |
| |
| // Display user's message in the chat |
| const userMessage = document.createElement('p'); |
| userMessage.classList.add('message', 'user'); |
| userMessage.innerHTML = message.replace(/\\n/g, '<br>'); // Preserve line breaks |
| output.appendChild(userMessage); |
| |
| // Clear the textarea and reset its height |
| messageElem.value = ''; |
| autoResizeTextarea(); |
| |
| // Scroll to the bottom of the output |
| output.scrollTop = output.scrollHeight; |
| |
| // Create a new div for the AI's response |
| let aiMessage = document.createElement('p'); |
| aiMessage.classList.add('message', 'ai'); |
| output.appendChild(aiMessage); |
| |
| // Open a connection to stream the AI's response |
| const eventSource = new EventSource(`/stream?message=${encodeURIComponent(message)}&session_id=${encodeURIComponent(sessionId)}`); |
| let partialResponse = ''; // Accumulate streaming response |
| |
| eventSource.onmessage = function(event) { |
| partialResponse += event.data; |
| |
| // Convert markdown to HTML and sanitize it |
| const sanitizedHtml = DOMPurify.sanitize(marked.parse(partialResponse)); |
| aiMessage.innerHTML = sanitizedHtml; |
| output.scrollTop = output.scrollHeight; // Scroll to the bottom |
| }; |
| |
| // Handle errors during the SSE connection |
| eventSource.onerror = function() { |
| console.error("Error occurred with SSE"); |
| resetInputState(messageElem, sendButton); // Re-enable input on error |
| eventSource.close(); // Close the connection |
| }; |
| |
| eventSource.onopen = function() { |
| console.log("Connection to server opened."); |
| }; |
| |
| // Re-enable textarea and button after the AI finishes responding |
| eventSource.onclose = function() { |
| console.log("Connection to server closed."); |
| resetInputState(messageElem, sendButton); // Re-enable input after response |
| }; |
| } |
| |
| // Function to reset the input state (re-enable textarea and send button) |
| function resetInputState(messageElem, sendButton) { |
| messageElem.disabled = false; |
| sendButton.disabled = false; |
| sendButton.classList.remove('disabled'); |
| messageElem.focus(); |
| } |
| |
| // Auto-resize the textarea as the user types and manage send button state |
| function autoResizeTextarea() { |
| const textarea = document.getElementById('message'); |
| const sendButton = document.querySelector('.send-button'); |
| |
| textarea.style.height = 'auto'; // Reset height to auto |
| const maxHeight = 220; |
| let newHeight = textarea.scrollHeight; |
| |
| if (newHeight > maxHeight) { |
| textarea.style.height = maxHeight + 'px'; |
| textarea.style.overflowY = 'auto'; |
| } else { |
| textarea.style.height = newHeight + 'px'; |
| textarea.style.overflowY = 'hidden'; |
| } |
| |
| // Enable/disable the send button based on textarea content |
| sendButton.disabled = textarea.value.trim() === ''; |
| sendButton.classList.toggle('disabled', !textarea.value.trim()); |
| } |
| |
| // Enable sending message on Enter key press (without shift) |
| function checkEnter(e) { |
| if (e.key === 'Enter' && !e.shiftKey) { |
| e.preventDefault(); |
| sendMessage(); |
| } |
| } |
| |
| // Function to render home page text from Markdown (on page load) |
| function renderHomeText() { |
| const homeTextContainer = document.getElementById('home-text-container'); |
| const markdownContent = homeTextContainer.getAttribute('data-home-text'); |
| |
| // Parse markdown and sanitize HTML |
| const sanitizedHtml = DOMPurify.sanitize(marked.parse(markdownContent)); |
| homeTextContainer.innerHTML = sanitizedHtml; |
| } |
| """ |