QED-75M_web / index.html
levossadtchi's picture
Upload folder using huggingface_hub
299677b verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>QED-75M Playground</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.container {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 { color: #333; }
textarea {
width: 100%;
min-height: 100px;
padding: 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
resize: vertical;
}
button {
background: #007bff;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
margin-top: 10px;
}
button:hover { background: #0056b3; }
button:disabled { background: #ccc; cursor: not-allowed; }
.output {
margin-top: 20px;
padding: 15px;
background: #f8f9fa;
border-radius: 4px;
white-space: pre-wrap;
line-height: 1.6;
}
.status {
margin-top: 10px;
padding: 10px;
border-radius: 4px;
font-size: 14px;
}
.loading { background: #fff3cd; color: #856404; }
.ready { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
.settings {
margin-top: 15px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 10px;
}
.settings label {
display: block;
font-size: 14px;
margin-bottom: 5px;
}
.settings input {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="container">
<h1>🧪 QED-75M Playground</h1>
<div id="status" class="status loading">Loading model...</div>
<div class="settings">
<div>
<label>Max tokens: <span id="maxTokensVal">128</span></label>
<input type="range" id="maxTokens" min="32" max="512" value="128" step="32">
</div>
<div>
<label>Temperature: <span id="tempVal">0.7</span></label>
<input type="range" id="temperature" min="0.1" max="1.5" value="0.7" step="0.1">
</div>
<div>
<label>Top K: <span id="topKVal">40</span></label>
<input type="range" id="topK" min="10" max="100" value="40" step="10">
</div>
</div>
<textarea id="prompt" placeholder="Enter your prompt here...
Example: <|user|>What is 2+2?<|assistant|>"></textarea>
<button id="generateBtn" disabled>Generate</button>
<div class="output" id="output"></div>
</div>
<script type="module">
// Import Transformers.js
import { AutoTokenizer, AutoModelForCausalLM, GenerationConfig } from 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.14.0';
const MODEL_ID = 'levossadtchi/QED-75M_web';
let tokenizer = null;
let model = null;
// UI elements
const statusEl = document.getElementById('status');
const promptEl = document.getElementById('prompt');
const outputEl = document.getElementById('output');
const generateBtn = document.getElementById('generateBtn');
const maxTokensEl = document.getElementById('maxTokens');
const tempEl = document.getElementById('temperature');
const topKEl = document.getElementById('topK');
// Update value displays
maxTokensEl.addEventListener('input', (e) => {
document.getElementById('maxTokensVal').textContent = e.target.value;
});
tempEl.addEventListener('input', (e) => {
document.getElementById('tempVal').textContent = e.target.value;
});
topKEl.addEventListener('input', (e) => {
document.getElementById('topKVal').textContent = e.target.value;
});
// Load model
async function loadModel() {
try {
// Load tokenizer
tokenizer = await AutoTokenizer.from_pretrained(MODEL_ID, {
local_files_only: false,
});
// Load model with quantization
model = await AutoModelForCausalLM.from_pretrained(MODEL_ID, {
quantized: true,
dtype: 'q8', // int8 quantization
device: 'webgpu', // Try WebGPU first, fallback to WASM
});
statusEl.textContent = '✅ Model ready!';
statusEl.className = 'status ready';
generateBtn.disabled = false;
} catch (error) {
statusEl.textContent = '❌ Error loading model: ' + error.message;
statusEl.className = 'status error';
console.error('Model loading error:', error);
}
}
// Generate text
async function generate() {
const prompt = promptEl.value.trim();
if (!prompt) return;
generateBtn.disabled = true;
generateBtn.textContent = 'Generating...';
outputEl.textContent = '';
try {
// Tokenize input
const inputs = await tokenizer(prompt, {
return_tensors: 'pt',
add_special_tokens: false,
});
// Generate
const outputs = await model.generate({
...inputs,
max_new_tokens: parseInt(maxTokensEl.value),
temperature: parseFloat(tempEl.value),
top_k: parseInt(topKEl.value),
do_sample: parseFloat(tempEl.value) > 0,
eos_token_id: tokenizer.eos_token_id,
pad_token_id: tokenizer.pad_token_id,
});
// Decode and display
const text = tokenizer.decode(outputs[0], {
skip_special_tokens: false,
});
outputEl.textContent = text;
} catch (error) {
outputEl.textContent = 'Error: ' + error.message;
} finally {
generateBtn.disabled = false;
generateBtn.textContent = 'Generate';
}
}
generateBtn.addEventListener('click', generate);
// Allow Ctrl+Enter to generate
promptEl.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 'Enter') {
generate();
}
});
// Start loading
loadModel();
</script>
</body>
</html>