Xenova's picture
Xenova HF Staff
Fix WASM inference
821f941 verified
Raw
History Blame Contribute Delete
2.21 kB
import {
AutoModel,
AutoTokenizer,
type PreTrainedModel,
type PreTrainedTokenizer,
} from "@huggingface/transformers";
const MODEL_ID = "onnx-community/embeddinggemma-300m-ONNX";
let model: PreTrainedModel | null = null;
let tokenizer: PreTrainedTokenizer | null = null;
let device: "webgpu" | "wasm" | null = null;
self.onmessage = async (event) => {
const { type, payload } = event.data;
if (type === "load-model") {
try {
// Only use webgpu if available
let isWebGPUAvailable = false;
if (navigator.gpu) {
try {
isWebGPUAvailable = !!(await navigator.gpu.requestAdapter());
} catch {}
}
device = isWebGPUAvailable ? "webgpu" : "wasm";
tokenizer = await AutoTokenizer.from_pretrained(MODEL_ID);
model = await AutoModel.from_pretrained(MODEL_ID, {
device,
dtype: "q4",
model_file_name: isWebGPUAvailable ? "model_no_gather" : "model",
progress_callback: (progress) => {
if (
progress.status === "progress" &&
progress.file.endsWith(".onnx_data")
) {
const percentage = Math.round(
(progress.loaded / progress.total) * 100,
);
self.postMessage({
type: "progress",
payload: {
percentage,
status: `Loading model... ${percentage}%`,
},
});
}
},
});
self.postMessage({ type: "ready", payload: { device } });
} catch (error) {
self.postMessage({
type: "error",
payload: error instanceof Error ? error.message : String(error),
});
}
} else if (type === "embed" && model && tokenizer) {
try {
const { sentences, options } = payload;
const inputs = tokenizer(sentences, options);
const { sentence_embedding } = await model(inputs);
const embeddings = sentence_embedding.tolist();
self.postMessage({ type: "embeddings", payload: { embeddings } });
} catch (error) {
self.postMessage({
type: "error",
payload: error instanceof Error ? error.message : String(error),
});
}
}
};