assemblyai 4.5.0-beta.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +53 -9
  3. package/dist/assemblyai.streaming.umd.js +288 -0
  4. package/dist/assemblyai.streaming.umd.min.js +1 -0
  5. package/dist/assemblyai.umd.js +131 -12
  6. package/dist/assemblyai.umd.min.js +1 -1
  7. package/dist/browser.mjs +125 -11
  8. package/dist/bun.mjs +125 -11
  9. package/dist/deno.mjs +125 -11
  10. package/dist/exports/index.d.ts +2 -0
  11. package/dist/exports/streaming.d.ts +4 -0
  12. package/dist/index.cjs +131 -12
  13. package/dist/index.mjs +131 -12
  14. package/dist/node.cjs +125 -11
  15. package/dist/node.mjs +125 -11
  16. package/dist/polyfills/fetch/default.d.ts +1 -0
  17. package/dist/polyfills/fetch/workerd.d.ts +1 -0
  18. package/dist/services/base.d.ts +1 -0
  19. package/dist/services/lemur/index.d.ts +8 -1
  20. package/dist/services/transcripts/index.d.ts +16 -3
  21. package/dist/streaming.browser.mjs +239 -0
  22. package/dist/streaming.cjs +277 -0
  23. package/dist/streaming.mjs +274 -0
  24. package/dist/types/index.d.ts +7 -0
  25. package/dist/types/openapi.generated.d.ts +60 -23
  26. package/dist/types/services/index.d.ts +7 -0
  27. package/dist/types/transcripts/index.d.ts +9 -0
  28. package/dist/utils/userAgent.d.ts +2 -0
  29. package/dist/workerd.mjs +722 -0
  30. package/docs/reference-types-from-js.md +27 -0
  31. package/package.json +39 -19
  32. package/src/exports/index.ts +2 -0
  33. package/src/exports/streaming.ts +4 -0
  34. package/src/polyfills/fetch/default.ts +3 -0
  35. package/src/polyfills/fetch/workerd.ts +1 -0
  36. package/src/services/base.ts +27 -7
  37. package/src/services/files/index.ts +19 -2
  38. package/src/services/index.ts +2 -1
  39. package/src/services/lemur/index.ts +12 -0
  40. package/src/services/transcripts/index.ts +41 -4
  41. package/src/types/index.ts +9 -0
  42. package/src/types/openapi.generated.ts +198 -41
  43. package/src/types/services/index.ts +8 -0
  44. package/src/types/transcripts/index.ts +10 -0
  45. package/src/utils/path.ts +1 -0
  46. package/src/utils/userAgent.ts +51 -0
package/CHANGELOG.md CHANGED
@@ -1,7 +1,41 @@
1
1
  # Changelog
2
+
2
3
  ## [4.5.0]
3
4
 
5
+ - You can now retrieve previous LeMUR responses using `client.lemur.getResponse<LemurTask>("YOUR_REQUEST_ID")`.
6
+ - LeMUR functions now return `usage` with the number of `input_tokens` and `output_tokens`.
7
+
8
+ ## [4.4.7]
9
+
10
+ - Rename `TranscriptService.redactions` function to `TranscriptService.redactedAudio`.
11
+ - Add `TranscriptService.redactedAudioFile` function.
12
+ - Add `workerd` export to fix `cache` issue with `fetch` on Cloudflare Workers.
13
+
14
+ ## [4.4.6]
15
+
16
+ - Fix Rollup exports so \_\_SDK_VERSION\_\_ is properly replaced with the version of the SDK.
17
+
18
+ ## [4.4.5]
19
+
20
+ - Add new `PiiPolicy` enum values
21
+
22
+ ## [4.4.4]
23
+
24
+ - Add an export that only includes the Streaming STT code. You can use the export
25
+ - by importing `assemblyai/streaming`,
26
+ - or by loading the `assemblyai.streaming.umd.js` file, or `assemblyai.streaming.umd.min.js` file in a script-tag.
27
+ - Add new `EntityType` enum values
28
+
29
+ ## [4.4.3] - 2024-05-09
30
+
31
+ - Add react-native exports that resolve to the browser version of the library.
32
+
33
+ ## [4.4.2] - 2024-05-03
34
+
4
35
  ### Changed
36
+
37
+ - Caching is disabled for all HTTP request made by the SDK
38
+ - Accept data-URIs in `client.files.upload(dataUri)`, `client.transcripts.submit(audio: dataUri)`, `client.transcripts.transcribe(audio: dataUri)`.
5
39
  - Change how the WebSocket libraries are imported for better compatibility across frameworks and runtimes.
