@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
88 lines (87 loc) • 4.66 kB
TypeScript
/**
* Whistle — the built-in, zero-config, on-device speech-to-text engine.
*
* Runs Cactus's Whistle model (17 MB) on the Cactus "needle" engine, an
* Emscripten WebAssembly build, inside a `worker_threads` Worker. No API key,
* no network after the first use, no native addon: it is the STT provider
* NeuroLink falls back to when no other one is configured.
*
* **Files.** `needle.js`, `needle.wasm` and `whistle.cact` (~17.9 MB in all)
* are downloaded from pinned Hugging Face revisions on first use, checked
* against SHA-256 and kept in the model directory:
* `credentials.stt.whistle.modelDir` → `NEUROLINK_WHISTLE_DIR` →
* `$NEUROLINK_MODEL_DIR/whistle` → `~/.neurolink/models/whistle`. Set
* `NEUROLINK_WHISTLE_AUTO_DOWNLOAD=0` (or `autoDownload: false`) to forbid the
* download; a missing file then fails with an error naming each file, where it
* goes and where to get it.
*
* **Languages.** English, German, French, Spanish, Italian, Dutch and Polish
* (`en de fr es it nl pl`). `options.language` accepts a code or a locale
* (`"de-DE"`); `"auto"`, omitted or any other language lets the engine detect
* one of the seven.
*
* **Limits.** The engine reads 30 s per call; longer audio is cut at the
* quietest 20 ms frame near every 24 s mark and the word times are offset
* back onto the whole recording. One hour per request. Roughly 0.5 s of CPU
* per 10 s of audio on a laptop core; one warm worker per handler instance,
* requests served in order.
*
* **Keyword biasing.** `options.vocabulary` is passed to the engine as
* keywords only when `options.model` is `"whistle-keywords"` or
* `NEUROLINK_WHISTLE_KEYWORDS=1` — the engine can loop on long keyword lists,
* so it is opt-in and capped at {@link MAX_KEYWORDS} entries.
*
* **Formats.** WAV (any PCM/float layout, rate and channel count) and raw
* `pcm16` are decoded in-process; mp3, m4a, ogg/opus, webm, flac and mp4 need
* ffmpeg (`ffmpeg-static`, `FFMPEG_PATH` or `ffmpeg` on PATH).
*
* **Streaming.** Native: `transcribeStream()` feeds the engine's own streaming
* decoder about a second at a time, on a dedicated worker per stream. Each
* step yields a final segment for the words two passes agreed on, and an
* interim segment for the unconfirmed tail. Input frames are PCM16LE mono at
* `options.sampleRate` (default 16 kHz).
*
* **Accuracy.** A 17 MB model: good on clear speech in its seven languages,
* noticeably behind cloud engines and large Whisper-class models on accents,
* noise, crosstalk, names and jargon. Use a dictionary/correction pass, or a
* cloud provider, where that matters.
*
* @module voice/providers/WhistleSTT
*/
import type { STTCredentials, STTHandler, STTLanguage, STTOptions, STTResult, TranscriptionSegment, TTSAudioFormat } from "../../types/index.js";
export declare class WhistleSTT implements STTHandler {
/** One hour per request (16 kHz float samples: ~230 MB in memory). */
readonly maxAudioDuration: number;
/** The engine has its own streaming decoder. */
readonly supportsStreaming = true;
private readonly modelDir;
private readonly autoDownload;
private engine;
constructor(slice?: STTCredentials["whistle"]);
/**
* True when the engine can run: its files are already in the model dir, or
* it is allowed to fetch them. With `NEUROLINK_WHISTLE_AUTO_DOWNLOAD=0` (or
* `autoDownload: false`) and no files, it reports unconfigured, so a caller
* asserting "no STT backend" is not answered by a 17 MB download.
*/
isConfigured(): boolean;
describeConfiguration(): string;
/** Directory the engine's files live in. */
getModelDir(): string;
getSupportedFormats(): TTSAudioFormat[];
getSupportedLanguages(): Promise<STTLanguage[]>;
/** Download/verify the files and start the worker now rather than on the first request. */
warmUp(): Promise<void>;
/** Stop the warm worker. The handler stays usable; the next call starts a new one. */
dispose(): Promise<void>;
transcribe(audio: Buffer | ArrayBuffer, options?: STTOptions): Promise<STTResult>;
/**
* Native streaming. `audioStream` yields PCM16LE mono frames at
* `options.sampleRate` (default 16 kHz), any frame size. Yields a final
* segment for each run of words the engine commits (times from the start of
* the stream; join the finals with a space for the transcript) and an
* interim segment carrying the unconfirmed tail whenever it changes.
*/
transcribeStream(audioStream: AsyncIterable<Buffer>, options?: STTOptions): AsyncIterable<TranscriptionSegment>;
private getEngine;
}