// === Qwen App Builder Logic === document.addEventListener('DOMContentLoaded', () => { const chatMessages = document.getElementById('chat-messages'); const promptInput = document.getElementById('prompt-input'); const sendBtn = document.getElementById('send-btn'); const attachBtn = document.getElementById('attach-btn'); const fileInput = document.getElementById('file-input'); const imagePreview = document.getElementById('image-preview'); const previewImg = document.getElementById('preview-img'); const previewName = document.getElementById('preview-name'); const removeImageBtn = document.getElementById('remove-image'); const apiKeyInput = document.getElementById('api-key'); const saveKeyBtn = document.getElementById('save-key'); const modelSelect = document.getElementById('model-select'); const clearChatBtn = document.getElementById('clear-chat'); let attachedImage = null; // { base64, name } let isStreaming = false; // Load saved API key const savedKey = localStorage.getItem('hf_token'); if (savedKey) apiKeyInput.value = savedKey; const savedModel = localStorage.getItem('hf_model'); if (savedModel) modelSelect.value = savedModel; // Save API key saveKeyBtn.addEventListener('click', () => { localStorage.setItem('hf_token', apiKeyInput.value.trim()); localStorage.setItem('hf_model', modelSelect.value); saveKeyBtn.textContent = 'Saved!'; setTimeout(() => { saveKeyBtn.textContent = 'Save'; }, 1500); }); // Auto-resize textarea promptInput.addEventListener('input', () => { promptInput.style.height = 'auto'; promptInput.style.height = Math.min(promptInput.scrollHeight, 128) + 'px'; }); // Enter to send promptInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }); sendBtn.addEventListener('click', sendMessage); // Image attachment attachBtn.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (!file) return; if (file.size > 4 * 1024 * 1024) { alert('Image too large. Max 4MB for base64 encoding.'); return; } const reader = new FileReader(); reader.onload = (event) => { attachedImage = { base64: event.target.result, name: file.name }; previewImg.src = event.target.result; previewName.textContent = file.name; imagePreview.classList.remove('hidden'); feather.replace(); }; reader.readAsDataURL(file); }); removeImageBtn.addEventListener('click', () => { attachedImage = null; imagePreview.classList.add('hidden'); fileInput.value = ''; }); // Clear chat clearChatBtn.addEventListener('click', () => { chatMessages.innerHTML = ''; addMessage('bot', '👋 Chat cleared. What app shall we build next?'); }); // Add message to chat function addMessage(role, content, isCode = false) { const wrapper = document.createElement('div'); wrapper.className = `flex ${role === 'user' ? 'justify-end' : 'justify-start'}`; const bubble = document.createElement('div'); bubble.className = role === 'user' ? 'bg-undefined-500 text-white rounded-2xl rounded-tr-sm px-4 py-3 max-w-[85%]' : 'bg-gray-100 dark:bg-gray-700 rounded-2xl rounded-tl-sm px-4 py-3 max-w-[85%]'; if (role === 'bot') { const header = document.createElement('div'); header.className = 'flex items-center gap-2 mb-1 text-xs text-gray-500'; header.innerHTML = ' Qwen'; bubble.appendChild(header); } const textDiv = document.createElement('div'); textDiv.className = 'text-sm whitespace-pre-wrap break-words'; textDiv.textContent = content; bubble.appendChild(textDiv); wrapper.appendChild(bubble); chatMessages.appendChild(wrapper); chatMessages.scrollTop = chatMessages.scrollHeight; feather.replace(); return textDiv; } // Add streaming message (returns the text element to update) function addStreamingMessage() { const wrapper = document.createElement('div'); wrapper.className = 'flex justify-start'; const bubble = document.createElement('div'); bubble.className = 'bg-gray-100 dark:bg-gray-700 rounded-2xl rounded-tl-sm px-4 py-3 max-w-[85%]'; const header = document.createElement('div'); header.className = 'flex items-center gap-2 mb-1 text-xs text-gray-500'; header.innerHTML = ' Qwen '; bubble.appendChild(header); const textDiv = document.createElement('div'); textDiv.className = 'text-sm whitespace-pre-wrap break-words'; bubble.appendChild(textDiv); wrapper.appendChild(bubble); chatMessages.appendChild(wrapper); chatMessages.scrollTop = chatMessages.scrollHeight; feather.replace(); return textDiv; } // Format code blocks in text function formatContent(element, text) { element.innerHTML = ''; const codeRegex = /