File size: 4,395 Bytes
c630093
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6079f1a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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;
}
"""