@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
82 lines (81 loc) • 3.92 kB
TypeScript
/**
* Energy-gated endpointer for client-side streaming of batch STT engines.
*
* Pure and synchronous: feed it float samples at any input rate, get back
* utterance start / end / drop events. It knows nothing about engines; the
* chunked adapter decides what to transcribe and when.
*
* The rules and their constants were measured on live microphones and on a
* 45 s three-speaker meeting slice, where they recover 155 of the 156 words a
* batch transcription of the whole file finds (a plain fixed-threshold gate
* recovered 125):
*
* - Work on 20 ms blocks.
* - The noise floor is a minimum statistic — the quietest block of the last
* 1.5 s — allowed to rise by at most ~2× per second and never below 0.0005.
* Because it follows the quietest block, a loud talker can never raise it
* enough to push a quieter second speaker below the gate.
* - Hysteresis: speech starts above `max(onsetRms, floor × 3)` and is
* sustained above `max(onsetRms × 0.58, floor × 1.8)`, so soft word endings
* are kept inside the utterance instead of counting as silence.
* - `prerollMs` of audio before the onset is kept, so the first consonant is
* not clipped.
* - An utterance ends after `endSilenceMs` without sustained speech. One with
* less than `minSpeechMs` of speech is a cough and is dropped — unless a
* pass already heard words in it, which must never be lost.
* - A long turn (`softCutSeconds`) ends at the next ≥ 320 ms gap; a turn with
* no gap at all is hard-cut at `maxUtteranceSeconds` at the quietest block
* of the last 3 s, and the remainder becomes the start of the next
* utterance, so no audio falls between the two.
*
* @module voice/streaming/endpointer
*/
import type { STTEndpointerConfig, STTEndpointerEvent, STTEndpointerUtterance, STTStreamingOptions } from "../../types/index.js";
/** Sample rate every engine pass receives. */
export declare const ENGINE_SAMPLE_RATE = 16000;
/** Defaults of `STTStreamingOptions` that the endpointer reads. */
export declare const ENDPOINTER_DEFAULTS: {
readonly endSilenceMs: 750;
readonly softCutSeconds: 16;
readonly maxUtteranceSeconds: 28;
readonly onsetRms: 0.006;
readonly prerollMs: 350;
readonly minSpeechMs: 250;
};
/** Applies the defaults to caller tuning; non-finite or non-positive values fall back. */
export declare function resolveEndpointerConfig(options: STTStreamingOptions | undefined, inputRate: number): STTEndpointerConfig;
export declare function rmsOf(samples: Float32Array): number;
/** Linear-interpolation resampler to 16 kHz; returns the input untouched when it already is. */
export declare function resampleTo16k(samples: Float32Array, inputRate: number): Float32Array;
export declare class Endpointer {
readonly config: STTEndpointerConfig;
private readonly blockLen;
private block;
private blockFill;
private noise;
private readonly noiseWin;
private pre;
private preLen;
private utt;
private seq;
/** Input samples that went through the gate so far: the audio clock, in whole blocks. */
private consumed;
constructor(config: STTEndpointerConfig);
/** The utterance being built, if speech is in progress. */
get current(): STTEndpointerUtterance | null;
/** Seconds of input consumed so far. */
get audioSeconds(): number;
/** Feeds samples at the input rate; returns the events they caused, in order. */
push(samples: Float32Array): STTEndpointerEvent[];
/**
* Ends the stream: a partial block is folded into the open utterance, which
* is then ended (`flush`) — or dropped when it is a cough nobody heard.
*/
flush(): STTEndpointerEvent[];
/** The utterance's audio at 16 kHz. */
pcm16k(u: STTEndpointerUtterance): Float32Array;
private sustainThreshold;
private newUtterance;
private onBlock;
private hardCut;
}