Better tests and more user feedback while doing transcription; WIP.
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
* Inference Web Worker (Decisions.md D-003 — inference never runs on the main
|
||||
* thread). Hosts the Transformers.js `automatic-speech-recognition` pipeline.
|
||||
*
|
||||
* M2: WebGPU detection with automatic WASM fallback (D-004), catalog-driven
|
||||
* dtype defaults (D-006), model switching with pipeline disposal, and
|
||||
* language/task options for multilingual models.
|
||||
* M2: hardware backend detection with automatic fallback — "auto" resolves
|
||||
* WebNN → WebGPU → WASM (D-004, D-017) — catalog-driven dtype defaults
|
||||
* (D-006), model switching with pipeline disposal, and language/task options
|
||||
* for multilingual models.
|
||||
*/
|
||||
|
||||
import {
|
||||
@@ -16,7 +17,9 @@ import {
|
||||
} from "@huggingface/transformers";
|
||||
import { resolveDefaultDtype } from "../lib/models";
|
||||
import {
|
||||
deviceAttempts,
|
||||
isUiToWorkerMessage,
|
||||
type DeviceCapabilities,
|
||||
type DevicePreference,
|
||||
type InferenceDevice,
|
||||
type LoadMessage,
|
||||
@@ -56,7 +59,7 @@ function errorMessage(error: unknown): string {
|
||||
* Forward Transformers.js progress events to the UI as load-progress messages.
|
||||
* The library's own "ready" event is swallowed — the worker posts its own
|
||||
* `ready` (with the selected device) once the pipeline actually resolved,
|
||||
* which also covers the WebGPU → WASM fallback retry (D-004).
|
||||
* which also covers the device fallback retries (D-004, D-017).
|
||||
*/
|
||||
function forwardProgress(info: ProgressInfo): void {
|
||||
switch (info.status) {
|
||||
@@ -83,7 +86,9 @@ function forwardProgress(info: ProgressInfo): void {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Device selection (D-004): WebGPU when available, automatic WASM fallback
|
||||
// Device selection (D-004, D-017): "auto" resolves WebNN → WebGPU → WASM.
|
||||
// The probe only answers "does the backend exist?"; the attempt ordering and
|
||||
// fallback policy live in the pure `deviceAttempts` (protocol.ts, unit-tested).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
interface NavigatorWithHardware {
|
||||
@@ -91,21 +96,26 @@ interface NavigatorWithHardware {
|
||||
ml?: unknown;
|
||||
}
|
||||
|
||||
async function detectDevice(preference: DevicePreference): Promise<InferenceDevice> {
|
||||
if (preference === "wasm") return "wasm";
|
||||
if (preference === "webnn") {
|
||||
async function probeCapabilities(
|
||||
preference: DevicePreference,
|
||||
): Promise<DeviceCapabilities> {
|
||||
const capabilities: DeviceCapabilities = { webnn: false, webgpu: false };
|
||||
const hardware = navigator as NavigatorWithHardware;
|
||||
if (preference === "auto" || preference === "webnn") {
|
||||
try {
|
||||
return (navigator as NavigatorWithHardware).ml ? "webnn" : "wasm";
|
||||
capabilities.webnn = Boolean(hardware.ml);
|
||||
} catch {
|
||||
return "wasm";
|
||||
// Probing threw — treat WebNN as unavailable.
|
||||
}
|
||||
}
|
||||
try {
|
||||
const adapter = await (navigator as NavigatorWithHardware).gpu?.requestAdapter();
|
||||
return adapter ? "webgpu" : "wasm";
|
||||
} catch {
|
||||
return "wasm";
|
||||
if (preference === "auto" || preference === "webgpu") {
|
||||
try {
|
||||
capabilities.webgpu = Boolean(await hardware.gpu?.requestAdapter());
|
||||
} catch {
|
||||
// Probing threw — treat WebGPU as unavailable.
|
||||
}
|
||||
}
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -131,12 +141,14 @@ function loadKey(message: LoadMessage): string {
|
||||
async function createPipeline(
|
||||
message: LoadMessage,
|
||||
): Promise<AutomaticSpeechRecognitionPipeline> {
|
||||
const detected = await detectDevice(message.device);
|
||||
// If WebGPU was selected but pipeline creation throws (driver quirks,
|
||||
// unsupported ops, out-of-memory), fall back to WASM automatically (D-004).
|
||||
const attempts: InferenceDevice[] =
|
||||
detected === "webgpu" ? ["webgpu", "wasm"] :
|
||||
detected === "webnn" ? ["webnn", "wasm"] : ["wasm"];
|
||||
// Ordered devices to try (D-004/D-017): the first is the selected device;
|
||||
// if pipeline creation throws there (driver quirks, unsupported ops,
|
||||
// out-of-memory), the next one is tried automatically. For "auto" the chain
|
||||
// is WebNN → WebGPU → WASM (filtered by the probe); WASM always terminates it.
|
||||
const attempts: InferenceDevice[] = deviceAttempts(
|
||||
message.device,
|
||||
await probeCapabilities(message.device),
|
||||
);
|
||||
|
||||
let lastError: unknown;
|
||||
for (const device of attempts) {
|
||||
|
||||
Reference in New Issue
Block a user