Spaces:
Running
Running
🐳 18/08 - 21:05 - cree un systeme pour ree des application ave qwen. import os from openai import OpenAI client = OpenAI( base_url="https://router.huggingface.co/v1", api_key=os.environ[
07ea14f verified | // === 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 = / |