@juspay/neurolink 12.48.2 → 12.49.0

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.
Files changed (104) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/dist/browser/neurolink.min.js +616 -595
  3. package/dist/cli/commands/serve.d.ts +0 -3
  4. package/dist/cli/commands/serve.js +85 -3
  5. package/dist/cli/commands/transcribe.d.ts +24 -0
  6. package/dist/cli/commands/transcribe.js +718 -0
  7. package/dist/cli/factories/commandFactory.d.ts +10 -0
  8. package/dist/cli/factories/commandFactory.js +13 -0
  9. package/dist/cli/parser.js +3 -0
  10. package/dist/factories/mediaHandlerCatalog.js +11 -9
  11. package/dist/factories/sttDescriptors.d.ts +63 -0
  12. package/dist/factories/sttDescriptors.js +286 -0
  13. package/dist/index.d.ts +4 -1
  14. package/dist/index.js +7 -1
  15. package/dist/neurolink.d.ts +68 -1
  16. package/dist/neurolink.js +202 -4
  17. package/dist/processors/media/AudioProcessor.d.ts +15 -56
  18. package/dist/processors/media/AudioProcessor.js +105 -276
  19. package/dist/processors/media/VideoProcessor.d.ts +3 -5
  20. package/dist/processors/media/VideoProcessor.js +52 -51
  21. package/dist/server/abstract/baseServerAdapter.d.ts +7 -0
  22. package/dist/server/abstract/baseServerAdapter.js +13 -1
  23. package/dist/server/adapters/expressAdapter.d.ts +1 -0
  24. package/dist/server/adapters/expressAdapter.js +48 -4
  25. package/dist/server/adapters/fastifyAdapter.d.ts +1 -0
  26. package/dist/server/adapters/fastifyAdapter.js +38 -1
  27. package/dist/server/adapters/honoAdapter.d.ts +1 -4
  28. package/dist/server/adapters/honoAdapter.js +83 -1
  29. package/dist/server/adapters/koaAdapter.d.ts +1 -0
  30. package/dist/server/adapters/koaAdapter.js +43 -0
  31. package/dist/server/index.d.ts +3 -2
  32. package/dist/server/index.js +3 -2
  33. package/dist/server/routes/index.d.ts +1 -0
  34. package/dist/server/routes/index.js +3 -0
  35. package/dist/server/routes/transcribeRoutes.d.ts +23 -0
  36. package/dist/server/routes/transcribeRoutes.js +506 -0
  37. package/dist/server/utils/rawBody.d.ts +32 -0
  38. package/dist/server/utils/rawBody.js +76 -0
  39. package/dist/server/utils/validation.d.ts +192 -0
  40. package/dist/server/utils/validation.js +100 -0
  41. package/dist/server/websocket/transcribeWebSocket.d.ts +42 -0
  42. package/dist/server/websocket/transcribeWebSocket.js +264 -0
  43. package/dist/types/cli.d.ts +46 -0
  44. package/dist/types/index.d.ts +1 -0
  45. package/dist/types/index.js +1 -0
  46. package/dist/types/providers.d.ts +7 -1
  47. package/dist/types/server.d.ts +117 -1
  48. package/dist/types/stt.d.ts +160 -7
  49. package/dist/types/transcribe.d.ts +506 -0
  50. package/dist/types/transcribe.js +29 -0
  51. package/dist/utils/speakerTurns.d.ts +28 -0
  52. package/dist/utils/speakerTurns.js +93 -0
  53. package/dist/utils/sttProcessor.d.ts +20 -2
  54. package/dist/utils/sttProcessor.js +73 -5
  55. package/dist/voice/correction/dictionary.d.ts +49 -0
  56. package/dist/voice/correction/dictionary.js +134 -0
  57. package/dist/voice/correction/guard.d.ts +35 -0
  58. package/dist/voice/correction/guard.js +161 -0
  59. package/dist/voice/correction/index.d.ts +47 -0
  60. package/dist/voice/correction/index.js +211 -0
  61. package/dist/voice/correction/rewrite.d.ts +92 -0
  62. package/dist/voice/correction/rewrite.js +322 -0
  63. package/dist/voice/errors.d.ts +15 -0
  64. package/dist/voice/errors.js +45 -0
  65. package/dist/voice/index.d.ts +20 -2
  66. package/dist/voice/index.js +75 -9
  67. package/dist/voice/providers/AzureSTT.d.ts +10 -7
  68. package/dist/voice/providers/AzureSTT.js +23 -75
  69. package/dist/voice/providers/DeepgramSTT.d.ts +17 -2
  70. package/dist/voice/providers/DeepgramSTT.js +109 -13
  71. package/dist/voice/providers/ElevenLabsSTT.d.ts +12 -2
  72. package/dist/voice/providers/ElevenLabsSTT.js +34 -8
  73. package/dist/voice/providers/GoogleSTT.d.ts +10 -8
  74. package/dist/voice/providers/GoogleSTT.js +21 -75
  75. package/dist/voice/providers/OpenAISTT.d.ts +30 -9
  76. package/dist/voice/providers/OpenAISTT.js +196 -21
  77. package/dist/voice/providers/WhistleSTT.d.ts +87 -0
  78. package/dist/voice/providers/WhistleSTT.js +313 -0
  79. package/dist/voice/streaming/chunkedStreamAdapter.d.ts +19 -0
  80. package/dist/voice/streaming/chunkedStreamAdapter.js +519 -0
  81. package/dist/voice/streaming/endpointer.d.ts +81 -0
  82. package/dist/voice/streaming/endpointer.js +247 -0
  83. package/dist/voice/streaming/localAgreement.d.ts +30 -0
  84. package/dist/voice/streaming/localAgreement.js +44 -0
  85. package/dist/voice/sttEnvCredentials.d.ts +12 -0
  86. package/dist/voice/sttEnvCredentials.js +12 -0
  87. package/dist/voice/transcribe.d.ts +47 -0
  88. package/dist/voice/transcribe.js +519 -0
  89. package/dist/voice/transcribeStream.d.ts +4 -0
  90. package/dist/voice/transcribeStream.js +584 -0
  91. package/dist/voice/whistle/assets.d.ts +47 -0
  92. package/dist/voice/whistle/assets.js +270 -0
  93. package/dist/voice/whistle/audio.d.ts +32 -0
  94. package/dist/voice/whistle/audio.js +267 -0
  95. package/dist/voice/whistle/engine.d.ts +32 -0
  96. package/dist/voice/whistle/engine.js +193 -0
  97. package/dist/voice/whistle/worker.d.ts +18 -0
  98. package/dist/voice/whistle/worker.js +294 -0
  99. package/docs-site/static/search-index.json +66 -8
  100. package/models/whistle/README.md +18 -0
  101. package/models/whistle/needle.js +2 -0
  102. package/models/whistle/needle.wasm +0 -0
  103. package/models/whistle/whistle.cact +0 -0
  104. package/package.json +7 -3
