// State untuk menyimpan riwayat percakapan let chatHistory = []; let conversationId = 1; let currentFile = null; let files = { 'main.py': '# Main application file\nprint("Hello, World!")', 'app.py': '# Flask application\nfrom flask import Flask\n\napp = Flask(__name__)\n\n@app.route("/")\ndef index():\n return "Hello from Flask!"\n\nif __name__ == "__main__":\n app.run(debug=True)', 'style.css': '/* Main styles */\nbody {\n font-family: Arial, sans-serif;\n background-color: #f0f0f0;\n}', 'script.js': '// Main script\nconsole.log("Hello from JavaScript!");', 'header.py': '# Header component\n\ndef render_header():\n return "
Header Content
"', 'footer.py': '# Footer component\n\ndef render_footer():\n return ""', 'README.md': '# My Project\nThis is a sample project.', 'requirements.txt': 'flask==2.3.3\nopenai==1.10.0' }; // DOM Elements const chatContainer = document.getElementById('chat-container'); const userInput = document.getElementById('user-input'); const sendButton = document.getElementById('send-button'); const welcomeScreen = document.getElementById('welcome-screen'); const hamburgerBtn = document.getElementById('hamburger-btn'); const closeSidebarBtn = document.getElementById('close-sidebar-btn'); const sidebar = document.getElementById('sidebar'); const newChatBtn = document.getElementById('new-chat-btn'); const floatingNewChatBtn = document.getElementById('floating-new-chat'); const suggestionCards = document.querySelectorAll('.suggestion-card'); const modeSelector = document.getElementById('mode-selector'); const modelSelector = document.getElementById('model-selector'); const tabs = document.querySelectorAll('.tab'); const tabContents = document.querySelectorAll('.tab-content'); const fileTree = document.getElementById('file-tree'); const terminalOutput = document.getElementById('terminal-output'); const terminalInput = document.getElementById('terminal-input'); const clearTerminalBtn = document.getElementById('clear-terminal-btn'); const runCodeBtn = document.getElementById('run-code-btn'); const previewFrame = document.getElementById('preview-frame'); const refreshPreviewBtn = document.getElementById('refresh-preview-btn'); const openPreviewBtn = document.getElementById('open-preview-btn'); const newFileBtn = document.getElementById('new-file-btn'); const newFolderBtn = document.getElementById('new-folder-btn'); const sidebarBackdrop = document.querySelector('.sidebar-backdrop'); // Fungsi untuk menambahkan pesan ke UI function addMessageToUI(role, content) { // Sembunyikan layar selamat datang saat pesan pertama muncul if (chatContainer.children.length === 1) { // hanya ada welcome-screen welcomeScreen.style.display = 'none'; } const messageDiv = document.createElement('div'); messageDiv.classList.add('message'); messageDiv.classList.add(role === 'user' ? 'user-message' : 'assistant-message'); const timeString = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); const avatarClass = role === 'user' ? 'user-avatar' : 'assistant-avatar'; const avatarText = role === 'user' ? 'U' : 'AI'; const sender = role === 'user' ? 'You' : 'VicoXDarkGPT'; messageDiv.innerHTML = `
${avatarText}
${sender} • ${timeString}
${formatMessageContent(content)}
`; chatContainer.appendChild(messageDiv); chatContainer.scrollTop = chatContainer.scrollHeight; } // Fungsi untuk memformat konten pesan (kode, pemikiran, dll) function formatMessageContent(content) { let formattedContent = content; // Gaya untuk blok kode formattedContent = formattedContent.replace(/```([\s\S]*?)```/g, '
$1
'); // Gaya untuk langkah-langkah berpikir formattedContent = formattedContent.replace(/(🎯|📋|🛠️|📁|💡|🏗️|📝|🔍)/g, '$1'); formattedContent = formattedContent.replace(/(Step \d+:?|Step \d\.)/gi, '
$1
'); formattedContent = formattedContent.replace(/(ANALYZE:|PLAN:|IMPLEMENT:|EXPLAIN:)/gi, '$1'); return formattedContent; } // Fungsi untuk menampilkan indikator pengetikan function showTypingIndicator() { const typingDiv = document.createElement('div'); typingDiv.id = 'typing-indicator'; typingDiv.classList.add('message', 'assistant-message'); typingDiv.innerHTML = `
AI
VicoXDarkGPT • typing...
`; chatContainer.appendChild(typingDiv); chatContainer.scrollTop = chatContainer.scrollHeight; return typingDiv; } // Fungsi untuk menghapus indikator pengetikan function removeTypingIndicator(typingElement) { if (typingElement && typingElement.parentNode) { typingElement.parentNode.removeChild(typingElement); } } // Fungsi untuk mengirim pesan pengguna async function sendUserMessage() { const message = userInput.value.trim(); if (!message) return; // Tambahkan pesan pengguna ke UI dan riwayat addMessageToUI('user', message); chatHistory.push({ role: 'user', content: message }); userInput.value = ''; userInput.style.height = 'auto'; // Tampilkan indikator pengetikan const typingElement = showTypingIndicator(); try { // Ambil model dan mode yang dipilih const selectedModel = modelSelector.value; const selectedMode = modeSelector.value; // Panggil fungsi getAIResponse yang didefinisikan di api.js const response = await getAIResponse(message, selectedModel, selectedMode); // Hapus indikator pengetikan removeTypingIndicator(typingElement); // Tambahkan respons AI ke UI dan riwayat addMessageToUI('assistant', response); chatHistory.push({ role: 'assistant', content: response }); } catch (error) { // Hapus indikator pengetikan removeTypingIndicator(typingElement); // Tampilkan pesan error addMessageToUI('assistant', `Error: ${error.message || 'Gagal menghubungi AI'}`); console.error('Error getting AI response:', error); } } // Fungsi untuk memulai percakapan baru function startNewChat() { chatHistory = []; conversationId++; chatContainer.innerHTML = ''; welcomeScreen.style.display = 'block'; chatContainer.appendChild(welcomeScreen); chatContainer.scrollTop = 0; } // Fungsi untuk menangani klik item sidebar function handleSidebarItemClick(itemId) { console.log('Sidebar item clicked:', itemId); // Untuk debugging // Tambahkan logika untuk setiap item di sini switch(itemId) { case 'new-chat': startNewChat(); break; case 'project-planning': userInput.value = 'Help me plan a new project. What should be the first steps?'; userInput.focus(); switchTab('chat'); break; case 'code-review': userInput.value = 'Please review this code snippet and suggest improvements:'; userInput.focus(); switchTab('chat'); break; case 'web-app-builder': userInput.value = 'Help me build a simple web application. What technologies should I use?'; userInput.focus(); switchTab('chat'); break; case 'file-explorer': switchTab('files'); break; case 'checkpoints': alert('Checkpoints clicked. This would show saved checkpoints.'); // Di sini Anda bisa menambahkan logika untuk menampilkan checkpoint break; case 'terminal': switchTab('terminal'); break; case 'create-application': userInput.value = 'Create a new application for me. What kind of application would you like?'; userInput.focus(); switchTab('chat'); break; case 'auto-debug': userInput.value = 'I have an error in my code. Can you help me debug it? Here is the error: '; userInput.focus(); switchTab('chat'); break; case 'code-suggestions': userInput.value = 'Can you suggest code improvements for best practices?'; userInput.focus(); switchTab('chat'); break; case 'performance-analysis': userInput.value = 'Analyze the performance of this code:'; userInput.focus(); switchTab('chat'); break; default: console.log('Unknown sidebar item:', itemId); } // Tutup sidebar setelah klik (opsional) sidebar.classList.remove('open'); sidebarBackdrop.classList.remove('active'); } // Fungsi untuk beralih antar tab function switchTab(tabName) { // Hapus kelas aktif dari semua tab dan konten tabs.forEach(tab => tab.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); // Tambahkan kelas aktif ke tab dan konten yang dipilih document.querySelector(`.tab[data-tab="${tabName}"]`).classList.add('active'); document.getElementById(`${tabName}-tab`).classList.add('active'); } // Fungsi untuk memperbarui tampilan file tree function updateFileTree() { fileTree.innerHTML = ''; // Simulasi struktur file const srcFolder = document.createElement('div'); srcFolder.classList.add('folder-item'); srcFolder.innerHTML = `
src
main.py
app.py
`; fileTree.appendChild(srcFolder); const staticFolder = document.createElement('div'); staticFolder.classList.add('folder-item'); staticFolder.innerHTML = `
static
css
style.css
js
script.js
`; fileTree.appendChild(staticFolder); const readmeFile = document.createElement('div'); readmeFile.classList.add('file-item'); readmeFile.setAttribute('data-file', 'README.md'); readmeFile.innerHTML = ` README.md`; fileTree.appendChild(readmeFile); const reqFile = document.createElement('div'); reqFile.classList.add('file-item'); reqFile.setAttribute('data-file', 'requirements.txt'); reqFile.innerHTML = ` requirements.txt`; fileTree.appendChild(reqFile); // Tambahkan event listener ke file document.querySelectorAll('.file-item').forEach(item => { item.addEventListener('click', () => { const filename = item.getAttribute('data-file'); openFile(filename); }); }); // Tambahkan event listener ke folder document.querySelectorAll('.folder-header').forEach(header => { header.addEventListener('click', () => { const folderItem = header.parentElement; folderItem.classList.toggle('expanded'); }); }); } // Fungsi untuk membuka file function openFile(filename) { currentFile = filename; alert(`File opened: ${filename}\nIn a real app, this would open the editor.`); // Di sini Anda bisa menambahkan logika untuk membuka editor file } // Fungsi untuk menambahkan output ke terminal function addTerminalOutput(output, isError = false) { const line = document.createElement('div'); line.classList.add('terminal-line'); if (isError) { line.classList.add('terminal-error'); line.textContent = `Error: ${output}`; } else { line.textContent = output; } terminalOutput.appendChild(line); terminalOutput.scrollTop = terminalOutput.scrollHeight; } // Fungsi untuk menjalankan perintah terminal function runTerminalCommand(command) { addTerminalOutput(`[user@ai-assistant ~]$ ${command}`); if (command === 'help') { addTerminalOutput('Available commands: help, ls, clear, run [file], pwd, cd'); } else if (command === 'ls') { addTerminalOutput('Files in directory:'); for (const filename of Object.keys(files)) { addTerminalOutput(` ${filename}`); } } else if (command === 'pwd') { addTerminalOutput('/home/user/project'); } else if (command.startsWith('cd ')) { const dir = command.split(' ')[1]; addTerminalOutput(`Changed directory to ${dir}`); } else if (command.startsWith('run ')) { const filename = command.split(' ')[1]; if (filename && files[filename]) { addTerminalOutput(`Running ${filename}...`); // Simulasi eksekusi kode setTimeout(() => { addTerminalOutput(`Output of ${filename}:`); addTerminalOutput(files[filename]); }, 500); } else { addTerminalOutput(`File not found: ${filename}`, true); } } else { addTerminalOutput(`Command not found: ${command}`, true); } } // Event Listeners sendButton.addEventListener('click', sendUserMessage); userInput.addEventListener('input', function() { this.style.height = 'auto'; this.style.height = (this.scrollHeight) + 'px'; }); userInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendUserMessage(); } }); hamburgerBtn.addEventListener('click', () => { sidebar.classList.add('open'); sidebarBackdrop.classList.add('active'); }); closeSidebarBtn.addEventListener('click', () => { sidebar.classList.remove('open'); sidebarBackdrop.classList.remove('active'); }); sidebarBackdrop.addEventListener('click', () => { sidebar.classList.remove('open'); sidebarBackdrop.classList.remove('active'); }); newChatBtn.addEventListener('click', startNewChat); floatingNewChatBtn.addEventListener('click', startNewChat); // Tambahkan event listener ke kartu saran suggestionCards.forEach(card => { card.addEventListener('click', () => { const prompt = card.getAttribute('data-prompt'); userInput.value = prompt; userInput.focus(); switchTab('chat'); }); }); // Tambahkan event listener ke semua item sidebar document.querySelectorAll('.sidebar-item').forEach(item => { // Gunakan data-id dari HTML untuk mengidentifikasi item const itemId = item.getAttribute('data-id'); if (itemId) { item.addEventListener('click', () => handleSidebarItemClick(itemId)); } }); // Tambahkan event listener ke semua tab tabs.forEach(tab => { tab.addEventListener('click', () => { const tabName = tab.getAttribute('data-tab'); switchTab(tabName); }); }); // Event listener untuk file tree newFileBtn.addEventListener('click', () => { const filename = prompt('Enter new file name (e.g., myfile.py):'); if (filename) { files[filename] = ''; updateFileTree(); } }); newFolderBtn.addEventListener('click', () => { alert('Folder creation is not implemented in this demo.'); }); // Event listener untuk terminal terminalInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') { const command = terminalInput.value.trim(); if (command) { runTerminalCommand(command); terminalInput.value = ''; } } }); runCodeBtn.addEventListener('click', () => { const filename = prompt('Enter file name to run:'); if (filename && files[filename]) { runTerminalCommand(`run ${filename}`); } else if (filename) { addTerminalOutput(`File not found: ${filename}`, true); } }); clearTerminalBtn.addEventListener('click', () => { terminalOutput.innerHTML = ''; addTerminalOutput('[user@ai-assistant ~]$ Welcome to VicoXDarkGPT Terminal'); addTerminalOutput('[user@ai-assistant ~]$ Type \'help\' for available commands'); }); // Event listener untuk preview refreshPreviewBtn.addEventListener('click', () => { alert('Preview refresh is not implemented in this demo.'); }); openPreviewBtn.addEventListener('click', () => { alert('Opening preview in new tab is not implemented in this demo.'); }); // Inisialisasi updateFileTree();