Spaces:
Running
Running
File size: 5,503 Bytes
07ea14f | 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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | // === 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 = '<i data-feather="cpu" class="w-3 h-3"></i> 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 = '<i data-feather="cpu" class="w-3 h-3"></i> Qwen <span class="animate-pulse">●</span>';
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 = / |