@@ -0,0 +1,247 @@
1
+ /** Sample rate every engine pass receives. */
2
+ export const ENGINE_SAMPLE_RATE = 16000;
3
+ const BLOCK_SECONDS = 0.02;
4
+ const BLOCK_MS = BLOCK_SECONDS * 1000;
5
+ /** Noise-floor window: 75 blocks = 1.5 s. */
6
+ const NOISE_WINDOW_BLOCKS = 75;
7
+ /** Per-block rise limit of the floor: 1.014^50 ≈ 2× per second. */
8
+ const NOISE_RISE_PER_BLOCK = 1.014;
9
+ const NOISE_FLOOR_MIN = 0.0005;
10
+ /** Starting floor, before the window has seen any quiet block. */
11
+ const NOISE_FLOOR_INITIAL = 0.004;
12
+ const ONSET_RATIO = 3;
13
+ const SUSTAIN_RATIO = 1.8;
14
+ const ABS_SUSTAIN_RATIO = 0.58;
15
+ /** A pause this long ends a turn that is already past `softCutSeconds`. */
16
+ const SOFT_GAP_MS = 320;
17
+ /** The hard cut looks for the quietest block in this many trailing seconds. */
18
+ const HARD_CUT_SEARCH_SECONDS = 3;
19
+ /** Defaults of `STTStreamingOptions` that the endpointer reads. */
20
+ export const ENDPOINTER_DEFAULTS = {
21
+ endSilenceMs: 750,
22
+ softCutSeconds: 16,
23
+ maxUtteranceSeconds: 28,
24
+ onsetRms: 0.006,
25
+ prerollMs: 350,
26
+ minSpeechMs: 250,
27
+ };
28
+ /** Applies the defaults to caller tuning; non-finite or non-positive values fall back. */
29
+ export function resolveEndpointerConfig(options, inputRate) {
30
+ const pick = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value > 0
31
+ ? value
32
+ : fallback;
33
+ const d = ENDPOINTER_DEFAULTS;
34
+ return {
35
+ inputRate: pick(inputRate, ENGINE_SAMPLE_RATE),
36
+ endSilenceMs: pick(options?.endSilenceMs, d.endSilenceMs),
37
+ softCutSeconds: pick(options?.softCutSeconds, d.softCutSeconds),
38
+ maxUtteranceSeconds: pick(options?.maxUtteranceSeconds, d.maxUtteranceSeconds),
39
+ onsetRms: pick(options?.onsetRms, d.onsetRms),
40
+ prerollMs: pick(options?.prerollMs, d.prerollMs),
41
+ minSpeechMs: pick(options?.minSpeechMs, d.minSpeechMs),
42
+ };
43
+ }
44
+ export function rmsOf(samples) {
45
+ if (samples.length === 0) {
46
+ return 0;
47
+ }
48
+ let sum = 0;
49
+ for (let i = 0; i < samples.length; i++) {
50
+ sum += samples[i] * samples[i];
51
+ }
52
+ return Math.sqrt(sum / samples.length);
53
+ }
54
+ /** Linear-interpolation resampler to 16 kHz; returns the input untouched when it already is. */
55
+ export function resampleTo16k(samples, inputRate) {
56
+ if (inputRate === ENGINE_SAMPLE_RATE) {
57
+ return samples;
58
+ }
59
+ const ratio = inputRate / ENGINE_SAMPLE_RATE;
60
+ const out = new Float32Array(Math.floor(samples.length / ratio));
61
+ for (let i = 0; i < out.length; i++) {
62
+ const pos = i * ratio;
63
+ const i0 = Math.floor(pos);
64
+ const i1 = Math.min(i0 + 1, samples.length - 1);
65
+ out[i] = samples[i0] + (samples[i1] - samples[i0]) * (pos - i0);
66
+ }
67
+ return out;
68
+ }
69
+ export class Endpointer {
70
+ config;
71
+ blockLen;
72
+ block;
73
+ blockFill = 0;
74
+ noise = NOISE_FLOOR_INITIAL;
75
+ noiseWin = [];
76
+ pre = [];
77
+ preLen = 0;
78
+ utt = null;
79
+ seq = 0;
80
+ /** Input samples that went through the gate so far: the audio clock, in whole blocks. */
81
+ consumed = 0;
82
+ constructor(config) {
83
+ this.config = config;
84
+ this.blockLen = Math.max(1, Math.round(BLOCK_SECONDS * config.inputRate));
85
+ this.block = new Float32Array(this.blockLen);
86
+ }
87
+ /** The utterance being built, if speech is in progress. */
88
+ get current() {
89
+ return this.utt;
90
+ }
91
+ /** Seconds of input consumed so far. */
92
+ get audioSeconds() {
93
+ return this.consumed / this.config.inputRate;
94
+ }
95
+ /** Feeds samples at the input rate; returns the events they caused, in order. */
96
+ push(samples) {
97
+ const events = [];
98
+ let i = 0;
99
+ while (i < samples.length) {
100
+ const n = Math.min(samples.length - i, this.blockLen - this.blockFill);
101
+ this.block.set(samples.subarray(i, i + n), this.blockFill);
102
+ this.blockFill += n;
103
+ i += n;
104
+ if (this.blockFill === this.blockLen) {
105
+ this.onBlock(this.block, events);
106
+ this.block = new Float32Array(this.blockLen);
107
+ this.blockFill = 0;
108
+ }
109
+ }
110
+ return events;
111
+ }
112
+ /**
113
+ * Ends the stream: a partial block is folded into the open utterance, which
114
+ * is then ended (`flush`) — or dropped when it is a cough nobody heard.
115
+ */
116
+ flush() {
117
+ const events = [];
118
+ const u = this.utt;
119
+ if (u && this.blockFill > 0) {
120
+ const tail = this.block.slice(0, this.blockFill);
121
+ u.blocks.push(tail);
122
+ u.rms.push(rmsOf(tail));
123
+ u.length += tail.length;
124
+ }
125
+ this.consumed += this.blockFill;
126
+ this.blockFill = 0;
127
+ if (u) {
128
+ this.utt = null;
129
+ events.push(u.speechMs >= this.config.minSpeechMs || u.heard
130
+ ? { type: "end", utterance: u, reason: "flush" }
131
+ : { type: "drop", utterance: u });
132
+ }
133
+ this.pre = [];
134
+ this.preLen = 0;
135
+ return events;
136
+ }
137
+ /** The utterance's audio at 16 kHz. */
138
+ pcm16k(u) {
139
+ const out = new Float32Array(u.length);
140
+ let o = 0;
141
+ for (const b of u.blocks) {
142
+ out.set(b, o);
143
+ o += b.length;
144
+ }
145
+ return resampleTo16k(out, this.config.inputRate);
146
+ }
147
+ sustainThreshold() {
148
+ return Math.max(this.config.onsetRms * ABS_SUSTAIN_RATIO, this.noise * SUSTAIN_RATIO);
149
+ }
150
+ newUtterance(blocks, rms) {
151
+ const length = blocks.reduce((a, b) => a + b.length, 0);
152
+ return {
153
+ id: ++this.seq,
154
+ // Called once the newest block is counted, so the utterance ends at the clock.
155
+ startSeconds: (this.consumed - length) / this.config.inputRate,
156
+ blocks,
157
+ rms,
158
+ length,
159
+ speechMs: 0,
160
+ silenceMs: 0,
161
+ heard: false,
162
+ };
163
+ }
164
+ onBlock(block, events) {
165
+ const cfg = this.config;
166
+ const rms = rmsOf(block);
167
+ this.consumed += block.length;
168
+ // Minimum statistic over the window; a drop is followed at once, a rise is rate-limited.
169
+ this.noiseWin.push(rms);
170
+ if (this.noiseWin.length > NOISE_WINDOW_BLOCKS) {
171
+ this.noiseWin.shift();
172
+ }
173
+ let winMin = Infinity;
174
+ for (const v of this.noiseWin) {
175
+ if (v < winMin) {
176
+ winMin = v;
177
+ }
178
+ }
179
+ this.noise = Math.max(NOISE_FLOOR_MIN, winMin > this.noise
180
+ ? Math.min(winMin, this.noise * NOISE_RISE_PER_BLOCK)
181
+ : winMin);
182
+ const onset = rms > Math.max(cfg.onsetRms, this.noise * ONSET_RATIO);
183
+ const sustain = rms > this.sustainThreshold();
184
+ const u = this.utt;
185
+ if (!u) {
186
+ this.pre.push({ block, rms });
187
+ this.preLen += block.length;
188
+ const maxPre = (cfg.prerollMs / 1000) * cfg.inputRate;
189
+ while (this.preLen > maxPre && this.pre.length > 1) {
190
+ const dropped = this.pre.shift();
191
+ this.preLen -= dropped ? dropped.block.length : 0;
192
+ }
193
+ if (onset) {
194
+ const started = this.newUtterance(this.pre.map((p) => p.block), this.pre.map((p) => p.rms));
195
+ started.speechMs = BLOCK_MS;
196
+ this.utt = started;
197
+ this.pre = [];
198
+ this.preLen = 0;
199
+ events.push({ type: "start", utterance: started });
200
+ }
201
+ return;
202
+ }
203
+ u.blocks.push(block);
204
+ u.rms.push(rms);
205
+ u.length += block.length;
206
+ if (sustain) {
207
+ u.speechMs += BLOCK_MS;
208
+ u.silenceMs = 0;
209
+ }
210
+ else {
211
+ u.silenceMs += BLOCK_MS;
212
+ }
213
+ if (u.silenceMs >= cfg.endSilenceMs) {
214
+ this.utt = null;
215
+ events.push(u.speechMs >= cfg.minSpeechMs || u.heard
216
+ ? { type: "end", utterance: u, reason: "silence" }
217
+ : { type: "drop", utterance: u });
218
+ }
219
+ else if (u.length >= cfg.softCutSeconds * cfg.inputRate &&
220
+ u.silenceMs >= SOFT_GAP_MS) {
221
+ this.utt = null;
222
+ events.push({ type: "end", utterance: u, reason: "softCut" });
223
+ }
224
+ else if (u.length >= cfg.maxUtteranceSeconds * cfg.inputRate) {
225
+ this.hardCut(u, events);
226
+ }
227
+ }
228
+ hardCut(u, events) {
229
+ const n = u.blocks.length;
230
+ const from = Math.max(1, n - Math.round(HARD_CUT_SEARCH_SECONDS / BLOCK_SECONDS));
231
+ let best = from;
232
+ for (let k = from; k < n; k++) {
233
+ if (u.rms[k] < u.rms[best]) {
234
+ best = k;
235
+ }
236
+ }
237
+ const restBlocks = u.blocks.splice(best);
238
+ const restRms = u.rms.splice(best);
239
+ u.length = u.blocks.reduce((a, b) => a + b.length, 0);
240
+ const next = this.newUtterance(restBlocks, restRms);
241
+ const threshold = this.sustainThreshold();
242
+ next.speechMs = restRms.filter((r) => r > threshold).length * BLOCK_MS;
243
+ this.utt = next;
244
+ events.push({ type: "end", utterance: u, reason: "hardCut" });
245
+ events.push({ type: "start", utterance: next });
246
+ }
247
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * LocalAgreement for rolling re-transcription.
3
+ *
4
+ * Each interim pass re-transcribes the whole utterance so far. Words two
5
+ * consecutive passes agree on are committed; the rest is the tail, which the
6
+ * next pass may still change. The committed prefix never shrinks: once a
7
+ * caption has been shown as stable it must not flicker back, even when a
8
+ * later pass hears the start differently (the next final pass is the place
9
+ * where the whole utterance is settled).
10
+ *
11
+ * @module voice/streaming/localAgreement
12
+ */
13
+ import type { STTLocalAgreementState, STTLocalAgreementUpdate } from "../../types/index.js";
14
+ /** Splits a transcript into words on any whitespace. */
15
+ export declare function splitWords(text: string): string[];
16
+ /** Length of the shared prefix of two word lists. */
17
+ export declare function commonPrefixLength(a: string[], b: string[]): number;
18
+ export declare function createLocalAgreement(): STTLocalAgreementState;
19
+ /**
20
+ * Folds one pass into the state and returns the split for display. Words
21
+ * this pass agrees on with the previous one, beyond what is already
22
+ * committed, are appended to the committed list; the words already committed
23
+ * are kept as they were shown — they are never re-read from the new pass, so
24
+ * a later pass that hears the start differently (or comes back shorter)
25
+ * cannot shrink or rewrite them. The tail is whatever this pass has past the
26
+ * committed count.
27
+ */
28
+ export declare function updateLocalAgreement(state: STTLocalAgreementState, text: string): STTLocalAgreementUpdate;
29
+ /** Forgets everything, e.g. when another engine takes the utterance over. */
30
+ export declare function resetLocalAgreement(state: STTLocalAgreementState): void;
@@ -0,0 +1,44 @@
1
+ /** Splits a transcript into words on any whitespace. */
2
+ export function splitWords(text) {
3
+ return text.split(/\s+/).filter(Boolean);
4
+ }
5
+ /** Length of the shared prefix of two word lists. */
6
+ export function commonPrefixLength(a, b) {
7
+ let n = 0;
8
+ while (n < a.length && n < b.length && a[n] === b[n]) {
9
+ n++;
10
+ }
11
+ return n;
12
+ }
13
+ export function createLocalAgreement() {
14
+ return { prevWords: [], committedWords: [], committedN: 0 };
15
+ }
16
+ /**
17
+ * Folds one pass into the state and returns the split for display. Words
18
+ * this pass agrees on with the previous one, beyond what is already
19
+ * committed, are appended to the committed list; the words already committed
20
+ * are kept as they were shown — they are never re-read from the new pass, so
21
+ * a later pass that hears the start differently (or comes back shorter)
22
+ * cannot shrink or rewrite them. The tail is whatever this pass has past the
23
+ * committed count.
24
+ */
25
+ export function updateLocalAgreement(state, text) {
26
+ const words = splitWords(text);
27
+ const agreedN = Math.max(state.committedN, commonPrefixLength(state.prevWords, words));
28
+ if (agreedN > state.committedN) {
29
+ state.committedWords.push(...words.slice(state.committedN, agreedN));
30
+ state.committedN = state.committedWords.length;
31
+ }
32
+ state.prevWords = words;
33
+ return {
34
+ words,
35
+ committed: state.committedWords.join(" "),
36
+ tail: words.slice(state.committedN).join(" "),
37
+ };
38
+ }
39
+ /** Forgets everything, e.g. when another engine takes the utterance over. */
40
+ export function resetLocalAgreement(state) {
41
+ state.prevWords = [];
42
+ state.committedWords = [];
43
+ state.committedN = 0;
44
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The credentials slice that makes `STTProcessor.resolveHandler` build the
3
+ * provider's handler from the environment as it is NOW, rather than reuse a
4
+ * registry instance built when the process started. The OpenAI-compatible
5
+ * handler additionally honours `OPENAI_BASE_URL`, which file transcription
6
+ * (audio attachments, video audio tracks) has always followed — a gateway
7
+ * that fronts both chat and `/audio/transcriptions`; `OPENAI_STT_BASE_URL`
8
+ * still wins over it. Shared by AudioProcessor and VideoProcessor so the two
9
+ * can never resolve different endpoints.
10
+ */
11
+ import type { STTCredentials } from "../types/index.js";
12
+ export declare function freshEnvSTTCredentials(credentialsKey: keyof STTCredentials): STTCredentials;
@@ -0,0 +1,12 @@
1
+ export function freshEnvSTTCredentials(credentialsKey) {
2
+ const credentials = {};
3
+ if (credentialsKey === "whisper") {
4
+ const baseURL = process.env.OPENAI_STT_BASE_URL?.trim() ||
5
+ process.env.OPENAI_BASE_URL?.trim();
6
+ credentials.whisper = baseURL ? { baseURL } : {};
7
+ }
8
+ else if (credentialsKey !== "endpoints") {
9
+ credentials[credentialsKey] = {};
10
+ }
11
+ return credentials;
12
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Batch transcription orchestration behind `neurolink.transcribe()`:
3
+ *
4
+ * load audio → resolve provider → transcribe (+ second opinion in parallel)
5
+ * → fallback → correction → TranscribeResult
6
+ *
7
+ * Everything that touches the SDK (handlers, credentials, `tryDecide`, the
8
+ * rewrite model) arrives through `TranscribeDeps`, so this module stays free
9
+ * of provider plumbing. Nothing here may lose words: a failed second opinion
10
+ * or fallback keeps the primary text, and a correction that comes back empty
11
+ * keeps the engine text.
12
+ *
13
+ * @module voice/transcribe
14
+ */
15
+ import type { STTOptions, TranscribeAudioInput, TranscribeDeps, TranscribeOptions, TranscribeResult, TTSAudioFormat } from "../types/index.js";
16
+ /** The container a path or URL names by its extension, if it is a known one. */
17
+ export declare function audioFormatFromName(name: string): TTSAudioFormat | undefined;
18
+ /**
19
+ * The container a buffer's leading bytes identify: WAV, MP3 and Ogg via the
20
+ * shared detector, plus FLAC, WebM/Matroska and ISO-BMFF (m4a/mp4).
21
+ */
22
+ export declare function audioFormatFromBytes(buffer: Buffer): TTSAudioFormat | undefined;
23
+ /**
24
+ * Read a batch audio input into a Buffer: bytes as they are, a local path or
25
+ * `file://` URL from disk, an `http(s)://` URL over the network. A format
26
+ * implied by the path or URL is returned alongside.
27
+ *
28
+ * @throws STTError when the input is a frame stream, or cannot be read
29
+ */
30
+ export declare function loadTranscribeAudio(input: TranscribeAudioInput, timeoutMs?: number): Promise<{
31
+ buffer: Buffer;
32
+ formatHint?: TTSAudioFormat;
33
+ }>;
34
+ /**
35
+ * The handler options for one engine. Fields only the orchestration reads
36
+ * (dictionary, correction, fallback, streaming, credentials) are dropped;
37
+ * the correction context rides along in the prompt for engines that take one.
38
+ */
39
+ export declare function buildEngineOptions(options: Omit<TranscribeOptions, "audio">, format: TTSAudioFormat | undefined, model: string | undefined): STTOptions;
40
+ /**
41
+ * Transcribe one recording with every configured layer. See the module
42
+ * comment for the order of operations.
43
+ *
44
+ * @throws STTError when the audio cannot be loaded, the provider is unknown,
45
+ * or the primary engine fails with no fallback that covers errors
46
+ */
47
+ export declare function runTranscribe(options: TranscribeOptions, deps: TranscribeDeps): Promise<TranscribeResult>;