Spaces:
Running
Running
| <html lang="vi"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Qwen 2.5 CPU Streaming</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <style> | |
| body { background: #121212; color: white; height: 100vh; display: flex; flex-direction: column; } | |
| #chat-container { flex: 1; overflow-y: auto; padding: 20px; font-family: sans-serif; } | |
| .message { margin-bottom: 15px; padding: 12px; border-radius: 10px; max-width: 85%; white-space: pre-wrap; } | |
| .user { background: #2b2b2b; align-self: flex-end; border: 1px solid #444; } | |
| .ai { background: #0056b3; align-self: flex-start; } | |
| #input-area { background: #1e1e1e; padding: 20px; border-top: 1px solid #333; } | |
| input { background: #2b2b2b ; color: white ; border: 1px solid #444 ; } | |
| .loading-dots::after { content: '...'; animation: blink 1s infinite; } | |
| @keyframes blink { 0% { opacity: 0; } 50% { opacity: 1; } 100% { opacity: 0; } } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="chat-container" class="d-flex flex-column"> | |
| <div class="message ai">Hệ thống đã sẵn sàng. Model: <b>Qwen2.5-0.5B (WASM/CPU)</b>.</div> | |
| </div> | |
| <div id="input-area"> | |
| <div class="input-group"> | |
| <input type="text" id="user-input" class="form-control" placeholder="Hỏi Qwen..."> | |
| <button class="btn btn-success" type="button" id="send-btn">Gửi</button> | |
| </div> | |
| <div id="status" class="small mt-2 text-secondary">Đang khởi tạo...</div> | |
| </div> | |
| <script type="module"> | |
| // Using the newer v3 namespace which supports TextStreamer properly | |
| import { | |
| pipeline, | |
| env, | |
| TextStreamer | |
| } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.0'; | |
| // Disable local file searching to fix CORS/File error | |
| env.allowLocalModels = false; | |
| env.useBrowserCache = true; | |
| const chatContainer = document.getElementById('chat-container'); | |
| const userInput = document.getElementById('user-input'); | |
| const sendBtn = document.getElementById('send-btn'); | |
| const status = document.getElementById('status'); | |
| let generator = null; | |
| async function init() { | |
| status.innerHTML = 'Đang tải Model (~300MB)... <span class="loading-dots"></span>'; | |
| try { | |
| // Loading the Qwen 2.5 0.5B Instruct model | |
| generator = await pipeline('text-generation', 'onnx-community/Qwen2.5-0.5B-Instruct', { | |
| device: 'wasm', // Force CPU usage via WebAssembly | |
| dtype: 'q4', // Use 4-bit quantization for faster browser performance | |
| }); | |
| status.textContent = 'Trạng thái: Sẵn sàng (CPU/WASM)'; | |
| } catch (e) { | |
| status.textContent = 'Lỗi: ' + e.message; | |
| console.error(e); | |
| } | |
| } | |
| async function chat() { | |
| const text = userInput.value.trim(); | |
| if (!text || !generator) return; | |
| // User UI | |
| const userDiv = document.createElement('div'); | |
| userDiv.className = 'message user'; | |
| userDiv.textContent = text; | |
| chatContainer.appendChild(userDiv); | |
| userInput.value = ''; | |
| // AI UI setup | |
| const aiDiv = document.createElement('div'); | |
| aiDiv.className = 'message ai'; | |
| chatContainer.appendChild(aiDiv); | |
| status.textContent = 'Qwen đang gõ...'; | |
| // Setup Streamer | |
| const streamer = new TextStreamer(generator.tokenizer, { | |
| skip_prompt: true, | |
| callback_function: (token) => { | |
| aiDiv.textContent += token; | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| }, | |
| }); | |
| // Execute Generation | |
| const messages = [{ role: "user", content: text }]; | |
| try { | |
| await generator(messages, { | |
| max_new_tokens: 256, | |
| streamer: streamer, | |
| }); | |
| status.textContent = 'Hoàn thành.'; | |
| } catch (err) { | |
| status.textContent = 'Lỗi khi tạo: ' + err.message; | |
| } | |
| } | |
| sendBtn.addEventListener('click', chat); | |
| userInput.addEventListener('keypress', (e) => { if(e.key === 'Enter') chat(); }); | |
| init(); | |
| </script> | |
| </body> | |
| </html> |