|
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; |
|
} |
|
""" |