// 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 ""',
'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 = `
${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, '');
// 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 = `
`;
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 = `
`;
fileTree.appendChild(srcFolder);
const staticFolder = document.createElement('div');
staticFolder.classList.add('folder-item');
staticFolder.innerHTML = `
`;
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();