@remotion/whisper-webgpu 4.0.518

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # @remotion/whisper-webgpu
2
+
3
+ Transcribe audio in the browser using Whisper and WebGPU
4
+
5
+ [![NPM Downloads](https://img.shields.io/npm/dm/@remotion/whisper-webgpu.svg?style=flat&color=black&label=Downloads)](https://npmcharts.com/compare/@remotion/whisper-webgpu?minimal=true)
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @remotion/whisper-webgpu --save-exact
11
+ ```
12
+
13
+ When installing a Remotion package, make sure to align the version of all `remotion` and `@remotion/*` packages to the same version.
14
+ Remove the `^` character from the version number to use the exact version.
15
+
16
+ ## Usage
17
+
18
+ See the [documentation](https://www.remotion.dev/docs/whisper-webgpu) for more information.
@@ -0,0 +1,13 @@
1
+ export declare enum WhisperWebGpuUnsupportedReason {
2
+ WindowUndefined = "window-undefined",
3
+ WebGpuUnavailable = "webgpu-unavailable",
4
+ WebGpuRequiresSecureContext = "webgpu-requires-secure-context"
5
+ }
6
+ export type CanUseWhisperWebGpuResult = {
7
+ supported: true;
8
+ } | {
9
+ supported: false;
10
+ reason: WhisperWebGpuUnsupportedReason;
11
+ detailedReason: string;
12
+ };
13
+ export declare const canUseWhisperWebGpu: () => Promise<CanUseWhisperWebGpuResult>;
@@ -0,0 +1 @@
1
+ export declare const clearStaleModels: () => Promise<void>;
@@ -0,0 +1,433 @@
1
+ var __create = Object.create;
2
+ var __getProtoOf = Object.getPrototypeOf;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __toESM = (mod, isNodeMode, target) => {
7
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
8
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
9
+ for (let key of __getOwnPropNames(mod))
10
+ if (!__hasOwnProp.call(to, key))
11
+ __defProp(to, key, {
12
+ get: () => mod[key],
13
+ enumerable: true
14
+ });
15
+ return to;
16
+ };
17
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
18
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
19
+ }) : x)(function(x) {
20
+ if (typeof require !== "undefined")
21
+ return require.apply(this, arguments);
22
+ throw Error('Dynamic require of "' + x + '" is not supported');
23
+ });
24
+
25
+ // src/can-use-whisper-webgpu.ts
26
+ var WhisperWebGpuUnsupportedReason;
27
+ ((WhisperWebGpuUnsupportedReason2) => {
28
+ WhisperWebGpuUnsupportedReason2["WindowUndefined"] = "window-undefined";
29
+ WhisperWebGpuUnsupportedReason2["WebGpuUnavailable"] = "webgpu-unavailable";
30
+ WhisperWebGpuUnsupportedReason2["WebGpuRequiresSecureContext"] = "webgpu-requires-secure-context";
31
+ })(WhisperWebGpuUnsupportedReason ||= {});
32
+ var canUseWhisperWebGpu = async () => {
33
+ if (typeof window === "undefined") {
34
+ return {
35
+ supported: false,
36
+ reason: "window-undefined" /* WindowUndefined */,
37
+ detailedReason: "`window` is not defined. @remotion/whisper-webgpu is intended for browser environments."
38
+ };
39
+ }
40
+ if (typeof navigator === "undefined" || !("gpu" in navigator)) {
41
+ return {
42
+ supported: false,
43
+ reason: "webgpu-unavailable" /* WebGpuUnavailable */,
44
+ detailedReason: "WebGPU is not available in this browser."
45
+ };
46
+ }
47
+ if (!window.isSecureContext) {
48
+ return {
49
+ supported: false,
50
+ reason: "webgpu-requires-secure-context" /* WebGpuRequiresSecureContext */,
51
+ detailedReason: "WebGPU requires HTTPS in production or localhost during development."
52
+ };
53
+ }
54
+ let adapter;
55
+ try {
56
+ const { gpu } = navigator;
57
+ adapter = await gpu.requestAdapter();
58
+ } catch {
59
+ adapter = null;
60
+ }
61
+ if (!adapter) {
62
+ return {
63
+ supported: false,
64
+ reason: "webgpu-unavailable" /* WebGpuUnavailable */,
65
+ detailedReason: "No usable WebGPU adapter is available in this browser."
66
+ };
67
+ }
68
+ return { supported: true };
69
+ };
70
+ // src/clear-stale-models.ts
71
+ var clearStaleModels = () => Promise.resolve();
72
+ // src/models.ts
73
+ var WHISPER_WEBGPU_MODELS = [
74
+ "tiny",
75
+ "tiny.en",
76
+ "base",
77
+ "base.en",
78
+ "small",
79
+ "small.en",
80
+ "medium",
81
+ "medium.en",
82
+ "large-v3-turbo"
83
+ ];
84
+ var MODEL_INFO = {
85
+ tiny: {
86
+ name: "tiny",
87
+ modelId: "onnx-community/whisper-tiny_timestamped",
88
+ parameters: 39000000,
89
+ multilingual: true,
90
+ webGpuDownloadSize: 119699015
91
+ },
92
+ "tiny.en": {
93
+ name: "tiny.en",
94
+ modelId: "onnx-community/whisper-tiny.en_timestamped",
95
+ parameters: 39000000,
96
+ multilingual: false,
97
+ webGpuDownloadSize: 119697479
98
+ },
99
+ base: {
100
+ name: "base",
101
+ modelId: "onnx-community/whisper-base_timestamped",
102
+ parameters: 74000000,
103
+ multilingual: true,
104
+ webGpuDownloadSize: 206190057
105
+ },
106
+ "base.en": {
107
+ name: "base.en",
108
+ modelId: "onnx-community/whisper-base.en_timestamped",
109
+ parameters: 74000000,
110
+ multilingual: false,
111
+ webGpuDownloadSize: 206188009
112
+ },
113
+ small: {
114
+ name: "small",
115
+ modelId: "onnx-community/whisper-small_timestamped",
116
+ parameters: 244000000,
117
+ multilingual: true,
118
+ webGpuDownloadSize: 586213010
119
+ },
120
+ "small.en": {
121
+ name: "small.en",
122
+ modelId: "onnx-community/whisper-small.en_timestamped",
123
+ parameters: 244000000,
124
+ multilingual: false,
125
+ webGpuDownloadSize: 586209938
126
+ },
127
+ medium: {
128
+ name: "medium",
129
+ modelId: "onnx-community/whisper-medium_timestamped",
130
+ parameters: 769000000,
131
+ multilingual: true,
132
+ webGpuDownloadSize: 1698508143
133
+ },
134
+ "medium.en": {
135
+ name: "medium.en",
136
+ modelId: "onnx-community/whisper-medium.en_timestamped",
137
+ parameters: 769000000,
138
+ multilingual: false,
139
+ webGpuDownloadSize: 1698504047
140
+ },
141
+ "large-v3-turbo": {
142
+ name: "large-v3-turbo",
143
+ modelId: "onnx-community/whisper-large-v3-turbo_timestamped",
144
+ parameters: 809000000,
145
+ multilingual: true,
146
+ webGpuDownloadSize: 2882584170
147
+ }
148
+ };
149
+ var getAvailableModels = () => {
150
+ return WHISPER_WEBGPU_MODELS.map((model) => ({ ...MODEL_INFO[model] }));
151
+ };
152
+ var getModelInfo = (model) => {
153
+ return MODEL_INFO[model];
154
+ };
155
+ var WHISPER_WEBGPU_DTYPE = {
156
+ encoder_model: "fp32",
157
+ decoder_model_merged: "q4"
158
+ };
159
+
160
+ // src/load-whisper-model.ts
161
+ var pipelines = new Map;
162
+ var getOrCreateWhisperPipeline = ({
163
+ model,
164
+ onProgress
165
+ }) => {
166
+ const modelInfo = getModelInfo(model);
167
+ const totalBytes = modelInfo.webGpuDownloadSize;
168
+ const existing = pipelines.get(model);
169
+ if (existing) {
170
+ return { state: existing, alreadyLoaded: true, totalBytes };
171
+ }
172
+ const loading = Promise.resolve().then(async () => {
173
+ const { pipeline } = await import("@huggingface/transformers");
174
+ onProgress?.({
175
+ status: "loading",
176
+ file: null,
177
+ progress: 0,
178
+ loadedBytes: 0,
179
+ totalBytes
180
+ });
181
+ const { modelId } = modelInfo;
182
+ const loadedByFile = new Map;
183
+ let lastProgress = 0;
184
+ let lastLoadedBytes = 0;
185
+ return pipeline("automatic-speech-recognition", modelId, {
186
+ device: "webgpu",
187
+ dtype: WHISPER_WEBGPU_DTYPE,
188
+ progress_callback: onProgress ? (event) => {
189
+ const record = event;
190
+ if (record.status === "progress" && typeof record.file === "string" && typeof record.loaded === "number" && Number.isFinite(record.loaded)) {
191
+ loadedByFile.set(record.file, Math.max(loadedByFile.get(record.file) ?? 0, record.loaded));
192
+ const loadedBytes = [...loadedByFile.values()].reduce((sum, loaded) => sum + loaded, 0);
193
+ lastProgress = Math.max(lastProgress, Math.min(loadedBytes / totalBytes, 0.99));
194
+ lastLoadedBytes = Math.max(lastLoadedBytes, loadedBytes);
195
+ onProgress({
196
+ status: "loading",
197
+ file: null,
198
+ progress: lastProgress,
199
+ loadedBytes: lastLoadedBytes,
200
+ totalBytes
201
+ });
202
+ }
203
+ if (record.status === "ready") {
204
+ onProgress({
205
+ status: "ready",
206
+ file: null,
207
+ progress: 1,
208
+ loadedBytes: Math.max(lastLoadedBytes, totalBytes),
209
+ totalBytes
210
+ });
211
+ }
212
+ } : undefined
213
+ });
214
+ });
215
+ const state = {
216
+ loading,
217
+ activeTranscriptions: 0,
218
+ onIdle: []
219
+ };
220
+ pipelines.set(model, state);
221
+ loading.catch(() => {
222
+ if (pipelines.get(model) === state) {
223
+ pipelines.delete(model);
224
+ }
225
+ });
226
+ return { state, alreadyLoaded: false, totalBytes };
227
+ };
228
+ var loadWhisperModel = async ({
229
+ model,
230
+ onProgress
231
+ }) => {
232
+ const { state, alreadyLoaded, totalBytes } = getOrCreateWhisperPipeline({
233
+ model,
234
+ onProgress
235
+ });
236
+ await state.loading;
237
+ if (alreadyLoaded) {
238
+ onProgress?.({
239
+ status: "ready",
240
+ file: null,
241
+ progress: 1,
242
+ loadedBytes: totalBytes,
243
+ totalBytes
244
+ });
245
+ }
246
+ return { alreadyLoaded };
247
+ };
248
+ var withLoadedWhisperPipeline = async ({
249
+ model,
250
+ onProgress,
251
+ run
252
+ }) => {
253
+ const { state, alreadyLoaded, totalBytes } = getOrCreateWhisperPipeline({
254
+ model,
255
+ onProgress
256
+ });
257
+ state.activeTranscriptions++;
258
+ try {
259
+ const loaded = await state.loading;
260
+ if (alreadyLoaded) {
261
+ onProgress?.({
262
+ status: "ready",
263
+ file: null,
264
+ progress: 1,
265
+ loadedBytes: totalBytes,
266
+ totalBytes
267
+ });
268
+ }
269
+ return await run(loaded);
270
+ } finally {
271
+ state.activeTranscriptions--;
272
+ if (state.activeTranscriptions === 0) {
273
+ for (const resolve of state.onIdle.splice(0)) {
274
+ resolve();
275
+ }
276
+ }
277
+ }
278
+ };
279
+ var disposeWhisperModel = async ({
280
+ model
281
+ } = {}) => {
282
+ const matching = [...pipelines.entries()].filter(([loadedModel]) => {
283
+ return model === undefined || loadedModel === model;
284
+ });
285
+ for (const [key, state] of matching) {
286
+ if (pipelines.get(key) === state) {
287
+ pipelines.delete(key);
288
+ }
289
+ }
290
+ await Promise.all(matching.map(async ([, state]) => {
291
+ const loadedPipeline = await state.loading;
292
+ if (state.activeTranscriptions > 0) {
293
+ await new Promise((resolve) => {
294
+ state.onIdle.push(resolve);
295
+ });
296
+ }
297
+ await loadedPipeline.dispose();
298
+ }));
299
+ };
300
+ // src/is-whisper-model-cached.ts
301
+ var isWhisperModelCached = async ({
302
+ model
303
+ }) => {
304
+ const { ModelRegistry } = await import("@huggingface/transformers");
305
+ const { modelId } = getModelInfo(model);
306
+ return ModelRegistry.is_pipeline_cached("automatic-speech-recognition", modelId, {
307
+ device: "webgpu",
308
+ dtype: WHISPER_WEBGPU_DTYPE
309
+ });
310
+ };
311
+ // src/resample-to-16khz.ts
312
+ var WHISPER_WEBGPU_SAMPLE_RATE = 16000;
313
+ var resampleTo16Khz = async ({
314
+ file,
315
+ onProgress
316
+ }) => {
317
+ if (typeof OfflineAudioContext === "undefined") {
318
+ throw new Error("OfflineAudioContext is not available in this environment.");
319
+ }
320
+ if (file.size === 0) {
321
+ throw new Error("The audio file is empty.");
322
+ }
323
+ onProgress?.(0);
324
+ const arrayBuffer = await file.arrayBuffer();
325
+ onProgress?.(0.25);
326
+ const decodingContext = new OfflineAudioContext(1, 1, 44100);
327
+ const decoded = await decodingContext.decodeAudioData(arrayBuffer);
328
+ onProgress?.(0.6);
329
+ const length = Math.max(1, Math.ceil(decoded.duration * WHISPER_WEBGPU_SAMPLE_RATE));
330
+ const offlineContext = new OfflineAudioContext(1, length, WHISPER_WEBGPU_SAMPLE_RATE);
331
+ const source = offlineContext.createBufferSource();
332
+ source.buffer = decoded;
333
+ source.connect(offlineContext.destination);
334
+ source.start();
335
+ const rendered = await offlineContext.startRendering();
336
+ onProgress?.(1);
337
+ return rendered.getChannelData(0).slice();
338
+ };
339
+ // src/to-captions.ts
340
+ var toCaptions = ({
341
+ whisperWebGpuOutput
342
+ }) => {
343
+ const words = Array.isArray(whisperWebGpuOutput) ? whisperWebGpuOutput : whisperWebGpuOutput.words;
344
+ return {
345
+ captions: words.map((word, index) => ({
346
+ text: index === 0 ? word.text.trimStart() : word.text,
347
+ startMs: Math.round(word.startInSeconds * 1000),
348
+ endMs: Math.round(word.endInSeconds * 1000),
349
+ timestampMs: Math.round((word.startInSeconds + word.endInSeconds) / 2 * 1000),
350
+ confidence: null
351
+ }))
352
+ };
353
+ };
354
+ // src/transcribe.ts
355
+ var transcribe = async ({
356
+ channelWaveform,
357
+ model,
358
+ language,
359
+ chunkLengthInSeconds = 30,
360
+ strideLengthInSeconds = 5,
361
+ onModelLoadProgress
362
+ }) => {
363
+ if (channelWaveform.length === 0) {
364
+ throw new Error("The audio waveform is empty.");
365
+ }
366
+ if (!Number.isFinite(chunkLengthInSeconds) || chunkLengthInSeconds <= 0) {
367
+ throw new Error("chunkLengthInSeconds must be a finite number greater than 0.");
368
+ }
369
+ if (!Number.isFinite(strideLengthInSeconds) || strideLengthInSeconds < 0 || strideLengthInSeconds * 2 >= chunkLengthInSeconds) {
370
+ throw new Error("strideLengthInSeconds must be a finite, non-negative number and less than half of chunkLengthInSeconds.");
371
+ }
372
+ const { multilingual } = getModelInfo(model);
373
+ if (multilingual && (language === undefined || language === "auto")) {
374
+ throw new Error(`The language option is required for the multilingual model "${model}" because automatic language detection is not supported.`);
375
+ }
376
+ if (!multilingual && language !== undefined && language !== "auto" && language !== "en" && language !== "english") {
377
+ throw new Error(`The English-only model "${model}" does not support the language "${language}".`);
378
+ }
379
+ const output = await withLoadedWhisperPipeline({
380
+ model,
381
+ onProgress: onModelLoadProgress,
382
+ run: async (transcriber) => {
383
+ return await transcriber(channelWaveform, {
384
+ return_timestamps: "word",
385
+ chunk_length_s: chunkLengthInSeconds,
386
+ stride_length_s: strideLengthInSeconds,
387
+ ...multilingual ? { language } : {}
388
+ });
389
+ }
390
+ });
391
+ if (!output.chunks) {
392
+ throw new Error("The model did not return word-level timestamps. Use one of the timestamped models returned by getAvailableModels().");
393
+ }
394
+ const audioDuration = channelWaveform.length / 16000;
395
+ const starts = output.chunks.map((chunk) => {
396
+ const start = chunk.timestamp[0];
397
+ if (start === null || !Number.isFinite(start)) {
398
+ throw new Error(`The model returned an invalid timestamp for "${chunk.text}".`);
399
+ }
400
+ return Math.max(0, Math.min(start, audioDuration));
401
+ });
402
+ const words = output.chunks.map((chunk, index) => {
403
+ const start = starts[index];
404
+ const modelEnd = chunk.timestamp[1];
405
+ const nextStart = starts[index + 1];
406
+ const fallbackEnd = nextStart === undefined || nextStart < start ? audioDuration : nextStart;
407
+ const end = Math.max(start, Math.min(modelEnd !== null && Number.isFinite(modelEnd) && modelEnd >= start ? modelEnd : fallbackEnd, audioDuration));
408
+ return {
409
+ text: index === 0 ? chunk.text.trimStart() : chunk.text,
410
+ startInSeconds: start,
411
+ endInSeconds: end
412
+ };
413
+ });
414
+ return {
415
+ text: output.text.trimStart(),
416
+ words,
417
+ model
418
+ };
419
+ };
420
+ export {
421
+ transcribe,
422
+ toCaptions,
423
+ resampleTo16Khz,
424
+ loadWhisperModel,
425
+ isWhisperModelCached,
426
+ getAvailableModels,
427
+ disposeWhisperModel,
428
+ clearStaleModels,
429
+ canUseWhisperWebGpu,
430
+ WhisperWebGpuUnsupportedReason,
431
+ WHISPER_WEBGPU_SAMPLE_RATE,
432
+ WHISPER_WEBGPU_MODELS
433
+ };
@@ -0,0 +1,15 @@
1
+ export { canUseWhisperWebGpu, WhisperWebGpuUnsupportedReason, } from './can-use-whisper-webgpu';
2
+ export type { CanUseWhisperWebGpuResult } from './can-use-whisper-webgpu';
3
+ export { clearStaleModels } from './clear-stale-models';
4
+ export { disposeWhisperModel, loadWhisperModel } from './load-whisper-model';
5
+ export type { DisposeWhisperModelOptions, LoadWhisperModelOptions, LoadWhisperModelResult, OnWhisperWebGpuModelLoadProgress, WhisperWebGpuModelLoadProgress, } from './load-whisper-model';
6
+ export { isWhisperModelCached } from './is-whisper-model-cached';
7
+ export type { IsWhisperModelCachedOptions } from './is-whisper-model-cached';
8
+ export { getAvailableModels, WHISPER_WEBGPU_MODELS } from './models';
9
+ export type { WhisperWebGpuModel, WhisperWebGpuModelInfo } from './models';
10
+ export { resampleTo16Khz, WHISPER_WEBGPU_SAMPLE_RATE } from './resample-to-16khz';
11
+ export type { ResampleTo16KhzOptions } from './resample-to-16khz';
12
+ export { toCaptions } from './to-captions';
13
+ export type { ToCaptionsOptions, ToCaptionsResult } from './to-captions';
14
+ export { transcribe } from './transcribe';
15
+ export type { TranscribeOptions, WhisperWebGpuTranscription, WhisperWebGpuWord, } from './transcribe';
@@ -0,0 +1,5 @@
1
+ import { type WhisperWebGpuModel } from './models';
2
+ export type IsWhisperModelCachedOptions = {
3
+ model: WhisperWebGpuModel;
4
+ };
5
+ export declare const isWhisperModelCached: ({ model, }: IsWhisperModelCachedOptions) => Promise<boolean>;
@@ -0,0 +1,31 @@
1
+ import { type WhisperWebGpuModel } from './models';
2
+ export type WhisperWebGpuModelLoadProgress = {
3
+ status: string;
4
+ file: string | null;
5
+ progress: number | null;
6
+ loadedBytes: number | null;
7
+ totalBytes: number | null;
8
+ };
9
+ export type OnWhisperWebGpuModelLoadProgress = (progress: WhisperWebGpuModelLoadProgress) => void;
10
+ type LoadedWhisperPipeline = {
11
+ (audio: Float32Array, options: Record<string, unknown>): Promise<unknown>;
12
+ dispose: () => Promise<void>;
13
+ };
14
+ export type LoadWhisperModelOptions = {
15
+ model: WhisperWebGpuModel;
16
+ onProgress?: OnWhisperWebGpuModelLoadProgress;
17
+ };
18
+ export type LoadWhisperModelResult = {
19
+ alreadyLoaded: boolean;
20
+ };
21
+ export declare const loadWhisperModel: ({ model, onProgress, }: LoadWhisperModelOptions) => Promise<LoadWhisperModelResult>;
22
+ export declare const withLoadedWhisperPipeline: <ReturnValue>({ model, onProgress, run, }: {
23
+ model: "base" | "base.en" | "large-v3-turbo" | "medium" | "medium.en" | "small" | "small.en" | "tiny" | "tiny.en";
24
+ onProgress?: OnWhisperWebGpuModelLoadProgress | undefined;
25
+ run: (pipeline: LoadedWhisperPipeline) => Promise<ReturnValue>;
26
+ }) => Promise<ReturnValue>;
27
+ export type DisposeWhisperModelOptions = {
28
+ model?: WhisperWebGpuModel;
29
+ };
30
+ export declare const disposeWhisperModel: ({ model, }?: DisposeWhisperModelOptions) => Promise<void>;
31
+ export {};
@@ -0,0 +1,15 @@
1
+ export declare const WHISPER_WEBGPU_MODELS: readonly ["tiny", "tiny.en", "base", "base.en", "small", "small.en", "medium", "medium.en", "large-v3-turbo"];
2
+ export type WhisperWebGpuModel = (typeof WHISPER_WEBGPU_MODELS)[number];
3
+ export type WhisperWebGpuModelInfo = {
4
+ name: WhisperWebGpuModel;
5
+ modelId: string;
6
+ parameters: number;
7
+ multilingual: boolean;
8
+ webGpuDownloadSize: number;
9
+ };
10
+ export declare const getAvailableModels: () => WhisperWebGpuModelInfo[];
11
+ export declare const getModelInfo: (model: "base" | "base.en" | "large-v3-turbo" | "medium" | "medium.en" | "small" | "small.en" | "tiny" | "tiny.en") => WhisperWebGpuModelInfo;
12
+ export declare const WHISPER_WEBGPU_DTYPE: {
13
+ readonly encoder_model: "fp32";
14
+ readonly decoder_model_merged: "q4";
15
+ };
@@ -0,0 +1,6 @@
1
+ export declare const WHISPER_WEBGPU_SAMPLE_RATE = 16000;
2
+ export type ResampleTo16KhzOptions = {
3
+ file: Blob;
4
+ onProgress?: (progress: number) => void;
5
+ };
6
+ export declare const resampleTo16Khz: ({ file, onProgress, }: ResampleTo16KhzOptions) => Promise<Float32Array<ArrayBufferLike>>;
@@ -0,0 +1,9 @@
1
+ import type { Caption } from '@remotion/captions';
2
+ import type { WhisperWebGpuTranscription, WhisperWebGpuWord } from './transcribe';
3
+ export type ToCaptionsOptions = {
4
+ whisperWebGpuOutput: WhisperWebGpuTranscription | WhisperWebGpuWord[];
5
+ };
6
+ export type ToCaptionsResult = {
7
+ captions: Caption[];
8
+ };
9
+ export declare const toCaptions: ({ whisperWebGpuOutput, }: ToCaptionsOptions) => ToCaptionsResult;
@@ -0,0 +1,21 @@
1
+ import { type OnWhisperWebGpuModelLoadProgress } from './load-whisper-model';
2
+ import { type WhisperWebGpuModel } from './models';
3
+ export type WhisperWebGpuWord = {
4
+ text: string;
5
+ startInSeconds: number;
6
+ endInSeconds: number;
7
+ };
8
+ export type WhisperWebGpuTranscription = {
9
+ text: string;
10
+ words: WhisperWebGpuWord[];
11
+ model: WhisperWebGpuModel;
12
+ };
13
+ export type TranscribeOptions = {
14
+ channelWaveform: Float32Array;
15
+ model: WhisperWebGpuModel;
16
+ language?: string;
17
+ chunkLengthInSeconds?: number;
18
+ strideLengthInSeconds?: number;
19
+ onModelLoadProgress?: OnWhisperWebGpuModelLoadProgress;
20
+ };
21
+ export declare const transcribe: ({ channelWaveform, model, language, chunkLengthInSeconds, strideLengthInSeconds, onModelLoadProgress, }: TranscribeOptions) => Promise<WhisperWebGpuTranscription>;
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@remotion/whisper-webgpu",
3
+ "version": "4.0.518",
4
+ "description": "Transcribe audio in the browser using Whisper and WebGPU",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "module": "dist/esm/index.mjs",
8
+ "repository": {
9
+ "url": "https://github.com/remotion-dev/remotion/tree/main/packages/whisper-webgpu"
10
+ },
11
+ "type": "module",
12
+ "scripts": {
13
+ "test": "bun test src/test",
14
+ "formatting": "oxfmt src --check",
15
+ "format": "oxfmt src",
16
+ "lint": "eslint src",
17
+ "watch": "tsgo -w",
18
+ "make": "tsgo && bun --env-file=../.env.bundle bundle.ts"
19
+ },
20
+ "author": "Jonny Burger <jonny@remotion.dev>",
21
+ "contributors": [],
22
+ "license": "MIT",
23
+ "bugs": {
24
+ "url": "https://github.com/remotion-dev/remotion/issues"
25
+ },
26
+ "dependencies": {
27
+ "@huggingface/transformers": "4.2.0",
28
+ "@remotion/captions": "4.0.518"
29
+ },
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "module": "./dist/esm/index.mjs",
34
+ "import": "./dist/esm/index.mjs"
35
+ },
36
+ "./package.json": "./package.json"
37
+ },
38
+ "devDependencies": {
39
+ "@remotion/eslint-config-internal": "4.0.518",
40
+ "@typescript/native-preview": "7.0.0-dev.20260217.1",
41
+ "eslint": "9.19.0"
42
+ },
43
+ "keywords": [
44
+ "remotion",
45
+ "whisper",
46
+ "webgpu",
47
+ "captions",
48
+ "speech-to-text"
49
+ ],
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "homepage": "https://www.remotion.dev/docs/whisper-webgpu"
54
+ }