6
40
  The library no longer relies on a internal `#ws` import, and instead compiles the imports into the dist bundles.
7
41
  Browser builds will use the native `WebSocket`, other builds will use the `ws` package.
package/README.md CHANGED
@@ -53,6 +53,38 @@ const client = new AssemblyAI({
53
53
 
54
54
  You can now use the `client` object to interact with the AssemblyAI API.
55
55
 
56
+ ### Using a CDN
57
+
58
+ You can use automatic CDNs like [UNPKG](https://unpkg.com/) to load the library from a script tag.
59
+
60
+ - Replace `:version` with the desired version or `latest`.
61
+ - Remove `.min` to load the non-minified version.
62
+ - Remove `.streaming` to load the entire SDK. Keep `.streaming` to load the Streaming STT specific version.
63
+
64
+ ```html
65
+ <!-- Unminified full SDK -->
66
+ <script src="https://www.unpkg.com/assemblyai@:version/dist/assemblyai.umd.js"></script>
67
+ <!-- Minified full SDK -->
68
+ <script src="https://www.unpkg.com/assemblyai@:version/dist/assemblyai.umd.min.js"></script>
69
+ <!-- Unminified Streaming STT only -->
70
+ <script src="https://www.unpkg.com/assemblyai@:version/dist/assemblyai.streaming.umd.js"></script>
71
+ <!-- Minified Streaming STT only -->
72
+ <script src="https://www.unpkg.com/assemblyai@:version/dist/assemblyai.streaming.umd.min.js"></script>
73
+ ```
74
+
75
+ The script creates a global `assemblyai` variable containing all the services.
76
+ Here's how you create a `RealtimeTranscriber` object.
77
+
78
+ ```js
79
+ const { RealtimeTranscriber } = assemblyai;
80
+ const transcriber = new RealtimeTranscriber({
81
+ token: "[GENERATE TEMPORARY AUTH TOKEN IN YOUR API]",
82
+ ...
83
+ });
84
+ ```
85
+
86
+ For type support in your IDE, see [Reference types from JavaScript](./docs/reference-types-from-js.md).
87
+
56
88
  ## Speech-To-Text
57
89
 
58
90
  ### Transcribe audio and video files
@@ -227,18 +259,26 @@ const rt = client.realtime.transcriber({
227
259
  });
228
260
  ```
229
261
 
230
- You can also generate a temporary auth token for real-time.
231
-
232
- ```typescript
233
- const token = await client.realtime.createTemporaryToken({ expires_in = 60 });
234
- const rt = client.realtime.transcriber({
235
- token: token,
236
- });
237
- ```
238
-
239
262
  > [!WARNING]
240
263
  > Storing your API key in client-facing applications exposes your API key.
241
264
  > Generate a temporary auth token on the server and pass it to your client.
265
+ > _Server code_:
266
+ >
267
+ > ```typescript
268
+ > const token = await client.realtime.createTemporaryToken({ expires_in = 60 });
269
+ > // TODO: return token to client
270
+ > ```
271
+ >
272
+ > _Client code_:
273
+ >
274
+ > ```typescript
275
+ > import { RealtimeTranscriber } from "assemblyai"; // or "assemblyai/streaming"
276
+ > // TODO: implement getToken to retrieve token from server
277
+ > const token = await getToken();
278
+ > const rt = new RealtimeTranscriber({
279
+ > token,
280
+ > });
281
+ > ```
242
282
 
243
283
  You can configure the following events.
244
284
 
@@ -344,3 +384,7 @@ const response = await client.lemur.purgeRequestData(lemurResponse.request_id);
344
384
  ```
345
385
 
346
386
  </details>
387
+
388
+ ## Contributing
389
+
390
+ If you want to contribute to the JavaScript SDK, follow the guidelines in [CONTRIBUTING.md](./CONTRIBUTING.md).
@@ -0,0 +1,288 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.assemblyai = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /******************************************************************************
8
+ Copyright (c) Microsoft Corporation.
9
+
10
+ Permission to use, copy, modify, and/or distribute this software for any
11
+ purpose with or without fee is hereby granted.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
14
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
16
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
18
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19
+ PERFORMANCE OF THIS SOFTWARE.
20
+ ***************************************************************************** */
21
+ /* global Reflect, Promise, SuppressedError, Symbol */
22
+
23
+
24
+ function __awaiter(thisArg, _arguments, P, generator) {
25
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
26
+ return new (P || (P = Promise))(function (resolve, reject) {
27
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
28
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
29
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
30
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
31
+ });
32
+ }
33
+
34
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
35
+ var e = new Error(message);
36
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
37
+ };
38
+
39
+ const { WritableStream } = typeof window !== "undefined"
40
+ ? window
41
+ : typeof global !== "undefined"
42
+ ? global
43
+ : globalThis;
44
+
45
+ var _a, _b;
46
+ const PolyfillWebSocket = (_b = (_a = WebSocket !== null && WebSocket !== void 0 ? WebSocket : global === null || global === void 0 ? void 0 : global.WebSocket) !== null && _a !== void 0 ? _a : window === null || window === void 0 ? void 0 : window.WebSocket) !== null && _b !== void 0 ? _b : self === null || self === void 0 ? void 0 : self.WebSocket;
47
+ const factory = (url, params) => {
48
+ if (params) {
49
+ return new PolyfillWebSocket(url, params);
50
+ }
51
+ return new PolyfillWebSocket(url);
52
+ };
53
+
54
+ var RealtimeErrorType;
55
+ (function (RealtimeErrorType) {
56
+ RealtimeErrorType[RealtimeErrorType["BadSampleRate"] = 4000] = "BadSampleRate";
57
+ RealtimeErrorType[RealtimeErrorType["AuthFailed"] = 4001] = "AuthFailed";
58
+ // Both InsufficientFunds and FreeAccount error use 4002
59
+ RealtimeErrorType[RealtimeErrorType["InsufficientFundsOrFreeAccount"] = 4002] = "InsufficientFundsOrFreeAccount";
60
+ RealtimeErrorType[RealtimeErrorType["NonexistentSessionId"] = 4004] = "NonexistentSessionId";
61
+ RealtimeErrorType[RealtimeErrorType["SessionExpired"] = 4008] = "SessionExpired";
62
+ RealtimeErrorType[RealtimeErrorType["ClosedSession"] = 4010] = "ClosedSession";
63
+ RealtimeErrorType[RealtimeErrorType["RateLimited"] = 4029] = "RateLimited";
64
+ RealtimeErrorType[RealtimeErrorType["UniqueSessionViolation"] = 4030] = "UniqueSessionViolation";
65
+ RealtimeErrorType[RealtimeErrorType["SessionTimeout"] = 4031] = "SessionTimeout";
66
+ RealtimeErrorType[RealtimeErrorType["AudioTooShort"] = 4032] = "AudioTooShort";
67
+ RealtimeErrorType[RealtimeErrorType["AudioTooLong"] = 4033] = "AudioTooLong";
68
+ RealtimeErrorType[RealtimeErrorType["BadJson"] = 4100] = "BadJson";
69
+ RealtimeErrorType[RealtimeErrorType["BadSchema"] = 4101] = "BadSchema";
70
+ RealtimeErrorType[RealtimeErrorType["TooManyStreams"] = 4102] = "TooManyStreams";
71
+ RealtimeErrorType[RealtimeErrorType["Reconnected"] = 4103] = "Reconnected";
72
+ RealtimeErrorType[RealtimeErrorType["ReconnectAttemptsExhausted"] = 1013] = "ReconnectAttemptsExhausted";
73
+ })(RealtimeErrorType || (RealtimeErrorType = {}));
74
+ const RealtimeErrorMessages = {
75
+ [RealtimeErrorType.BadSampleRate]: "Sample rate must be a positive integer",
76
+ [RealtimeErrorType.AuthFailed]: "Not Authorized",
77
+ [RealtimeErrorType.InsufficientFundsOrFreeAccount]: "Insufficient funds or you are using a free account. This feature is paid-only and requires you to add a credit card. Please visit https://assemblyai.com/dashboard/ to add a credit card to your account.",
78
+ [RealtimeErrorType.NonexistentSessionId]: "Session ID does not exist",
79
+ [RealtimeErrorType.SessionExpired]: "Session has expired",
80
+ [RealtimeErrorType.ClosedSession]: "Session is closed",
81
+ [RealtimeErrorType.RateLimited]: "Rate limited",
82
+ [RealtimeErrorType.UniqueSessionViolation]: "Unique session violation",
83
+ [RealtimeErrorType.SessionTimeout]: "Session Timeout",
84
+ [RealtimeErrorType.AudioTooShort]: "Audio too short",
85
+ [RealtimeErrorType.AudioTooLong]: "Audio too long",
86
+ [RealtimeErrorType.BadJson]: "Bad JSON",
87
+ [RealtimeErrorType.BadSchema]: "Bad schema",
88
+ [RealtimeErrorType.TooManyStreams]: "Too many streams",
89
+ [RealtimeErrorType.Reconnected]: "Reconnected",
90
+ [RealtimeErrorType.ReconnectAttemptsExhausted]: "Reconnect attempts exhausted",
91
+ };
92
+ class RealtimeError extends Error {
93
+ }
94
+
95
+ const defaultRealtimeUrl = "wss://api.assemblyai.com/v2/realtime/ws";
96
+ const forceEndOfUtteranceMessage = `{"force_end_utterance":true}`;
97
+ const terminateSessionMessage = `{"terminate_session":true}`;
98
+ class RealtimeTranscriber {
99
+ constructor(params) {
100
+ var _a, _b;
101
+ this.listeners = {};
102
+ this.realtimeUrl = (_a = params.realtimeUrl) !== null && _a !== void 0 ? _a : defaultRealtimeUrl;
103
+ this.sampleRate = (_b = params.sampleRate) !== null && _b !== void 0 ? _b : 16000;
104
+ this.wordBoost = params.wordBoost;
105
+ this.encoding = params.encoding;
106
+ this.endUtteranceSilenceThreshold = params.endUtteranceSilenceThreshold;
107
+ this.disablePartialTranscripts = params.disablePartialTranscripts;
108
+ if ("token" in params && params.token)
109
+ this.token = params.token;
110
+ if ("apiKey" in params && params.apiKey)
111
+ this.apiKey = params.apiKey;
112
+ if (!(this.token || this.apiKey)) {
113
+ throw new Error("API key or temporary token is required.");
114
+ }
115
+ }
116
+ connectionUrl() {
117
+ const url = new URL(this.realtimeUrl);
118
+ if (url.protocol !== "wss:") {
119
+ throw new Error("Invalid protocol, must be wss");
120
+ }
121
+ const searchParams = new URLSearchParams();
122
+ if (this.token) {
123
+ searchParams.set("token", this.token);
124
+ }
125
+ searchParams.set("sample_rate", this.sampleRate.toString());
126
+ if (this.wordBoost && this.wordBoost.length > 0) {
127
+ searchParams.set("word_boost", JSON.stringify(this.wordBoost));
128
+ }
129
+ if (this.encoding) {
130
+ searchParams.set("encoding", this.encoding);
131
+ }
132
+ searchParams.set("enable_extra_session_information", "true");
133
+ if (this.disablePartialTranscripts) {
134
+ searchParams.set("disable_partial_transcripts", this.disablePartialTranscripts.toString());
135
+ }
136
+ url.search = searchParams.toString();
137
+ return url;
138
+ }
139
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
140
+ on(event, listener) {
141
+ this.listeners[event] = listener;
142
+ }
143
+ connect() {
144
+ return new Promise((resolve) => {
145
+ if (this.socket) {
146
+ throw new Error("Already connected");
147
+ }
148
+ const url = this.connectionUrl();
149
+ if (this.token) {
150
+ this.socket = factory(url.toString());
151
+ }
152
+ else {
153
+ this.socket = factory(url.toString(), {
154
+ headers: { Authorization: this.apiKey },
155
+ });
156
+ }
157
+ this.socket.binaryType = "arraybuffer";
158
+ this.socket.onopen = () => {
159
+ if (this.endUtteranceSilenceThreshold === undefined ||
160
+ this.endUtteranceSilenceThreshold === null) {
161
+ return;
162
+ }
163
+ this.configureEndUtteranceSilenceThreshold(this.endUtteranceSilenceThreshold);
164
+ };
165
+ this.socket.onclose = ({ code, reason }) => {
166
+ var _a, _b;
167
+ if (!reason) {
168
+ if (code in RealtimeErrorType) {
169
+ reason = RealtimeErrorMessages[code];
170
+ }
171
+ }
172
+ (_b = (_a = this.listeners).close) === null || _b === void 0 ? void 0 : _b.call(_a, code, reason);
173
+ };
174
+ this.socket.onerror = (event) => {
175
+ var _a, _b, _c, _d;
176
+ if (event.error)
177
+ (_b = (_a = this.listeners).error) === null || _b === void 0 ? void 0 : _b.call(_a, event.error);
178
+ else
179
+ (_d = (_c = this.listeners).error) === null || _d === void 0 ? void 0 : _d.call(_c, new Error(event.message));
180
+ };
181
+ this.socket.onmessage = ({ data }) => {
182
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
183
+ const message = JSON.parse(data.toString());
184
+ if ("error" in message) {
185
+ (_b = (_a = this.listeners).error) === null || _b === void 0 ? void 0 : _b.call(_a, new RealtimeError(message.error));
186
+ return;
187
+ }
188
+ switch (message.message_type) {
189
+ case "SessionBegins": {
190
+ const openObject = {
191
+ sessionId: message.session_id,
192
+ expiresAt: new Date(message.expires_at),
193
+ };
194
+ resolve(openObject);
195
+ (_d = (_c = this.listeners).open) === null || _d === void 0 ? void 0 : _d.call(_c, openObject);
196
+ break;
197
+ }
198
+ case "PartialTranscript": {
199
+ // message.created is actually a string when coming from the socket
200
+ message.created = new Date(message.created);
201
+ (_f = (_e = this.listeners).transcript) === null || _f === void 0 ? void 0 : _f.call(_e, message);
202
+ (_h = (_g = this.listeners)["transcript.partial"]) === null || _h === void 0 ? void 0 : _h.call(_g, message);
203
+ break;
204
+ }
205
+ case "FinalTranscript": {
206
+ // message.created is actually a string when coming from the socket
207
+ message.created = new Date(message.created);
208
+ (_k = (_j = this.listeners).transcript) === null || _k === void 0 ? void 0 : _k.call(_j, message);
209
+ (_m = (_l = this.listeners)["transcript.final"]) === null || _m === void 0 ? void 0 : _m.call(_l, message);
210
+ break;
211
+ }
212
+ case "SessionInformation": {
213
+ (_p = (_o = this.listeners).session_information) === null || _p === void 0 ? void 0 : _p.call(_o, message);
214
+ break;
215
+ }
216
+ case "SessionTerminated": {
217
+ (_q = this.sessionTerminatedResolve) === null || _q === void 0 ? void 0 : _q.call(this);
218
+ break;
219
+ }
220
+ }
221
+ };
222
+ });
223
+ }
224
+ sendAudio(audio) {
225
+ this.send(audio);
226
+ }
227
+ stream() {
228
+ return new WritableStream({
229
+ write: (chunk) => {
230
+ this.sendAudio(chunk);
231
+ },
232
+ });
233
+ }
234
+ /**
235
+ * Manually end an utterance
236
+ */
237
+ forceEndUtterance() {
238
+ this.send(forceEndOfUtteranceMessage);
239
+ }
240
+ /**
241
+ * Configure the threshold for how long to wait before ending an utterance. Default is 700ms.
242
+ * @param threshold - The duration of the end utterance silence threshold in milliseconds.
243
+ * This value must be an integer between 0 and 20_000.
244
+ */
245
+ configureEndUtteranceSilenceThreshold(threshold) {
246
+ this.send(`{"end_utterance_silence_threshold":${threshold}}`);
247
+ }
248
+ send(data) {
249
+ if (!this.socket || this.socket.readyState !== this.socket.OPEN) {
250
+ throw new Error("Socket is not open for communication");
251
+ }
252
+ this.socket.send(data);
253
+ }
254
+ close() {
255
+ return __awaiter(this, arguments, void 0, function* (waitForSessionTermination = true) {
256
+ var _a;
257
+ if (this.socket) {
258
+ if (this.socket.readyState === this.socket.OPEN) {
259
+ if (waitForSessionTermination) {
260
+ const sessionTerminatedPromise = new Promise((resolve) => {
261
+ this.sessionTerminatedResolve = resolve;
262
+ });
263
+ this.socket.send(terminateSessionMessage);
264
+ yield sessionTerminatedPromise;
265
+ }
266
+ else {
267
+ this.socket.send(terminateSessionMessage);
268
+ }
269
+ }
270
+ if ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.removeAllListeners)
271
+ this.socket.removeAllListeners();
272
+ this.socket.close();
273
+ }
274
+ this.listeners = {};
275
+ this.socket = undefined;
276
+ });
277
+ }
278
+ }
279
+ /**
280
+ * @deprecated Use RealtimeTranscriber instead
281
+ */
282
+ class RealtimeService extends RealtimeTranscriber {
283
+ }
284
+
285
+ exports.RealtimeService = RealtimeService;
286
+ exports.RealtimeTranscriber = RealtimeTranscriber;
287
+
288
+ }));
@@ -0,0 +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";function t(e,t,s,i){return new(s||(s=Promise))((function(o,n){function r(e){try{l(i.next(e))}catch(e){n(e)}}function a(e){try{l(i.throw(e))}catch(e){n(e)}}function l(e){var t;e.done?o(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(r,a)}l((i=i.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const{WritableStream:s}="undefined"!=typeof window?window:"undefined"!=typeof global?global:globalThis;var i,o;const n=null!==(o=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!==o?o:null===self||void 0===self?void 0:self.WebSocket,r=(e,t)=>t?new n(e,t):new n(e);var a;!function(e){e[e.BadSampleRate=4e3]="BadSampleRate",e[e.AuthFailed=4001]="AuthFailed",e[e.InsufficientFundsOrFreeAccount=4002]="InsufficientFundsOrFreeAccount",e[e.NonexistentSessionId=4004]="NonexistentSessionId",e[e.SessionExpired=4008]="SessionExpired",e[e.ClosedSession=4010]="ClosedSession",e[e.RateLimited=4029]="RateLimited",e[e.UniqueSessionViolation=4030]="UniqueSessionViolation",e[e.SessionTimeout=4031]="SessionTimeout",e[e.AudioTooShort=4032]="AudioTooShort",e[e.AudioTooLong=4033]="AudioTooLong",e[e.BadJson=4100]="BadJson",e[e.BadSchema=4101]="BadSchema",e[e.TooManyStreams=4102]="TooManyStreams",e[e.Reconnected=4103]="Reconnected",e[e.ReconnectAttemptsExhausted=1013]="ReconnectAttemptsExhausted"}(a||(a={}));const l={[a.BadSampleRate]:"Sample rate must be a positive integer",[a.AuthFailed]:"Not Authorized",[a.InsufficientFundsOrFreeAccount]:"Insufficient funds or you are using a free account. This feature is paid-only and requires you to add a credit card. Please visit https://assemblyai.com/dashboard/ to add a credit card to your account.",[a.NonexistentSessionId]:"Session ID does not exist",[a.SessionExpired]:"Session has expired",[a.ClosedSession]:"Session is closed",[a.RateLimited]:"Rate limited",[a.UniqueSessionViolation]:"Unique session violation",[a.SessionTimeout]:"Session Timeout",[a.AudioTooShort]:"Audio too short",[a.AudioTooLong]:"Audio too long",[a.BadJson]:"Bad JSON",[a.BadSchema]:"Bad schema",[a.TooManyStreams]:"Too many streams",[a.Reconnected]:"Reconnected",[a.ReconnectAttemptsExhausted]:"Reconnect attempts exhausted"};class c extends Error{}const d='{"terminate_session":true}';class h{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=r(t.toString()):this.socket=r(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,i;t||e in a&&(t=l[e]),null===(i=(s=this.listeners).close)||void 0===i||i.call(s,e,t)},this.socket.onerror=e=>{var t,s,i,o;e.error?null===(s=(t=this.listeners).error)||void 0===s||s.call(t,e.error):null===(o=(i=this.listeners).error)||void 0===o||o.call(i,new Error(e.message))},this.socket.onmessage=({data:t})=>{var s,i,o,n,r,a,l,d,h,u,p,m,S,f,v;const w=JSON.parse(t.toString());if("error"in w)null===(i=(s=this.listeners).error)||void 0===i||i.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===(n=(o=this.listeners).open)||void 0===n||n.call(o,t);break}case"PartialTranscript":w.created=new Date(w.created),null===(a=(r=this.listeners).transcript)||void 0===a||a.call(r,w),null===(d=(l=this.listeners)["transcript.partial"])||void 0===d||d.call(l,w);break;case"FinalTranscript":w.created=new Date(w.created),null===(u=(h=this.listeners).transcript)||void 0===u||u.call(h,w),null===(m=(p=this.listeners)["transcript.final"])||void 0===m||m.call(p,w);break;case"SessionInformation":null===(f=(S=this.listeners).session_information)||void 0===f||f.call(S,w);break;case"SessionTerminated":null===(v=this.sessionTerminatedResolve)||void 0===v||v.call(this)}}}))}sendAudio(e){this.send(e)}stream(){return new s({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 t(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(d),yield e}else this.socket.send(d);(null===(t=this.socket)||void 0===t?void 0:t.removeAllListeners)&&this.socket.removeAllListeners(),this.socket.close()}this.listeners={},this.socket=void 0}))}}e.RealtimeService=class extends h{},e.RealtimeTranscriber=h}));
@@ -48,6 +48,45 @@
48
48
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
49
49
  };
