Prefer WASM on firefox cause WebGPU is incredibly slow there.
This commit is contained in:
+60
-3
@@ -106,7 +106,18 @@ export type LoadProgressMessage =
|
||||
progress: number;
|
||||
}
|
||||
| { type: "load-progress"; status: "done"; file: string }
|
||||
| { type: "load-progress"; status: "ready"; device: InferenceDevice };
|
||||
| {
|
||||
type: "load-progress";
|
||||
status: "ready";
|
||||
device: InferenceDevice;
|
||||
/**
|
||||
* WASM thread count onnxruntime actually ended up with (D-025) — ort
|
||||
* clamps to 1 when cross-origin isolation is missing, so this is field
|
||||
* observability for "is multithreading really on?". Accelerator devices
|
||||
* report 1 (their WASM side must be single-threaded, D-023).
|
||||
*/
|
||||
threads?: number;
|
||||
};
|
||||
|
||||
/** Incremental transcript fragment — append to the text streamed so far. */
|
||||
export interface PartialMessage {
|
||||
@@ -155,12 +166,32 @@ export interface ErrorMessage {
|
||||
requestId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The worker cannot finish this load usefully in-place and asks the UI to
|
||||
* respawn it (D-025). Posted when an accelerator attempt already initialized
|
||||
* onnxruntime's WASM runtime — whose thread pool is fixed at first init —
|
||||
* single-threaded, so the WASM fallback in *this* worker would run on one
|
||||
* thread for the worker's whole life. The UI terminates the worker, spawns a
|
||||
* fresh one, and re-issues the load with the explicit `device`, remembering
|
||||
* `modelId`+`preference` so later loads skip the doomed attempt entirely.
|
||||
*/
|
||||
export interface LoadRestartMessage {
|
||||
type: "load-restart";
|
||||
/** Echo of the aborted load's model id. */
|
||||
modelId: string;
|
||||
/** Echo of the aborted load's device preference. */
|
||||
preference: DevicePreference;
|
||||
/** Explicit device the fresh worker should load with. */
|
||||
device: InferenceDevice;
|
||||
}
|
||||
|
||||
export type WorkerToUiMessage =
|
||||
| LoadProgressMessage
|
||||
| PartialMessage
|
||||
| TranscribeProgressMessage
|
||||
| ResultMessage
|
||||
| ErrorMessage;
|
||||
| ErrorMessage
|
||||
| LoadRestartMessage;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Device selection policy (D-004, D-017) — pure so it is unit-testable; the
|
||||
@@ -173,6 +204,23 @@ export interface DeviceCapabilities {
|
||||
webnn: boolean;
|
||||
/** `navigator.gpu.requestAdapter()` returned an adapter (WebGPU). */
|
||||
webgpu: boolean;
|
||||
/**
|
||||
* The WebGPU adapter supports the "shader-f16" feature. Firefox ships
|
||||
* WebGPU without it, so fp16 weights cannot run there (D-025); the worker
|
||||
* skips the WebGPU attempt when the resolved dtype needs fp16 and this is
|
||||
* false. Optional so `deviceAttempts` callers that don't probe it (tests)
|
||||
* stay valid.
|
||||
*/
|
||||
webgpuF16?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a dtype spec involves fp16 weights anywhere — such a model cannot
|
||||
* run on a WebGPU adapter without the "shader-f16" feature (D-025).
|
||||
*/
|
||||
export function dtypeRequiresF16(dtype: DtypeSpec): boolean {
|
||||
if (typeof dtype === "string") return dtype === "fp16";
|
||||
return dtype.encoder_model === "fp16" || dtype.decoder_model_merged === "fp16";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,7 +332,10 @@ export function isWorkerToUiMessage(value: unknown): value is WorkerToUiMessage
|
||||
typeof value.progress === "number"
|
||||
);
|
||||
case "ready":
|
||||
return isInferenceDevice(value.device);
|
||||
return (
|
||||
isInferenceDevice(value.device) &&
|
||||
(value.threads === undefined || typeof value.threads === "number")
|
||||
);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -308,6 +359,12 @@ export function isWorkerToUiMessage(value: unknown): value is WorkerToUiMessage
|
||||
(value.stage === "load" || value.stage === "transcribe") &&
|
||||
isOptionalString(value.requestId)
|
||||
);
|
||||
case "load-restart":
|
||||
return (
|
||||
typeof value.modelId === "string" &&
|
||||
isDevicePreference(value.preference) &&
|
||||
isInferenceDevice(value.device)
|
||||
);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user