Spaces:
Running
Running
File size: 4,953 Bytes
5d037dd fc9b90e f3b6176 fc9b90e 5d037dd f3b6176 fc9b90e f3b6176 6d7ed4f f3b6176 82534fe f3b6176 c187faa f3b6176 fc9b90e a981da6 f3b6176 fc9b90e f3b6176 5d037dd f3b6176 fc9b90e a981da6 c187faa fc9b90e 5d037dd f3b6176 c187faa f3b6176 fc9b90e 82534fe f3b6176 a981da6 fc9b90e 82534fe fc9b90e c187faa f3b6176 c187faa fc9b90e f3b6176 fc9b90e f3b6176 fc9b90e f3b6176 fc9b90e a981da6 fc9b90e c187faa fc9b90e c187faa 82534fe fc9b90e a981da6 |
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 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ONNX WebGPU Download & Streaming Text Generation</title>
<script type="module">
import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/[email protected]/dist/transformers.min.js';
// Helper: download a file with progress
async function downloadWithProgress(url, onProgress) {
const response = await fetch(url);
if (!response.ok) throw new Error("Network response was not ok");
const contentLength = +response.headers.get("Content-Length");
if (!contentLength) throw new Error("Content-Length header missing");
const reader = response.body.getReader();
let received = 0;
const chunks = [];
while(true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
received += value.length;
onProgress(received / contentLength);
}
const blob = new Blob(chunks);
return blob;
}
async function runPrompt(prompt) {
const progressBar = document.getElementById("progress");
const progressText = document.getElementById("progressText");
const outputElem = document.getElementById("output");
// 1️⃣ Download model ONNX file manually
const modelUrl = "https://huggingface.co/onnx-community/gemma-3-1b-it-ONNX/resolve/main/onnx/model_q4.onnx"; // example file
console.log("%cDownloading model...", "color: orange; font-weight: bold;");
outputElem.textContent = "Downloading model...\n";
progressBar.style.width = "0%";
progressText.textContent = "0%";
await downloadWithProgress(modelUrl, (ratio) => {
const pct = Math.floor(ratio * 100);
progressBar.style.width = pct + "%";
progressText.textContent = pct + "%";
});
console.log("%cModel downloaded!", "color: green; font-weight: bold;");
outputElem.textContent += "Model downloaded.\n";
// 2️⃣ Initialize generator using WebGPU
outputElem.textContent += "Initializing pipeline...\n";
const generator = await pipeline(
"text-generation",
"onnx-community/gemma-3-1b-it-ONNX",
{ dtype: "q4", providers: ["webgpu"] }
);
outputElem.textContent += "Pipeline ready. Generating text...\n";
// 3️⃣ Stream output
const messages = [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: prompt },
];
let generatedTokens = 0;
const maxTokens = 512;
for await (const token of generator.stream(messages, { max_new_tokens: maxTokens, do_sample: false })) {
outputElem.textContent += token.content;
outputElem.scrollTop = outputElem.scrollHeight;
generatedTokens++;
const progress = Math.min((generatedTokens / maxTokens) * 100, 100);
progressBar.style.width = progress + "%";
progressText.textContent = Math.floor(progress) + "%";
}
progressBar.style.width = "100%";
progressText.textContent = "100%";
console.log("%cGeneration complete!", "color: blue; font-weight: bold;");
}
window.onload = () => {
const form = document.getElementById("promptForm");
form.onsubmit = (e) => {
e.preventDefault();
const prompt = document.getElementById("promptInput").value;
document.getElementById("output").textContent = "";
runPrompt(prompt);
}
};
</script>
<style>
body { font-family: 'Segoe UI', sans-serif; background: #1e1e2f; color: #f0f0f0; display: flex; flex-direction: column; align-items: center; padding: 2rem; }
h1 { color: #ffcc00; margin-bottom: 1rem; }
#promptForm { display: flex; gap: 0.5rem; margin-bottom: 1rem; }
#promptInput { padding: 0.5rem; width: 400px; border-radius: 5px; border: none; font-size: 1rem; }
#generateBtn { padding: 0.5rem 1rem; background: #ffcc00; border: none; border-radius: 5px; font-weight: bold; cursor: pointer; color: #1e1e2f; }
#generateBtn:hover { background: #ffdd33; }
#progressContainer { width: 400px; height: 20px; background: #333; border-radius: 5px; overflow: hidden; margin-bottom: 1rem; position: relative; }
#progress { width: 0%; height: 100%; background: #ffcc00; transition: width 0.05s; }
#progressText { position: absolute; right: 10px; top: 0; bottom: 0; display: flex; align-items: center; justify-content: flex-end; font-size: 0.8rem; color: #1e1e2f; font-weight: bold; }
pre#output { width: 400px; background: #2e2e44; padding: 1rem; border-radius: 8px; white-space: pre-wrap; word-wrap: break-word; min-height: 150px; overflow-y: auto; }
</style>
</head>
<body>
<h1>ONNX WebGPU Streaming Text Generation</h1>
<form id="promptForm">
<input id="promptInput" type="text" placeholder="Type your prompt..." required />
<button id="generateBtn">Generate</button>
</form>
<div id="progressContainer">
<div id="progress"></div>
<div id="progressText">0%</div>
</div>
<pre id="output">Enter a prompt and hit Generate...</pre>
</body>
</html>
|