Full example
Requirements before running:
flora.jsandflora.wasmare accessible by the page in the folder /wasm- Internet access is required to download the public demo model when loading the page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Flora WASM Minimal</title>
</head>
<body>
<main>
<label for="prompt-input">Prompt</label>
<textarea id="prompt-input" rows="4" cols="80">Hello</textarea>
<div><button id="run-btn" type="button" disabled>Run</button></div>
<div id="status"></div>
<div id="error" style="color: #b00020;"></div>
<pre id="output"></pre>
<div id="token-speed"></div>
</main>
<script src="/wasm/flora.js"></script>
<script>
(async () => {
const $ = (id) => document.getElementById(id);
const outputEl = $('output');
const tokenSpeedEl = $('token-speed');
const promptInput = $('prompt-input');
const runBtn = $('run-btn');
const statusEl = $('status');
const errorEl = $('error');
const MODEL_BUCKET_PATH = 'databiomes-public-models/cat';
const MODEL_BASE_URL = `https://storage.googleapis.com/${MODEL_BUCKET_PATH}`;
const MODEL_FILES = ['tokenizer.bin', 'weights.bin'];
const setStatus = (text) => (statusEl.textContent = text);
const showError = (err) => {
const msg = err instanceof Error ? err.message : String(err);
errorEl.textContent = `Error: ${msg}`;
};
const ensureMemoryViews = (mod) => {
if (!mod.HEAPU32 && mod.wasmMemory) {
const b = mod.wasmMemory.buffer;
mod.HEAPU32 = new Uint32Array(b);
mod.HEAP32 = new Int32Array(b);
mod.HEAPF32 = new Float32Array(b);
}
};
const call = (mod, name, ret, types, args) => {
const base = name.startsWith('_') ? name.slice(1) : name;
if (typeof mod[`_${base}`] !== 'function') throw new Error(`Missing export: _${base}`);
return mod.ccall(base, ret, types, args);
};
const loadModel = async (mod) => {
try {
mod.FS.mkdir('/model');
} catch {}
for (const f of MODEL_FILES) {
setStatus(`Downloading ${f}...`);
const res = await fetch(`${MODEL_BASE_URL}/${f}`);
if (!res.ok) throw new Error(`Failed to download ${f}: HTTP ${res.status}`);
mod.FS.writeFile(`/model/${f}`, new Uint8Array(await res.arrayBuffer()));
}
};
try {
if (typeof createFloraModule === 'undefined') {
showError('createFloraModule not found. Make sure flora.js is loaded.');
return;
}
const mod = await createFloraModule({
locateFile: (p) => (p.endsWith('.wasm') ? '/wasm/flora.wasm' : p),
print: () => {},
printErr: () => {},
onRuntimeInitialized() {
ensureMemoryViews(this);
},
});
setStatus('Initializing model...');
try { call(mod, 'LogAddFilePointer', null, [], []); } catch {}
await loadModel(mod);
const instance = call(mod, 'InitNLM', 'number', ['string'], ['/model']);
if (!instance) throw new Error('InitNLM failed.');
setStatus('Model initialized.');
runBtn.disabled = false;
// Here is where the model is called and the response is read.
runBtn.addEventListener('click', () => {
try {
call(mod, 'Inference', null, ['number', 'string'], [instance, promptInput.value || '']);
const outPtr = call(mod, 'OutputNLM', 'number', ['number'], [instance]);
ensureMemoryViews(mod);
const speed = mod.HEAPF32[outPtr / 4];
const size = mod.HEAP32[(outPtr + 4) / 4];
const buf = mod.HEAPU32[(outPtr + 8) / 4];
outputEl.textContent = mod.UTF8ToString(buf, size);
tokenSpeedEl.textContent = `Token speed: ${speed}`;
} catch (err) {
showError(err);
}
});
window.addEventListener('beforeunload', () => {
mod.ccall('Delete', null, ['number'], [instance]);
});
} catch (err) {
showError(err);
}
})();
</script>
</body>
</html>
Databiomes