@nodetool-ai/whisper-cpp 0.0.0-stage → 0.8.2

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 CHANGED
@@ -1,3 +1,30 @@
1
- # Temporary Holding Version
1
+ # whisper.cpp
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Local speech recognition providers and streaming transcription for NodeTool.
4
+
5
+ Install `@fugood/whisper.node@1.1.3` through the desktop Package Manager.
6
+ Download GGML ASR models from `ggerganov/whisper.cpp` through Models.
7
+ The providers are excluded from the cloud profile.
8
+
9
+ - `whisper_cpp` runs ASR inside the backend. Model ids are absolute paths from
10
+ discovery. `WHISPER_CPP_MODELS_DIR` adds a directory to the Hugging Face hub
11
+ cache scan. `WHISPER_CPP_GPU_BACKEND` accepts `auto`, `metal`, `cuda`,
12
+ `vulkan`, or `cpu`. Restart after changing the backend because the binding
13
+ caches the first native variant loaded.
14
+ - `whisper_cpp_server` posts to `/inference` on `WHISPER_CPP_SERVER_URL` and
15
+ serves the model id `default`.
16
+ - Enable the `whisper-cpp` node pack for `whisper_cpp.LiveTranscription`.
17
+ Supply mono PCM16 audio as base64 chunks. `content_metadata.sample_rate`
18
+ defaults to 16000. A `done: true` chunk ends the stream. Install
19
+ `ggml-org/whisper-vad/ggml-silero-v5.1.2.bin` for speech boundaries, otherwise
20
+ the node uses fixed windows.
21
+
22
+ The binding returns transcription timestamps in milliseconds and VAD times
23
+ in centiseconds. The provider returns ASR timestamps in seconds.
24
+
25
+ Run tests with `npm run test --workspace=packages/whisper-cpp`.
26
+ Set `WHISPER_CPP_TEST_MODEL` to a real model path to enable the native test.
27
+ Set `WHISPER_CPP_TEST_SERVER_URL` to test a running whisper-server serving an
28
+ English-capable model.
29
+ The speech fixture is the public-domain JFK inaugural-address excerpt from
30
+ [whisper.cpp samples](https://github.com/ggml-org/whisper.cpp/blob/master/samples/jfk.wav).
@@ -0,0 +1 @@
1
+ 2026-10-12T08:49:36.215Z
@@ -0,0 +1,4 @@
1
+ export declare function samplesToPcm16(samples: Float32Array): ArrayBuffer;
2
+ export declare function decodeToPcm16(bytes: Uint8Array): Promise<ArrayBuffer>;
3
+ export declare function pcm16Base64ToSamples(b64: string, sampleRate: number): Float32Array;
4
+ //# sourceMappingURL=audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAKA,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW,CAcjE;AACD,wBAAsB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAK3E;AACD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,YAAY,CAkBd"}
package/dist/audio.js ADDED
@@ -0,0 +1,38 @@
1
+ import { decodeAudioBytesToSamples, resampleLinear } from "@nodetool-ai/transformers-js-nodes";
2
+ export function samplesToPcm16(samples) {
3
+ if (samples.length === 0) {
4
+ throw new Error("Audio input is empty");
5
+ }
6
+ const buffer = new ArrayBuffer(samples.length * 2);
7
+ const view = new DataView(buffer);
8
+ for (let i = 0; i < samples.length; i++) {
9
+ view.setInt16(i * 2, Math.round(Math.max(-1, Math.min(1, samples[i])) * 0x7fff), true);
10
+ }
11
+ return buffer;
12
+ }
13
+ export async function decodeToPcm16(bytes) {
14
+ if (bytes.length === 0) {
15
+ throw new Error("Audio input is empty");
16
+ }
17
+ return samplesToPcm16(await decodeAudioBytesToSamples(bytes, 16000));
18
+ }
19
+ export function pcm16Base64ToSamples(b64, sampleRate) {
20
+ const bytes = Buffer.from(b64, "base64");
21
+ if (bytes.length === 0) {
22
+ throw new Error("Audio input is empty");
23
+ }
24
+ if (bytes.length % 2 !== 0) {
25
+ throw new Error("PCM16 audio must contain complete samples");
26
+ }
27
+ if (!Number.isFinite(sampleRate) || sampleRate <= 0) {
28
+ throw new Error("Audio sample rate must be positive");
29
+ }
30
+ const samples = new Float32Array(bytes.length / 2);
31
+ for (let i = 0; i < samples.length; i++) {
32
+ samples[i] = bytes.readInt16LE(i * 2) / 32768;
33
+ }
34
+ return sampleRate === 16000
35
+ ? samples
36
+ : resampleLinear(samples, sampleRate, 16000);
37
+ }
38
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,cAAc,EACf,MAAM,oCAAoC,CAAC;AAE5C,MAAM,UAAU,cAAc,CAAC,OAAqB;IAClD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,QAAQ,CACX,CAAC,GAAG,CAAC,EACL,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,EAC1D,IAAI,CACL,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAiB;IACnD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,cAAc,CAAC,MAAM,yBAAyB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AACvE,CAAC;AACD,MAAM,UAAU,oBAAoB,CAClC,GAAW,EACX,UAAkB;IAElB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;IAChD,CAAC;IACD,OAAO,UAAU,KAAK,KAAK;QACzB,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,70 @@
1
+ export type LibVariant = "default" | "vulkan" | "cuda";
2
+ export interface Segment {
3
+ text: string;
4
+ t0: number;
5
+ t1: number;
6
+ }
7
+ export interface TranscribeOptions {
8
+ language?: string;
9
+ translate?: boolean;
10
+ maxThreads?: number;
11
+ tokenTimestamps?: boolean;
12
+ temperature?: number;
13
+ beamSize?: number;
14
+ prompt?: string;
15
+ onProgress?: (progress: number) => void;
16
+ onNewSegments?: (result: {
17
+ result: string;
18
+ segments: Segment[];
19
+ }) => void;
20
+ }
21
+ export interface TranscribeResult {
22
+ language?: string;
23
+ result: string;
24
+ segments: Segment[];
25
+ isAborted: boolean;
26
+ }
27
+ export interface WhisperContext {
28
+ transcribeData(audio: ArrayBuffer, options?: TranscribeOptions): {
29
+ stop: () => Promise<void>;
30
+ promise: Promise<TranscribeResult>;
31
+ };
32
+ release(): Promise<void>;
33
+ }
34
+ export interface WhisperVadContext {
35
+ detectSpeechData(audio: ArrayBuffer, options?: {
36
+ threshold?: number;
37
+ minSpeechDurationMs?: number;
38
+ minSilenceDurationMs?: number;
39
+ }): Promise<{
40
+ t0: number;
41
+ t1: number;
42
+ }[]>;
43
+ release(): Promise<void>;
44
+ }
45
+ export interface WhisperNodeModule {
46
+ initWhisper(options: {
47
+ filePath: string;
48
+ useGpu?: boolean;
49
+ useFlashAttn?: boolean;
50
+ }, variant?: LibVariant): Promise<WhisperContext>;
51
+ initWhisperVad(options: {
52
+ filePath: string;
53
+ useGpu?: boolean;
54
+ nThreads?: number;
55
+ }, variant?: LibVariant): Promise<WhisperVadContext>;
56
+ }
57
+ export declare const INSTALL_MESSAGE = "The local whisper.cpp provider requires the optional '@fugood/whisper.node' package, which is not installed. Install it from the Package Manager.";
58
+ export declare function loadWhisperNode(): Promise<WhisperNodeModule>;
59
+ /**
60
+ * The whisper.node build to load for a WHISPER_CPP_GPU_BACKEND setting.
61
+ *
62
+ * `cuda` and `vulkan` select that build. `metal` and `cpu` use the default
63
+ * build (Metal on macOS). `auto` (or unset) on Windows and Linux probes the
64
+ * CUDA build, then the Vulkan build, like node-llama-cpp's `auto`: a build
65
+ * whose native library cannot load (no NVIDIA driver, no Vulkan loader) is
66
+ * skipped, and the default CPU build is the last resort. On macOS `auto` is
67
+ * the default build.
68
+ */
69
+ export declare function resolveVariant(setting: string | undefined): Promise<LibVariant>;
70
+ //# sourceMappingURL=binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AACvD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AACD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;KAAE,KAAK,IAAI,CAAC;CAC3E;AACD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB;AACD,MAAM,WAAW,cAAc;IAC7B,cAAc,CACZ,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,iBAAiB,GAC1B;QACD,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;KACpC,CAAC;IACF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AACD,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,CACd,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;KAC/B,GACA,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,CAAC;IACzC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AACD,MAAM,WAAW,iBAAiB;IAChC,WAAW,CACT,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,EACvE,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3B,cAAc,CACZ,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAClE,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/B;AACD,eAAO,MAAM,eAAe,sJACyH,CAAC;AAEtJ,wBAAgB,eAAe,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAW5D;AACD;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,OAAO,CAAC,UAAU,CAAC,CASrB"}
@@ -0,0 +1,48 @@
1
+ import { importOptionalModule } from "@nodetool-ai/config";
2
+ import { MissingRuntimePackageError } from "@nodetool-ai/protocol";
3
+ export const INSTALL_MESSAGE = "The local whisper.cpp provider requires the optional '@fugood/whisper.node' package, which is not installed. Install it from the Package Manager.";
4
+ let modulePromise;
5
+ export function loadWhisperNode() {
6
+ modulePromise ??= importOptionalModule("@fugood/whisper.node", { commonJs: true }).catch((cause) => {
7
+ modulePromise = undefined;
8
+ throw new MissingRuntimePackageError(INSTALL_MESSAGE, "whisper-cpp", {
9
+ cause
10
+ });
11
+ });
12
+ return modulePromise;
13
+ }
14
+ /**
15
+ * The whisper.node build to load for a WHISPER_CPP_GPU_BACKEND setting.
16
+ *
17
+ * `cuda` and `vulkan` select that build. `metal` and `cpu` use the default
18
+ * build (Metal on macOS). `auto` (or unset) on Windows and Linux probes the
19
+ * CUDA build, then the Vulkan build, like node-llama-cpp's `auto`: a build
20
+ * whose native library cannot load (no NVIDIA driver, no Vulkan loader) is
21
+ * skipped, and the default CPU build is the last resort. On macOS `auto` is
22
+ * the default build.
23
+ */
24
+ export async function resolveVariant(setting) {
25
+ if (setting === "cuda" || setting === "vulkan") {
26
+ return setting;
27
+ }
28
+ if ((setting === undefined || setting === "" || setting === "auto") && process.platform !== "darwin") {
29
+ autoVariant ??= probeGpuVariant();
30
+ return autoVariant;
31
+ }
32
+ return "default";
33
+ }
34
+ let autoVariant;
35
+ /** First GPU build of whisper.node that loads on this machine, else `default`. */
36
+ async function probeGpuVariant() {
37
+ for (const variant of ["cuda", "vulkan"]) {
38
+ try {
39
+ await importOptionalModule(`@fugood/node-whisper-${process.platform}-${process.arch}-${variant}`, { commonJs: true });
40
+ return variant;
41
+ }
42
+ catch {
43
+ // Not installed for this platform, or its native library cannot load.
44
+ }
45
+ }
46
+ return "default";
47
+ }
48
+ //# sourceMappingURL=binding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding.js","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAwDnE,MAAM,CAAC,MAAM,eAAe,GAC1B,mJAAmJ,CAAC;AACtJ,IAAI,aAAqD,CAAC;AAC1D,MAAM,UAAU,eAAe;IAC7B,aAAa,KAAK,oBAAoB,CACpC,sBAAsB,EACtB,EAAE,QAAQ,EAAE,IAAI,EAAE,CACnB,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACzB,aAAa,GAAG,SAAS,CAAC;QAC1B,MAAM,IAAI,0BAA0B,CAAC,eAAe,EAAE,aAAa,EAAE;YACnE,KAAK;SACN,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,aAAa,CAAC;AACvB,CAAC;AACD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAA2B;IAE3B,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC/C,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACrG,WAAW,KAAK,eAAe,EAAE,CAAC;QAClC,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,IAAI,WAA4C,CAAC;AAEjD,kFAAkF;AAClF,KAAK,UAAU,eAAe;IAC5B,KAAK,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAU,EAAE,CAAC;QAClD,IAAI,CAAC;YACH,MAAM,oBAAoB,CACxB,wBAAwB,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,EAAE,EACrE,EAAE,QAAQ,EAAE,IAAI,EAAE,CACnB,CAAC;YACF,OAAO,OAAO,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,sEAAsE;QACxE,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type LibVariant, type WhisperContext } from "./binding.js";
2
+ export declare class ContextCache {
3
+ private readonly maxModels;
4
+ private readonly idleMs;
5
+ private readonly entries;
6
+ private admission;
7
+ private readonly timer;
8
+ constructor(maxModels?: number, idleMs?: number);
9
+ private release;
10
+ private evictIdle;
11
+ withContext<T>(modelPath: string, variant: LibVariant, useGpu: boolean, run: (context: WhisperContext) => Promise<T>): Promise<T>;
12
+ dispose(): Promise<void>;
13
+ }
14
+ export declare const contextCache: ContextCache;
15
+ //# sourceMappingURL=context-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-cache.d.ts","sourceRoot":"","sources":["../src/context-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAStB,qBAAa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,YACmB,SAAS,SAAI,EACb,MAAM,SAAiB,EAgBzC;YACa,OAAO;YAIP,SAAS;IAWjB,WAAW,CAAC,CAAC,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,OAAO,EACf,GAAG,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,GAC3C,OAAO,CAAC,CAAC,CAAC,CA6DZ;IACK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAM7B;CACF;AACD,eAAO,MAAM,YAAY,cAAqB,CAAC"}
@@ -0,0 +1,103 @@
1
+ import { createLogger } from "@nodetool-ai/config";
2
+ import { loadWhisperNode } from "./binding.js";
3
+ const log = createLogger("whisper-cpp.context-cache");
4
+ export class ContextCache {
5
+ maxModels;
6
+ idleMs;
7
+ entries = new Map();
8
+ admission = Promise.resolve();
9
+ timer;
10
+ constructor(maxModels = 2, idleMs = 10 * 60 * 1000) {
11
+ this.maxModels = maxModels;
12
+ this.idleMs = idleMs;
13
+ const sweep = async () => {
14
+ try {
15
+ await this.evictIdle();
16
+ }
17
+ catch (error) {
18
+ log.warn("Context eviction failed: %s", String(error));
19
+ }
20
+ };
21
+ this.timer = setInterval(() => {
22
+ void sweep();
23
+ }, Math.min(idleMs, 60000));
24
+ this.timer.unref();
25
+ }
26
+ async release(key, entry) {
27
+ this.entries.delete(key);
28
+ await (await entry.context).release();
29
+ }
30
+ async evictIdle() {
31
+ const eviction = this.admission.then(async () => {
32
+ for (const [key, entry] of this.entries) {
33
+ if (entry.pending === 0 && Date.now() - entry.lastUsed >= this.idleMs) {
34
+ await this.release(key, entry);
35
+ }
36
+ }
37
+ });
38
+ this.admission = eviction.catch(() => { });
39
+ await eviction;
40
+ }
41
+ async withContext(modelPath, variant, useGpu, run) {
42
+ const key = JSON.stringify([modelPath, variant, useGpu]);
43
+ const admitted = this.admission.then(async () => {
44
+ let entry = this.entries.get(key);
45
+ if (!entry) {
46
+ while (this.entries.size >= this.maxModels) {
47
+ // Evict the least recently used idle context. A busy context's
48
+ // lastUsed is from before its job started, so it would otherwise
49
+ // look oldest and make this admission wait for its whole job.
50
+ const oldest = [...this.entries].sort((a, b) => Number(a[1].pending > 0) - Number(b[1].pending > 0) ||
51
+ a[1].lastUsed - b[1].lastUsed)[0];
52
+ if (!oldest) {
53
+ break;
54
+ }
55
+ await oldest[1].tail;
56
+ if (this.entries.get(oldest[0]) === oldest[1]) {
57
+ await this.release(oldest[0], oldest[1]);
58
+ }
59
+ }
60
+ const context = loadWhisperNode().then((binding) => binding.initWhisper({ filePath: modelPath, useGpu }, variant));
61
+ entry = {
62
+ context,
63
+ tail: Promise.resolve(),
64
+ pending: 0,
65
+ lastUsed: Date.now()
66
+ };
67
+ this.entries.set(key, entry);
68
+ }
69
+ const current = entry;
70
+ current.pending++;
71
+ const result = current.tail.then(async () => {
72
+ try {
73
+ return await run(await current.context);
74
+ }
75
+ finally {
76
+ current.pending--;
77
+ current.lastUsed = Date.now();
78
+ try {
79
+ await current.context;
80
+ }
81
+ catch {
82
+ if (this.entries.get(key) === current) {
83
+ this.entries.delete(key);
84
+ }
85
+ }
86
+ }
87
+ });
88
+ current.tail = result.then(() => { }, () => { });
89
+ return { result };
90
+ });
91
+ this.admission = admitted.then(() => { }, () => { });
92
+ return (await admitted).result;
93
+ }
94
+ async dispose() {
95
+ clearInterval(this.timer);
96
+ for (const [key, entry] of this.entries) {
97
+ await entry.tail;
98
+ await this.release(key, entry);
99
+ }
100
+ }
101
+ }
102
+ export const contextCache = new ContextCache();
103
+ //# sourceMappingURL=context-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-cache.js","sourceRoot":"","sources":["../src/context-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { NodeRegistry } from "@nodetool-ai/node-sdk";
2
+ import { WhisperCppProvider } from "./whisper-cpp-provider.js";
3
+ import { WhisperServerProvider } from "./whisper-server-provider.js";
4
+ import { LiveTranscriptionNode } from "./nodes/live-transcription.js";
5
+ export { WhisperCppProvider, WhisperServerProvider, LiveTranscriptionNode };
6
+ export { discoverASRModels, discoverVadModels } from "./model-discovery.js";
7
+ export declare const ALL_NODES: readonly [typeof LiveTranscriptionNode];
8
+ export declare function registerWhisperCppProviders(): void;
9
+ export declare function registerWhisperCppNodes(registry: NodeRegistry): void;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC5E,eAAO,MAAM,SAAS,yCAAmC,CAAC;AAE1D,wBAAgB,2BAA2B,IAAI,IAAI,CAyBlD;AACD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAIpE"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ import { registerProvider } from "@nodetool-ai/runtime";
2
+ import { isCloudProfileActive } from "@nodetool-ai/protocol";
3
+ import { WhisperCppProvider } from "./whisper-cpp-provider.js";
4
+ import { WhisperServerProvider } from "./whisper-server-provider.js";
5
+ import { LiveTranscriptionNode } from "./nodes/live-transcription.js";
6
+ export { WhisperCppProvider, WhisperServerProvider, LiveTranscriptionNode };
7
+ export { discoverASRModels, discoverVadModels } from "./model-discovery.js";
8
+ export const ALL_NODES = [LiveTranscriptionNode];
9
+ let registered = false;
10
+ export function registerWhisperCppProviders() {
11
+ if (registered ||
12
+ isCloudProfileActive(process.env.NODETOOL_NODE_PROFILE, process.env.NODETOOL_ENV)) {
13
+ return;
14
+ }
15
+ registerProvider("whisper_cpp", WhisperCppProvider, {}, { WHISPER_CPP_MODELS_DIR: "", WHISPER_CPP_GPU_BACKEND: "" }, { access: "in_process", displayName: "whisper.cpp" });
16
+ registerProvider("whisper_cpp_server", WhisperServerProvider, { WHISPER_CPP_SERVER_URL: "" }, {}, { access: "local_service", displayName: "whisper.cpp server" });
17
+ registered = true;
18
+ }
19
+ export function registerWhisperCppNodes(registry) {
20
+ for (const node of ALL_NODES) {
21
+ registry.register(node);
22
+ }
23
+ }
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC5E,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,qBAAqB,CAAU,CAAC;AAC1D,IAAI,UAAU,GAAG,KAAK,CAAC;AACvB,MAAM,UAAU,2BAA2B;IACzC,IACE,UAAU;QACV,oBAAoB,CAClB,OAAO,CAAC,GAAG,CAAC,qBAAqB,EACjC,OAAO,CAAC,GAAG,CAAC,YAAY,CACzB,EACD,CAAC;QACD,OAAO;IACT,CAAC;IACD,gBAAgB,CACd,aAAa,EACb,kBAAkB,EAClB,EAAE,EACF,EAAE,sBAAsB,EAAE,EAAE,EAAE,uBAAuB,EAAE,EAAE,EAAE,EAC3D,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,CACrD,CAAC;IACF,gBAAgB,CACd,oBAAoB,EACpB,qBAAqB,EACrB,EAAE,sBAAsB,EAAE,EAAE,EAAE,EAC9B,EAAE,EACF,EAAE,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAC/D,CAAC;IACF,UAAU,GAAG,IAAI,CAAC;AACpB,CAAC;AACD,MAAM,UAAU,uBAAuB,CAAC,QAAsB;IAC5D,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ASRModel } from "@nodetool-ai/runtime";
2
+ /** HuggingFace hub cache root, from the resolver every hub reader shares. */
3
+ export declare function getHfHubCacheDir(): string;
4
+ export declare function discoverASRModels(modelsDir?: string): Promise<ASRModel[]>;
5
+ export declare function discoverVadModels(modelsDir?: string): Promise<ASRModel[]>;
6
+ export declare function resolveModelPath(id: string, modelsDir?: string): Promise<string>;
7
+ //# sourceMappingURL=model-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-discovery.d.ts","sourceRoot":"","sources":["../src/model-discovery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOrD,6EAA6E;AAC7E,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAmFD,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAEzE;AACD,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAEzE;AACD,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,MAAM,EACV,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAYjB"}
@@ -0,0 +1,106 @@
1
+ import { readdir, stat } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import path from "node:path";
4
+ import { getHfHubCacheDir as getConfigHfHubCacheDir } from "@nodetool-ai/config";
5
+ function expand(value) {
6
+ return path.resolve(value.startsWith("~/") ? path.join(homedir(), value.slice(2)) : value);
7
+ }
8
+ /** HuggingFace hub cache root, from the resolver every hub reader shares. */
9
+ export function getHfHubCacheDir() {
10
+ return path.resolve(getConfigHfHubCacheDir());
11
+ }
12
+ async function directories(dir) {
13
+ try {
14
+ return (await readdir(dir, { withFileTypes: true }))
15
+ .filter((entry) => entry.isDirectory())
16
+ .map((entry) => path.join(dir, entry.name));
17
+ }
18
+ catch (error) {
19
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
20
+ return [];
21
+ }
22
+ throw error;
23
+ }
24
+ }
25
+ async function discover(vad, modelsDir) {
26
+ const hub = getHfHubCacheDir();
27
+ const dirs = [];
28
+ for (const repo of [
29
+ "models--ggerganov--whisper.cpp",
30
+ "models--ggml-org--whisper.cpp",
31
+ "models--ggml-org--whisper-vad"
32
+ ]) {
33
+ dirs.push(...(await directories(path.join(hub, repo, "snapshots"))));
34
+ }
35
+ const extra = modelsDir || process.env.WHISPER_CPP_MODELS_DIR;
36
+ if (extra) {
37
+ dirs.push(expand(extra));
38
+ }
39
+ const files = new Map();
40
+ for (const dir of dirs) {
41
+ let entries;
42
+ try {
43
+ entries = await readdir(dir, { withFileTypes: true });
44
+ }
45
+ catch (error) {
46
+ if (error instanceof Error &&
47
+ "code" in error &&
48
+ error.code === "ENOENT") {
49
+ continue;
50
+ }
51
+ throw error;
52
+ }
53
+ const mtime = (await stat(dir)).mtimeMs;
54
+ for (const entry of entries) {
55
+ if ((!entry.isFile() && !entry.isSymbolicLink()) ||
56
+ !/^ggml-.+\.bin$/i.test(entry.name) ||
57
+ /silero|vad/i.test(entry.name) !== vad) {
58
+ continue;
59
+ }
60
+ const id = path.resolve(dir, entry.name);
61
+ try {
62
+ if (!(await stat(id)).isFile()) {
63
+ continue;
64
+ }
65
+ }
66
+ catch (error) {
67
+ if (error instanceof Error &&
68
+ "code" in error &&
69
+ error.code === "ENOENT") {
70
+ continue;
71
+ }
72
+ throw error;
73
+ }
74
+ if ((files.get(entry.name)?.mtime ?? -Infinity) > mtime) {
75
+ continue;
76
+ }
77
+ files.set(entry.name, {
78
+ model: {
79
+ id,
80
+ name: entry.name.replace(/^ggml-/i, "").replace(/\.bin$/i, ""),
81
+ provider: "whisper_cpp"
82
+ },
83
+ mtime
84
+ });
85
+ }
86
+ }
87
+ return [...files.values()]
88
+ .map((entry) => entry.model)
89
+ .sort((a, b) => a.name.localeCompare(b.name));
90
+ }
91
+ export function discoverASRModels(modelsDir) {
92
+ return discover(false, modelsDir);
93
+ }
94
+ export function discoverVadModels(modelsDir) {
95
+ return discover(true, modelsDir);
96
+ }
97
+ export async function resolveModelPath(id, modelsDir) {
98
+ // State saved before redaction stopped rewriting paths holds "~/..." ids.
99
+ const wanted = expand(id);
100
+ const model = (await discoverASRModels(modelsDir)).find((entry) => entry.id === wanted);
101
+ if (!model) {
102
+ throw new Error(`Unknown whisper.cpp model "${id}". Download one from the Models panel.`);
103
+ }
104
+ return model.id;
105
+ }
106
+ //# sourceMappingURL=model-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-discovery.js","sourceRoot":"","sources":["../src/model-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { BaseNode, type StreamingInputs, type StreamingOutputs } from "@nodetool-ai/node-sdk";
2
+ import type { ProcessingContext } from "@nodetool-ai/runtime";
3
+ import type { ASRModel } from "@nodetool-ai/runtime";
4
+ export declare class LiveTranscriptionNode extends BaseNode {
5
+ static readonly nodeType = "whisper_cpp.LiveTranscription";
6
+ static readonly title = "Live Transcription";
7
+ static readonly description = "Transcribe streaming PCM16 audio locally with whisper.cpp.\n speech, audio, transcription, streaming";
8
+ static readonly isStreamingInput = true;
9
+ static readonly inputFields: string[];
10
+ static readonly metadataOutputTypes: {
11
+ chunk: string;
12
+ text: string;
13
+ };
14
+ static readonly outputCorrelation: {
15
+ readonly chunk: {
16
+ readonly kind: "iteration";
17
+ readonly source: "__execution__";
18
+ readonly group: "stream";
19
+ };
20
+ readonly text: {
21
+ readonly kind: "single";
22
+ readonly source: "__execution__";
23
+ };
24
+ };
25
+ static readonly requiredSettings: string[];
26
+ chunk: unknown;
27
+ model: ASRModel;
28
+ language: string;
29
+ prompt: string;
30
+ vad_threshold: number;
31
+ min_silence_ms: number;
32
+ max_segment_s: number;
33
+ process(): Promise<Record<string, never>>;
34
+ run(inputs: StreamingInputs, outputs: StreamingOutputs, context?: ProcessingContext): Promise<void>;
35
+ }
36
+ //# sourceMappingURL=live-transcription.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-transcription.d.ts","sourceRoot":"","sources":["../../src/nodes/live-transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAER,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAsBrD,qBAAa,qBAAsB,SAAQ,QAAQ;IACjD,MAAM,CAAC,QAAQ,CAAC,QAAQ,mCAAmC;IAC3D,MAAM,CAAC,QAAQ,CAAC,KAAK,wBAAwB;IAC7C,MAAM,CAAC,QAAQ,CAAC,WAAW,6GACiF;IAC5G,MAAM,CAAC,QAAQ,CAAC,gBAAgB,QAAQ;IACxC,MAAM,CAAC,QAAQ,CAAC,WAAW,WAAa;IACxC,MAAM,CAAC,QAAQ,CAAC,mBAAmB;QAAK,KAAK;QAAW,IAAI;MAAU;IACtE,MAAM,CAAC,QAAQ,CAAC,iBAAiB;iBAC/B,KAAK;qBAAI,IAAI,EAAE,WAAW;qBAAE,MAAM,EAAE,eAAe;qBAAE,KAAK,EAAE,QAAQ;;iBACpE,IAAI;qBAAI,IAAI,EAAE,QAAQ;qBAAE,MAAM,EAAE,eAAe;;MACtC;IACX,MAAM,CAAC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAM;IAEC,KAAK,EAAE,OAAO,CAAC;IAMxD,KAAK,EAAE,QAAQ,CAAC;IAEhB,QAAQ,EAAE,MAAM,CAAC;IACoC,MAAM,EAAE,MAAM,CAAC;IAEpE,aAAa,EAAE,MAAM,CAAC;IAEtB,cAAc,EAAE,MAAM,CAAC;IAEvB,aAAa,EAAE,MAAM,CAAC;IAEf,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAEvD;IACc,GAAG,CAChB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,gBAAgB,EACzB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAiKf;CACF"}
@@ -0,0 +1,212 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { BaseNode, prop } from "@nodetool-ai/node-sdk";
8
+ import { z } from "zod";
9
+ import { createLogger } from "@nodetool-ai/config";
10
+ import { loadWhisperNode, resolveVariant } from "../binding.js";
11
+ import { pcm16Base64ToSamples, samplesToPcm16 } from "../audio.js";
12
+ import { discoverVadModels } from "../model-discovery.js";
13
+ import { WhisperCppProvider } from "../whisper-cpp-provider.js";
14
+ /** Each field degrades to absent when malformed, so one bad field never drops the chunk. */
15
+ const liveItemSchema = z.object({
16
+ done: z.boolean().optional().catch(undefined),
17
+ content_type: z.string().optional().catch(undefined),
18
+ content: z.string().optional().catch(undefined),
19
+ content_metadata: z
20
+ .object({ sample_rate: z.number().optional().catch(undefined) })
21
+ .optional()
22
+ .catch(undefined)
23
+ });
24
+ const log = createLogger("whisper-cpp.live-transcription");
25
+ export class LiveTranscriptionNode extends BaseNode {
26
+ static nodeType = "whisper_cpp.LiveTranscription";
27
+ static title = "Live Transcription";
28
+ static description = "Transcribe streaming PCM16 audio locally with whisper.cpp.\n speech, audio, transcription, streaming";
29
+ static isStreamingInput = true;
30
+ static inputFields = ["chunk"];
31
+ static metadataOutputTypes = { chunk: "chunk", text: "str" };
32
+ static outputCorrelation = {
33
+ chunk: { kind: "iteration", source: "__execution__", group: "stream" },
34
+ text: { kind: "single", source: "__execution__" }
35
+ };
36
+ static requiredSettings = [];
37
+ async process() {
38
+ return {};
39
+ }
40
+ async run(inputs, outputs, context) {
41
+ if (!Number.isFinite(this.max_segment_s) || this.max_segment_s < 1) {
42
+ throw new Error("Maximum segment duration must be at least one second");
43
+ }
44
+ if (this.model.provider !== "whisper_cpp") {
45
+ throw new Error("Live Transcription requires a whisper_cpp model");
46
+ }
47
+ const provider = new WhisperCppProvider({
48
+ WHISPER_CPP_MODELS_DIR: (await context?.getSecret("WHISPER_CPP_MODELS_DIR")) || undefined,
49
+ WHISPER_CPP_GPU_BACKEND: (await context?.getSecret("WHISPER_CPP_GPU_BACKEND")) || undefined
50
+ });
51
+ const modelPath = await provider.resolveModel(this.model.id);
52
+ const binding = await loadWhisperNode();
53
+ const signal = context
54
+ ? AbortSignal.any([context.signal, inputs.signal])
55
+ : inputs.signal;
56
+ signal?.throwIfAborted();
57
+ let vad;
58
+ let worker = Promise.resolve();
59
+ let workerError;
60
+ const texts = [];
61
+ let buffer = new Float32Array();
62
+ const maxSamples = Math.floor(this.max_segment_s * 16000);
63
+ const enqueue = (samples) => {
64
+ worker = worker.then(async () => {
65
+ try {
66
+ signal?.throwIfAborted();
67
+ if (workerError) {
68
+ return;
69
+ }
70
+ const result = await provider.transcribePcm(modelPath, samplesToPcm16(samples), { language: this.language || "auto", prompt: this.prompt }, signal);
71
+ texts.push(result.text);
72
+ await outputs.emit("chunk", {
73
+ type: "chunk",
74
+ content: result.text,
75
+ content_type: "text",
76
+ done: false
77
+ });
78
+ }
79
+ catch (error) {
80
+ workerError = error;
81
+ }
82
+ });
83
+ };
84
+ try {
85
+ const vadModel = (await discoverVadModels(provider.modelsDir))[0];
86
+ if (vadModel) {
87
+ vad = await binding.initWhisperVad({ filePath: vadModel.id, useGpu: provider.gpuBackend !== "cpu" }, await resolveVariant(provider.gpuBackend));
88
+ }
89
+ else {
90
+ log.warn("No whisper.cpp VAD model installed. Using fixed transcription windows.");
91
+ }
92
+ for await (const [handle, item] of inputs.any()) {
93
+ signal?.throwIfAborted();
94
+ if (workerError) {
95
+ throw workerError;
96
+ }
97
+ if (handle === "__control__") {
98
+ continue;
99
+ }
100
+ let content = "";
101
+ let sampleRate = 16000;
102
+ let done = false;
103
+ const text = z.string().safeParse(item);
104
+ const parsed = liveItemSchema.safeParse(item);
105
+ if (text.success) {
106
+ content = text.data;
107
+ }
108
+ else if (parsed.success) {
109
+ const value = parsed.data;
110
+ done = value.done === true;
111
+ if (value.content_type === "audio") {
112
+ content = value.content ?? "";
113
+ sampleRate = value.content_metadata?.sample_rate ?? sampleRate;
114
+ }
115
+ }
116
+ if (content) {
117
+ const samples = pcm16Base64ToSamples(content, sampleRate);
118
+ const combined = new Float32Array(buffer.length + samples.length);
119
+ combined.set(buffer);
120
+ combined.set(samples, buffer.length);
121
+ buffer = combined;
122
+ while (buffer.length >= 16000) {
123
+ let cut = 0;
124
+ let speech = true;
125
+ if (vad) {
126
+ const segments = await vad.detectSpeechData(samplesToPcm16(buffer), {
127
+ threshold: this.vad_threshold,
128
+ minSilenceDurationMs: this.min_silence_ms
129
+ });
130
+ // Whisper hallucinates text ("Thank you.") on silence, so a
131
+ // window VAD finds no speech in is dropped, not transcribed.
132
+ speech = segments.length > 0;
133
+ const last = segments.at(-1);
134
+ // VAD passes through whisper.cpp centiseconds (ASR uses milliseconds).
135
+ if (last &&
136
+ (buffer.length / 16000 - last.t1 / 100) * 1000 >=
137
+ this.min_silence_ms) {
138
+ cut = Math.min(buffer.length, Math.round((last.t1 / 100) * 16000));
139
+ }
140
+ }
141
+ if (buffer.length >= maxSamples) {
142
+ cut = cut > 0 ? Math.min(cut, maxSamples) : maxSamples;
143
+ }
144
+ if (cut <= 0) {
145
+ break;
146
+ }
147
+ if (speech) {
148
+ enqueue(buffer.slice(0, cut));
149
+ }
150
+ buffer = buffer.slice(cut);
151
+ }
152
+ }
153
+ if (done) {
154
+ break;
155
+ }
156
+ }
157
+ if (buffer.length) {
158
+ const speech = vad
159
+ ? await vad.detectSpeechData(samplesToPcm16(buffer), {
160
+ threshold: this.vad_threshold,
161
+ minSilenceDurationMs: this.min_silence_ms
162
+ })
163
+ : undefined;
164
+ if (!speech || speech.length > 0) {
165
+ enqueue(buffer);
166
+ }
167
+ }
168
+ await worker;
169
+ if (workerError) {
170
+ throw workerError;
171
+ }
172
+ signal?.throwIfAborted();
173
+ await outputs.emit("chunk", {
174
+ type: "chunk",
175
+ content: "",
176
+ content_type: "text",
177
+ done: true
178
+ });
179
+ await outputs.emit("text", texts.filter(Boolean).join(" "));
180
+ }
181
+ finally {
182
+ await worker;
183
+ await vad?.release();
184
+ }
185
+ }
186
+ }
187
+ __decorate([
188
+ prop({ type: "chunk", title: "Chunk" })
189
+ ], LiveTranscriptionNode.prototype, "chunk", void 0);
190
+ __decorate([
191
+ prop({
192
+ type: "asr_model",
193
+ default: { type: "asr_model", provider: "whisper_cpp", id: "" },
194
+ title: "Model"
195
+ })
196
+ ], LiveTranscriptionNode.prototype, "model", void 0);
197
+ __decorate([
198
+ prop({ type: "str", default: "", title: "Language" })
199
+ ], LiveTranscriptionNode.prototype, "language", void 0);
200
+ __decorate([
201
+ prop({ type: "str", default: "", title: "Prompt" })
202
+ ], LiveTranscriptionNode.prototype, "prompt", void 0);
203
+ __decorate([
204
+ prop({ type: "float", default: 0.5, min: 0, max: 1, title: "VAD Threshold" })
205
+ ], LiveTranscriptionNode.prototype, "vad_threshold", void 0);
206
+ __decorate([
207
+ prop({ type: "int", default: 500, min: 0, title: "Minimum Silence (ms)" })
208
+ ], LiveTranscriptionNode.prototype, "min_silence_ms", void 0);
209
+ __decorate([
210
+ prop({ type: "float", default: 20, min: 1, title: "Maximum Segment (s)" })
211
+ ], LiveTranscriptionNode.prototype, "max_segment_s", void 0);
212
+ //# sourceMappingURL=live-transcription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-transcription.js","sourceRoot":"","sources":["../../src/nodes/live-transcription.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { BaseProvider, type ASRModel, type ASRResult, type Message, type ProviderStreamItem, type ProviderCapability } from "@nodetool-ai/runtime";
2
+ import { type TranscribeOptions } from "./binding.js";
3
+ export interface WhisperSettings {
4
+ WHISPER_CPP_MODELS_DIR?: string;
5
+ WHISPER_CPP_GPU_BACKEND?: string;
6
+ }
7
+ export type AsrArgs = Parameters<BaseProvider["automaticSpeechRecognition"]>[0];
8
+ export declare class WhisperCppProvider extends BaseProvider {
9
+ readonly modelsDir: string | undefined;
10
+ readonly gpuBackend: string | undefined;
11
+ constructor(secrets?: WhisperSettings);
12
+ static requiredSecrets(): string[];
13
+ protected declaredCapabilities(): readonly ProviderCapability[];
14
+ getCapabilities(): ProviderCapability[];
15
+ generateMessage(_args: Parameters<BaseProvider["generateMessage"]>[0]): Promise<Message>;
16
+ generateMessages(_args: Parameters<BaseProvider["generateMessages"]>[0]): AsyncGenerator<ProviderStreamItem>;
17
+ unavailableReason(): Promise<string | null>;
18
+ getAvailableASRModels(): Promise<ASRModel[]>;
19
+ resolveModel(id: string): Promise<string>;
20
+ transcribePcm(modelPath: string, audio: ArrayBuffer, options: TranscribeOptions, signal?: AbortSignal): Promise<ASRResult>;
21
+ automaticSpeechRecognition(args: AsrArgs): Promise<ASRResult>;
22
+ }
23
+ //# sourceMappingURL=whisper-cpp-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper-cpp-provider.d.ts","sourceRoot":"","sources":["../src/whisper-cpp-provider.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAKtB,MAAM,WAAW,eAAe;IAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AACD,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,YAAY,OAAO,GAAE,eAAoB,EAMxC;IACD,OAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;IACD,UAAmB,oBAAoB,IAAI,SAAS,kBAAkB,EAAE,CAEvE;IACQ,eAAe,IAAI,kBAAkB,EAAE,CAE/C;IACc,eAAe,CAC5B,KAAK,EAAE,UAAU,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,GACpD,OAAO,CAAC,OAAO,CAAC,CAElB;IACQ,gBAAgB,CACvB,KAAK,EAAE,UAAU,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,GACrD,cAAc,CAAC,kBAAkB,CAAC,CAEpC;IACc,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOzD;IACc,qBAAqB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAK1D;IACD,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAExC;IACK,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,SAAS,CAAC,CAiCpB;IACc,0BAA0B,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAmB3E;CACF"}
@@ -0,0 +1,101 @@
1
+ import { availableParallelism } from "node:os";
2
+ import { BaseProvider } from "@nodetool-ai/runtime";
3
+ import { loadWhisperNode, resolveVariant } from "./binding.js";
4
+ import { decodeToPcm16 } from "./audio.js";
5
+ import { contextCache } from "./context-cache.js";
6
+ import { discoverASRModels, resolveModelPath } from "./model-discovery.js";
7
+ export class WhisperCppProvider extends BaseProvider {
8
+ modelsDir;
9
+ gpuBackend;
10
+ constructor(secrets = {}) {
11
+ super("whisper_cpp");
12
+ this.modelsDir =
13
+ secrets.WHISPER_CPP_MODELS_DIR || process.env.WHISPER_CPP_MODELS_DIR;
14
+ this.gpuBackend =
15
+ secrets.WHISPER_CPP_GPU_BACKEND || process.env.WHISPER_CPP_GPU_BACKEND;
16
+ }
17
+ static requiredSecrets() {
18
+ return [];
19
+ }
20
+ declaredCapabilities() {
21
+ return ["automatic_speech_recognition"];
22
+ }
23
+ getCapabilities() {
24
+ return ["automatic_speech_recognition"];
25
+ }
26
+ async generateMessage(_args) {
27
+ throw new Error("whisper_cpp does not support chat generation");
28
+ }
29
+ generateMessages(_args) {
30
+ throw new Error("whisper_cpp does not support chat generation");
31
+ }
32
+ async unavailableReason() {
33
+ try {
34
+ await loadWhisperNode();
35
+ return null;
36
+ }
37
+ catch (error) {
38
+ return error instanceof Error ? error.message : String(error);
39
+ }
40
+ }
41
+ async getAvailableASRModels() {
42
+ if (await this.unavailableReason()) {
43
+ return [];
44
+ }
45
+ return discoverASRModels(this.modelsDir);
46
+ }
47
+ resolveModel(id) {
48
+ return resolveModelPath(id, this.modelsDir);
49
+ }
50
+ async transcribePcm(modelPath, audio, options, signal) {
51
+ return contextCache.withContext(modelPath, await resolveVariant(this.gpuBackend), this.gpuBackend !== "cpu", async (context) => {
52
+ signal?.throwIfAborted();
53
+ const task = context.transcribeData(audio, {
54
+ ...options,
55
+ maxThreads: Math.max(1, Math.min(8, availableParallelism() - 1))
56
+ });
57
+ const abort = () => {
58
+ void task.stop().catch(() => {
59
+ /* The task promise reports native failures. */
60
+ });
61
+ };
62
+ signal?.addEventListener("abort", abort, { once: true });
63
+ try {
64
+ const result = await task.promise;
65
+ signal?.throwIfAborted();
66
+ return {
67
+ text: result.result.trim(),
68
+ chunks: result.segments.map((segment) => ({
69
+ // whisper.node 1.1.3 converts whisper.cpp ticks to milliseconds.
70
+ timestamp: [segment.t0 / 1000, segment.t1 / 1000],
71
+ text: segment.text
72
+ }))
73
+ };
74
+ }
75
+ finally {
76
+ signal?.removeEventListener("abort", abort);
77
+ }
78
+ });
79
+ }
80
+ async automaticSpeechRecognition(args) {
81
+ if (args.audio.length === 0) {
82
+ throw new Error("audio must not be empty");
83
+ }
84
+ await loadWhisperNode();
85
+ const modelPath = await this.resolveModel(args.model);
86
+ const audio = await decodeToPcm16(args.audio);
87
+ // BaseProvider ASR arguments do not expose cancellation yet.
88
+ const options = {
89
+ language: args.language || "auto",
90
+ tokenTimestamps: args.word_timestamps ?? false
91
+ };
92
+ if (args.prompt !== undefined) {
93
+ options.prompt = args.prompt;
94
+ }
95
+ if (args.temperature !== undefined) {
96
+ options.temperature = args.temperature;
97
+ }
98
+ return this.transcribePcm(modelPath, audio, options);
99
+ }
100
+ }
101
+ //# sourceMappingURL=whisper-cpp-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper-cpp-provider.js","sourceRoot":"","sources":["../src/whisper-cpp-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { BaseProvider, type ASRModel, type ASRResult, type Message, type ProviderStreamItem, type ProviderCapability } from "@nodetool-ai/runtime";
2
+ import type { AsrArgs } from "./whisper-cpp-provider.js";
3
+ export declare class WhisperServerProvider extends BaseProvider {
4
+ readonly baseUrl: string;
5
+ private readonly fetchFn;
6
+ constructor(secrets?: {
7
+ WHISPER_CPP_SERVER_URL?: string;
8
+ }, options?: {
9
+ fetchFn?: typeof fetch;
10
+ });
11
+ static requiredSecrets(): string[];
12
+ protected declaredCapabilities(): readonly ProviderCapability[];
13
+ getCapabilities(): ProviderCapability[];
14
+ generateMessage(_args: Parameters<BaseProvider["generateMessage"]>[0]): Promise<Message>;
15
+ generateMessages(_args: Parameters<BaseProvider["generateMessages"]>[0]): AsyncGenerator<ProviderStreamItem>;
16
+ getAvailableASRModels(): Promise<ASRModel[]>;
17
+ automaticSpeechRecognition(args: AsrArgs): Promise<ASRResult>;
18
+ }
19
+ //# sourceMappingURL=whisper-server-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper-server-provider.d.ts","sourceRoot":"","sources":["../src/whisper-server-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAEZ,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAoEzD,qBAAa,qBAAsB,SAAQ,YAAY;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,YACE,OAAO,GAAE;QAAE,sBAAsB,CAAC,EAAE,MAAM,CAAA;KAAO,EACjD,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;KAAO,EAUzC;IACD,OAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;IACD,UAAmB,oBAAoB,IAAI,SAAS,kBAAkB,EAAE,CAEvE;IACQ,eAAe,IAAI,kBAAkB,EAAE,CAE/C;IACc,eAAe,CAC5B,KAAK,EAAE,UAAU,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,GACpD,OAAO,CAAC,OAAO,CAAC,CAElB;IACQ,gBAAgB,CACvB,KAAK,EAAE,UAAU,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,GACrD,cAAc,CAAC,kBAAkB,CAAC,CAEpC;IACc,qBAAqB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAI1D;IACc,0BAA0B,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CA+B3E;CACF"}
@@ -0,0 +1,121 @@
1
+ import { BaseProvider, sniffAudioMime } from "@nodetool-ai/runtime";
2
+ import { decodeAudioBytesToSamples, encodeWav } from "@nodetool-ai/transformers-js-nodes";
3
+ import { z } from "zod";
4
+ const resultSchema = z.object({ text: z.string() });
5
+ const segmentSchema = z.object({
6
+ start: z.number(),
7
+ end: z.number(),
8
+ text: z.string()
9
+ });
10
+ async function readResult(response) {
11
+ const value = await response.json();
12
+ const result = resultSchema.safeParse(value);
13
+ if (!result.success) {
14
+ throw new Error("Invalid whisper-server response: expected text");
15
+ }
16
+ const chunks = [];
17
+ const segments = Array.isArray(value.segments) ? value.segments : [];
18
+ for (const raw of segments) {
19
+ const segment = segmentSchema.safeParse(raw);
20
+ if (!segment.success) {
21
+ throw new Error("Invalid whisper-server response: expected segment start, end and text");
22
+ }
23
+ chunks.push({
24
+ timestamp: [segment.data.start, segment.data.end],
25
+ text: segment.data.text
26
+ });
27
+ }
28
+ return { text: result.data.text.trim(), chunks };
29
+ }
30
+ /** ID3-tagged MP3 or a raw MPEG audio frame sync. */
31
+ function isMp3(bytes) {
32
+ return ((bytes[0] === 0x49 && bytes[1] === 0x44 && bytes[2] === 0x33) ||
33
+ (bytes[0] === 0xff && (bytes[1] & 0xe0) === 0xe0));
34
+ }
35
+ /**
36
+ * whisper-server decodes uploads with miniaudio, which reads WAV, MP3 and
37
+ * FLAC only (unless the server runs with `--convert`). Send those unchanged
38
+ * and convert anything else (WebM/Opus, M4A, OGG) to 16 kHz mono WAV.
39
+ * When local decoding fails, send the original bytes so a `--convert`
40
+ * server can still try.
41
+ */
42
+ async function toServerAudio(audio) {
43
+ const mime = sniffAudioMime(audio);
44
+ if (mime === "audio/wav") {
45
+ return { bytes: audio, mime, extension: "wav" };
46
+ }
47
+ if (mime === "audio/flac") {
48
+ return { bytes: audio, mime, extension: "flac" };
49
+ }
50
+ if (isMp3(audio)) {
51
+ return { bytes: audio, mime: "audio/mpeg", extension: "mp3" };
52
+ }
53
+ let samples;
54
+ try {
55
+ samples = await decodeAudioBytesToSamples(audio, 16000);
56
+ }
57
+ catch {
58
+ return { bytes: audio, mime: "application/octet-stream", extension: "bin" };
59
+ }
60
+ return { bytes: encodeWav(samples, 16000), mime: "audio/wav", extension: "wav" };
61
+ }
62
+ export class WhisperServerProvider extends BaseProvider {
63
+ baseUrl;
64
+ fetchFn;
65
+ constructor(secrets = {}, options = {}) {
66
+ super("whisper_cpp_server");
67
+ const url = secrets.WHISPER_CPP_SERVER_URL || process.env.WHISPER_CPP_SERVER_URL;
68
+ if (!url?.trim()) {
69
+ throw new Error("WHISPER_CPP_SERVER_URL is required");
70
+ }
71
+ this.baseUrl = url.trim().replace(/\/+$/, "");
72
+ this.fetchFn = options.fetchFn ?? globalThis.fetch.bind(globalThis);
73
+ }
74
+ static requiredSecrets() {
75
+ return ["WHISPER_CPP_SERVER_URL"];
76
+ }
77
+ declaredCapabilities() {
78
+ return ["automatic_speech_recognition"];
79
+ }
80
+ getCapabilities() {
81
+ return ["automatic_speech_recognition"];
82
+ }
83
+ async generateMessage(_args) {
84
+ throw new Error("whisper_cpp_server does not support chat generation");
85
+ }
86
+ generateMessages(_args) {
87
+ throw new Error("whisper_cpp_server does not support chat generation");
88
+ }
89
+ async getAvailableASRModels() {
90
+ return [
91
+ { id: "default", name: "whisper-server", provider: "whisper_cpp_server" }
92
+ ];
93
+ }
94
+ async automaticSpeechRecognition(args) {
95
+ if (args.audio.length === 0) {
96
+ throw new Error("audio must not be empty");
97
+ }
98
+ const { bytes, mime, extension } = await toServerAudio(args.audio);
99
+ const form = new FormData();
100
+ form.set("file", new Blob([new Uint8Array(bytes)], { type: mime }), `audio.${extension}`);
101
+ form.set("response_format", "verbose_json");
102
+ form.set("language", args.language || "auto");
103
+ if (args.temperature !== undefined) {
104
+ form.set("temperature", String(args.temperature));
105
+ }
106
+ if (args.prompt !== undefined) {
107
+ form.set("prompt", args.prompt);
108
+ }
109
+ // Operator-configured local service, following LlamaProvider's fetch policy.
110
+ const response = await this.fetchFn(`${this.baseUrl}/inference`, {
111
+ method: "POST",
112
+ body: form,
113
+ signal: AbortSignal.timeout(10 * 60 * 1000)
114
+ });
115
+ if (!response.ok) {
116
+ throw new Error(`whisper-server inference failed (${response.status}): ${await response.text()}`);
117
+ }
118
+ return readResult(response);
119
+ }
120
+ }
121
+ //# sourceMappingURL=whisper-server-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper-server-provider.js","sourceRoot":"","sources":["../src/whisper-server-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,cAAc,EAMf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,yBAAyB,EACzB,SAAS,EACV,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACpD,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC;AAEH,KAAK,UAAU,UAAU,CAAC,QAAkB;IAC1C,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,MAAM,GAAqC,EAAE,CAAC;IACpD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,aAAa,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,uEAAuE,CACxE,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,IAAI,CAAC;YACV,SAAS,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;YACjD,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;SACxB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC;AACnD,CAAC;AACD,qDAAqD;AACrD,SAAS,KAAK,CAAC,KAAiB;IAC9B,OAAO,CACL,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;QAC7D,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAClD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAC1B,KAAiB;IAEjB,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAClD,CAAC;IACD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IACnD,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACjB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAChE,CAAC;IACD,IAAI,OAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,yBAAyB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,0BAA0B,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACnF,CAAC;AAED,MAAM,OAAO,qBAAsB,SAAQ,YAAY;IAC5C,OAAO,CAAS;IACR,OAAO,CAAe;IACvC,YACE,OAAO,GAAwC,EAAE,EACjD,OAAO,GAA+B,EAAE;QAExC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAC5B,MAAM,GAAG,GACP,OAAO,CAAC,sBAAsB,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;QACvE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,CAAU,eAAe;QAC7B,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACpC,CAAC;IACkB,oBAAoB;QACrC,OAAO,CAAC,8BAA8B,CAAU,CAAC;IACnD,CAAC;IACQ,eAAe;QACtB,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC1C,CAAC;IACQ,KAAK,CAAC,eAAe,CAC5B,KAAqD;QAErD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACQ,gBAAgB,CACvB,KAAsD;QAEtD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACQ,KAAK,CAAC,qBAAqB;QAClC,OAAO;YACL,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,oBAAoB,EAAE;SAC1E,CAAC;IACJ,CAAC;IACQ,KAAK,CAAC,0BAA0B,CAAC,IAAa;QACrD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CACN,MAAM,EACN,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EACjD,SAAS,SAAS,EAAE,CACrB,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAC;QAC9C,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;QACD,6EAA6E;QAC7E,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,YAAY,EAAE;YAC/D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;SAC5C,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,oCAAoC,QAAQ,CAAC,MAAM,MAAM,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CACjF,CAAC;QACJ,CAAC;QACD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,55 @@
1
1
  {
2
2
  "name": "@nodetool-ai/whisper-cpp",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "type": "module",
4
+ "engines": {
5
+ "node": ">=22.0.0"
6
+ },
7
+ "version": "0.8.2",
8
+ "description": "Local whisper.cpp speech recognition providers and streaming transcription",
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "dependencies": {
12
+ "@nodetool-ai/config": "0.8.2",
13
+ "@nodetool-ai/protocol": "0.8.2",
14
+ "@nodetool-ai/runtime": "0.8.2",
15
+ "@nodetool-ai/transformers-js-nodes": "0.8.2",
16
+ "@nodetool-ai/node-sdk": "0.8.2"
17
+ },
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "default": "./dist/index.js"
23
+ }
24
+ },
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/nodetool-ai/nodetool.git",
29
+ "directory": "packages/whisper-cpp"
30
+ },
31
+ "homepage": "https://nodetool.ai",
32
+ "bugs": {
33
+ "url": "https://github.com/nodetool-ai/nodetool/issues"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md"
41
+ ],
42
+ "keywords": [
43
+ "nodetool",
44
+ "whisper",
45
+ "asr"
46
+ ],
47
+ "peerDependencies": {
48
+ "@fugood/whisper.node": "1.1.3"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "@fugood/whisper.node": {
52
+ "optional": true
53
+ }
54
+ }
55
+ }