assemblyai 4.34.6 → 4.35.3
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/CHANGELOG.md +16 -0
- package/README.md +7 -8
- package/dist/assemblyai.streaming.umd.js +150 -10
- package/dist/assemblyai.streaming.umd.min.js +1 -1
- package/dist/assemblyai.umd.js +150 -10
- package/dist/assemblyai.umd.min.js +1 -1
- package/dist/browser.mjs +148 -12
- package/dist/bun.mjs +148 -12
- package/dist/deno.mjs +148 -12
- package/dist/exports/streaming.d.ts +1 -1
- package/dist/index.cjs +150 -10
- package/dist/index.mjs +150 -10
- package/dist/node.cjs +148 -12
- package/dist/node.mjs +148 -12
- package/dist/services/streaming/service.d.ts +22 -0
- package/dist/streaming.browser.mjs +148 -12
- package/dist/streaming.cjs +149 -9
- package/dist/streaming.mjs +149 -9
- package/dist/types/asyncapi.generated.d.ts +1 -1
- package/dist/types/streaming/index.d.ts +38 -1
- package/dist/workerd.mjs +148 -12
- package/package.json +1 -1
- package/src/exports/streaming.ts +1 -1
- package/src/services/streaming/service.ts +177 -11
- package/src/types/asyncapi.generated.ts +1 -1
- package/src/types/streaming/index.ts +39 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [4.35.3]
|
|
4
|
+
|
|
5
|
+
- Allow `language_codes` in `updateConfiguration()` — re-steer the transcription language mid-stream without reconnecting; pass `[]` to clear steering and restore the model's default multilingual code-switching (Universal-3.5 Pro Streaming only)
|
|
6
|
+
|
|
7
|
+
## [4.35.2]
|
|
8
|
+
|
|
9
|
+
- Add `opus` and `ogg_opus` streaming `encoding` values — accepts compressed Opus audio (raw packet-per-message or Ogg-encapsulated). `sampleRate` is ignored for both; the Opus stream is self-describing
|
|
10
|
+
|
|
11
|
+
## [4.35.1]
|
|
12
|
+
|
|
13
|
+
- Add `languageCodes` streaming parameter — steers transcription toward a set of languages (Universal-3.5 Pro Streaming only). Recommended replacement for `languageCode`, which is now deprecated but still supported
|
|
14
|
+
|
|
15
|
+
## [4.34.6]
|
|
16
|
+
|
|
17
|
+
- Add `keepAlive()` method to `StreamingTranscriber` — sends a `KeepAlive` message to reset the server's inactivity timer when `inactivityTimeout` is configured
|
|
18
|
+
|
|
3
19
|
## [4.33.0]
|
|
4
20
|
|
|
5
21
|
- Add streaming parameters to match the Python SDK:
|
package/README.md
CHANGED
|
@@ -129,7 +129,7 @@ const audioFile = "https://assembly.ai/sports_injuries.mp3";
|
|
|
129
129
|
|
|
130
130
|
const params = {
|
|
131
131
|
audio: audioFile,
|
|
132
|
-
speech_models: ["universal-3-pro", "universal-2"],
|
|
132
|
+
speech_models: ["universal-3-5-pro", "universal-2"],
|
|
133
133
|
language_detection: true,
|
|
134
134
|
};
|
|
135
135
|
|
|
@@ -151,7 +151,7 @@ If you don't want to wait until the transcript is ready, you can use `submit`:
|
|
|
151
151
|
```js
|
|
152
152
|
let transcript = await client.transcripts.submit({
|
|
153
153
|
audio: "https://assembly.ai/espn.m4a",
|
|
154
|
-
speech_models: ["universal-3-pro", "universal-2"],
|
|
154
|
+
speech_models: ["universal-3-5-pro", "universal-2"],
|
|
155
155
|
language_detection: true,
|
|
156
156
|
});
|
|
157
157
|
```
|
|
@@ -167,7 +167,7 @@ When you create a transcript, you can either pass in a URL to an audio file or u
|
|
|
167
167
|
// Upload a file via local path and transcribe
|
|
168
168
|
let transcript = await client.transcripts.transcribe({
|
|
169
169
|
audio: "./news.mp4",
|
|
170
|
-
speech_models: ["universal-3-pro", "universal-2"],
|
|
170
|
+
speech_models: ["universal-3-5-pro", "universal-2"],
|
|
171
171
|
language_detection: true,
|
|
172
172
|
});
|
|
173
173
|
```
|
|
@@ -182,7 +182,7 @@ If you don't want to wait until the transcript is ready, you can use `submit`:
|
|
|
182
182
|
```js
|
|
183
183
|
let transcript = await client.transcripts.submit({
|
|
184
184
|
audio: "./news.mp4",
|
|
185
|
-
speech_models: ["universal-3-pro", "universal-2"],
|
|
185
|
+
speech_models: ["universal-3-5-pro", "universal-2"],
|
|
186
186
|
language_detection: true,
|
|
187
187
|
});
|
|
188
188
|
```
|
|
@@ -206,7 +206,7 @@ const audioFile = "https://assembly.ai/wildfires.mp3";
|
|
|
206
206
|
|
|
207
207
|
const params = {
|
|
208
208
|
audio: audioFile,
|
|
209
|
-
speech_models: ["universal-3-pro", "universal-2"],
|
|
209
|
+
speech_models: ["universal-3-5-pro", "universal-2"],
|
|
210
210
|
language_detection: true,
|
|
211
211
|
speaker_labels: true,
|
|
212
212
|
};
|
|
@@ -313,15 +313,14 @@ const res = await client.transcripts.delete(transcript.id);
|
|
|
313
313
|
|
|
314
314
|
### Transcribe streaming audio
|
|
315
315
|
|
|
316
|
-
Refer to [AssemblyAI's streaming documentation](https://www.assemblyai.com/docs/getting-started/transcribe-streaming-audio) for full code examples.
|
|
316
|
+
Refer to [AssemblyAI's streaming documentation](https://www.assemblyai.com/docs/streaming/getting-started/transcribe-streaming-audio) for full code examples.
|
|
317
317
|
|
|
318
318
|
Create the streaming transcriber.
|
|
319
319
|
|
|
320
320
|
```typescript
|
|
321
321
|
const transcriber = client.streaming.transcriber({
|
|
322
|
-
speechModel: "
|
|
322
|
+
speechModel: "universal-3-5-pro",
|
|
323
323
|
sampleRate: 16_000,
|
|
324
|
-
formatTurns: true,
|
|
325
324
|
});
|
|
326
325
|
```
|
|
327
326
|
|
|
@@ -592,6 +592,24 @@ Learn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/c
|
|
|
592
592
|
}
|
|
593
593
|
const defaultStreamingUrl = "wss://streaming.assemblyai.com/v3/ws";
|
|
594
594
|
const terminateSessionMessage = `{"type":"Terminate"}`;
|
|
595
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 1000;
|
|
596
|
+
const DEFAULT_MAX_CONNECTION_RETRIES = 2;
|
|
597
|
+
const DEFAULT_CONNECTION_RETRY_DELAY_MS = 500;
|
|
598
|
+
/**
|
|
599
|
+
* Close/error codes that signal a permanent client-side problem (auth,
|
|
600
|
+
* billing, malformed config). A retry would hit the same failure, so the
|
|
601
|
+
* connection is never retried on these.
|
|
602
|
+
*/
|
|
603
|
+
const NON_RETRYABLE_CLOSE_CODES = new Set([
|
|
604
|
+
StreamingErrorType.BadSampleRate,
|
|
605
|
+
StreamingErrorType.AuthFailed,
|
|
606
|
+
StreamingErrorType.InsufficientFunds,
|
|
607
|
+
StreamingErrorType.FreeTierUser,
|
|
608
|
+
StreamingErrorType.BadSchema,
|
|
609
|
+
]);
|
|
610
|
+
function isRetryableCloseCode(code) {
|
|
611
|
+
return code !== 1000 && !NON_RETRYABLE_CLOSE_CODES.has(code);
|
|
612
|
+
}
|
|
595
613
|
/**
|
|
596
614
|
* Per-send chunk cap in milliseconds for the dual-channel mixer. The streaming
|
|
597
615
|
* server rejects audio messages longer than 1000 ms (`Input Duration Error`).
|
|
@@ -723,8 +741,12 @@ Learn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/c
|
|
|
723
741
|
searchParams.set("speech_model", this.params.speechModel.toString());
|
|
724
742
|
}
|
|
725
743
|
if (this.params.languageCode !== undefined) {
|
|
744
|
+
console.warn("[Deprecation Warning] `languageCode` is deprecated and will be removed in a future release. Please use `languageCodes` instead.");
|
|
726
745
|
searchParams.set("language_code", this.params.languageCode);
|
|
727
746
|
}
|
|
747
|
+
if (this.params.languageCodes !== undefined) {
|
|
748
|
+
searchParams.set("language_codes", JSON.stringify(this.params.languageCodes));
|
|
749
|
+
}
|
|
728
750
|
if (this.params.languageDetection !== undefined) {
|
|
729
751
|
searchParams.set("language_detection", this.params.languageDetection.toString());
|
|
730
752
|
}
|
|
@@ -798,12 +820,85 @@ Learn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/c
|
|
|
798
820
|
on(event, listener) {
|
|
799
821
|
this.listeners[event] = listener;
|
|
800
822
|
}
|
|
823
|
+
/**
|
|
824
|
+
* Open the streaming session.
|
|
825
|
+
*
|
|
826
|
+
* Resolves with the server's `Begin` event once the handshake completes. A
|
|
827
|
+
* single attempt is bounded by `connectTimeout` (default 1000ms); transient
|
|
828
|
+
* failures (timeout, network drop, unexpected close) are retried up to
|
|
829
|
+
* `maxConnectionRetries` times (default 2), waiting `connectionRetryDelay`
|
|
830
|
+
* (default 500ms) between attempts. Permanent failures (auth, insufficient
|
|
831
|
+
* funds, malformed config) are not retried.
|
|
832
|
+
*
|
|
833
|
+
* Unlike previously, a failed connection now rejects this promise rather
|
|
834
|
+
* than only invoking the `error` listener — necessary for the caller (and
|
|
835
|
+
* the retry loop) to observe the failure.
|
|
836
|
+
*/
|
|
801
837
|
connect() {
|
|
802
|
-
return
|
|
838
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
839
|
+
var _a, _b;
|
|
803
840
|
if (this.socket) {
|
|
804
841
|
throw new Error("Already connected");
|
|
805
842
|
}
|
|
843
|
+
const maxRetries = (_a = this.params.maxConnectionRetries) !== null && _a !== void 0 ? _a : DEFAULT_MAX_CONNECTION_RETRIES;
|
|
844
|
+
const retryDelay = (_b = this.params.connectionRetryDelay) !== null && _b !== void 0 ? _b : DEFAULT_CONNECTION_RETRY_DELAY_MS;
|
|
845
|
+
let lastError;
|
|
846
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
847
|
+
try {
|
|
848
|
+
return yield this.connectOnce();
|
|
849
|
+
}
|
|
850
|
+
catch (err) {
|
|
851
|
+
lastError = err;
|
|
852
|
+
const retryable = err.retryable === true;
|
|
853
|
+
if (!retryable || attempt === maxRetries) {
|
|
854
|
+
throw err;
|
|
855
|
+
}
|
|
856
|
+
console.warn(`Streaming connect attempt ${attempt + 1}/${maxRetries + 1} failed (${err.message}); retrying`);
|
|
857
|
+
if (retryDelay > 0) {
|
|
858
|
+
yield new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
// The loop above always returns or throws; this only satisfies the type
|
|
863
|
+
// checker that a value is produced on every path.
|
|
864
|
+
throw lastError !== null && lastError !== void 0 ? lastError : new Error("Failed to connect to streaming server");
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
connectOnce() {
|
|
868
|
+
return new Promise((resolve, reject) => {
|
|
869
|
+
var _a;
|
|
806
870
|
const url = this.connectionUrl();
|
|
871
|
+
const timeoutMs = (_a = this.params.connectTimeout) !== null && _a !== void 0 ? _a : DEFAULT_CONNECT_TIMEOUT_MS;
|
|
872
|
+
// `settled` flips once this attempt has resolved (`Begin`) or rejected
|
|
873
|
+
// (timeout / pre-`Begin` close / error). Before it flips the socket
|
|
874
|
+
// handlers drive this promise; after it flips they revert to normal
|
|
875
|
+
// runtime dispatch (close / error / message listeners).
|
|
876
|
+
let settled = false;
|
|
877
|
+
let timer;
|
|
878
|
+
const failAttempt = (error) => {
|
|
879
|
+
if (settled)
|
|
880
|
+
return;
|
|
881
|
+
settled = true;
|
|
882
|
+
if (timer)
|
|
883
|
+
clearTimeout(timer);
|
|
884
|
+
this.discardPendingSocket();
|
|
885
|
+
reject(error);
|
|
886
|
+
};
|
|
887
|
+
const succeed = (begin) => {
|
|
888
|
+
if (settled)
|
|
889
|
+
return;
|
|
890
|
+
settled = true;
|
|
891
|
+
if (timer)
|
|
892
|
+
clearTimeout(timer);
|
|
893
|
+
resolve(begin);
|
|
894
|
+
};
|
|
895
|
+
if (timeoutMs > 0) {
|
|
896
|
+
timer = setTimeout(() => {
|
|
897
|
+
const err = new StreamingError(`Streaming connection timed out after ${timeoutMs}ms`);
|
|
898
|
+
err.retryable = true;
|
|
899
|
+
failAttempt(err);
|
|
900
|
+
}, timeoutMs);
|
|
901
|
+
}
|
|
807
902
|
if (this.token) {
|
|
808
903
|
this.socket = factory(url.toString());
|
|
809
904
|
}
|
|
@@ -825,6 +920,15 @@ Learn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/c
|
|
|
825
920
|
reason = StreamingErrorMessages[code];
|
|
826
921
|
}
|
|
827
922
|
}
|
|
923
|
+
// A close before `Begin` is a failed connection attempt — reject so
|
|
924
|
+
// connect() can retry (or surface a permanent failure).
|
|
925
|
+
if (!settled) {
|
|
926
|
+
const err = new StreamingError(reason || `Streaming connection closed (code=${code})`);
|
|
927
|
+
err.code = code;
|
|
928
|
+
err.retryable = isRetryableCloseCode(code);
|
|
929
|
+
failAttempt(err);
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
828
932
|
// Stop the flush timer when the socket is gone (server-initiated close,
|
|
829
933
|
// network drop, etc.) — otherwise subsequent ticks call send() on a
|
|
830
934
|
// closed socket and spam the error listener.
|
|
@@ -835,11 +939,15 @@ Learn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/c
|
|
|
835
939
|
(_b = (_a = this.listeners).close) === null || _b === void 0 ? void 0 : _b.call(_a, code, reason);
|
|
836
940
|
};
|
|
837
941
|
this.socket.onerror = (event) => {
|
|
838
|
-
var _a, _b, _c
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
942
|
+
var _a, _b, _c;
|
|
943
|
+
const error = (_a = event.error) !== null && _a !== void 0 ? _a : new Error(event.message);
|
|
944
|
+
// A socket error before `Begin` is a failed attempt → reject/retry.
|
|
945
|
+
if (!settled) {
|
|
946
|
+
error.retryable = true;
|
|
947
|
+
failAttempt(error);
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
(_c = (_b = this.listeners).error) === null || _c === void 0 ? void 0 : _c.call(_b, error);
|
|
843
951
|
};
|
|
844
952
|
this.socket.onmessage = ({ data }) => {
|
|
845
953
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
@@ -847,15 +955,23 @@ Learn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/c
|
|
|
847
955
|
if ("error" in message) {
|
|
848
956
|
const err = new StreamingError(message.error);
|
|
849
957
|
if ("error_code" in message) {
|
|
850
|
-
err.code =
|
|
851
|
-
|
|
958
|
+
err.code = message.error_code;
|
|
959
|
+
}
|
|
960
|
+
// A server error frame before `Begin` fails the attempt; the code
|
|
961
|
+
// decides whether a retry is worthwhile.
|
|
962
|
+
if (!settled) {
|
|
963
|
+
const attemptErr = err;
|
|
964
|
+
attemptErr.retryable =
|
|
965
|
+
err.code === undefined ? true : isRetryableCloseCode(err.code);
|
|
966
|
+
failAttempt(attemptErr);
|
|
967
|
+
return;
|
|
852
968
|
}
|
|
853
969
|
(_b = (_a = this.listeners).error) === null || _b === void 0 ? void 0 : _b.call(_a, err);
|
|
854
970
|
return;
|
|
855
971
|
}
|
|
856
972
|
switch (message.type) {
|
|
857
973
|
case "Begin": {
|
|
858
|
-
|
|
974
|
+
succeed(message);
|
|
859
975
|
(_d = (_c = this.listeners).open) === null || _d === void 0 ? void 0 : _d.call(_c, message);
|
|
860
976
|
break;
|
|
861
977
|
}
|
|
@@ -902,6 +1018,20 @@ Learn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/c
|
|
|
902
1018
|
};
|
|
903
1019
|
});
|
|
904
1020
|
}
|
|
1021
|
+
/** Tear down a half-open socket from a failed connection attempt. */
|
|
1022
|
+
discardPendingSocket() {
|
|
1023
|
+
if (!this.socket)
|
|
1024
|
+
return;
|
|
1025
|
+
try {
|
|
1026
|
+
if (this.socket.removeAllListeners)
|
|
1027
|
+
this.socket.removeAllListeners();
|
|
1028
|
+
this.socket.close();
|
|
1029
|
+
}
|
|
1030
|
+
catch (_a) {
|
|
1031
|
+
// Best-effort cleanup; a half-open socket may throw on close.
|
|
1032
|
+
}
|
|
1033
|
+
this.socket = undefined;
|
|
1034
|
+
}
|
|
905
1035
|
/**
|
|
906
1036
|
* Returns a WritableStream that pumps PCM chunks into `sendAudio`. Single-channel
|
|
907
1037
|
* only — in dual-channel mode use `sendAudio(pcm, { channel })` directly, since
|
|
@@ -1175,6 +1305,16 @@ Learn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/c
|
|
|
1175
1305
|
};
|
|
1176
1306
|
this.send(JSON.stringify(message));
|
|
1177
1307
|
}
|
|
1308
|
+
/**
|
|
1309
|
+
* Reset the server's inactivity timer. Only needed when the session was
|
|
1310
|
+
* created with `inactivityTimeout` and no audio is being sent.
|
|
1311
|
+
*/
|
|
1312
|
+
keepAlive() {
|
|
1313
|
+
const message = {
|
|
1314
|
+
type: "KeepAlive",
|
|
1315
|
+
};
|
|
1316
|
+
this.send(JSON.stringify(message));
|
|
1317
|
+
}
|
|
1178
1318
|
send(data) {
|
|
1179
1319
|
if (!this.socket || this.socket.readyState !== this.socket.OPEN) {
|
|
1180
1320
|
throw new Error("Socket is not open for communication");
|
|
@@ -1233,7 +1373,7 @@ Learn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/c
|
|
|
1233
1373
|
defaultUserAgentString += navigator.userAgent;
|
|
1234
1374
|
}
|
|
1235
1375
|
const defaultUserAgent = {
|
|
1236
|
-
sdk: { name: "JavaScript", version: "4.
|
|
1376
|
+
sdk: { name: "JavaScript", version: "4.35.3" },
|
|
1237
1377
|
};
|
|
1238
1378
|
if (typeof process !== "undefined") {
|
|
1239
1379
|
if (process.versions.node && defaultUserAgentString.indexOf("Node") === -1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).assemblyai={})}(this,(function(e){"use strict";class t extends Error{constructor(e="DualChannelCapture requires a browser environment (AudioContext is undefined)."){super(e),this.name="BrowserOnlyError"}}function s(e,t,s,n){return new(s||(s=Promise))((function(i,r){function o(e){try{l(n.next(e))}catch(e){r(e)}}function a(e){try{l(n.throw(e))}catch(e){r(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(o,a)}l((n=n.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const{WritableStream:n}="undefined"!=typeof window?window:"undefined"!=typeof global?global:globalThis;var i,r;const o=null!==(r=null!==(i=null!==WebSocket&&void 0!==WebSocket?WebSocket:null===global||void 0===global?void 0:global.WebSocket)&&void 0!==i?i:null===window||void 0===window?void 0:window.WebSocket)&&void 0!==r?r:null===self||void 0===self?void 0:self.WebSocket,a=(e,t)=>t?new o(e,t):new o(e),l={[4e3]:"Sample rate must be a positive integer",[4001]:"Not Authorized",[4002]:"Insufficient funds",[4003]:"This feature is paid-only and requires you to add a credit card. Please visit https://app.assemblyai.com/ to add a credit card to your account.",[4004]:"Session ID does not exist",[4008]:"Session has expired",[4010]:"Session is closed",[4029]:"Rate limited",[4030]:"Unique session violation",[4031]:"Session Timeout",[4032]:"Audio too short",[4033]:"Audio too long",[4034]:"Audio too small to transcode",[4100]:"Bad JSON",[4101]:"Bad schema",[4102]:"Too many streams",[4103]:"This session has been reconnected. This WebSocket is no longer valid.",[1013]:"Reconnect attempts exhausted",[4104]:"Could not parse word boost parameter"};class h extends Error{}const c={[3005]:"Server error",[3006]:"Input validation error",[3007]:"Audio chunk duration violation",[3008]:"Session expired: maximum session duration exceeded",[3009]:"Too many concurrent sessions",[4e3]:"Sample rate must be a positive integer",[4001]:"Not Authorized",[4002]:"Insufficient funds",[4003]:"This feature is paid-only and requires you to add a credit card. Please visit https://app.assemblyai.com/ to add a credit card to your account.",[4004]:"Session ID does not exist",[4008]:"Session has expired",[4010]:"Session is closed",[4029]:"Rate limited",[4030]:"Unique session violation",[4031]:"Session Timeout",[4032]:"Audio too short",[4033]:"Audio too long",[4034]:"Audio too small to transcode",[4101]:"Bad schema",[4102]:"Too many streams",[4103]:"This session has been reconnected. This WebSocket is no longer valid."};class d extends Error{}const u='{"terminate_session":true}';class m{constructor(e){var t,s;if(this.listeners={},this.realtimeUrl=null!==(t=e.realtimeUrl)&&void 0!==t?t:"wss://api.assemblyai.com/v2/realtime/ws",this.sampleRate=null!==(s=e.sampleRate)&&void 0!==s?s:16e3,this.wordBoost=e.wordBoost,this.encoding=e.encoding,this.endUtteranceSilenceThreshold=e.endUtteranceSilenceThreshold,this.disablePartialTranscripts=e.disablePartialTranscripts,"token"in e&&e.token&&(this.token=e.token),"apiKey"in e&&e.apiKey&&(this.apiKey=e.apiKey),!this.token&&!this.apiKey)throw new Error("API key or temporary token is required.")}connectionUrl(){const e=new URL(this.realtimeUrl);if("wss:"!==e.protocol)throw new Error("Invalid protocol, must be wss");const t=new URLSearchParams;return this.token&&t.set("token",this.token),t.set("sample_rate",this.sampleRate.toString()),this.wordBoost&&this.wordBoost.length>0&&t.set("word_boost",JSON.stringify(this.wordBoost)),this.encoding&&t.set("encoding",this.encoding),t.set("enable_extra_session_information","true"),this.disablePartialTranscripts&&t.set("disable_partial_transcripts",this.disablePartialTranscripts.toString()),e.search=t.toString(),e}on(e,t){this.listeners[e]=t}connect(){return new Promise((e=>{if(this.socket)throw new Error("Already connected");const t=this.connectionUrl();this.token?this.socket=a(t.toString()):(console.warn("API key authentication is not supported for the RealtimeTranscriber in browser environment. Use temporary token authentication instead.\nLearn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/compat.md#browser-compatibility."),this.socket=a(t.toString(),{headers:{Authorization:this.apiKey}})),this.socket.binaryType="arraybuffer",this.socket.onopen=()=>{void 0!==this.endUtteranceSilenceThreshold&&null!==this.endUtteranceSilenceThreshold&&this.configureEndUtteranceSilenceThreshold(this.endUtteranceSilenceThreshold)},this.socket.onclose=({code:e,reason:t})=>{var s,n;t||e in l&&(t=l[e]),null===(n=(s=this.listeners).close)||void 0===n||n.call(s,e,t)},this.socket.onerror=e=>{var t,s,n,i;e.error?null===(s=(t=this.listeners).error)||void 0===s||s.call(t,e.error):null===(i=(n=this.listeners).error)||void 0===i||i.call(n,new Error(e.message))},this.socket.onmessage=({data:t})=>{var s,n,i,r,o,a,l,c,d,u,m,p,f,v,g;const w=JSON.parse(t.toString());if("error"in w)null===(n=(s=this.listeners).error)||void 0===n||n.call(s,new h(w.error));else switch(w.message_type){case"SessionBegins":{const t={sessionId:w.session_id,expiresAt:new Date(w.expires_at)};e(t),null===(r=(i=this.listeners).open)||void 0===r||r.call(i,t);break}case"PartialTranscript":w.created=new Date(w.created),null===(a=(o=this.listeners).transcript)||void 0===a||a.call(o,w),null===(c=(l=this.listeners)["transcript.partial"])||void 0===c||c.call(l,w);break;case"FinalTranscript":w.created=new Date(w.created),null===(u=(d=this.listeners).transcript)||void 0===u||u.call(d,w),null===(p=(m=this.listeners)["transcript.final"])||void 0===p||p.call(m,w);break;case"SessionInformation":null===(v=(f=this.listeners).session_information)||void 0===v||v.call(f,w);break;case"SessionTerminated":null===(g=this.sessionTerminatedResolve)||void 0===g||g.call(this)}}}))}sendAudio(e){this.send(e)}stream(){return new n({write:e=>{this.sendAudio(e)}})}forceEndUtterance(){this.send('{"force_end_utterance":true}')}configureEndUtteranceSilenceThreshold(e){this.send(`{"end_utterance_silence_threshold":${e}}`)}send(e){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("Socket is not open for communication");this.socket.send(e)}close(){return s(this,arguments,void 0,(function*(e=!0){var t;if(this.socket){if(this.socket.readyState===this.socket.OPEN)if(e){const e=new Promise((e=>{this.sessionTerminatedResolve=e}));this.socket.send(u),yield e}else this.socket.send(u);(null===(t=this.socket)||void 0===t?void 0:t.removeAllListeners)&&this.socket.removeAllListeners(),this.socket.close()}this.listeners={},this.socket=void 0}))}}class p{constructor(e={}){var t,s,n,i;this.hangoverRemaining=0,this.thresholdRatio=null!==(t=e.thresholdRatio)&&void 0!==t?t:3,this.noiseFloorAlpha=null!==(s=e.noiseFloorAlpha)&&void 0!==s?s:.05,this.hangoverFrames=null!==(n=e.hangoverFrames)&&void 0!==n?n:10,this.initialNoiseFloor=null!==(i=e.initialNoiseFloor)&&void 0!==i?i:1e-4,this.noiseFloor=this.initialNoiseFloor}process(e){let t=0;for(let s=0;s<e.length;s++)t+=e[s]*e[s];const s=e.length>0?Math.sqrt(t/e.length):0;let n=s>this.noiseFloor*this.thresholdRatio;return n?this.hangoverRemaining=this.hangoverFrames:this.hangoverRemaining>0?(this.hangoverRemaining--,n=!0):this.noiseFloor=this.noiseFloor*(1-this.noiseFloorAlpha)+s*this.noiseFloorAlpha,{active:n,energy:s}}reset(){this.noiseFloor=this.initialNoiseFloor,this.hangoverRemaining=0}}class f{constructor(e){this.windowMs=e,this.frames=[],this.head=0}pushFrame(e){this.frames.push(e);const t=e.ts-this.windowMs;for(;this.head<this.frames.length&&this.frames[this.head].ts<t;)this.head++;this.head>1024&&2*this.head>this.frames.length&&(this.frames=this.frames.slice(this.head),this.head=0)}framesInWindow(e,t){const s=[];for(let n=this.head;n<this.frames.length;n++){const i=this.frames[n];if(!(i.ts<e)){if(i.ts>t)break;s.push(i)}}return s}clear(){this.frames=[],this.head=0}}function v(e,t,s){const n=function(e){var t;const s=new Map;for(const n of e)n.active&&s.set(n.channel,(null!==(t=s.get(n.channel))&&void 0!==t?t:0)+n.rms);return s}(t.framesInWindow(e.start,e.end));if(0===n.size)return"unknown";const i=[...n.entries()].sort(((e,t)=>t[1]-e[1]));if(1===i.length)return i[0][0];const[r,o]=i[0],[a,l]=i[1];return o>=s.dominanceRatio*l||o>l?r:l>o?a:"unknown"}function g(e){var t;const s=new Map;for(const n of e){if(!n.channel||"unknown"===n.channel)continue;const e=Math.max(0,n.end-n.start);s.set(n.channel,(null!==(t=s.get(n.channel))&&void 0!==t?t:0)+e)}if(0===s.size)return"unknown";const n=[...s.entries()].sort(((e,t)=>t[1]-e[1]));if(1===n.length)return n[0][0];const[i,r]=n[0],[,o]=n[1];return r===o?"unknown":i}function w(e,t,s){for(const n of e.words)n.channel=v(n,t,s);e.channel=g(e.words)}const k='{"type":"Terminate"}';class y{constructor(e){var t,s,n,i,r,o,a,l,h;if(this.listeners={},this.isDualChannel=!1,this.vadFrameSamples=0,this.minChunkSamples=0,this.maxChunkSamples=0,this.params=Object.assign(Object.assign({},e),{websocketBaseUrl:e.websocketBaseUrl||"wss://streaming.assemblyai.com/v3/ws"}),"token"in e&&e.token&&(this.token=e.token),"apiKey"in e&&e.apiKey&&(this.apiKey=e.apiKey),!this.token&&!this.apiKey)throw new Error("API key or temporary token is required.");if(e.channels){if(2!==e.channels.length)throw new Error("StreamingTranscriber.channels must have exactly 2 entries.");const c=e.channels.map((e=>e.name));if(new Set(c).size!==c.length)throw new Error("StreamingTranscriber.channels names must be unique.");this.isDualChannel=!0,this.channelNames=c;const d=null!==(t=e.channelAttribution)&&void 0!==t?t:{};this.attributionParams={dominanceRatio:null!==(s=d.dominanceRatio)&&void 0!==s?s:4,timelineWindowMs:null!==(n=d.timelineWindowMs)&&void 0!==n?n:3e4,createVad:null!==(i=d.createVad)&&void 0!==i?i:()=>new p,flushIntervalMs:null!==(r=d.flushIntervalMs)&&void 0!==r?r:50,resolveUnknownChannelsMethod:null!==(o=d.resolveUnknownChannelsMethod)&&void 0!==o?o:"window",resolutionWindowWords:null!==(a=d.resolutionWindowWords)&&void 0!==a?a:2,speakerHistoryMinRmsEvidence:null!==(l=d.speakerHistoryMinRmsEvidence)&&void 0!==l?l:.5,speakerHistoryDominanceRatio:null!==(h=d.speakerHistoryDominanceRatio)&&void 0!==h?h:3},"speaker-history"===this.attributionParams.resolveUnknownChannelsMethod&&(this.speakerHistory=new Map),this.vadFrameSamples=Math.max(1,Math.round(.02*e.sampleRate)),this.minChunkSamples=Math.max(1,Math.round(.05*e.sampleRate)),this.maxChunkSamples=Math.max(this.minChunkSamples,Math.round(.2*e.sampleRate)),this.channelBuffers=new Map(c.map((e=>[e,[]]))),this.channelSamplesReceived=new Map(c.map((e=>[e,0]))),this.channelVadFloatBuffers=new Map(c.map((e=>[e,new Float32Array(this.vadFrameSamples)]))),this.channelVadBufferIdx=new Map(c.map((e=>[e,0]))),this.channelVads=new Map(c.map((e=>[e,this.attributionParams.createVad(e)]))),this.timeline=new f(this.attributionParams.timelineWindowMs)}}connectionUrl(){var e,t;const s=new URL(null!==(e=this.params.websocketBaseUrl)&&void 0!==e?e:"");if("wss:"!==s.protocol)throw new Error("Invalid protocol, must be wss");const n=new URLSearchParams;this.token&&n.set("token",this.token),n.set("sample_rate",this.params.sampleRate.toString()),this.params.endOfTurnConfidenceThreshold&&n.set("end_of_turn_confidence_threshold",this.params.endOfTurnConfidenceThreshold.toString()),void 0!==this.params.minEndOfTurnSilenceWhenConfident&&(void 0!==this.params.minTurnSilence?console.warn("[Deprecation Warning] Both `minEndOfTurnSilenceWhenConfident` and `minTurnSilence` are set. Using `minTurnSilence`; `minEndOfTurnSilenceWhenConfident` is deprecated."):console.warn("[Deprecation Warning] `minEndOfTurnSilenceWhenConfident` is deprecated and will be removed in a future release. Please use `minTurnSilence` instead."));const i=null!==(t=this.params.minTurnSilence)&&void 0!==t?t:this.params.minEndOfTurnSilenceWhenConfident;return void 0!==i&&n.set("min_turn_silence",i.toString()),this.params.maxTurnSilence&&n.set("max_turn_silence",this.params.maxTurnSilence.toString()),void 0!==this.params.vadThreshold&&n.set("vad_threshold",this.params.vadThreshold.toString()),this.params.formatTurns&&n.set("format_turns",this.params.formatTurns.toString()),this.params.encoding&&n.set("encoding",this.params.encoding.toString()),this.params.keytermsPrompt?n.set("keyterms_prompt",JSON.stringify(this.params.keytermsPrompt)):this.params.keyterms&&(console.warn("[Deprecation Warning] `keyterms` is deprecated and will be removed in a future release. Please use `keytermsPrompt` instead."),n.set("keyterms_prompt",JSON.stringify(this.params.keyterms))),this.params.prompt&&n.set("prompt",this.params.prompt),this.params.agentContext&&n.set("agent_context",this.params.agentContext),this.params.filterProfanity&&n.set("filter_profanity",this.params.filterProfanity.toString()),"u3-pro"===this.params.speechModel&&console.warn("[Deprecation Warning] The speech model `u3-pro` is deprecated and will be removed in a future release. Please use `u3-rt-pro` instead."),void 0!==this.params.speechModel&&n.set("speech_model",this.params.speechModel.toString()),void 0!==this.params.languageCode&&n.set("language_code",this.params.languageCode),void 0!==this.params.languageDetection&&n.set("language_detection",this.params.languageDetection.toString()),this.params.domain&&n.set("domain",this.params.domain),void 0!==this.params.inactivityTimeout&&n.set("inactivity_timeout",this.params.inactivityTimeout.toString()),void 0!==this.params.speakerLabels&&n.set("speaker_labels",this.params.speakerLabels.toString()),void 0!==this.params.maxSpeakers&&n.set("max_speakers",this.params.maxSpeakers.toString()),this.params.voiceFocus&&n.set("voice_focus",this.params.voiceFocus),void 0!==this.params.voiceFocusThreshold&&n.set("voice_focus_threshold",this.params.voiceFocusThreshold.toString()),void 0!==this.params.continuousPartials&&n.set("continuous_partials",this.params.continuousPartials.toString()),void 0!==this.params.interruptionDelay&&n.set("interruption_delay",this.params.interruptionDelay.toString()),void 0!==this.params.turnLeftPadMs&&n.set("turn_left_pad_ms",this.params.turnLeftPadMs.toString()),this.params.customerSupportAudioCapture&&(console.warn("`customerSupportAudioCapture=true` will record session audio. Only enable this when explicitly coordinating with AssemblyAI support."),n.set("_customer_support_audio_capture",this.params.customerSupportAudioCapture.toString())),this.params.webhookUrl&&n.set("webhook_url",this.params.webhookUrl),this.params.webhookAuthHeaderName&&n.set("webhook_auth_header_name",this.params.webhookAuthHeaderName),this.params.webhookAuthHeaderValue&&n.set("webhook_auth_header_value",this.params.webhookAuthHeaderValue),void 0!==this.params.includePartialTurns&&n.set("include_partial_turns",this.params.includePartialTurns.toString()),void 0!==this.params.redactPii&&n.set("redact_pii",this.params.redactPii.toString()),void 0!==this.params.redactPiiPolicies&&n.set("redact_pii_policies",JSON.stringify(this.params.redactPiiPolicies)),void 0!==this.params.redactPiiSub&&n.set("redact_pii_sub",this.params.redactPiiSub),void 0!==this.params.mode&&n.set("mode",this.params.mode),void 0!==this.params.llmGateway&&n.set("llm_gateway",JSON.stringify(this.params.llmGateway)),s.search=n.toString(),s}on(e,t){this.listeners[e]=t}connect(){return new Promise((e=>{if(this.socket)throw new Error("Already connected");const t=this.connectionUrl();this.token?this.socket=a(t.toString()):(console.warn("API key authentication is not supported for the StreamingTranscriber in browser environment. Use temporary token authentication instead.\nLearn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/compat.md#browser-compatibility."),this.socket=a(t.toString(),{headers:{Authorization:this.apiKey}})),this.socket.binaryType="arraybuffer",this.socket.onopen=()=>{},this.socket.onclose=({code:e,reason:t})=>{var s,n;t||e in c&&(t=c[e]),this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=void 0),null===(n=(s=this.listeners).close)||void 0===n||n.call(s,e,t)},this.socket.onerror=e=>{var t,s,n,i;e.error?null===(s=(t=this.listeners).error)||void 0===s||s.call(t,e.error):null===(i=(n=this.listeners).error)||void 0===i||i.call(n,new Error(e.message))},this.socket.onmessage=({data:t})=>{var s,n,i,r,o,a,l,h,c,u,m,p,f,v,g;const k=JSON.parse(t.toString());if("error"in k){const e=new d(k.error);return"error_code"in k&&(e.code=k.error_code),void(null===(n=(s=this.listeners).error)||void 0===n||n.call(s,e))}switch(k.type){case"Begin":e(k),null===(r=(i=this.listeners).open)||void 0===r||r.call(i,k);break;case"Turn":if(this.isDualChannel&&this.timeline&&this.attributionParams)switch(w(k,this.timeline,{dominanceRatio:this.attributionParams.dominanceRatio}),this.attributionParams.resolveUnknownChannelsMethod){case"window":this.resolveUnknownChannelsByWindow(k);break;case"speaker-history":this.resolveUnknownChannelsBySpeakerHistory(k)}null===(a=(o=this.listeners).turn)||void 0===a||a.call(o,k);break;case"SpeechStarted":null===(h=(l=this.listeners).speechStarted)||void 0===h||h.call(l,k);break;case"LLMGatewayResponse":null===(u=(c=this.listeners).llmGatewayResponse)||void 0===u||u.call(c,k);break;case"SpeakerRevision":null===(p=(m=this.listeners).speakerRevision)||void 0===p||p.call(m,k);break;case"Warning":{const e=k;console.warn(`Streaming warning (code=${e.warning_code}): ${e.warning}`),null===(v=(f=this.listeners).warning)||void 0===v||v.call(f,e);break}case"Termination":null===(g=this.sessionTerminatedResolve)||void 0===g||g.call(this)}}}))}stream(){return new n({write:e=>{this.sendAudio(e)}})}sendAudio(e,t){if(this.isDualChannel){if(!(null==t?void 0:t.channel))throw new Error("StreamingTranscriber is in dual-channel mode; sendAudio requires { channel }.");if(!this.channelNames.includes(t.channel))throw new Error(`Unknown channel "${t.channel}"; declared channels: ${this.channelNames.join(", ")}.`);this.ingestChannelAudio(t.channel,e)}else this.send(e)}ingestChannelAudio(e,t){var s,n;const i=function(e){if(e instanceof Int16Array)return e;if(ArrayBuffer.isView(e)){const t=e;return new Int16Array(t.buffer,t.byteOffset,Math.floor(t.byteLength/2))}return new Int16Array(e)}(t),r=this.channelBuffers.get(e),o=this.channelVadFloatBuffers.get(e);let a=this.channelVadBufferIdx.get(e),l=this.channelSamplesReceived.get(e);const h=this.channelVads.get(e),c=this.params.sampleRate,d=this.vadFrameSamples;for(let t=0;t<i.length;t++){const u=i[t];if(r.push(u),o[a++]=u/32768,l++,a===d){const t=h.process(o),i={ts:l/c*1e3,channel:e,active:t.active,rms:t.energy};this.timeline.pushFrame(i),null===(n=(s=this.listeners).vad)||void 0===n||n.call(s,i),a=0}}this.channelVadBufferIdx.set(e,a),this.channelSamplesReceived.set(e,l),this.flushTimer||this.startFlushTimer()}startFlushTimer(){this.flushTimer=setInterval((()=>this.flushMix()),this.attributionParams.flushIntervalMs)}flushMix(e=!1){var t,s;if(!this.channelNames||!this.channelBuffers)return;const n=this.channelNames.map((e=>this.channelBuffers.get(e))),i=n.length;for(;;){let r=1/0;for(const e of n)e.length<r&&(r=e.length);if(!Number.isFinite(r)||0===r)return;if(!e&&r<this.minChunkSamples)return;r>this.maxChunkSamples&&(r=this.maxChunkSamples);const o=new Int16Array(r);for(let e=0;e<r;e++){let t=0;for(let s=0;s<i;s++)t+=n[s][e];const s=Math.round(t/i);o[e]=s<-32768?-32768:s>32767?32767:s}for(const e of n)e.splice(0,r);try{this.send(o.buffer)}catch(e){return void(null===(s=(t=this.listeners).error)||void 0===s||s.call(t,e))}}}resolveUnknownChannelsByWindow(e){var t;if(!this.attributionParams)return;const s=this.attributionParams.resolutionWindowWords,n=e.words;let i=!1;for(let e=0;e<n.length;e++){if("unknown"!==n[e].channel)continue;const r=new Map,o=Math.max(0,e-s),a=Math.min(n.length-1,e+s);for(let s=o;s<=a;s++){if(s===e)continue;const i=n[s].channel;i&&"unknown"!==i&&r.set(i,(null!==(t=r.get(i))&&void 0!==t?t:0)+1)}if(0===r.size)continue;let l,h=0,c=!1;for(const[e,t]of r)t>h?(l=e,h=t,c=!1):t===h&&(c=!0);l&&!c&&(n[e].channel=l,n[e].channelResolved=!0,i=!0)}i&&(e.channel=g(n))}resolveUnknownChannelsBySpeakerHistory(e){var t;if(!this.timeline||!this.attributionParams||!this.speakerHistory)return;const s=this.attributionParams.speakerHistoryMinRmsEvidence,n=this.attributionParams.speakerHistoryDominanceRatio;for(const s of e.words){if(!s.speaker)continue;const e=this.timeline.framesInWindow(s.start,s.end);let n=this.speakerHistory.get(s.speaker);n||(n=new Map,this.speakerHistory.set(s.speaker,n));for(const s of e)s.active&&n.set(s.channel,(null!==(t=n.get(s.channel))&&void 0!==t?t:0)+s.rms)}let i=!1;for(const t of e.words){if("unknown"!==t.channel||!t.speaker)continue;const e=this.speakerHistory.get(t.speaker);if(!e||0===e.size)continue;let r,o=0,a=0,l=0;for(const[t,s]of e)o+=s,s>a?(l=a,a=s,r=t):s>l&&(l=s);o<s||(l>0&&a<n*l||r&&(t.channel=r,t.channelResolved=!0,i=!0))}i&&(e.channel=g(e.words))}updateConfiguration(e){const{min_end_of_turn_silence_when_confident:t,min_turn_silence:s}=e,n=function(e,t){var s={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(s[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(n=Object.getOwnPropertySymbols(e);i<n.length;i++)t.indexOf(n[i])<0&&Object.prototype.propertyIsEnumerable.call(e,n[i])&&(s[n[i]]=e[n[i]])}return s}(e,["min_end_of_turn_silence_when_confident","min_turn_silence"]);void 0!==t&&(void 0!==s?console.warn("[Deprecation Warning] Both `min_end_of_turn_silence_when_confident` and `min_turn_silence` are set. Using `min_turn_silence`; `min_end_of_turn_silence_when_confident` is deprecated."):console.warn("[Deprecation Warning] `min_end_of_turn_silence_when_confident` is deprecated and will be removed in a future release. Please use `min_turn_silence` instead."));const i=null!=s?s:t,r=Object.assign(Object.assign({type:"UpdateConfiguration"},n),void 0!==i?{min_turn_silence:i}:{});this.send(JSON.stringify(r))}forceEndpoint(){this.send(JSON.stringify({type:"ForceEndpoint"}))}send(e){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("Socket is not open for communication");this.socket.send(e)}close(){return s(this,arguments,void 0,(function*(e=!0){var t;if(this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=void 0,this.flushMix(!0)),this.socket){if(this.socket.readyState===this.socket.OPEN)if(e){const e=new Promise((e=>{this.sessionTerminatedResolve=e}));this.socket.send(k),yield e}else this.socket.send(k);(null===(t=this.socket)||void 0===t?void 0:t.removeAllListeners)&&this.socket.removeAllListeners(),this.socket.close()}this.listeners={},this.socket=void 0}))}}const S={cache:"no-store"};let b="";"undefined"!=typeof navigator&&navigator.userAgent&&(b+=navigator.userAgent);const _={sdk:{name:"JavaScript",version:"4.34.6"}};"undefined"!=typeof process&&(process.versions.node&&-1===b.indexOf("Node")&&(_.runtime_env={name:"Node",version:process.versions.node}),process.versions.bun&&-1===b.indexOf("Bun")&&(_.runtime_env={name:"Bun",version:process.versions.bun})),"undefined"!=typeof Deno&&process.versions.bun&&-1===b.indexOf("Deno")&&(_.runtime_env={name:"Deno",version:Deno.version.deno});class T{constructor(e){var t;this.params=e,!1===e.userAgent?this.userAgent=void 0:this.userAgent=(t=e.userAgent||{},b+(!1===t?"":" AssemblyAI/1.0 ("+Object.entries(Object.assign(Object.assign({},_),t)).map((([e,t])=>t?`${e}=${t.name}/${t.version}`:"")).join(" ")+")"))}fetch(e,t){return s(this,void 0,void 0,(function*(){t=Object.assign(Object.assign({},S),t);let s={Authorization:this.params.apiKey,"Content-Type":"application/json"};(null==S?void 0:S.headers)&&(s=Object.assign(Object.assign({},s),S.headers)),(null==t?void 0:t.headers)&&(s=Object.assign(Object.assign({},s),t.headers)),this.userAgent&&(s["User-Agent"]=this.userAgent,"undefined"!=typeof window&&"chrome"in window&&(s["AssemblyAI-Agent"]=this.userAgent)),t.headers=s,e.startsWith("http")||(e=this.params.baseUrl+e);const n=yield fetch(e,t);if(n.status>=400){let e;const t=yield n.text();if(t){try{e=JSON.parse(t)}catch(e){}if(null==e?void 0:e.error)throw new Error(e.error);throw new Error(t)}throw new Error(`HTTP Error: ${n.status} ${n.statusText}`)}return n}))}fetchJson(e,t){return s(this,void 0,void 0,(function*(){return(yield this.fetch(e,t)).json()}))}}class A extends T{constructor(e){super(e),this.baseServiceParams=e}transcriber(e){const t=Object.assign({},e);return t.token||t.apiKey||(t.apiKey=this.baseServiceParams.apiKey),new y(t)}createTemporaryToken(e){return s(this,void 0,void 0,(function*(){const t=new URLSearchParams;Object.entries(e).forEach((([e,s])=>{null!=s&&t.append(e,String(s))}));const s=t.toString(),n=s?`/v3/token?${s}`:"/v3/token";return(yield this.fetchJson(n,{method:"GET"})).token}))}}e.BrowserOnlyError=t,e.DualChannelCapture=class{constructor(e){var s;if(this.running=!1,void 0===globalThis.AudioContext)throw new t;this.params={micStream:e.micStream,systemStream:e.systemStream,transcriber:e.transcriber,targetSampleRate:null!==(s=e.targetSampleRate)&&void 0!==s?s:16e3}}on(e,t){"error"===e&&(this.errorListener=t)}start(){return s(this,void 0,void 0,(function*(){if(this.running)throw new Error("DualChannelCapture already started");this.context=new AudioContext;const e=new Blob(['\nclass Pcm16EncoderProcessor extends AudioWorkletProcessor {\n constructor(options) {\n super();\n const opts = (options && options.processorOptions) || {};\n this.targetRate = opts.targetRate || 16000;\n this.chunkMs = opts.chunkMs || 50;\n this.ratio = sampleRate / this.targetRate;\n this.chunkSize = Math.round(this.targetRate * this.chunkMs / 1000);\n this.buffer = new Int16Array(this.chunkSize);\n this.bufferIdx = 0;\n this.samplesSent = 0;\n this.lastSample = 0;\n this.fractional = 0;\n }\n\n process(inputs) {\n const input = inputs[0];\n if (!input || input.length === 0 || !input[0] || input[0].length === 0) {\n return true;\n }\n const mono = input[0];\n let pos = this.fractional;\n while (pos < mono.length) {\n const i = Math.floor(pos);\n const frac = pos - i;\n const a = i === 0 ? this.lastSample : mono[i - 1];\n const b = mono[i];\n const sample = a + (b - a) * frac;\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n this.buffer[this.bufferIdx++] = clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff;\n if (this.bufferIdx === this.chunkSize) {\n const out = new Int16Array(this.chunkSize);\n out.set(this.buffer);\n this.samplesSent += this.chunkSize;\n this.port.postMessage(\n { pcm: out.buffer, samplesSent: this.samplesSent },\n [out.buffer],\n );\n this.bufferIdx = 0;\n }\n pos += this.ratio;\n }\n this.lastSample = mono[mono.length - 1];\n this.fractional = pos - mono.length;\n return true;\n }\n}\nregisterProcessor("aai-pcm16-encoder", Pcm16EncoderProcessor);\n'],{type:"application/javascript"}),t=URL.createObjectURL(e);try{yield this.context.audioWorklet.addModule(t)}finally{URL.revokeObjectURL(t)}this.micSource=this.context.createMediaStreamSource(this.params.micStream),this.sysSource=this.context.createMediaStreamSource(this.params.systemStream),this.micEncoder=this.makeEncoder("mic"),this.sysEncoder=this.makeEncoder("system"),this.micSource.connect(this.micEncoder),this.sysSource.connect(this.sysEncoder),this.running=!0}))}makeEncoder(e){const t=new AudioWorkletNode(this.context,"aai-pcm16-encoder",{numberOfInputs:1,numberOfOutputs:0,channelCount:1,channelCountMode:"explicit",channelInterpretation:"speakers",processorOptions:{targetRate:this.params.targetSampleRate,chunkMs:50}});return t.port.onmessage=t=>{var s;try{this.params.transcriber.sendAudio(t.data.pcm,{channel:e})}catch(e){null===(s=this.errorListener)||void 0===s||s.call(this,e)}},t}stop(){return s(this,void 0,void 0,(function*(){var e,t,s,n,i,r;if(this.running){this.running=!1;try{null===(e=this.micEncoder)||void 0===e||e.port.close(),null===(t=this.sysEncoder)||void 0===t||t.port.close(),null===(s=this.micEncoder)||void 0===s||s.disconnect(),null===(n=this.sysEncoder)||void 0===n||n.disconnect(),null===(i=this.micSource)||void 0===i||i.disconnect(),null===(r=this.sysSource)||void 0===r||r.disconnect()}catch(e){}this.context&&"closed"!==this.context.state&&(yield this.context.close()),this.context=void 0,this.micSource=void 0,this.sysSource=void 0,this.micEncoder=void 0,this.sysEncoder=void 0}}))}},e.EnergyVad=p,e.LinearResampler=class{constructor(e,t){if(this.sourceRate=e,this.targetRate=t,this.lastSample=0,this.fractional=0,e<=0||t<=0)throw new Error("sourceRate and targetRate must be positive");this.ratio=e/t}process(e){var t;if(this.sourceRate===this.targetRate)return e;const s=new Float32Array(Math.ceil(e.length/this.ratio)+1);let n=0,i=this.fractional;for(;i<e.length;){const t=Math.floor(i),r=i-t,o=0===t?this.lastSample:e[t-1],a=e[t];s[n++]=o+(a-o)*r,i+=this.ratio}return this.lastSample=null!==(t=e[e.length-1])&&void 0!==t?t:this.lastSample,this.fractional=i-e.length,s.subarray(0,n)}reset(){this.lastSample=0,this.fractional=0}},e.RealtimeService=class extends m{},e.RealtimeTranscriber=m,e.StreamingServiceFactory=class extends A{},e.StreamingTranscriber=y,e.StreamingTranscriberFactory=A,e.VadTimeline=f,e.attributeTurn=w,e.attributeWord=v,e.float32ToPcm16=function(e){const t=new ArrayBuffer(2*e.length),s=new DataView(t);for(let t=0;t<e.length;t++){const n=Math.max(-1,Math.min(1,e[t]));s.setInt16(2*t,n<0?32768*n:32767*n,!0)}return t},e.rollUpTurnChannel=g}));
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).assemblyai={})}(this,(function(e){"use strict";class t extends Error{constructor(e="DualChannelCapture requires a browser environment (AudioContext is undefined)."){super(e),this.name="BrowserOnlyError"}}function s(e,t,s,n){return new(s||(s=Promise))((function(i,r){function o(e){try{l(n.next(e))}catch(e){r(e)}}function a(e){try{l(n.throw(e))}catch(e){r(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(o,a)}l((n=n.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const{WritableStream:n}="undefined"!=typeof window?window:"undefined"!=typeof global?global:globalThis;var i,r;const o=null!==(r=null!==(i=null!==WebSocket&&void 0!==WebSocket?WebSocket:null===global||void 0===global?void 0:global.WebSocket)&&void 0!==i?i:null===window||void 0===window?void 0:window.WebSocket)&&void 0!==r?r:null===self||void 0===self?void 0:self.WebSocket,a=(e,t)=>t?new o(e,t):new o(e),l={[4e3]:"Sample rate must be a positive integer",[4001]:"Not Authorized",[4002]:"Insufficient funds",[4003]:"This feature is paid-only and requires you to add a credit card. Please visit https://app.assemblyai.com/ to add a credit card to your account.",[4004]:"Session ID does not exist",[4008]:"Session has expired",[4010]:"Session is closed",[4029]:"Rate limited",[4030]:"Unique session violation",[4031]:"Session Timeout",[4032]:"Audio too short",[4033]:"Audio too long",[4034]:"Audio too small to transcode",[4100]:"Bad JSON",[4101]:"Bad schema",[4102]:"Too many streams",[4103]:"This session has been reconnected. This WebSocket is no longer valid.",[1013]:"Reconnect attempts exhausted",[4104]:"Could not parse word boost parameter"};class c extends Error{}const h=4e3,d=4001,u=4002,m=4003,p=4101,f={[3005]:"Server error",[3006]:"Input validation error",[3007]:"Audio chunk duration violation",[3008]:"Session expired: maximum session duration exceeded",[3009]:"Too many concurrent sessions",[h]:"Sample rate must be a positive integer",[d]:"Not Authorized",[u]:"Insufficient funds",[m]:"This feature is paid-only and requires you to add a credit card. Please visit https://app.assemblyai.com/ to add a credit card to your account.",[4004]:"Session ID does not exist",[4008]:"Session has expired",[4010]:"Session is closed",[4029]:"Rate limited",[4030]:"Unique session violation",[4031]:"Session Timeout",[4032]:"Audio too short",[4033]:"Audio too long",[4034]:"Audio too small to transcode",[p]:"Bad schema",[4102]:"Too many streams",[4103]:"This session has been reconnected. This WebSocket is no longer valid."};class v extends Error{}const g='{"terminate_session":true}';class w{constructor(e){var t,s;if(this.listeners={},this.realtimeUrl=null!==(t=e.realtimeUrl)&&void 0!==t?t:"wss://api.assemblyai.com/v2/realtime/ws",this.sampleRate=null!==(s=e.sampleRate)&&void 0!==s?s:16e3,this.wordBoost=e.wordBoost,this.encoding=e.encoding,this.endUtteranceSilenceThreshold=e.endUtteranceSilenceThreshold,this.disablePartialTranscripts=e.disablePartialTranscripts,"token"in e&&e.token&&(this.token=e.token),"apiKey"in e&&e.apiKey&&(this.apiKey=e.apiKey),!this.token&&!this.apiKey)throw new Error("API key or temporary token is required.")}connectionUrl(){const e=new URL(this.realtimeUrl);if("wss:"!==e.protocol)throw new Error("Invalid protocol, must be wss");const t=new URLSearchParams;return this.token&&t.set("token",this.token),t.set("sample_rate",this.sampleRate.toString()),this.wordBoost&&this.wordBoost.length>0&&t.set("word_boost",JSON.stringify(this.wordBoost)),this.encoding&&t.set("encoding",this.encoding),t.set("enable_extra_session_information","true"),this.disablePartialTranscripts&&t.set("disable_partial_transcripts",this.disablePartialTranscripts.toString()),e.search=t.toString(),e}on(e,t){this.listeners[e]=t}connect(){return new Promise((e=>{if(this.socket)throw new Error("Already connected");const t=this.connectionUrl();this.token?this.socket=a(t.toString()):(console.warn("API key authentication is not supported for the RealtimeTranscriber in browser environment. Use temporary token authentication instead.\nLearn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/compat.md#browser-compatibility."),this.socket=a(t.toString(),{headers:{Authorization:this.apiKey}})),this.socket.binaryType="arraybuffer",this.socket.onopen=()=>{void 0!==this.endUtteranceSilenceThreshold&&null!==this.endUtteranceSilenceThreshold&&this.configureEndUtteranceSilenceThreshold(this.endUtteranceSilenceThreshold)},this.socket.onclose=({code:e,reason:t})=>{var s,n;t||e in l&&(t=l[e]),null===(n=(s=this.listeners).close)||void 0===n||n.call(s,e,t)},this.socket.onerror=e=>{var t,s,n,i;e.error?null===(s=(t=this.listeners).error)||void 0===s||s.call(t,e.error):null===(i=(n=this.listeners).error)||void 0===i||i.call(n,new Error(e.message))},this.socket.onmessage=({data:t})=>{var s,n,i,r,o,a,l,h,d,u,m,p,f,v,g;const w=JSON.parse(t.toString());if("error"in w)null===(n=(s=this.listeners).error)||void 0===n||n.call(s,new c(w.error));else switch(w.message_type){case"SessionBegins":{const t={sessionId:w.session_id,expiresAt:new Date(w.expires_at)};e(t),null===(r=(i=this.listeners).open)||void 0===r||r.call(i,t);break}case"PartialTranscript":w.created=new Date(w.created),null===(a=(o=this.listeners).transcript)||void 0===a||a.call(o,w),null===(h=(l=this.listeners)["transcript.partial"])||void 0===h||h.call(l,w);break;case"FinalTranscript":w.created=new Date(w.created),null===(u=(d=this.listeners).transcript)||void 0===u||u.call(d,w),null===(p=(m=this.listeners)["transcript.final"])||void 0===p||p.call(m,w);break;case"SessionInformation":null===(v=(f=this.listeners).session_information)||void 0===v||v.call(f,w);break;case"SessionTerminated":null===(g=this.sessionTerminatedResolve)||void 0===g||g.call(this)}}}))}sendAudio(e){this.send(e)}stream(){return new n({write:e=>{this.sendAudio(e)}})}forceEndUtterance(){this.send('{"force_end_utterance":true}')}configureEndUtteranceSilenceThreshold(e){this.send(`{"end_utterance_silence_threshold":${e}}`)}send(e){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("Socket is not open for communication");this.socket.send(e)}close(){return s(this,arguments,void 0,(function*(e=!0){var t;if(this.socket){if(this.socket.readyState===this.socket.OPEN)if(e){const e=new Promise((e=>{this.sessionTerminatedResolve=e}));this.socket.send(g),yield e}else this.socket.send(g);(null===(t=this.socket)||void 0===t?void 0:t.removeAllListeners)&&this.socket.removeAllListeners(),this.socket.close()}this.listeners={},this.socket=void 0}))}}class y{constructor(e={}){var t,s,n,i;this.hangoverRemaining=0,this.thresholdRatio=null!==(t=e.thresholdRatio)&&void 0!==t?t:3,this.noiseFloorAlpha=null!==(s=e.noiseFloorAlpha)&&void 0!==s?s:.05,this.hangoverFrames=null!==(n=e.hangoverFrames)&&void 0!==n?n:10,this.initialNoiseFloor=null!==(i=e.initialNoiseFloor)&&void 0!==i?i:1e-4,this.noiseFloor=this.initialNoiseFloor}process(e){let t=0;for(let s=0;s<e.length;s++)t+=e[s]*e[s];const s=e.length>0?Math.sqrt(t/e.length):0;let n=s>this.noiseFloor*this.thresholdRatio;return n?this.hangoverRemaining=this.hangoverFrames:this.hangoverRemaining>0?(this.hangoverRemaining--,n=!0):this.noiseFloor=this.noiseFloor*(1-this.noiseFloorAlpha)+s*this.noiseFloorAlpha,{active:n,energy:s}}reset(){this.noiseFloor=this.initialNoiseFloor,this.hangoverRemaining=0}}class k{constructor(e){this.windowMs=e,this.frames=[],this.head=0}pushFrame(e){this.frames.push(e);const t=e.ts-this.windowMs;for(;this.head<this.frames.length&&this.frames[this.head].ts<t;)this.head++;this.head>1024&&2*this.head>this.frames.length&&(this.frames=this.frames.slice(this.head),this.head=0)}framesInWindow(e,t){const s=[];for(let n=this.head;n<this.frames.length;n++){const i=this.frames[n];if(!(i.ts<e)){if(i.ts>t)break;s.push(i)}}return s}clear(){this.frames=[],this.head=0}}function S(e,t,s){const n=function(e){var t;const s=new Map;for(const n of e)n.active&&s.set(n.channel,(null!==(t=s.get(n.channel))&&void 0!==t?t:0)+n.rms);return s}(t.framesInWindow(e.start,e.end));if(0===n.size)return"unknown";const i=[...n.entries()].sort(((e,t)=>t[1]-e[1]));if(1===i.length)return i[0][0];const[r,o]=i[0],[a,l]=i[1];return o>=s.dominanceRatio*l||o>l?r:l>o?a:"unknown"}function b(e){var t;const s=new Map;for(const n of e){if(!n.channel||"unknown"===n.channel)continue;const e=Math.max(0,n.end-n.start);s.set(n.channel,(null!==(t=s.get(n.channel))&&void 0!==t?t:0)+e)}if(0===s.size)return"unknown";const n=[...s.entries()].sort(((e,t)=>t[1]-e[1]));if(1===n.length)return n[0][0];const[i,r]=n[0],[,o]=n[1];return r===o?"unknown":i}function _(e,t,s){for(const n of e.words)n.channel=S(n,t,s);e.channel=b(e.words)}const T='{"type":"Terminate"}',A=new Set([h,d,u,m,p]);function x(e){return 1e3!==e&&!A.has(e)}class P{constructor(e){var t,s,n,i,r,o,a,l,c;if(this.listeners={},this.isDualChannel=!1,this.vadFrameSamples=0,this.minChunkSamples=0,this.maxChunkSamples=0,this.params=Object.assign(Object.assign({},e),{websocketBaseUrl:e.websocketBaseUrl||"wss://streaming.assemblyai.com/v3/ws"}),"token"in e&&e.token&&(this.token=e.token),"apiKey"in e&&e.apiKey&&(this.apiKey=e.apiKey),!this.token&&!this.apiKey)throw new Error("API key or temporary token is required.");if(e.channels){if(2!==e.channels.length)throw new Error("StreamingTranscriber.channels must have exactly 2 entries.");const h=e.channels.map((e=>e.name));if(new Set(h).size!==h.length)throw new Error("StreamingTranscriber.channels names must be unique.");this.isDualChannel=!0,this.channelNames=h;const d=null!==(t=e.channelAttribution)&&void 0!==t?t:{};this.attributionParams={dominanceRatio:null!==(s=d.dominanceRatio)&&void 0!==s?s:4,timelineWindowMs:null!==(n=d.timelineWindowMs)&&void 0!==n?n:3e4,createVad:null!==(i=d.createVad)&&void 0!==i?i:()=>new y,flushIntervalMs:null!==(r=d.flushIntervalMs)&&void 0!==r?r:50,resolveUnknownChannelsMethod:null!==(o=d.resolveUnknownChannelsMethod)&&void 0!==o?o:"window",resolutionWindowWords:null!==(a=d.resolutionWindowWords)&&void 0!==a?a:2,speakerHistoryMinRmsEvidence:null!==(l=d.speakerHistoryMinRmsEvidence)&&void 0!==l?l:.5,speakerHistoryDominanceRatio:null!==(c=d.speakerHistoryDominanceRatio)&&void 0!==c?c:3},"speaker-history"===this.attributionParams.resolveUnknownChannelsMethod&&(this.speakerHistory=new Map),this.vadFrameSamples=Math.max(1,Math.round(.02*e.sampleRate)),this.minChunkSamples=Math.max(1,Math.round(.05*e.sampleRate)),this.maxChunkSamples=Math.max(this.minChunkSamples,Math.round(.2*e.sampleRate)),this.channelBuffers=new Map(h.map((e=>[e,[]]))),this.channelSamplesReceived=new Map(h.map((e=>[e,0]))),this.channelVadFloatBuffers=new Map(h.map((e=>[e,new Float32Array(this.vadFrameSamples)]))),this.channelVadBufferIdx=new Map(h.map((e=>[e,0]))),this.channelVads=new Map(h.map((e=>[e,this.attributionParams.createVad(e)]))),this.timeline=new k(this.attributionParams.timelineWindowMs)}}connectionUrl(){var e,t;const s=new URL(null!==(e=this.params.websocketBaseUrl)&&void 0!==e?e:"");if("wss:"!==s.protocol)throw new Error("Invalid protocol, must be wss");const n=new URLSearchParams;this.token&&n.set("token",this.token),n.set("sample_rate",this.params.sampleRate.toString()),this.params.endOfTurnConfidenceThreshold&&n.set("end_of_turn_confidence_threshold",this.params.endOfTurnConfidenceThreshold.toString()),void 0!==this.params.minEndOfTurnSilenceWhenConfident&&(void 0!==this.params.minTurnSilence?console.warn("[Deprecation Warning] Both `minEndOfTurnSilenceWhenConfident` and `minTurnSilence` are set. Using `minTurnSilence`; `minEndOfTurnSilenceWhenConfident` is deprecated."):console.warn("[Deprecation Warning] `minEndOfTurnSilenceWhenConfident` is deprecated and will be removed in a future release. Please use `minTurnSilence` instead."));const i=null!==(t=this.params.minTurnSilence)&&void 0!==t?t:this.params.minEndOfTurnSilenceWhenConfident;return void 0!==i&&n.set("min_turn_silence",i.toString()),this.params.maxTurnSilence&&n.set("max_turn_silence",this.params.maxTurnSilence.toString()),void 0!==this.params.vadThreshold&&n.set("vad_threshold",this.params.vadThreshold.toString()),this.params.formatTurns&&n.set("format_turns",this.params.formatTurns.toString()),this.params.encoding&&n.set("encoding",this.params.encoding.toString()),this.params.keytermsPrompt?n.set("keyterms_prompt",JSON.stringify(this.params.keytermsPrompt)):this.params.keyterms&&(console.warn("[Deprecation Warning] `keyterms` is deprecated and will be removed in a future release. Please use `keytermsPrompt` instead."),n.set("keyterms_prompt",JSON.stringify(this.params.keyterms))),this.params.prompt&&n.set("prompt",this.params.prompt),this.params.agentContext&&n.set("agent_context",this.params.agentContext),this.params.filterProfanity&&n.set("filter_profanity",this.params.filterProfanity.toString()),"u3-pro"===this.params.speechModel&&console.warn("[Deprecation Warning] The speech model `u3-pro` is deprecated and will be removed in a future release. Please use `u3-rt-pro` instead."),void 0!==this.params.speechModel&&n.set("speech_model",this.params.speechModel.toString()),void 0!==this.params.languageCode&&(console.warn("[Deprecation Warning] `languageCode` is deprecated and will be removed in a future release. Please use `languageCodes` instead."),n.set("language_code",this.params.languageCode)),void 0!==this.params.languageCodes&&n.set("language_codes",JSON.stringify(this.params.languageCodes)),void 0!==this.params.languageDetection&&n.set("language_detection",this.params.languageDetection.toString()),this.params.domain&&n.set("domain",this.params.domain),void 0!==this.params.inactivityTimeout&&n.set("inactivity_timeout",this.params.inactivityTimeout.toString()),void 0!==this.params.speakerLabels&&n.set("speaker_labels",this.params.speakerLabels.toString()),void 0!==this.params.maxSpeakers&&n.set("max_speakers",this.params.maxSpeakers.toString()),this.params.voiceFocus&&n.set("voice_focus",this.params.voiceFocus),void 0!==this.params.voiceFocusThreshold&&n.set("voice_focus_threshold",this.params.voiceFocusThreshold.toString()),void 0!==this.params.continuousPartials&&n.set("continuous_partials",this.params.continuousPartials.toString()),void 0!==this.params.interruptionDelay&&n.set("interruption_delay",this.params.interruptionDelay.toString()),void 0!==this.params.turnLeftPadMs&&n.set("turn_left_pad_ms",this.params.turnLeftPadMs.toString()),this.params.customerSupportAudioCapture&&(console.warn("`customerSupportAudioCapture=true` will record session audio. Only enable this when explicitly coordinating with AssemblyAI support."),n.set("_customer_support_audio_capture",this.params.customerSupportAudioCapture.toString())),this.params.webhookUrl&&n.set("webhook_url",this.params.webhookUrl),this.params.webhookAuthHeaderName&&n.set("webhook_auth_header_name",this.params.webhookAuthHeaderName),this.params.webhookAuthHeaderValue&&n.set("webhook_auth_header_value",this.params.webhookAuthHeaderValue),void 0!==this.params.includePartialTurns&&n.set("include_partial_turns",this.params.includePartialTurns.toString()),void 0!==this.params.redactPii&&n.set("redact_pii",this.params.redactPii.toString()),void 0!==this.params.redactPiiPolicies&&n.set("redact_pii_policies",JSON.stringify(this.params.redactPiiPolicies)),void 0!==this.params.redactPiiSub&&n.set("redact_pii_sub",this.params.redactPiiSub),void 0!==this.params.mode&&n.set("mode",this.params.mode),void 0!==this.params.llmGateway&&n.set("llm_gateway",JSON.stringify(this.params.llmGateway)),s.search=n.toString(),s}on(e,t){this.listeners[e]=t}connect(){return s(this,void 0,void 0,(function*(){var e,t;if(this.socket)throw new Error("Already connected");const s=null!==(e=this.params.maxConnectionRetries)&&void 0!==e?e:2,n=null!==(t=this.params.connectionRetryDelay)&&void 0!==t?t:500;let i;for(let e=0;e<=s;e++)try{return yield this.connectOnce()}catch(t){i=t;if(!(!0===t.retryable)||e===s)throw t;console.warn(`Streaming connect attempt ${e+1}/${s+1} failed (${t.message}); retrying`),n>0&&(yield new Promise((e=>setTimeout(e,n))))}throw null!=i?i:new Error("Failed to connect to streaming server")}))}connectOnce(){return new Promise(((e,t)=>{var s;const n=this.connectionUrl(),i=null!==(s=this.params.connectTimeout)&&void 0!==s?s:1e3;let r,o=!1;const l=e=>{o||(o=!0,r&&clearTimeout(r),this.discardPendingSocket(),t(e))};i>0&&(r=setTimeout((()=>{const e=new v(`Streaming connection timed out after ${i}ms`);e.retryable=!0,l(e)}),i)),this.token?this.socket=a(n.toString()):(console.warn("API key authentication is not supported for the StreamingTranscriber in browser environment. Use temporary token authentication instead.\nLearn more at https://github.com/AssemblyAI/assemblyai-node-sdk/blob/main/docs/compat.md#browser-compatibility."),this.socket=a(n.toString(),{headers:{Authorization:this.apiKey}})),this.socket.binaryType="arraybuffer",this.socket.onopen=()=>{},this.socket.onclose=({code:e,reason:t})=>{var s,n;if(t||e in f&&(t=f[e]),!o){const s=new v(t||`Streaming connection closed (code=${e})`);return s.code=e,s.retryable=x(e),void l(s)}this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=void 0),null===(n=(s=this.listeners).close)||void 0===n||n.call(s,e,t)},this.socket.onerror=e=>{var t,s,n;const i=null!==(t=e.error)&&void 0!==t?t:new Error(e.message);if(!o)return i.retryable=!0,void l(i);null===(n=(s=this.listeners).error)||void 0===n||n.call(s,i)},this.socket.onmessage=({data:t})=>{var s,n,i,a,c,h,d,u,m,p,f,g,w,y,k;const S=JSON.parse(t.toString());if("error"in S){const e=new v(S.error);if("error_code"in S&&(e.code=S.error_code),!o){const t=e;return t.retryable=void 0===e.code||x(e.code),void l(t)}null===(n=(s=this.listeners).error)||void 0===n||n.call(s,e)}else{switch(S.type){case"Begin":b=S,o||(o=!0,r&&clearTimeout(r),e(b)),null===(a=(i=this.listeners).open)||void 0===a||a.call(i,S);break;case"Turn":if(this.isDualChannel&&this.timeline&&this.attributionParams)switch(_(S,this.timeline,{dominanceRatio:this.attributionParams.dominanceRatio}),this.attributionParams.resolveUnknownChannelsMethod){case"window":this.resolveUnknownChannelsByWindow(S);break;case"speaker-history":this.resolveUnknownChannelsBySpeakerHistory(S)}null===(h=(c=this.listeners).turn)||void 0===h||h.call(c,S);break;case"SpeechStarted":null===(u=(d=this.listeners).speechStarted)||void 0===u||u.call(d,S);break;case"LLMGatewayResponse":null===(p=(m=this.listeners).llmGatewayResponse)||void 0===p||p.call(m,S);break;case"SpeakerRevision":null===(g=(f=this.listeners).speakerRevision)||void 0===g||g.call(f,S);break;case"Warning":{const e=S;console.warn(`Streaming warning (code=${e.warning_code}): ${e.warning}`),null===(y=(w=this.listeners).warning)||void 0===y||y.call(w,e);break}case"Termination":null===(k=this.sessionTerminatedResolve)||void 0===k||k.call(this)}var b}}}))}discardPendingSocket(){if(this.socket){try{this.socket.removeAllListeners&&this.socket.removeAllListeners(),this.socket.close()}catch(e){}this.socket=void 0}}stream(){return new n({write:e=>{this.sendAudio(e)}})}sendAudio(e,t){if(this.isDualChannel){if(!(null==t?void 0:t.channel))throw new Error("StreamingTranscriber is in dual-channel mode; sendAudio requires { channel }.");if(!this.channelNames.includes(t.channel))throw new Error(`Unknown channel "${t.channel}"; declared channels: ${this.channelNames.join(", ")}.`);this.ingestChannelAudio(t.channel,e)}else this.send(e)}ingestChannelAudio(e,t){var s,n;const i=function(e){if(e instanceof Int16Array)return e;if(ArrayBuffer.isView(e)){const t=e;return new Int16Array(t.buffer,t.byteOffset,Math.floor(t.byteLength/2))}return new Int16Array(e)}(t),r=this.channelBuffers.get(e),o=this.channelVadFloatBuffers.get(e);let a=this.channelVadBufferIdx.get(e),l=this.channelSamplesReceived.get(e);const c=this.channelVads.get(e),h=this.params.sampleRate,d=this.vadFrameSamples;for(let t=0;t<i.length;t++){const u=i[t];if(r.push(u),o[a++]=u/32768,l++,a===d){const t=c.process(o),i={ts:l/h*1e3,channel:e,active:t.active,rms:t.energy};this.timeline.pushFrame(i),null===(n=(s=this.listeners).vad)||void 0===n||n.call(s,i),a=0}}this.channelVadBufferIdx.set(e,a),this.channelSamplesReceived.set(e,l),this.flushTimer||this.startFlushTimer()}startFlushTimer(){this.flushTimer=setInterval((()=>this.flushMix()),this.attributionParams.flushIntervalMs)}flushMix(e=!1){var t,s;if(!this.channelNames||!this.channelBuffers)return;const n=this.channelNames.map((e=>this.channelBuffers.get(e))),i=n.length;for(;;){let r=1/0;for(const e of n)e.length<r&&(r=e.length);if(!Number.isFinite(r)||0===r)return;if(!e&&r<this.minChunkSamples)return;r>this.maxChunkSamples&&(r=this.maxChunkSamples);const o=new Int16Array(r);for(let e=0;e<r;e++){let t=0;for(let s=0;s<i;s++)t+=n[s][e];const s=Math.round(t/i);o[e]=s<-32768?-32768:s>32767?32767:s}for(const e of n)e.splice(0,r);try{this.send(o.buffer)}catch(e){return void(null===(s=(t=this.listeners).error)||void 0===s||s.call(t,e))}}}resolveUnknownChannelsByWindow(e){var t;if(!this.attributionParams)return;const s=this.attributionParams.resolutionWindowWords,n=e.words;let i=!1;for(let e=0;e<n.length;e++){if("unknown"!==n[e].channel)continue;const r=new Map,o=Math.max(0,e-s),a=Math.min(n.length-1,e+s);for(let s=o;s<=a;s++){if(s===e)continue;const i=n[s].channel;i&&"unknown"!==i&&r.set(i,(null!==(t=r.get(i))&&void 0!==t?t:0)+1)}if(0===r.size)continue;let l,c=0,h=!1;for(const[e,t]of r)t>c?(l=e,c=t,h=!1):t===c&&(h=!0);l&&!h&&(n[e].channel=l,n[e].channelResolved=!0,i=!0)}i&&(e.channel=b(n))}resolveUnknownChannelsBySpeakerHistory(e){var t;if(!this.timeline||!this.attributionParams||!this.speakerHistory)return;const s=this.attributionParams.speakerHistoryMinRmsEvidence,n=this.attributionParams.speakerHistoryDominanceRatio;for(const s of e.words){if(!s.speaker)continue;const e=this.timeline.framesInWindow(s.start,s.end);let n=this.speakerHistory.get(s.speaker);n||(n=new Map,this.speakerHistory.set(s.speaker,n));for(const s of e)s.active&&n.set(s.channel,(null!==(t=n.get(s.channel))&&void 0!==t?t:0)+s.rms)}let i=!1;for(const t of e.words){if("unknown"!==t.channel||!t.speaker)continue;const e=this.speakerHistory.get(t.speaker);if(!e||0===e.size)continue;let r,o=0,a=0,l=0;for(const[t,s]of e)o+=s,s>a?(l=a,a=s,r=t):s>l&&(l=s);o<s||(l>0&&a<n*l||r&&(t.channel=r,t.channelResolved=!0,i=!0))}i&&(e.channel=b(e.words))}updateConfiguration(e){const{min_end_of_turn_silence_when_confident:t,min_turn_silence:s}=e,n=function(e,t){var s={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(s[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(n=Object.getOwnPropertySymbols(e);i<n.length;i++)t.indexOf(n[i])<0&&Object.prototype.propertyIsEnumerable.call(e,n[i])&&(s[n[i]]=e[n[i]])}return s}(e,["min_end_of_turn_silence_when_confident","min_turn_silence"]);void 0!==t&&(void 0!==s?console.warn("[Deprecation Warning] Both `min_end_of_turn_silence_when_confident` and `min_turn_silence` are set. Using `min_turn_silence`; `min_end_of_turn_silence_when_confident` is deprecated."):console.warn("[Deprecation Warning] `min_end_of_turn_silence_when_confident` is deprecated and will be removed in a future release. Please use `min_turn_silence` instead."));const i=null!=s?s:t,r=Object.assign(Object.assign({type:"UpdateConfiguration"},n),void 0!==i?{min_turn_silence:i}:{});this.send(JSON.stringify(r))}forceEndpoint(){this.send(JSON.stringify({type:"ForceEndpoint"}))}keepAlive(){this.send(JSON.stringify({type:"KeepAlive"}))}send(e){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("Socket is not open for communication");this.socket.send(e)}close(){return s(this,arguments,void 0,(function*(e=!0){var t;if(this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=void 0,this.flushMix(!0)),this.socket){if(this.socket.readyState===this.socket.OPEN)if(e){const e=new Promise((e=>{this.sessionTerminatedResolve=e}));this.socket.send(T),yield e}else this.socket.send(T);(null===(t=this.socket)||void 0===t?void 0:t.removeAllListeners)&&this.socket.removeAllListeners(),this.socket.close()}this.listeners={},this.socket=void 0}))}}const R={cache:"no-store"};let E="";"undefined"!=typeof navigator&&navigator.userAgent&&(E+=navigator.userAgent);const O={sdk:{name:"JavaScript",version:"4.35.3"}};"undefined"!=typeof process&&(process.versions.node&&-1===E.indexOf("Node")&&(O.runtime_env={name:"Node",version:process.versions.node}),process.versions.bun&&-1===E.indexOf("Bun")&&(O.runtime_env={name:"Bun",version:process.versions.bun})),"undefined"!=typeof Deno&&process.versions.bun&&-1===E.indexOf("Deno")&&(O.runtime_env={name:"Deno",version:Deno.version.deno});class M{constructor(e){var t;this.params=e,!1===e.userAgent?this.userAgent=void 0:this.userAgent=(t=e.userAgent||{},E+(!1===t?"":" AssemblyAI/1.0 ("+Object.entries(Object.assign(Object.assign({},O),t)).map((([e,t])=>t?`${e}=${t.name}/${t.version}`:"")).join(" ")+")"))}fetch(e,t){return s(this,void 0,void 0,(function*(){t=Object.assign(Object.assign({},R),t);let s={Authorization:this.params.apiKey,"Content-Type":"application/json"};(null==R?void 0:R.headers)&&(s=Object.assign(Object.assign({},s),R.headers)),(null==t?void 0:t.headers)&&(s=Object.assign(Object.assign({},s),t.headers)),this.userAgent&&(s["User-Agent"]=this.userAgent,"undefined"!=typeof window&&"chrome"in window&&(s["AssemblyAI-Agent"]=this.userAgent)),t.headers=s,e.startsWith("http")||(e=this.params.baseUrl+e);const n=yield fetch(e,t);if(n.status>=400){let e;const t=yield n.text();if(t){try{e=JSON.parse(t)}catch(e){}if(null==e?void 0:e.error)throw new Error(e.error);throw new Error(t)}throw new Error(`HTTP Error: ${n.status} ${n.statusText}`)}return n}))}fetchJson(e,t){return s(this,void 0,void 0,(function*(){return(yield this.fetch(e,t)).json()}))}}class C extends M{constructor(e){super(e),this.baseServiceParams=e}transcriber(e){const t=Object.assign({},e);return t.token||t.apiKey||(t.apiKey=this.baseServiceParams.apiKey),new P(t)}createTemporaryToken(e){return s(this,void 0,void 0,(function*(){const t=new URLSearchParams;Object.entries(e).forEach((([e,s])=>{null!=s&&t.append(e,String(s))}));const s=t.toString(),n=s?`/v3/token?${s}`:"/v3/token";return(yield this.fetchJson(n,{method:"GET"})).token}))}}e.BrowserOnlyError=t,e.DualChannelCapture=class{constructor(e){var s;if(this.running=!1,void 0===globalThis.AudioContext)throw new t;this.params={micStream:e.micStream,systemStream:e.systemStream,transcriber:e.transcriber,targetSampleRate:null!==(s=e.targetSampleRate)&&void 0!==s?s:16e3}}on(e,t){"error"===e&&(this.errorListener=t)}start(){return s(this,void 0,void 0,(function*(){if(this.running)throw new Error("DualChannelCapture already started");this.context=new AudioContext;const e=new Blob(['\nclass Pcm16EncoderProcessor extends AudioWorkletProcessor {\n constructor(options) {\n super();\n const opts = (options && options.processorOptions) || {};\n this.targetRate = opts.targetRate || 16000;\n this.chunkMs = opts.chunkMs || 50;\n this.ratio = sampleRate / this.targetRate;\n this.chunkSize = Math.round(this.targetRate * this.chunkMs / 1000);\n this.buffer = new Int16Array(this.chunkSize);\n this.bufferIdx = 0;\n this.samplesSent = 0;\n this.lastSample = 0;\n this.fractional = 0;\n }\n\n process(inputs) {\n const input = inputs[0];\n if (!input || input.length === 0 || !input[0] || input[0].length === 0) {\n return true;\n }\n const mono = input[0];\n let pos = this.fractional;\n while (pos < mono.length) {\n const i = Math.floor(pos);\n const frac = pos - i;\n const a = i === 0 ? this.lastSample : mono[i - 1];\n const b = mono[i];\n const sample = a + (b - a) * frac;\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n this.buffer[this.bufferIdx++] = clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff;\n if (this.bufferIdx === this.chunkSize) {\n const out = new Int16Array(this.chunkSize);\n out.set(this.buffer);\n this.samplesSent += this.chunkSize;\n this.port.postMessage(\n { pcm: out.buffer, samplesSent: this.samplesSent },\n [out.buffer],\n );\n this.bufferIdx = 0;\n }\n pos += this.ratio;\n }\n this.lastSample = mono[mono.length - 1];\n this.fractional = pos - mono.length;\n return true;\n }\n}\nregisterProcessor("aai-pcm16-encoder", Pcm16EncoderProcessor);\n'],{type:"application/javascript"}),t=URL.createObjectURL(e);try{yield this.context.audioWorklet.addModule(t)}finally{URL.revokeObjectURL(t)}this.micSource=this.context.createMediaStreamSource(this.params.micStream),this.sysSource=this.context.createMediaStreamSource(this.params.systemStream),this.micEncoder=this.makeEncoder("mic"),this.sysEncoder=this.makeEncoder("system"),this.micSource.connect(this.micEncoder),this.sysSource.connect(this.sysEncoder),this.running=!0}))}makeEncoder(e){const t=new AudioWorkletNode(this.context,"aai-pcm16-encoder",{numberOfInputs:1,numberOfOutputs:0,channelCount:1,channelCountMode:"explicit",channelInterpretation:"speakers",processorOptions:{targetRate:this.params.targetSampleRate,chunkMs:50}});return t.port.onmessage=t=>{var s;try{this.params.transcriber.sendAudio(t.data.pcm,{channel:e})}catch(e){null===(s=this.errorListener)||void 0===s||s.call(this,e)}},t}stop(){return s(this,void 0,void 0,(function*(){var e,t,s,n,i,r;if(this.running){this.running=!1;try{null===(e=this.micEncoder)||void 0===e||e.port.close(),null===(t=this.sysEncoder)||void 0===t||t.port.close(),null===(s=this.micEncoder)||void 0===s||s.disconnect(),null===(n=this.sysEncoder)||void 0===n||n.disconnect(),null===(i=this.micSource)||void 0===i||i.disconnect(),null===(r=this.sysSource)||void 0===r||r.disconnect()}catch(e){}this.context&&"closed"!==this.context.state&&(yield this.context.close()),this.context=void 0,this.micSource=void 0,this.sysSource=void 0,this.micEncoder=void 0,this.sysEncoder=void 0}}))}},e.EnergyVad=y,e.LinearResampler=class{constructor(e,t){if(this.sourceRate=e,this.targetRate=t,this.lastSample=0,this.fractional=0,e<=0||t<=0)throw new Error("sourceRate and targetRate must be positive");this.ratio=e/t}process(e){var t;if(this.sourceRate===this.targetRate)return e;const s=new Float32Array(Math.ceil(e.length/this.ratio)+1);let n=0,i=this.fractional;for(;i<e.length;){const t=Math.floor(i),r=i-t,o=0===t?this.lastSample:e[t-1],a=e[t];s[n++]=o+(a-o)*r,i+=this.ratio}return this.lastSample=null!==(t=e[e.length-1])&&void 0!==t?t:this.lastSample,this.fractional=i-e.length,s.subarray(0,n)}reset(){this.lastSample=0,this.fractional=0}},e.RealtimeService=class extends w{},e.RealtimeTranscriber=w,e.StreamingServiceFactory=class extends C{},e.StreamingTranscriber=P,e.StreamingTranscriberFactory=C,e.VadTimeline=k,e.attributeTurn=_,e.attributeWord=S,e.float32ToPcm16=function(e){const t=new ArrayBuffer(2*e.length),s=new DataView(t);for(let t=0;t<e.length;t++){const n=Math.max(-1,Math.min(1,e[t]));s.setInt16(2*t,n<0?32768*n:32767*n,!0)}return t},e.rollUpTurnChannel=b}));
|