@juspay/neurolink 13.7.0 → 13.8.1

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 (84) hide show
  1. package/CHANGELOG.md +3 -6
  2. package/dist/browser/neurolink.min.js +480 -460
  3. package/dist/cli/commands/serve.js +11 -1
  4. package/dist/cli/commands/transcribe.js +39 -3
  5. package/dist/constants/langfuse.d.ts +2 -0
  6. package/dist/constants/langfuse.js +2 -0
  7. package/dist/factories/sttDescriptors.js +7 -0
  8. package/dist/index.d.ts +3 -2
  9. package/dist/index.js +4 -2
  10. package/dist/mcp/externalServerManager.js +4 -1
  11. package/dist/mcp/mcpClientFactory.d.ts +6 -0
  12. package/dist/mcp/mcpClientFactory.js +44 -0
  13. package/dist/neurolink.js +42 -3
  14. package/dist/observability/exporters/langfuseExporter.d.ts +4 -0
  15. package/dist/observability/exporters/langfuseExporter.js +29 -8
  16. package/dist/observability/otlpEncoding.js +2 -2
  17. package/dist/server/abstract/baseServerAdapter.js +2 -0
  18. package/dist/server/adapters/expressAdapter.js +1 -1
  19. package/dist/server/adapters/fastifyAdapter.js +4 -1
  20. package/dist/server/adapters/honoAdapter.js +1 -1
  21. package/dist/server/adapters/koaAdapter.js +1 -1
  22. package/dist/server/routes/transcribeRoutes.d.ts +0 -8
  23. package/dist/server/routes/transcribeRoutes.js +130 -3
  24. package/dist/server/utils/validation.d.ts +409 -15
  25. package/dist/server/utils/validation.js +106 -4
  26. package/dist/server/websocket/frameQueue.d.ts +16 -0
  27. package/dist/server/websocket/frameQueue.js +55 -0
  28. package/dist/server/websocket/realtimeTranscription.d.ts +48 -0
  29. package/dist/server/websocket/realtimeTranscription.js +603 -0
  30. package/dist/server/websocket/transcribeWebSocket.d.ts +17 -1
  31. package/dist/server/websocket/transcribeWebSocket.js +263 -64
  32. package/dist/services/server/ai/observability/langfuseSetup.js +6 -1
  33. package/dist/types/cli.d.ts +6 -0
  34. package/dist/types/exporter.d.ts +3 -1
  35. package/dist/types/server.d.ts +304 -2
  36. package/dist/types/stt.d.ts +38 -3
  37. package/dist/types/transcribe.d.ts +401 -5
  38. package/dist/voice/audioLevel.d.ts +14 -0
  39. package/dist/voice/audioLevel.js +60 -0
  40. package/dist/voice/codeMix.d.ts +40 -0
  41. package/dist/voice/codeMix.js +282 -0
  42. package/dist/voice/correction/align.d.ts +12 -0
  43. package/dist/voice/correction/align.js +48 -0
  44. package/dist/voice/correction/guards.d.ts +39 -0
  45. package/dist/voice/correction/guards.js +122 -0
  46. package/dist/voice/correction/index.d.ts +25 -3
  47. package/dist/voice/correction/index.js +132 -4
  48. package/dist/voice/correction/rewrite.d.ts +64 -3
  49. package/dist/voice/correction/rewrite.js +295 -25
  50. package/dist/voice/eval/sttEvalLangfuse.d.ts +14 -0
  51. package/dist/voice/eval/sttEvalLangfuse.js +182 -0
  52. package/dist/voice/eval/sttEvalStore.d.ts +27 -0
  53. package/dist/voice/eval/sttEvalStore.js +397 -0
  54. package/dist/voice/index.js +3 -0
  55. package/dist/voice/languages.d.ts +34 -0
  56. package/dist/voice/languages.js +290 -0
  57. package/dist/voice/modelAssets.d.ts +28 -0
  58. package/dist/voice/modelAssets.js +113 -0
  59. package/dist/voice/output/render.d.ts +32 -0
  60. package/dist/voice/output/render.js +368 -0
  61. package/dist/voice/providers/OpenAISTT.d.ts +11 -1
  62. package/dist/voice/providers/OpenAISTT.js +57 -6
  63. package/dist/voice/session/transcriptionSession.d.ts +55 -0
  64. package/dist/voice/session/transcriptionSession.js +225 -0
  65. package/dist/voice/streaming/chunkedStreamAdapter.d.ts +7 -0
  66. package/dist/voice/streaming/chunkedStreamAdapter.js +711 -28
  67. package/dist/voice/streaming/endpointer.d.ts +50 -17
  68. package/dist/voice/streaming/endpointer.js +115 -19
  69. package/dist/voice/transcribe.d.ts +18 -1
  70. package/dist/voice/transcribe.js +459 -18
  71. package/dist/voice/transcribeStream.d.ts +18 -1
  72. package/dist/voice/transcribeStream.js +413 -16
  73. package/dist/voice/vad/assets.d.ts +36 -0
  74. package/dist/voice/vad/assets.js +142 -0
  75. package/dist/voice/vad/frameScorer.d.ts +28 -0
  76. package/dist/voice/vad/frameScorer.js +90 -0
  77. package/dist/voice/vad/sileroVad.d.ts +43 -0
  78. package/dist/voice/vad/sileroVad.js +178 -0
  79. package/dist/voice/whistle/assets.d.ts +3 -4
  80. package/dist/voice/whistle/assets.js +11 -95
  81. package/docs-site/static/search-index.json +21 -6
  82. package/models/silero-vad/README.md +19 -0
  83. package/models/silero-vad/silero_vad.onnx +0 -0
  84. package/package.json +3 -1
