// Handles key down event to send message on Enter function handleKeyDown(event) { if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); sendMessage(); } } // Sends a message to the chat API async function sendMessage() { const messageInput = document.getElementById('messageInput'); let message = messageInput.value.trim(); if (message === '') return; // Encode the message to avoid XSS attacks message = he.encode(message); // Display the user's message in the chat displayMessage(message, 'user'); messageInput.value = ''; // Clear the input toggleLoading(true); // Show loading indicator try { const response = await fetch('https://infer.x64.world/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: message }) }); if (response.ok) { const data = await response.json(); displayMessage(data.content, 'assistant'); } else { handleErrorResponse(response.status); } } catch (error) { displayMessage('Error: ' + error.message, 'assistant'); } finally { toggleLoading(false); // Hide loading indicator } } // Toggles the loading indicator function toggleLoading(show) { const loadingElement = document.getElementById('loading'); loadingElement.style.display = show ? 'block' : 'none'; } // Displays a message in the chat window function displayMessage(content, sender) { const messages = document.getElementById('messages'); const messageElement = document.createElement('div'); messageElement.classList.add('message', sender); // Decode HTML entities and render Markdown const decodedContent = he.decode(content); const htmlContent = marked(decodedContent); messageElement.innerHTML = htmlContent; messages.appendChild(messageElement); messages.scrollTop = messages.scrollHeight; // Scroll to the bottom of the chat // Highlight code blocks if any document.querySelectorAll('pre code').forEach((block) => { hljs.highlightElement(block); if (sender === 'assistant') { addCopyButton(block); // Add copy button to code blocks } }); // Add "Copy Full Response" button after each assistant response if (sender === 'assistant') { addCopyFullResponseButton(messages, messageElement); } } // Adds a copy button to a code block function addCopyButton(block) { const button = document.createElement('button'); button.classList.add('copy-button'); button.textContent = 'Copy'; button.addEventListener('click', () => copyToClipboard(block)); block.parentNode.appendChild(button); } // Adds "Copy Full Response" button below the assistant response function addCopyFullResponseButton(messagesContainer, messageElement) { const copyFullResponseButton = document.createElement('button'); copyFullResponseButton.classList.add('copy-button'); copyFullResponseButton.textContent = 'Copy Full Response'; copyFullResponseButton.addEventListener('click', () => copyFullResponse(messageElement)); messagesContainer.appendChild(copyFullResponseButton); } // Copies code block content to the clipboard function copyToClipboard(block) { const text = block.innerText; navigator.clipboard.writeText(text).then(() => { displayAlert('success', 'The code block was copied to the clipboard!'); }).catch((err) => { displayAlert('error', 'Failed to copy code: ' + err); }); } // Copies the full response content to the clipboard in Markdown format function copyFullResponse(messageElement) { const markdownContent = convertToMarkdown(messageElement); navigator.clipboard.writeText(markdownContent).then(() => { displayAlert('success', 'Full response copied to clipboard!'); }).catch((err) => { displayAlert('error', 'Failed to copy response: ' + err); }); } // Converts the HTML content of the response to Markdown, including language identifier function convertToMarkdown(element) { let markdown = ''; const nodes = element.childNodes; nodes.forEach(node => { if (node.nodeName === 'P') { markdown += `${node.innerText}\n\n`; } else if (node.nodeName === 'PRE') { const codeBlock = node.querySelector('code'); const languageClass = codeBlock.className.match(/language-(\w+)/); // Extract language from class if available const language = languageClass ? languageClass[1] : ''; // Default to empty if no language found const codeText = codeBlock.innerText; // Add language identifier to the Markdown code block markdown += `\`\`\`${language}\n${codeText}\n\`\`\`\n\n`; } }); return markdown; } // Displays an alert message with animation function displayAlert(type, message) { const alertElement = document.getElementById(`${type}-alert`); alertElement.textContent = message; alertElement.style.display = 'flex'; // Show the alert alertElement.classList.remove('fade-out'); // Remove fade-out class if present alertElement.style.opacity = '1'; // Ensure it's fully visible // Automatically hide the alert after 3 seconds with animation setTimeout(() => { alertElement.classList.add('fade-out'); // Add fade-out class to trigger animation setTimeout(() => { alertElement.style.display = 'none'; // Hide after animation finishes }, 500); // Match this time to the animation duration }, 3000); // Show the alert for 3 seconds before hiding } // Handles error responses based on status code function handleErrorResponse(status) { if (status === 429) { displayAlert('error', 'Sorry, I am currently too busy at the moment!'); } else { displayMessage('Error: ' + status, 'assistant'); } } // Helper function to reset the conversation on the server async function sendResetRequest() { const response = await fetch('https://infer.x64.world/reset-conversation', { method: 'POST', headers: { 'Content-Type': 'application/json' } }); return response; } // Resets the chat messages and optionally displays a success message async function resetChat(displaySuccessMessage = true) { try { const response = await sendResetRequest(); if (response.ok) { const messagesContainer = document.getElementById('messages'); messagesContainer.innerHTML = ''; // Clear all messages if (displaySuccessMessage) { displayAlert('success', 'Messages Cleared!'); } } else { displayAlert('error', 'Failed to reset conversation. Please try again.'); } } catch (error) { displayAlert('error', 'An error occurred while resetting the conversation.'); } } // Resets the chat on page load without displaying the success message document.addEventListener('DOMContentLoaded', function () { resetChat(false); }); function openGpuStats() { window.open('https://chat.x64.world/smi.html', 'gpuStatsWindow', 'width=800,height=600,menubar=no,toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes'); } function openLiveLog() { window.open('https://llama-live-log.x64.world/', 'liveLogWindow', 'width=600,height=600,menubar=no,toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes'); } function openTop() { window.open('https://ai-top.x64.world/', 'liveLogGtopWindow', 'width=800,height=600,menubar=no,toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes'); } const NETDATA_URL = 'https://ai-monitor.x64.world'; // Function to fetch data from the Netdata API async function fetchData(chart) { const response = await fetch(`${NETDATA_URL}/api/v1/data?chart=${chart}&format=json`, { cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } }); return await response.json(); } // Function to update all metrics every 2 seconds async function updateMetrics() { await updateCpuUsage(); await updateMemoryUsage(); await updateNetworkUsage(); await fetchGpuStats(); // Fetch GPU stats too setTimeout(updateMetrics, 2000); } // Function to update CPU usage async function updateCpuUsage() { const data = await fetchData('system.cpu'); const totalCPU = data.data[0].slice(1).reduce((acc, curr) => acc + curr, 0); document.getElementById('cpuUsageItem').textContent = `CPU Usage: ${totalCPU.toFixed(2)}%`; } // Function to update Memory usage async function updateMemoryUsage() { const data = await fetchData('mem.available'); const usedMemoryMB = data.data[0][1]; const usedMemoryGB = usedMemoryMB / 1024; document.getElementById('memoryUsageItem').textContent = `Memory Usage: ${usedMemoryGB.toFixed(2)} GB`; } // Function to update Network usage async function updateNetworkUsage() { const data = await fetchData('system.net'); const totalNetwork = data.data[0].slice(1).reduce((acc, curr) => acc + curr, 0); let networkText; if (totalNetwork > 1024) { const totalNetworkInMB = totalNetwork / 1024; networkText = `${totalNetworkInMB.toFixed(2)} MB/s (Down)`; } else if (totalNetwork < -1024) { const totalNetworkInMB = Math.abs(totalNetwork) / 1024; networkText = `${totalNetworkInMB.toFixed(2)} MB/s (Up)`; } else { const totalNetworkInKB = Math.abs(totalNetwork); networkText = `${totalNetworkInKB.toFixed(2)} KB/s (Up)`; } document.getElementById('networkUsageItem').textContent = `Network Usage: ${networkText}`; } // Function to fetch GPU stats async function fetchGpuStats() { try { const response = await fetch('https://smi.x64.world/nvidia-smi'); const data = await response.json(); updateGpuStats(data); } catch (error) { console.error('Error fetching GPU stats:', error); } } // Function to update GPU stats function updateGpuStats(data) { const gpu = data.nvidia_smi_log.gpu; document.getElementById('gpuUsageItem').textContent = `GPU Utilization: ${gpu.utilization.gpu_util}%`; document.getElementById('gpuMemoryUsageItem').textContent = `GPU Memory Utilization: ${gpu.utilization.memory_util}%`; } // Function to initialize the dynamic menu items function initializeMenu() { const menu = document.getElementById('monitorMenu'); // Create CPU Usage item const cpuItem = document.createElement('li'); cpuItem.classList.add('nav-item'); cpuItem.innerHTML = 'CPU Usage: --%'; menu.appendChild(cpuItem); // Create Memory Usage item const memoryItem = document.createElement('li'); memoryItem.classList.add('nav-item'); memoryItem.innerHTML = 'Memory Usage: -- GB'; menu.appendChild(memoryItem); // Create Network Usage item const networkItem = document.createElement('li'); networkItem.classList.add('nav-item'); networkItem.innerHTML = 'Network Usage: -- KB/s'; menu.appendChild(networkItem); // Create GPU Usage item const gpuItem = document.createElement('li'); gpuItem.classList.add('nav-item'); gpuItem.innerHTML = 'GPU Utilization: --%'; menu.appendChild(gpuItem); // Create GPU Memory Utilization item const gpuMemoryItem = document.createElement('li'); gpuMemoryItem.classList.add('nav-item'); gpuMemoryItem.innerHTML = 'GPU Memory Utilization: --%'; menu.appendChild(gpuMemoryItem); } // Start the updates initializeMenu(); updateMetrics();