zero-tvm / weights-cache-sw.js
abgunaydin's picture
sync from github@30b8f47
e26c434
Raw
History Blame Contribute Delete
3.9 kB
/* eslint-env serviceworker */
/**
* weights-cache-sw.js — Phi-3 weight cache, shared by any page that loads those weights.
*
* Both zero-tvm's hand-written loader and WebLLM fetch the same files from the
* HF mirror at
* `huggingface.co/mlc-ai/Phi-3-mini-4k-instruct-q4f16_1-MLC/resolve/main/*`.
* Without this SW each cache their own copy, so visiting both pages downloads
* 1.8 GB twice. This SW intercepts those URLs and serves from a shared OPFS
* directory (`zero-tvm-weights/`, the same dir zero-tvm's own loader uses for
* its fast path) — populating it on first download from either side.
*
* Result: whichever page the visitor opens first pays the network cost once.
* Subsequent visits to either page hit OPFS instantly.
*/
// KEEP IN SYNC with WEIGHTS_OPFS_DIR in src/zero-tvm/weight-loader.ts — this
// SW is plain JS and cannot import the exported constant, so the two
// definitions are paired by hand.
const SHARED_DIR = "zero-tvm-weights";
const HF_PHI3_HOST = "huggingface.co";
const HF_PHI3_PATH_RE = /^\/mlc-ai\/Phi-3-mini-4k-instruct-q4f16_1-MLC\/resolve\/[^/]+\//;
self.addEventListener("install", () => self.skipWaiting());
self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim()));
self.addEventListener("fetch", (event) => {
const req = event.request;
if (req.method !== "GET") return;
let url;
try { url = new URL(req.url); } catch { return; }
if (url.host !== HF_PHI3_HOST || !HF_PHI3_PATH_RE.test(url.pathname)) return;
event.respondWith(handle(req, url));
});
async function handle(req, url) {
// Flatten the path-suffix into an OPFS-safe filename, matching the
// `opfsKey()` convention in zero-tvm's weight-loader.ts byte-for-byte
// (so files written by the SW are reused by zero-tvm's direct loader,
// and vice versa).
const dataPath = url.pathname.replace(HF_PHI3_PATH_RE, "");
const key = dataPath.replace(/[^A-Za-z0-9._-]/g, "_");
// 1. Try OPFS hit first.
const cached = await opfsRead(key).catch(() => null);
if (cached) {
return new Response(cached, {
status: 200,
headers: {
"content-type": guessType(key),
"content-length": String(cached.byteLength),
"x-zero-tvm-cache": "opfs-hit",
},
});
}
// 2. Network fall-through. Stream into OPFS so subsequent visits hit cache.
const netResp = await fetch(req);
// Only cache complete 200 bodies: a 206 (the weight-loader resumes dead
// transfers with Range requests) buffered under the full key would poison
// the shared cache with a truncated shard. Pass everything else through.
if (netResp.status !== 200 || !netResp.body) return netResp;
const buf = await netResp.clone().arrayBuffer();
// Best-effort write — failures (quota, no OPFS) are fine; just no caching.
opfsWrite(key, buf).catch(() => {});
return new Response(buf, {
status: netResp.status,
headers: {
"content-type": netResp.headers.get("content-type") || guessType(key),
"content-length": String(buf.byteLength),
"x-zero-tvm-cache": "network",
},
});
}
async function getDir() {
if (!self.navigator?.storage?.getDirectory) throw new Error("no OPFS in SW");
const root = await self.navigator.storage.getDirectory();
return root.getDirectoryHandle(SHARED_DIR, { create: true });
}
async function opfsRead(key) {
const dir = await getDir();
const fh = await dir.getFileHandle(key);
const file = await fh.getFile();
return await file.arrayBuffer();
}
async function opfsWrite(key, buf) {
const dir = await getDir();
const fh = await dir.getFileHandle(key, { create: true });
const writer = await fh.createWritable();
await writer.write(buf);
await writer.close();
}
function guessType(key) {
if (key.endsWith(".json")) return "application/json";
if (key.endsWith(".wasm")) return "application/wasm";
return "application/octet-stream";
}