50
50
 
51
+ const DEFAULT_FETCH_INIT = {
52
+ cache: "no-store",
53
+ };
54
+
55
+ const buildUserAgent = (userAgent) => defaultUserAgentString +
56
+ (userAgent === false
57
+ ? ""
58
+ : " AssemblyAI/1.0 (" +
59
+ Object.entries(Object.assign(Object.assign({}, defaultUserAgent), userAgent))
60
+ .map(([key, item]) => item ? `${key}=${item.name}/${item.version}` : "")
61
+ .join(" ") +
62
+ ")");
63
+ let defaultUserAgentString = "";
64
+ if (typeof navigator !== "undefined" && navigator.userAgent) {
65
+ defaultUserAgentString += navigator.userAgent;
66
+ }
67
+ const defaultUserAgent = {
68
+ sdk: { name: "JavaScript", version: "4.5.0" },
69
+ };
70
+ if (typeof process !== "undefined") {
71
+ if (process.versions.node && defaultUserAgentString.indexOf("Node") === -1) {
72
+ defaultUserAgent.runtime_env = {
73
+ name: "Node",
74
+ version: process.versions.node,
75
+ };
76
+ }
77
+ if (process.versions.bun && defaultUserAgentString.indexOf("Bun") === -1) {
78
+ defaultUserAgent.runtime_env = {
79
+ name: "Bun",
80
+ version: process.versions.bun,
81
+ };
82
+ }
83
+ }
84
+ if (typeof Deno !== "undefined") {
85
+ if (process.versions.bun && defaultUserAgentString.indexOf("Deno") === -1) {
86
+ defaultUserAgent.runtime_env = { name: "Deno", version: Deno.version.deno };
87
+ }
88
+ }
89
+
51
90
  /**
52
91
  * Base class for services that communicate with the API.
53
92
  */