@@ -9,7 +9,7 @@ import type { JsonObject, JsonValue } from "./common.js";
9
9
  import type { ExternalMCPServerStatus } from "./externalMcp.js";
10
10
  import type { ProxyRuntimeConfigProvider } from "./proxy.js";
11
11
  import type { TTSAudioFormat } from "./tts.js";
12
- import type { STTCorrectionOptions, STTDictionaryEntry, STTFallbackOptions, STTDecisionRecord, STTEngineInfo, STTStreamingOptions, TranscribeTimings } from "./transcribe.js";
12
+ import type { STTCorrectionOptions, STTDecisionRecord, STTDictionaryEntry, STTEngineInfo, STTFallbackOptions, STTOutputOptions, STTOutputRendering, STTRoutingOptions, STTStreamingOptions, TranscribeTimings } from "./transcribe.js";
13
13
  /**
14
14
  * Server adapter configuration
15
15
  */
@@ -124,10 +124,18 @@ export type RequiredRateLimitConfig = {
124
124
  export type BodyParserConfig = {
125
125
  /** Enable body parsing (default: true) */
126
126
  enabled?: boolean;
127
- /** Maximum body size (default: "10mb") */
127
+ /** Maximum body size for parsed bodies (default: "10mb") */
128
128
  maxSize?: string;
129
129
  /** JSON body limit (default: "10mb") */
130
130
  jsonLimit?: string;
131
+ /**
132
+ * Maximum size of a raw upload: `multipart/form-data`, `audio/*` and
133
+ * `application/octet-stream` bodies, which reach a route as bytes
134
+ * (the transcription routes). Default: `maxSize` when set, else "64mb";
135
+ * the transcription routes apply their own `maxAudioBytes` (50 MB)
136
+ * beneath it.
137
+ */
138
+ rawMaxSize?: string;
131
139
  /** Enable URL-encoded body parsing */
132
140
  urlEncoded?: boolean;
133
141
  };
@@ -138,6 +146,7 @@ export type RequiredBodyParserConfig = {
138
146
  enabled: boolean;
139
147
  maxSize: string;
140
148
  jsonLimit: string;
149
+ rawMaxSize: string;
141
150
  urlEncoded: boolean;
142
151
  };
143
152
  /**
@@ -1170,6 +1179,37 @@ export type CreateRoutesOptions = {
1170
1179
  agent?: ServerAgentRouteOptions;
1171
1180
  };
1172
1181
  /** Options for `createTranscribeRoutes()`. */
1182
+ /**
1183
+ * What `GET /agent/transcribe/providers` reports: the engines this server
1184
+ * can transcribe with, which one a request without a provider gets, and the
1185
+ * models behind the correction layer. Never a key or a URL with a secret.
1186
+ */
1187
+ export type ServerTranscribeCapabilities = {
1188
+ /** The provider a request without one goes to. */
1189
+ default: string;
1190
+ providers: Array<{
1191
+ name: string;
1192
+ /** `builtin` ships with NeuroLink, `endpoint` comes from `NEUROLINK_STT_ENDPOINTS`, `registered` was added at runtime. */
1193
+ kind: "builtin" | "endpoint" | "registered";
1194
+ model?: string;
1195
+ /** The endpoint can answer a language verdict without transcribing (batch probe). */
1196
+ languageProbe?: boolean;
1197
+ /** The endpoint takes a language prior between utterances. */
1198
+ languagePrior?: boolean;
1199
+ }>;
1200
+ correction: {
1201
+ /** The decision model that judges dictionary candidates; `null` when none is configured (the dictionary is then applied as is). */
1202
+ decision: {
1203
+ provider: string;
1204
+ model: string;
1205
+ } | null;
1206
+ /** The text model of the rewrite; `provider` is `null` when the instance default applies. */
1207
+ rewrite: {
1208
+ provider: string | null;
1209
+ model: string | null;
1210
+ };
1211
+ };
1212
+ };
1173
1213
  export type ServerTranscribeRouteOptions = {
1174
1214
  /**
1175
1215
  * Directories a request's `audioPath` may point into. Empty or omitted (the
@@ -1185,6 +1225,165 @@ export type ServerTranscribeRouteOptions = {
1185
1225
  * `http://host:port/v1` works unchanged.
1186
1226
  */
1187
1227
  openaiBasePath?: string;
1228
+ /**
1229
+ * The STT evaluation collector, `POST <openaiBasePath>/v1/evals/stt`.
1230
+ * On by default; `false` removes its routes.
1231
+ */
1232
+ evals?: ServerSTTEvalOptions | false;
1233
+ };
1234
+ /** Where and how much the STT evaluation collector keeps. */
1235
+ export type ServerSTTEvalOptions = {
1236
+ /**
1237
+ * Directory for one JSON-lines file per call, replayed on start. Default
1238
+ * `NEUROLINK_STT_EVAL_DIR`; without either, calls live in memory only.
1239
+ */
1240
+ dir?: string;
1241
+ /** Calls held in memory; the least recently updated are evicted (still on disk). Default 1000. */
1242
+ maxCalls?: number;
1243
+ /** Segments kept per call; later new ids are counted as `ignored`. Default 50,000. */
1244
+ maxSegmentsPerCall?: number;
1245
+ };
1246
+ /** One finalized transcript segment, from the STT people saw or the one run alongside it. */
1247
+ export type ServerSTTEvalSegment = {
1248
+ /** Stable per segment: a resend with the same id replaces it. */
1249
+ id: string;
1250
+ /** `primary` = shown to users, `shadow` = run for evaluation only. */
1251
+ source: "primary" | "shadow";
1252
+ model: string;
1253
+ participant_identity: string;
1254
+ participant_name?: string;
1255
+ text: string;
1256
+ language?: string | null;
1257
+ /** Epoch seconds, when the STT reports timings. */
1258
+ start_time?: number | null;
1259
+ end_time?: number | null;
1260
+ /** Epoch seconds the sender received the final. */
1261
+ received_at: number;
1262
+ };
1263
+ /** Body of `POST /v1/evals/stt`: one batch of a call's segments. */
1264
+ export type ServerSTTEvalBatchRequest = {
1265
+ call_id: string;
1266
+ room?: string;
1267
+ /** 1, 2, … per call. Numbers may skip when a send failed and was folded into the next. */
1268
+ batch: number;
1269
+ /** True on the batch sent after the last participant left. */
1270
+ final?: boolean;
1271
+ models: {
1272
+ primary: string;
1273
+ shadow: string;
1274
+ };
1275
+ segments: ServerSTTEvalSegment[];
1276
+ };
1277
+ /** Answer to `POST /v1/evals/stt`. */
1278
+ export type ServerSTTEvalBatchResponse = {
1279
+ call_id: string;
1280
+ batch: number;
1281
+ final: boolean;
1282
+ /** New segment ids. */
1283
+ inserted: number;
1284
+ /** Ids already held (a resend), replaced. */
1285
+ updated: number;
1286
+ /** New ids refused because the call is at `maxSegmentsPerCall`. */
1287
+ ignored: number;
1288
+ segments: {
1289
+ primary: number;
1290
+ shadow: number;
1291
+ };
1292
+ };
1293
+ /** One call in `GET /v1/evals/stt`. */
1294
+ export type ServerSTTEvalCallSummary = {
1295
+ call_id: string;
1296
+ room: string | null;
1297
+ models: {
1298
+ primary: string;
1299
+ shadow: string;
1300
+ };
1301
+ final: boolean;
1302
+ batches: number;
1303
+ segments: {
1304
+ primary: number;
1305
+ shadow: number;
1306
+ };
1307
+ speakers: number;
1308
+ first_received_at: number | null;
1309
+ last_received_at: number | null;
1310
+ /** Epoch ms this server last accepted a batch. */
1311
+ updated_at: number;
1312
+ };
1313
+ /** One STT's side of a speaker's comparison. */
1314
+ export type ServerSTTEvalSide = {
1315
+ model: string;
1316
+ segments: number;
1317
+ words: number;
1318
+ /** Languages the STT reported, most frequent first. */
1319
+ languages: string[];
1320
+ /** Mean seconds from the end of speech to the final, when the STT reports timings. */
1321
+ mean_latency_s: number | null;
1322
+ };
1323
+ /**
1324
+ * Agreement between the two STTs for one speaker. Neither side is ground
1325
+ * truth: `disagreement` is the word edit distance between them divided by the
1326
+ * primary's word count, so 0 means both wrote the same words.
1327
+ */
1328
+ export type ServerSTTEvalComparison = {
1329
+ participant_identity: string;
1330
+ participant_name: string;
1331
+ primary: ServerSTTEvalSide;
1332
+ shadow: ServerSTTEvalSide;
1333
+ /** Word edit distance / primary words, on normalized text. Null when the primary wrote nothing. */
1334
+ disagreement: number | null;
1335
+ /** The same on phonetic word keys, so one STT writing Devanagari and the other Latin is not counted as a difference. */
1336
+ phonetic_disagreement: number | null;
1337
+ /** `full` aligns the whole speaker; `windowed` aligns 5-minute windows of a long speaker. */
1338
+ method: "full" | "windowed";
1339
+ };
1340
+ /**
1341
+ * Where the STT evaluation collector exports to Langfuse. Read only from the
1342
+ * server's environment (`NEUROLINK_STT_EVAL_LANGFUSE_*`): neither a request
1343
+ * nor a route option can redirect evaluation data.
1344
+ */
1345
+ export type ServerSTTEvalLangfuseConfig = {
1346
+ publicKey: string;
1347
+ secretKey: string;
1348
+ /** Default `https://cloud.langfuse.com`. */
1349
+ baseUrl: string;
1350
+ environment?: string;
1351
+ };
1352
+ /** One event of Langfuse's public ingestion API (`POST /api/public/ingestion`). */
1353
+ export type ServerSTTEvalLangfuseEvent = {
1354
+ id: string;
1355
+ timestamp: string;
1356
+ type: "trace-create" | "event-create" | "score-create";
1357
+ body: Record<string, unknown>;
1358
+ };
1359
+ /** A call as the evaluation store holds it in memory. */
1360
+ export type ServerSTTEvalCallRecord = {
1361
+ callId: string;
1362
+ room: string | null;
1363
+ models: {
1364
+ primary: string;
1365
+ shadow: string;
1366
+ };
1367
+ final: boolean;
1368
+ batches: Set<number>;
1369
+ segments: Map<string, ServerSTTEvalSegment>;
1370
+ updatedAt: number;
1371
+ };
1372
+ /** Word edit distance between two readings, and the reference's word count. */
1373
+ export type ServerSTTEvalAlignment = {
1374
+ distance: number;
1375
+ refWords: number;
1376
+ };
1377
+ /** `GET /v1/evals/stt/:callId`. */
1378
+ export type ServerSTTEvalReport = ServerSTTEvalCallSummary & {
1379
+ /** Over every speaker: summed edit distances / summed primary words. */
1380
+ overall: {
1381
+ disagreement: number | null;
1382
+ phonetic_disagreement: number | null;
1383
+ };
1384
+ speakers_compared: ServerSTTEvalComparison[];
1385
+ /** Present with `?segments=true`, ordered by time. */
1386
+ segment_list?: ServerSTTEvalSegment[];
1188
1387
  };
1189
1388
  /**
1190
1389
  * Body of `POST <basePath>/agent/transcribe`. Exactly one of `audio`,
@@ -1206,6 +1405,13 @@ export type ServerTranscribeRequest = {
1206
1405
  dictionary?: STTDictionaryEntry[];
1207
1406
  correction?: STTCorrectionOptions;
1208
1407
  fallback?: STTFallbackOptions;
1408
+ routing?: STTRoutingOptions;
1409
+ /** `"utterances"` runs the recording through the live pipeline (see `TranscribeOptions.chunking`). */
1410
+ chunking?: "engine" | "utterances";
1411
+ /** Renderings in other languages and scripts (see `TranscribeOptions.output`). */
1412
+ output?: Omit<STTOutputOptions, "languages"> & {
1413
+ languages: string[];
1414
+ };
1209
1415
  diarization?: boolean;
1210
1416
  wordTimestamps?: boolean;
1211
1417
  timeoutMs?: number;
@@ -1251,6 +1457,8 @@ export type ServerOpenAITranscriptionResponse = {
1251
1457
  language_detected?: boolean;
1252
1458
  steps: string[];
1253
1459
  timings: TranscribeTimings;
1460
+ /** NeuroLink extension: one rendering per requested output language. */
1461
+ outputs?: Record<string, STTOutputRendering>;
1254
1462
  };
1255
1463
  /** Options for `attachTranscribeWebSocket()`. */
1256
1464
  export type ServerTranscribeWebSocketOptions = {
@@ -1273,6 +1481,100 @@ export type ServerTranscribeWebSocketOptions = {
1273
1481
  allowedOrigins?: readonly string[];
1274
1482
  /** Largest single frame, in bytes. Default 1 MiB. */
1275
1483
  maxPayload?: number;
1484
+ /**
1485
+ * Listener path of transcription sessions: a socket here reads one
1486
+ * session's speakers in its own languages. Default `<path>/subscribe`;
1487
+ * `false` turns sessions off (a `?session=` on the stream path is then
1488
+ * ignored).
1489
+ */
1490
+ subscribePath?: string | false;
1491
+ /**
1492
+ * OpenAI Realtime transcription path (`?intent=transcription`): the
1493
+ * protocol of OpenAI's `/v1/realtime`, so any OpenAI-Realtime client — the
1494
+ * LiveKit `openai.STT(use_realtime=True)` plugin, Pipecat, the OpenAI SDK —
1495
+ * streams to NeuroLink with no adapter. Default `/v1/realtime`; `false`
1496
+ * turns it off.
1497
+ */
1498
+ realtimePath?: string | false;
1499
+ /**
1500
+ * Profiles a realtime client selects with its `model` name. Merged over
1501
+ * `NEUROLINK_STT_REALTIME_PROFILES` (a JSON object of the same shape);
1502
+ * these win on a name in both.
1503
+ */
1504
+ realtimeProfiles?: Readonly<Record<string, ServerSTTRealtimeProfile>>;
1505
+ };
1506
+ /**
1507
+ * What an OpenAI-Realtime client gets when it names this profile as its
1508
+ * `model`. A realtime client can send only a model, a language, a prompt and
1509
+ * turn-detection numbers, so everything NeuroLink-specific (engine, fallback,
1510
+ * dictionary, correction, output languages) is the operator's, here.
1511
+ *
1512
+ * A `model` that is no profile but a configured STT provider uses that
1513
+ * provider with the defaults; any other name (OpenAI's own
1514
+ * `gpt-4o-mini-transcribe`, say) uses the profile named `default`, or the
1515
+ * server's defaults when there is none.
1516
+ */
1517
+ export type ServerSTTRealtimeProfile = Omit<ServerTranscribeStreamConfig, "mode"> & {
1518
+ /**
1519
+ * What `…input_audio_transcription.completed` carries: the corrected text
1520
+ * (`"corrected"`, default; it waits up to `correctionWaitMs` for the
1521
+ * correction, then sends the raw final) or the raw final at once.
1522
+ */
1523
+ completed?: "corrected" | "final";
1524
+ /** Longest wait for the correction before `completed` goes out with the final. Default 3000. */
1525
+ correctionWaitMs?: number;
1526
+ /**
1527
+ * Whether the client's `language` pins the transcription. Default `true`.
1528
+ * Note the LiveKit plugin sends `"en"` unless `detect_language=True`.
1529
+ */
1530
+ clientLanguage?: boolean;
1531
+ /**
1532
+ * Whether the client's `turn_detection.silence_duration_ms` sets the
1533
+ * utterance's closing pause. Default `false`: NeuroLink's endpointer keeps
1534
+ * its own (750 ms), since a client default such as LiveKit's 350 ms cuts
1535
+ * conversational speech mid-sentence.
1536
+ */
1537
+ clientTurnDetection?: boolean;
1538
+ };
1539
+ /** The parts of a `ws` socket the realtime handler uses. */
1540
+ export type ServerRealtimeSocket = {
1541
+ readonly readyState: number;
1542
+ send(data: string): void;
1543
+ close(code?: number, reason?: string): void;
1544
+ on(event: "message", listener: (data: Buffer | ArrayBuffer | Buffer[], isBinary: boolean) => void): unknown;
1545
+ on(event: "close" | "error", listener: () => void): unknown;
1546
+ };
1547
+ /** What a realtime client configured, read from either session dialect. */
1548
+ export type ServerRealtimeSessionConfig = {
1549
+ dialect: "ga" | "beta";
1550
+ rate: number;
1551
+ model?: string;
1552
+ language?: string;
1553
+ prompt?: string;
1554
+ silenceMs?: number;
1555
+ };
1556
+ /** One utterance on the realtime wire: a conversation item. */
1557
+ export type ServerRealtimeItem = {
1558
+ utterance: number;
1559
+ itemId: string;
1560
+ /** `speech_started` went out. */
1561
+ started: boolean;
1562
+ /** The committed prefix already sent as deltas. */
1563
+ sent: string;
1564
+ /** Server events held until every earlier item has completed. */
1565
+ pending: Array<{
1566
+ type: string;
1567
+ body: Record<string, unknown>;
1568
+ }>;
1569
+ finalText?: string;
1570
+ engine?: string;
1571
+ language?: string;
1572
+ languageDetected?: boolean;
1573
+ corrected: boolean;
1574
+ /** The transcript `completed` will carry, once known. */
1575
+ ready?: string;
1576
+ done: boolean;
1577
+ timer?: ReturnType<typeof setTimeout>;
1276
1578
  };
1277
1579
  /** Data stream finish event. */
1278
1580
  export type FinishEvent = DataStreamEvent & {
@@ -45,6 +45,13 @@ export type STTOptions = {
45
45
  * `vocabulary` terms are appended by the handlers that accept a prompt.
46
46
  */
47
47
  prompt?: string;
48
+ /**
49
+ * The language a previous utterance was confidently detected as. Engines
50
+ * that take a prior (the IndicConformer wrapper, through its
51
+ * `priorLanguageForm`) keep it unless the audio clearly says otherwise;
52
+ * every other engine ignores it. Only sent when no `language` is pinned.
53
+ */
54
+ languagePrior?: string;
48
55
  /** Per-request timeout in milliseconds, for handlers that honour one. */
49
56
  timeoutMs?: number;
50
57
  /** Minimum confidence threshold */
@@ -97,6 +104,12 @@ export type STTResult = {
97
104
  provider?: string;
98
105
  /** Model used */
99
106
  model?: string;
107
+ /** Set by the output guards: what the engine produced was not speech. */
108
+ hallucination?: "prompt-echo";
109
+ /** Share of the words a collapsed decoding loop had taken (0 when none). */
110
+ loopShare?: number;
111
+ /** Set by language routing: the provider whose text this is, when not the pass's own engine. */
112
+ routedProvider?: string;
100
113
  /** What `confidence` was derived from, for providers that must choose. */
101
114
  confidenceSource?: STTConfidenceSource;
102
115
  /** Additional provider-specific metadata */
@@ -175,6 +188,13 @@ export type STTHandler = {
175
188
  * what to do rather than "set the required API keys".
176
189
  */
177
190
  describeConfiguration?(): string;
191
+ /**
192
+ * The model name that runs this engine in language-identification-only
193
+ * mode (no transcript, just the language verdict and scores, in a fraction
194
+ * of the time), when the server has one. The batch path probes with it
195
+ * before deciding which engine transcribes.
196
+ */
197
+ languageProbeModel?(): string | undefined;
178
198
  maxAudioDuration?: number;
179
199
  supportsStreaming?: boolean;
180
200
  };
@@ -460,6 +480,17 @@ export type WhisperTranscriptionSegment = {
460
480
  * segment with a speaker; the handler surfaces it as `TranscriptionSegment.speaker`.
461
481
  */
462
482
  speaker?: string;
483
+ /**
484
+ * Extension, same meaning as the response-level fields: a gateway that
485
+ * normalises the top level of `verbose_json` to OpenAI's schema (LiteLLM
486
+ * does) keeps unknown keys inside segments, so a server may repeat its
487
+ * language-detection verdict here and it survives the hop.
488
+ */
489
+ language_detected?: boolean;
490
+ language_scores?: Array<{
491
+ language: string;
492
+ score: number;
493
+ }>;
463
494
  };
464
495
  export type WhisperVerboseResponse = {
465
496
  task: string;
@@ -692,14 +723,18 @@ export type GeminiResponse = {
692
723
  };
693
724
  /** The three files the built-in Whistle engine needs on disk. */
694
725
  export type WhistleAssetName = "needle.js" | "needle.wasm" | "whistle.cact";
695
- /** One pinned Whistle asset: where it comes from and what it must hash to. */
696
- export type WhistleAsset = {
697
- name: WhistleAssetName;
726
+ /** One pinned model file NeuroLink ships or fetches on first use: where it comes from and what it must hash to. */
727
+ export type LocalModelAsset = {
728
+ name: string;
698
729
  url: string;
699
730
  sha256: string;
700
731
  /** Exact size in bytes, used for the download notice and a cheap pre-check. */
701
732
  bytes: number;
702
733
  };
734
+ /** One pinned Whistle asset. */
735
+ export type WhistleAsset = LocalModelAsset & {
736
+ name: WhistleAssetName;
737
+ };
703
738
  /** Absolute paths of the three Whistle files once they are present and verified. */
704
739
  export type WhistleAssetPaths = Record<WhistleAssetName, string>;
705
740
  /** One word as the Whistle engine reports it (seconds from the start of the audio). */