Implement speedups for transcription.

This commit is contained in:
Lucas Winther committed 2026-07-15 14:45:40 +02:00
1 parent 742053144e
commit a5cfd219f6
3 files changed
+118 -16

No files matched your search

+52 -16
View File
@@ -16,6 +16,36 @@ const IS_PRODUCTION = process.env.NODE_ENV === "production";
const NOT_FOUND = () => new Response("Not Found", { status: 404 });
/**
* Cross-origin isolation (D-023): COOP + COEP make `crossOriginIsolated`
* true in the browser, which unlocks SharedArrayBuffer — without it,
* onnxruntime-web silently runs its WASM backend on a SINGLE thread and
* browser inference is several times slower than it should be. Applied to
* every response: only documents/workers consume them, and they are harmless
* on assets and API responses. Cross-origin model downloads keep working —
* the Hugging Face Hub is fetched with CORS, which `require-corp` allows.
*/
const ISOLATION_HEADERS: Record<string, string> = {
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp",
};
function withIsolationHeaders(response: Response): Response {
try {
for (const [name, value] of Object.entries(ISOLATION_HEADERS)) {
response.headers.set(name, value);
}
return response;
} catch {
// Responses produced by fetch() have immutable headers — rebuild.
const copy = new Response(response.body, response);
for (const [name, value] of Object.entries(ISOLATION_HEADERS)) {
copy.headers.set(name, value);
}
return copy;
}
}
// onnxruntime-web fetches its .wasm binaries at runtime — from the jsdelivr
// CDN by default, which would break offline. The worker points
// `env.backends.onnx.wasm.wasmPaths` at /ort/ instead (see
@@ -138,15 +168,15 @@ async function productionServeOptions(): Promise<ServeOptions> {
// API routes are dynamic (M4/M5) and network-only in the SW (D-007).
if (url.pathname.includes("/api/")) {
const response = await handleApiRequest(request, server);
if (response) return response;
if (response) return withIsolationHeaders(response);
return new Response("Upgrading...", { status: 101 }); // actually Bun handles the real response, but TypeScript requires a return
}
let relative = url.pathname === "/" ? "index.html" : decodeURIComponent(url.pathname.slice(1));
if (relative.endsWith("/")) relative += "index.html";
let path = normalize(join(dist, relative));
// Auto-strip proxy subpaths for static assets
while (relative.includes("/") && !(await Bun.file(path).exists())) {
relative = relative.substring(relative.indexOf("/") + 1);
@@ -163,9 +193,9 @@ async function productionServeOptions(): Promise<ServeOptions> {
? "public, max-age=31536000, immutable"
: "no-cache",
);
if (response.status !== 404) return response;
if (response.status !== 404) return withIsolationHeaders(response);
// SPA fallback: serve the app shell for unknown navigations.
return serveFile(join(dist, "index.html"), "no-cache");
return withIsolationHeaders(await serveFile(join(dist, "index.html"), "no-cache"));
},
};
}
@@ -215,7 +245,10 @@ async function developmentServeOptions(): Promise<ServeOptions> {
routes: {
// The HTML import is an HTMLBundle, which Bun only serves as a route
// value — returning it from fetch() throws "Expected a Response object".
"/": index,
// It is mounted on an internal path so "/" can flow through fetch()
// below, which re-serves it with the COOP/COEP isolation headers
// (D-023) that Bun cannot attach to an HTMLBundle route directly.
"/__shell": index,
},
// Fallback for everything the route table doesn't match, including
@@ -226,34 +259,37 @@ async function developmentServeOptions(): Promise<ServeOptions> {
if (pathname.includes("/api/")) {
const response = await handleApiRequest(request, server);
if (response) return response;
if (response) return withIsolationHeaders(response);
return new Response("Upgrading...", { status: 101 });
}
if (pathname.endsWith("/inference.worker.js")) {
return new Response(workerScript, { headers: scriptHeaders });
return withIsolationHeaders(new Response(workerScript, { headers: scriptHeaders }));
}
if (pathname.endsWith("/sw.js")) {
return new Response(swScript, { headers: { ...scriptHeaders, "Cache-Control": "no-cache" } });
return withIsolationHeaders(
new Response(swScript, { headers: { ...scriptHeaders, "Cache-Control": "no-cache" } }),
);
}
if (pathname.endsWith("/manifest.webmanifest")) {
return serveFile(join(import.meta.dir, "pwa/manifest.webmanifest"));
return withIsolationHeaders(await serveFile(join(import.meta.dir, "pwa/manifest.webmanifest")));
}
const iconsMatch = pathname.match(/\/icons\/(icon-\d+\.png)$/);
if (iconsMatch?.[1]) {
return serveFile(join(ICONS_DIR, iconsMatch[1]));
return withIsolationHeaders(await serveFile(join(ICONS_DIR, iconsMatch[1])));
}
const ortMatch = pathname.match(/\/ort\/(.*(?:wasm|mjs))$/);
if (ortMatch?.[1]) {
return serveOrtFile(ORT_DIST, ortMatch[1]);
return withIsolationHeaders(await serveOrtFile(ORT_DIST, ortMatch[1]));
}
// SPA fallback: unknown navigations (including subpath ones) get the
// app shell. The HTMLBundle itself can only live in `routes`, so
// re-enter the server at "/" to let it produce the dev-bundled HTML.
return fetch(new URL("/", server.url));
// The app shell ("/" and SPA fallback for unknown navigations,
// including subpath ones). The HTMLBundle itself can only live in
// `routes`, so re-enter the server at "/__shell" to let it produce the
// dev-bundled HTML, then stamp the isolation headers on the document.
return withIsolationHeaders(await fetch(new URL("/__shell", server.url)));
},
development: {