@@ -58,13 +97,33 @@
58
97
  */
59
98
  constructor(params) {
60
99
  this.params = params;
100
+ if (params.userAgent === false) {
101
+ this.userAgent = undefined;
102
+ }
103
+ else {
104
+ this.userAgent = buildUserAgent(params.userAgent || {});
105
+ }
61
106
  }
62
107
  fetch(input, init) {
63
108
  return __awaiter(this, void 0, void 0, function* () {
64
- var _a;
65
- init = init !== null && init !== void 0 ? init : {};
66
- init.headers = (_a = init.headers) !== null && _a !== void 0 ? _a : {};
67
- init.headers = Object.assign({ Authorization: this.params.apiKey, "Content-Type": "application/json" }, init.headers);
109
+ init = Object.assign(Object.assign({}, DEFAULT_FETCH_INIT), init);
110
+ let headers = {
111
+ Authorization: this.params.apiKey,
112
+ "Content-Type": "application/json",
113
+ };
114
+ if (DEFAULT_FETCH_INIT === null || DEFAULT_FETCH_INIT === void 0 ? void 0 : DEFAULT_FETCH_INIT.headers)
115
+ headers = Object.assign(Object.assign({}, headers), DEFAULT_FETCH_INIT.headers);
116
+ if (init === null || init === void 0 ? void 0 : init.headers)
117
+ headers = Object.assign(Object.assign({}, headers), init.headers);
118
+ if (this.userAgent) {
119
+ headers["User-Agent"] = this.userAgent;
120
+ // chromium browsers have a bug where the user agent can't be modified
121
+ if (typeof window !== "undefined" && "chrome" in window) {
122
+ headers["AssemblyAI-Agent"] =
123
+ this.userAgent;
124
+ }
125
+ }
126
+ init.headers = headers;
68
127
  if (!input.startsWith("http"))
69
128
  input = this.params.baseUrl + input;
70
129
  const response = yield fetch(input, init);
@@ -75,7 +134,7 @@
75
134
  try {
76
135
  json = JSON.parse(text);
77
136
  }
78
- catch (_b) {
137
+ catch (_a) {
79
138
  /* empty */
80
139
  }
81
140
  if (json === null || json === void 0 ? void 0 : json.error)
@@ -120,6 +179,9 @@
120
179
  body: JSON.stringify(params),
121
180
  });
122
181
  }
182
+ getResponse(id) {
183
+ return this.fetchJson(`/lemur/v3/${id}`);
184
+ }
123
185
  /**
124
186
  * Delete the data for a previously submitted LeMUR request.
125
187
  * @param id - ID of the LeMUR request
@@ -416,6 +478,8 @@
416
478
  return null;
417
479
  if (path.startsWith("https"))
418
480
  return null;
481
+ if (path.startsWith("data:"))
482
+ return null;
419
483
  if (path.startsWith("file://"))
420
484
  return path.substring(7);
421
485
  if (path.startsWith("file:"))
@@ -460,8 +524,13 @@
460
524
  audioUrl = yield this.files.upload(path);
461
525
  }
462
526
  else {
463
- // audio is not a local path, assume it's a URL
464
- audioUrl = audio;
527
+ if (audio.startsWith("data:")) {
528
+ audioUrl = yield this.files.upload(audio);
529
+ }
530
+ else {
531
+ // audio is not a local path, and not a data-URI, assume it's a normal URL
532
+ audioUrl = audio;
533
+ }
465
534
  }
466
535
  }
467
536
  else {
@@ -626,13 +695,45 @@
626
695
  });
627
696
  }
628
697
  /**
629
- * Retrieve redactions of a transcript.
698
+ * Retrieve the redacted audio URL of a transcript.
630
699
  * @param id - The identifier of the transcript.
631
- * @returns A promise that resolves to the subtitles text.
700
+ * @returns A promise that resolves to the details of the redacted audio.
701
+ * @deprecated Use `redactedAudio` instead.
632
702
  */
633
703
  redactions(id) {
704
+ return this.redactedAudio(id);
705
+ }
706
+ /**
707
+ * Retrieve the redacted audio URL of a transcript.
708
+ * @param id - The identifier of the transcript.
709
+ * @returns A promise that resolves to the details of the redacted audio.
710
+ */
711
+ redactedAudio(id) {
634
712
  return this.fetchJson(`/v2/transcript/${id}/redacted-audio`);
635
713
  }
714
+ /**
715
+ * Retrieve the redacted audio file of a transcript.
716
+ * @param id - The identifier of the transcript.
717
+ * @returns A promise that resolves to the fetch HTTP response of the redacted audio file.
718
+ */
719
+ redactedAudioFile(id) {
720
+ return __awaiter(this, void 0, void 0, function* () {
721
+ const { redacted_audio_url, status } = yield this.redactedAudio(id);
722
+ if (status !== "redacted_audio_ready") {
723
+ throw new Error(`Redacted audio status is ${status}`);
724
+ }
725
+ const response = yield fetch(redacted_audio_url);
726
+ if (!response.ok) {
727
+ throw new Error(`Failed to fetch redacted audio: ${response.statusText}`);
728
+ }
729
+ return {
730
+ arrayBuffer: response.arrayBuffer.bind(response),
731
+ blob: response.blob.bind(response),
732
+ body: response.body,
733
+ bodyUsed: response.bodyUsed,
734
+ };
735
+ });
736
+ }
636
737
  }
