TransformerWebs / index (4).html
Accordic's picture
Upload index (4).html
33e8392 verified
<!DOCTYPE html>
<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 !important; color: white !important; border: 1px solid #444 !important; }
.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>