637
738
  function deprecateConformer2(params) {
638
739
  if (!params)
@@ -659,8 +760,14 @@
659
760
  upload(input) {
660
761
  return __awaiter(this, void 0, void 0, function* () {
661
762
  let fileData;
662
- if (typeof input === "string")
663
- fileData = yield readFile();
763
+ if (typeof input === "string") {
764
+ if (input.startsWith("data:")) {
765
+ fileData = dataUrlToBlob(input);
766
+ }
767
+ else {
768
+ fileData = yield readFile();
769
+ }
770
+ }
664
771
  else
665
772
  fileData = input;
666
773
  const data = yield this.fetchJson("/v2/upload", {
@@ -675,6 +782,17 @@
675
782
  });
676
783
  }
677
784
  }
785
+ function dataUrlToBlob(dataUrl) {
786
+ const arr = dataUrl.split(",");
787
+ const mime = arr[0].match(/:(.*?);/)[1];
788
+ const bstr = atob(arr[1]);
789
+ let n = bstr.length;
790
+ const u8arr = new Uint8Array(n);
791
+ while (n--) {
792
+ u8arr[n] = bstr.charCodeAt(n);
793
+ }
794
+ return new Blob([u8arr], { type: mime });
795
+ }
678
796
 
679
797
  const defaultBaseUrl = "https://api.assemblyai.com";
680
798
  class AssemblyAI {
@@ -684,8 +802,9 @@
684
802
  */
685
803
  constructor(params) {
686
804
  params.baseUrl = params.baseUrl || defaultBaseUrl;
687
- if (params.baseUrl && params.baseUrl.endsWith("/"))
805
+ if (params.baseUrl && params.baseUrl.endsWith("/")) {
688
806
  params.baseUrl = params.baseUrl.slice(0, -1);
807
+ }
689
808
  this.files = new FileService(params);
690
809
  this.transcripts = new TranscriptService(params, this.files);
691
810
  this.lemur = new LemurService(params);