assemblyai 4.5.0-beta.0 → 4.6.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 (48) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +53 -9
  3. package/dist/assemblyai.streaming.umd.js +317 -0
  4. package/dist/assemblyai.streaming.umd.min.js +1 -0
  5. package/dist/assemblyai.umd.js +160 -12
  6. package/dist/assemblyai.umd.min.js +1 -1
  7. package/dist/browser.mjs +154 -11
  8. package/dist/bun.mjs +154 -11
  9. package/dist/deno.mjs +154 -11
  10. package/dist/exports/index.d.ts +2 -0
  11. package/dist/exports/streaming.d.ts +4 -0
  12. package/dist/index.cjs +160 -12
  13. package/dist/index.mjs +160 -12
  14. package/dist/node.cjs +154 -11
  15. package/dist/node.mjs +154 -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/realtime/service.d.ts +60 -0
  21. package/dist/services/transcripts/index.d.ts +16 -3
  22. package/dist/streaming.browser.mjs +268 -0
  23. package/dist/streaming.cjs +306 -0
  24. package/dist/streaming.mjs +303 -0
  25. package/dist/types/index.d.ts +7 -0
  26. package/dist/types/openapi.generated.d.ts +75 -29
  27. package/dist/types/services/index.d.ts +7 -0
  28. package/dist/types/transcripts/index.d.ts +9 -0
  29. package/dist/utils/userAgent.d.ts +2 -0
  30. package/dist/workerd.mjs +751 -0
  31. package/docs/reference-types-from-js.md +27 -0
  32. package/package.json +57 -25
  33. package/src/exports/index.ts +2 -0
  34. package/src/exports/streaming.ts +4 -0
  35. package/src/polyfills/fetch/default.ts +3 -0
  36. package/src/polyfills/fetch/workerd.ts +1 -0
  37. package/src/services/base.ts +27 -7
  38. package/src/services/files/index.ts +19 -2
  39. package/src/services/index.ts +2 -1
  40. package/src/services/lemur/index.ts +12 -0
  41. package/src/services/realtime/service.ts +65 -0
  42. package/src/services/transcripts/index.ts +41 -4
  43. package/src/types/index.ts +9 -0
  44. package/src/types/openapi.generated.ts +224 -48
  45. package/src/types/services/index.ts +8 -0
  46. package/src/types/transcripts/index.ts +10 -0
  47. package/src/utils/path.ts +1 -0
  48. package/src/utils/userAgent.ts +51 -0
@@ -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.6.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
@@ -190,7 +252,14 @@
190
252
  const defaultRealtimeUrl = "wss://api.assemblyai.com/v2/realtime/ws";
191
253
  const forceEndOfUtteranceMessage = `{"force_end_utterance":true}`;
192
254
  const terminateSessionMessage = `{"terminate_session":true}`;
255
+ /**
256
+ * RealtimeTranscriber connects to the Streaming Speech-to-Text API and lets you transcribe audio in real-time.
257
+ */
193
258
  class RealtimeTranscriber {
259
+ /**
260
+ * Create a new RealtimeTranscriber.
261
+ * @param params - Parameters to configure the RealtimeTranscriber
262
+ */
194
263
  constructor(params) {
195
264
  var _a, _b;
196
265
  this.listeners = {};
@@ -231,10 +300,19 @@
231
300
  url.search = searchParams.toString();
232
301
  return url;
233
302
  }
303
+ /**
304
+ * Add a listener for an event.
305
+ * @param event - The event to listen for.
306
+ * @param listener - The function to call when the event is emitted.
307
+ */
234
308
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
235
309
  on(event, listener) {
236
310
  this.listeners[event] = listener;
237
311
  }
312
+ /**
313
+ * Connect to the server and begin a new session.
314
+ * @returns A promise that resolves when the connection is established and the session begins.
315
+ */
238
316
  connect() {
239
317
  return new Promise((resolve) => {
240
318
  if (this.socket) {
@@ -316,9 +394,17 @@
316
394
  };
317
395
  });
318
396
  }
397
+ /**
398
+ * Send audio data to the server.
399
+ * @param audio - The audio data to send to the server.
400
+ */
319
401
  sendAudio(audio) {
320
402
  this.send(audio);
321
403
  }
404
+ /**
405
+ * Create a writable stream that can be used to send audio data to the server.
406
+ * @returns A writable stream that can be used to send audio data to the server.
407
+ */
322
408
  stream() {
323
409
  return new WritableStream({
324
410
  write: (chunk) => {
@@ -346,6 +432,11 @@
346
432
  }
347
433
  this.socket.send(data);
348
434
  }
435
+ /**
436
+ * Close the connection to the server.
437
+ * @param waitForSessionTermination - If true, the method will wait for the session to be terminated before closing the connection.
438
+ * While waiting for the session to be terminated, you will receive the final transcript and session information.
439
+ */
349
440
  close() {
350
441
  return __awaiter(this, arguments, void 0, function* (waitForSessionTermination = true) {
351
442
  var _a;
@@ -416,6 +507,8 @@
416
507
  return null;
417
508
  if (path.startsWith("https"))
418
509
  return null;
510
+ if (path.startsWith("data:"))
511
+ return null;
419
512
  if (path.startsWith("file://"))
420
513
  return path.substring(7);
421
514
  if (path.startsWith("file:"))
@@ -460,8 +553,13 @@
460
553
  audioUrl = yield this.files.upload(path);
461
554
  }
462
555
  else {
463
- // audio is not a local path, assume it's a URL
464
- audioUrl = audio;
556
+ if (audio.startsWith("data:")) {
557
+ audioUrl = yield this.files.upload(audio);
558
+ }
559
+ else {
560
+ // audio is not a local path, and not a data-URI, assume it's a normal URL
561
+ audioUrl = audio;
562
+ }
465
563
  }
466
564
  }
467
565
  else {
@@ -626,13 +724,45 @@
626
724
  });
627
725
  }
628
726
  /**
629
- * Retrieve redactions of a transcript.
727
+ * Retrieve the redacted audio URL of a transcript.
630
728
  * @param id - The identifier of the transcript.
631
- * @returns A promise that resolves to the subtitles text.
729
+ * @returns A promise that resolves to the details of the redacted audio.
730
+ * @deprecated Use `redactedAudio` instead.
632
731
  */
633
732
  redactions(id) {
733
+ return this.redactedAudio(id);
734
+ }
735
+ /**
736
+ * Retrieve the redacted audio URL of a transcript.
737
+ * @param id - The identifier of the transcript.
738
+ * @returns A promise that resolves to the details of the redacted audio.
739
+ */
740
+ redactedAudio(id) {
634
741
  return this.fetchJson(`/v2/transcript/${id}/redacted-audio`);
635
742
  }
743
+ /**
744
+ * Retrieve the redacted audio file of a transcript.
745
+ * @param id - The identifier of the transcript.
746
+ * @returns A promise that resolves to the fetch HTTP response of the redacted audio file.
747
+ */
748
+ redactedAudioFile(id) {
749
+ return __awaiter(this, void 0, void 0, function* () {
750
+ const { redacted_audio_url, status } = yield this.redactedAudio(id);
751
+ if (status !== "redacted_audio_ready") {
752
+ throw new Error(`Redacted audio status is ${status}`);
753
+ }
754
+ const response = yield fetch(redacted_audio_url);
755
+ if (!response.ok) {
756
+ throw new Error(`Failed to fetch redacted audio: ${response.statusText}`);
757
+ }
758
+ return {
759
+ arrayBuffer: response.arrayBuffer.bind(response),
760
+ blob: response.blob.bind(response),
761
+ body: response.body,
762
+ bodyUsed: response.bodyUsed,
763
+ };
764
+ });
765
+ }
636
766
  }
637
767
  function deprecateConformer2(params) {
638
768
  if (!params)
@@ -659,8 +789,14 @@
659
789
  upload(input) {
660
790
  return __awaiter(this, void 0, void 0, function* () {
661
791
  let fileData;
662
- if (typeof input === "string")
663
- fileData = yield readFile();
792
+ if (typeof input === "string") {
793
+ if (input.startsWith("data:")) {
794
+ fileData = dataUrlToBlob(input);
795
+ }
796
+ else {
797
+ fileData = yield readFile();
798
+ }
799
+ }
664
800
  else
665
801
  fileData = input;
666
802
  const data = yield this.fetchJson("/v2/upload", {
@@ -675,6 +811,17 @@
675
811
  });
676
812
  }
677
813
  }
814
+ function dataUrlToBlob(dataUrl) {
815
+ const arr = dataUrl.split(",");
816
+ const mime = arr[0].match(/:(.*?);/)[1];
817
+ const bstr = atob(arr[1]);
818
+ let n = bstr.length;
819
+ const u8arr = new Uint8Array(n);
820
+ while (n--) {
821
+ u8arr[n] = bstr.charCodeAt(n);
822
+ }
823
+ return new Blob([u8arr], { type: mime });
824
+ }
678
825
 
679
826
  const defaultBaseUrl = "https://api.assemblyai.com";
680
827
  class AssemblyAI {
@@ -684,8 +831,9 @@
684
831
  */
685
832
  constructor(params) {
686
833
  params.baseUrl = params.baseUrl || defaultBaseUrl;
687
- if (params.baseUrl && params.baseUrl.endsWith("/"))
834
+ if (params.baseUrl && params.baseUrl.endsWith("/")) {
688
835
  params.baseUrl = params.baseUrl.slice(0, -1);
836
+ }
689
837
  this.files = new FileService(params);
690
838
  this.transcripts = new TranscriptService(params, this.files);
691
839
  this.lemur = new LemurService(params);
@@ -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";function t(e,t,s,i){return new(s||(s=Promise))((function(n,o){function r(e){try{l(i.next(e))}catch(e){o(e)}}function a(e){try{l(i.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?n(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;class s{constructor(e){this.params=e}fetch(e,s){return t(this,void 0,void 0,(function*(){var t;(s=null!=s?s:{}).headers=null!==(t=s.headers)&&void 0!==t?t:{},s.headers=Object.assign({Authorization:this.params.apiKey,"Content-Type":"application/json"},s.headers),e.startsWith("http")||(e=this.params.baseUrl+e);const i=yield fetch(e,s);if(i.status>=400){let e;const t=yield i.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: ${i.status} ${i.statusText}`)}return i}))}fetchJson(e,s){return t(this,void 0,void 0,(function*(){return(yield this.fetch(e,s)).json()}))}}class i extends s{summary(e){return this.fetchJson("/lemur/v3/generate/summary",{method:"POST",body:JSON.stringify(e)})}questionAnswer(e){return this.fetchJson("/lemur/v3/generate/question-answer",{method:"POST",body:JSON.stringify(e)})}actionItems(e){return this.fetchJson("/lemur/v3/generate/action-items",{method:"POST",body:JSON.stringify(e)})}task(e){return this.fetchJson("/lemur/v3/generate/task",{method:"POST",body:JSON.stringify(e)})}purgeRequestData(e){return this.fetchJson(`/lemur/v3/${e}`,{method:"DELETE"})}}const{WritableStream:n}="undefined"!=typeof window?window:"undefined"!=typeof global?global:globalThis;var o,r;const a=null!==(r=null!==(o=null!==WebSocket&&void 0!==WebSocket?WebSocket:null===global||void 0===global?void 0:global.WebSocket)&&void 0!==o?o:null===window||void 0===window?void 0:window.WebSocket)&&void 0!==r?r:null===self||void 0===self?void 0:self.WebSocket,l=(e,t)=>t?new a(e,t):new a(e);var c;!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"}(c||(c={}));const d={[c.BadSampleRate]:"Sample rate must be a positive integer",[c.AuthFailed]:"Not Authorized",[c.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.",[c.NonexistentSessionId]:"Session ID does not exist",[c.SessionExpired]:"Session has expired",[c.ClosedSession]:"Session is closed",[c.RateLimited]:"Rate limited",[c.UniqueSessionViolation]:"Unique session violation",[c.SessionTimeout]:"Session Timeout",[c.AudioTooShort]:"Audio too short",[c.AudioTooLong]:"Audio too long",[c.BadJson]:"Bad JSON",[c.BadSchema]:"Bad schema",[c.TooManyStreams]:"Too many streams",[c.Reconnected]:"Reconnected",[c.ReconnectAttemptsExhausted]:"Reconnect attempts exhausted"};class h extends Error{}const u='{"terminate_session":true}';class p{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=l(t.toString()):this.socket=l(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 c&&(t=d[e]),null===(i=(s=this.listeners).close)||void 0===i||i.call(s,e,t)},this.socket.onerror=e=>{var t,s,i,n;e.error?null===(s=(t=this.listeners).error)||void 0===s||s.call(t,e.error):null===(n=(i=this.listeners).error)||void 0===n||n.call(i,new Error(e.message))},this.socket.onmessage=({data:t})=>{var s,i,n,o,r,a,l,c,d,u,p,f,m,v,y;const S=JSON.parse(t.toString());if("error"in S)null===(i=(s=this.listeners).error)||void 0===i||i.call(s,new h(S.error));else switch(S.message_type){case"SessionBegins":{const t={sessionId:S.session_id,expiresAt:new Date(S.expires_at)};e(t),null===(o=(n=this.listeners).open)||void 0===o||o.call(n,t);break}case"PartialTranscript":S.created=new Date(S.created),null===(a=(r=this.listeners).transcript)||void 0===a||a.call(r,S),null===(c=(l=this.listeners)["transcript.partial"])||void 0===c||c.call(l,S);break;case"FinalTranscript":S.created=new Date(S.created),null===(u=(d=this.listeners).transcript)||void 0===u||u.call(d,S),null===(f=(p=this.listeners)["transcript.final"])||void 0===f||f.call(p,S);break;case"SessionInformation":null===(v=(m=this.listeners).session_information)||void 0===v||v.call(m,S);break;case"SessionTerminated":null===(y=this.sessionTerminatedResolve)||void 0===y||y.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 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(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 f extends s{constructor(e){super(e),this.rtFactoryParams=e}createService(e){return this.transcriber(e)}transcriber(e){const t=Object.assign({},e);return t.token||t.apiKey||(t.apiKey=this.rtFactoryParams.apiKey),new p(t)}createTemporaryToken(e){return t(this,void 0,void 0,(function*(){return(yield this.fetchJson("/v2/realtime/token",{method:"POST",body:JSON.stringify(e)})).token}))}}function m(e){return e.startsWith("http")||e.startsWith("https")?null:e.startsWith("file://")?e.substring(7):e.startsWith("file:")?e.substring(5):e}class v extends s{constructor(e,t){super(e),this.files=t}transcribe(e,s){return t(this,void 0,void 0,(function*(){y(e);const t=yield this.submit(e);return yield this.waitUntilReady(t.id,s)}))}submit(e){return t(this,void 0,void 0,(function*(){let t,s;if(y(e),"audio"in e){const{audio:i}=e,n=function(e,t){var s={};for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&t.indexOf(i)<0&&(s[i]=e[i]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(i=Object.getOwnPropertySymbols(e);n<i.length;n++)t.indexOf(i[n])<0&&Object.prototype.propertyIsEnumerable.call(e,i[n])&&(s[i[n]]=e[i[n]])}return s}(e,["audio"]);if("string"==typeof i){const e=m(i);t=null!==e?yield this.files.upload(e):i}else t=yield this.files.upload(i);s=Object.assign(Object.assign({},n),{audio_url:t})}else s=e;return yield this.fetchJson("/v2/transcript",{method:"POST",body:JSON.stringify(s)})}))}create(e,s){return t(this,void 0,void 0,(function*(){var t;y(e);const i=m(e.audio_url);if(null!==i){const t=yield this.files.upload(i);e.audio_url=t}const n=yield this.fetchJson("/v2/transcript",{method:"POST",body:JSON.stringify(e)});return null===(t=null==s?void 0:s.poll)||void 0===t||t?yield this.waitUntilReady(n.id,s):n}))}waitUntilReady(e,s){return t(this,void 0,void 0,(function*(){var t,i;const n=null!==(t=null==s?void 0:s.pollingInterval)&&void 0!==t?t:3e3,o=null!==(i=null==s?void 0:s.pollingTimeout)&&void 0!==i?i:-1,r=Date.now();for(;;){const t=yield this.get(e);if("completed"===t.status||"error"===t.status)return t;if(o>0&&Date.now()-r>o)throw new Error("Polling timeout");yield new Promise((e=>setTimeout(e,n)))}}))}get(e){return this.fetchJson(`/v2/transcript/${e}`)}list(e){return t(this,void 0,void 0,(function*(){let t="/v2/transcript";"string"==typeof e?t=e:e&&(t=`${t}?${new URLSearchParams(Object.keys(e).map((t=>{var s;return[t,(null===(s=e[t])||void 0===s?void 0:s.toString())||""]})))}`);const s=yield this.fetchJson(t);for(const e of s.transcripts)e.created=new Date(e.created),e.completed&&(e.completed=new Date(e.completed));return s}))}delete(e){return this.fetchJson(`/v2/transcript/${e}`,{method:"DELETE"})}wordSearch(e,t){const s=new URLSearchParams({words:t.join(",")});return this.fetchJson(`/v2/transcript/${e}/word-search?${s.toString()}`)}sentences(e){return this.fetchJson(`/v2/transcript/${e}/sentences`)}paragraphs(e){return this.fetchJson(`/v2/transcript/${e}/paragraphs`)}subtitles(e){return t(this,arguments,void 0,(function*(e,t="srt",s){let i=`/v2/transcript/${e}/${t}`;if(s){const e=new URLSearchParams;e.set("chars_per_caption",s.toString()),i+=`?${e.toString()}`}const n=yield this.fetch(i);return yield n.text()}))}redactions(e){return this.fetchJson(`/v2/transcript/${e}/redacted-audio`)}}function y(e){e&&"conformer-2"===e.speech_model&&console.warn("The speech_model conformer-2 option is deprecated and will stop working in the near future. Use best or nano instead.")}class S extends s{upload(e){return t(this,void 0,void 0,(function*(){let s;s="string"==typeof e?yield function(e){return t(this,void 0,void 0,(function*(){throw new Error("Interacting with the file system is not supported in this environment.")}))}():e;return(yield this.fetchJson("/v2/upload",{method:"POST",body:s,headers:{"Content-Type":"application/octet-stream"},duplex:"half"})).upload_url}))}}e.AssemblyAI=class{constructor(e){e.baseUrl=e.baseUrl||"https://api.assemblyai.com",e.baseUrl&&e.baseUrl.endsWith("/")&&(e.baseUrl=e.baseUrl.slice(0,-1)),this.files=new S(e),this.transcripts=new v(e,this.files),this.lemur=new i(e),this.realtime=new f(e)}},e.FileService=S,e.LemurService=i,e.RealtimeService=class extends p{},e.RealtimeServiceFactory=class extends f{},e.RealtimeTranscriber=p,e.RealtimeTranscriberFactory=f,e.TranscriptService=v}));
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(n,o){function r(e){try{c(i.next(e))}catch(e){o(e)}}function a(e){try{c(i.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?n(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(r,a)}c((i=i.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const s={cache:"no-store"};let i="";"undefined"!=typeof navigator&&navigator.userAgent&&(i+=navigator.userAgent);const n={sdk:{name:"JavaScript",version:"4.6.0"}};"undefined"!=typeof process&&(process.versions.node&&-1===i.indexOf("Node")&&(n.runtime_env={name:"Node",version:process.versions.node}),process.versions.bun&&-1===i.indexOf("Bun")&&(n.runtime_env={name:"Bun",version:process.versions.bun})),"undefined"!=typeof Deno&&process.versions.bun&&-1===i.indexOf("Deno")&&(n.runtime_env={name:"Deno",version:Deno.version.deno});class o{constructor(e){var t;this.params=e,!1===e.userAgent?this.userAgent=void 0:this.userAgent=(t=e.userAgent||{},i+(!1===t?"":" AssemblyAI/1.0 ("+Object.entries(Object.assign(Object.assign({},n),t)).map((([e,t])=>t?`${e}=${t.name}/${t.version}`:"")).join(" ")+")"))}fetch(e,i){return t(this,void 0,void 0,(function*(){i=Object.assign(Object.assign({},s),i);let t={Authorization:this.params.apiKey,"Content-Type":"application/json"};(null==s?void 0:s.headers)&&(t=Object.assign(Object.assign({},t),s.headers)),(null==i?void 0:i.headers)&&(t=Object.assign(Object.assign({},t),i.headers)),this.userAgent&&(t["User-Agent"]=this.userAgent,"undefined"!=typeof window&&"chrome"in window&&(t["AssemblyAI-Agent"]=this.userAgent)),i.headers=t,e.startsWith("http")||(e=this.params.baseUrl+e);const n=yield fetch(e,i);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,s){return t(this,void 0,void 0,(function*(){return(yield this.fetch(e,s)).json()}))}}class r extends o{summary(e){return this.fetchJson("/lemur/v3/generate/summary",{method:"POST",body:JSON.stringify(e)})}questionAnswer(e){return this.fetchJson("/lemur/v3/generate/question-answer",{method:"POST",body:JSON.stringify(e)})}actionItems(e){return this.fetchJson("/lemur/v3/generate/action-items",{method:"POST",body:JSON.stringify(e)})}task(e){return this.fetchJson("/lemur/v3/generate/task",{method:"POST",body:JSON.stringify(e)})}getResponse(e){return this.fetchJson(`/lemur/v3/${e}`)}purgeRequestData(e){return this.fetchJson(`/lemur/v3/${e}`,{method:"DELETE"})}}const{WritableStream:a}="undefined"!=typeof window?window:"undefined"!=typeof global?global:globalThis;var c,d;const l=null!==(d=null!==(c=null!==WebSocket&&void 0!==WebSocket?WebSocket:null===global||void 0===global?void 0:global.WebSocket)&&void 0!==c?c:null===window||void 0===window?void 0:window.WebSocket)&&void 0!==d?d:null===self||void 0===self?void 0:self.WebSocket,u=(e,t)=>t?new l(e,t):new l(e);var h;!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"}(h||(h={}));const f={[h.BadSampleRate]:"Sample rate must be a positive integer",[h.AuthFailed]:"Not Authorized",[h.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.",[h.NonexistentSessionId]:"Session ID does not exist",[h.SessionExpired]:"Session has expired",[h.ClosedSession]:"Session is closed",[h.RateLimited]:"Rate limited",[h.UniqueSessionViolation]:"Unique session violation",[h.SessionTimeout]:"Session Timeout",[h.AudioTooShort]:"Audio too short",[h.AudioTooLong]:"Audio too long",[h.BadJson]:"Bad JSON",[h.BadSchema]:"Bad schema",[h.TooManyStreams]:"Too many streams",[h.Reconnected]:"Reconnected",[h.ReconnectAttemptsExhausted]:"Reconnect attempts exhausted"};class p extends Error{}const m='{"terminate_session":true}';class v{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=u(t.toString()):this.socket=u(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 h&&(t=f[e]),null===(i=(s=this.listeners).close)||void 0===i||i.call(s,e,t)},this.socket.onerror=e=>{var t,s,i,n;e.error?null===(s=(t=this.listeners).error)||void 0===s||s.call(t,e.error):null===(n=(i=this.listeners).error)||void 0===n||n.call(i,new Error(e.message))},this.socket.onmessage=({data:t})=>{var s,i,n,o,r,a,c,d,l,u,h,f,m,v,y;const b=JSON.parse(t.toString());if("error"in b)null===(i=(s=this.listeners).error)||void 0===i||i.call(s,new p(b.error));else switch(b.message_type){case"SessionBegins":{const t={sessionId:b.session_id,expiresAt:new Date(b.expires_at)};e(t),null===(o=(n=this.listeners).open)||void 0===o||o.call(n,t);break}case"PartialTranscript":b.created=new Date(b.created),null===(a=(r=this.listeners).transcript)||void 0===a||a.call(r,b),null===(d=(c=this.listeners)["transcript.partial"])||void 0===d||d.call(c,b);break;case"FinalTranscript":b.created=new Date(b.created),null===(u=(l=this.listeners).transcript)||void 0===u||u.call(l,b),null===(f=(h=this.listeners)["transcript.final"])||void 0===f||f.call(h,b);break;case"SessionInformation":null===(v=(m=this.listeners).session_information)||void 0===v||v.call(m,b);break;case"SessionTerminated":null===(y=this.sessionTerminatedResolve)||void 0===y||y.call(this)}}}))}sendAudio(e){this.send(e)}stream(){return new a({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(m),yield e}else this.socket.send(m);(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 extends o{constructor(e){super(e),this.rtFactoryParams=e}createService(e){return this.transcriber(e)}transcriber(e){const t=Object.assign({},e);return t.token||t.apiKey||(t.apiKey=this.rtFactoryParams.apiKey),new v(t)}createTemporaryToken(e){return t(this,void 0,void 0,(function*(){return(yield this.fetchJson("/v2/realtime/token",{method:"POST",body:JSON.stringify(e)})).token}))}}function b(e){return e.startsWith("http")||e.startsWith("https")||e.startsWith("data:")?null:e.startsWith("file://")?e.substring(7):e.startsWith("file:")?e.substring(5):e}class S extends o{constructor(e,t){super(e),this.files=t}transcribe(e,s){return t(this,void 0,void 0,(function*(){g(e);const t=yield this.submit(e);return yield this.waitUntilReady(t.id,s)}))}submit(e){return t(this,void 0,void 0,(function*(){let t,s;if(g(e),"audio"in e){const{audio:i}=e,n=function(e,t){var s={};for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&t.indexOf(i)<0&&(s[i]=e[i]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(i=Object.getOwnPropertySymbols(e);n<i.length;n++)t.indexOf(i[n])<0&&Object.prototype.propertyIsEnumerable.call(e,i[n])&&(s[i[n]]=e[i[n]])}return s}(e,["audio"]);if("string"==typeof i){const e=b(i);t=null!==e?yield this.files.upload(e):i.startsWith("data:")?yield this.files.upload(i):i}else t=yield this.files.upload(i);s=Object.assign(Object.assign({},n),{audio_url:t})}else s=e;return yield this.fetchJson("/v2/transcript",{method:"POST",body:JSON.stringify(s)})}))}create(e,s){return t(this,void 0,void 0,(function*(){var t;g(e);const i=b(e.audio_url);if(null!==i){const t=yield this.files.upload(i);e.audio_url=t}const n=yield this.fetchJson("/v2/transcript",{method:"POST",body:JSON.stringify(e)});return null===(t=null==s?void 0:s.poll)||void 0===t||t?yield this.waitUntilReady(n.id,s):n}))}waitUntilReady(e,s){return t(this,void 0,void 0,(function*(){var t,i;const n=null!==(t=null==s?void 0:s.pollingInterval)&&void 0!==t?t:3e3,o=null!==(i=null==s?void 0:s.pollingTimeout)&&void 0!==i?i:-1,r=Date.now();for(;;){const t=yield this.get(e);if("completed"===t.status||"error"===t.status)return t;if(o>0&&Date.now()-r>o)throw new Error("Polling timeout");yield new Promise((e=>setTimeout(e,n)))}}))}get(e){return this.fetchJson(`/v2/transcript/${e}`)}list(e){return t(this,void 0,void 0,(function*(){let t="/v2/transcript";"string"==typeof e?t=e:e&&(t=`${t}?${new URLSearchParams(Object.keys(e).map((t=>{var s;return[t,(null===(s=e[t])||void 0===s?void 0:s.toString())||""]})))}`);const s=yield this.fetchJson(t);for(const e of s.transcripts)e.created=new Date(e.created),e.completed&&(e.completed=new Date(e.completed));return s}))}delete(e){return this.fetchJson(`/v2/transcript/${e}`,{method:"DELETE"})}wordSearch(e,t){const s=new URLSearchParams({words:t.join(",")});return this.fetchJson(`/v2/transcript/${e}/word-search?${s.toString()}`)}sentences(e){return this.fetchJson(`/v2/transcript/${e}/sentences`)}paragraphs(e){return this.fetchJson(`/v2/transcript/${e}/paragraphs`)}subtitles(e){return t(this,arguments,void 0,(function*(e,t="srt",s){let i=`/v2/transcript/${e}/${t}`;if(s){const e=new URLSearchParams;e.set("chars_per_caption",s.toString()),i+=`?${e.toString()}`}const n=yield this.fetch(i);return yield n.text()}))}redactions(e){return this.redactedAudio(e)}redactedAudio(e){return this.fetchJson(`/v2/transcript/${e}/redacted-audio`)}redactedAudioFile(e){return t(this,void 0,void 0,(function*(){const{redacted_audio_url:t,status:s}=yield this.redactedAudio(e);if("redacted_audio_ready"!==s)throw new Error(`Redacted audio status is ${s}`);const i=yield fetch(t);if(!i.ok)throw new Error(`Failed to fetch redacted audio: ${i.statusText}`);return{arrayBuffer:i.arrayBuffer.bind(i),blob:i.blob.bind(i),body:i.body,bodyUsed:i.bodyUsed}}))}}function g(e){e&&"conformer-2"===e.speech_model&&console.warn("The speech_model conformer-2 option is deprecated and will stop working in the near future. Use best or nano instead.")}class w extends o{upload(e){return t(this,void 0,void 0,(function*(){let s;s="string"==typeof e?e.startsWith("data:")?function(e){const t=e.split(","),s=t[0].match(/:(.*?);/)[1],i=atob(t[1]);let n=i.length;const o=new Uint8Array(n);for(;n--;)o[n]=i.charCodeAt(n);return new Blob([o],{type:s})}(e):yield function(e){return t(this,void 0,void 0,(function*(){throw new Error("Interacting with the file system is not supported in this environment.")}))}():e;return(yield this.fetchJson("/v2/upload",{method:"POST",body:s,headers:{"Content-Type":"application/octet-stream"},duplex:"half"})).upload_url}))}}e.AssemblyAI=class{constructor(e){e.baseUrl=e.baseUrl||"https://api.assemblyai.com",e.baseUrl&&e.baseUrl.endsWith("/")&&(e.baseUrl=e.baseUrl.slice(0,-1)),this.files=new w(e),this.transcripts=new S(e,this.files),this.lemur=new r(e),this.realtime=new y(e)}},e.FileService=w,e.LemurService=r,e.RealtimeService=class extends v{},e.RealtimeServiceFactory=class extends y{},e.RealtimeTranscriber=v,e.RealtimeTranscriberFactory=y,e.TranscriptService=S}));
package/dist/browser.mjs CHANGED
@@ -1,3 +1,42 @@
1
+ const DEFAULT_FETCH_INIT = {
2
+ cache: "no-store",
3
+ };
4
+
5
+ const buildUserAgent = (userAgent) => defaultUserAgentString +
6
+ (userAgent === false
7
+ ? ""
8
+ : " AssemblyAI/1.0 (" +
9
+ Object.entries({ ...defaultUserAgent, ...userAgent })
10
+ .map(([key, item]) => item ? `${key}=${item.name}/${item.version}` : "")
11
+ .join(" ") +
12
+ ")");
13
+ let defaultUserAgentString = "";
14
+ if (typeof navigator !== "undefined" && navigator.userAgent) {
15
+ defaultUserAgentString += navigator.userAgent;
16
+ }
17
+ const defaultUserAgent = {
18
+ sdk: { name: "JavaScript", version: "4.6.0" },
19
+ };
20
+ if (typeof process !== "undefined") {
21
+ if (process.versions.node && defaultUserAgentString.indexOf("Node") === -1) {
22
+ defaultUserAgent.runtime_env = {
23
+ name: "Node",
24
+ version: process.versions.node,
25
+ };
26
+ }
27
+ if (process.versions.bun && defaultUserAgentString.indexOf("Bun") === -1) {
28
+ defaultUserAgent.runtime_env = {
29
+ name: "Bun",
30
+ version: process.versions.bun,
31
+ };
32
+ }
33
+ }
34
+ if (typeof Deno !== "undefined") {
35
+ if (process.versions.bun && defaultUserAgentString.indexOf("Deno") === -1) {
36
+ defaultUserAgent.runtime_env = { name: "Deno", version: Deno.version.deno };
37
+ }
38
+ }
39
+
1
40
  /**
2
41
  * Base class for services that communicate with the API.
3
42
  */
@@ -8,15 +47,32 @@ class BaseService {
8
47
  */
9
48
  constructor(params) {
10
49
  this.params = params;
50
+ if (params.userAgent === false) {
51
+ this.userAgent = undefined;
52
+ }
53
+ else {
54
+ this.userAgent = buildUserAgent(params.userAgent || {});
55
+ }
11
56
  }
12
57
  async fetch(input, init) {
13
- init = init ?? {};
14
- init.headers = init.headers ?? {};
15
- init.headers = {
58
+ init = { ...DEFAULT_FETCH_INIT, ...init };
59
+ let headers = {
16
60
  Authorization: this.params.apiKey,
17
61
  "Content-Type": "application/json",
18
- ...init.headers,
19
62
  };
63
+ if (DEFAULT_FETCH_INIT?.headers)
64
+ headers = { ...headers, ...DEFAULT_FETCH_INIT.headers };
65
+ if (init?.headers)
66
+ headers = { ...headers, ...init.headers };
67
+ if (this.userAgent) {
68
+ headers["User-Agent"] = this.userAgent;
69
+ // chromium browsers have a bug where the user agent can't be modified
70
+ if (typeof window !== "undefined" && "chrome" in window) {
71
+ headers["AssemblyAI-Agent"] =
72
+ this.userAgent;
73
+ }
74
+ }
75
+ init.headers = headers;
20
76
  if (!input.startsWith("http"))
21
77
  input = this.params.baseUrl + input;
22
78
  const response = await fetch(input, init);
@@ -69,6 +125,9 @@ class LemurService extends BaseService {
69
125
  body: JSON.stringify(params),
70
126
  });
71
127
  }
128
+ getResponse(id) {
129
+ return this.fetchJson(`/lemur/v3/${id}`);
130
+ }
72
131
  /**
73
132
  * Delete the data for a previously submitted LeMUR request.
74
133
  * @param id - ID of the LeMUR request
@@ -138,7 +197,14 @@ class RealtimeError extends Error {
138
197
  const defaultRealtimeUrl = "wss://api.assemblyai.com/v2/realtime/ws";
139
198
  const forceEndOfUtteranceMessage = `{"force_end_utterance":true}`;
140
199
  const terminateSessionMessage = `{"terminate_session":true}`;
200
+ /**
201
+ * RealtimeTranscriber connects to the Streaming Speech-to-Text API and lets you transcribe audio in real-time.
202
+ */
141
203
  class RealtimeTranscriber {
204
+ /**
205
+ * Create a new RealtimeTranscriber.
206
+ * @param params - Parameters to configure the RealtimeTranscriber
207
+ */
142
208
  constructor(params) {
143
209
  this.listeners = {};
144
210
  this.realtimeUrl = params.realtimeUrl ?? defaultRealtimeUrl;
@@ -178,10 +244,19 @@ class RealtimeTranscriber {
178
244
  url.search = searchParams.toString();
179
245
  return url;
180
246
  }
247
+ /**
248
+ * Add a listener for an event.
249
+ * @param event - The event to listen for.
250
+ * @param listener - The function to call when the event is emitted.
251
+ */
181
252
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
253
  on(event, listener) {
183
254
  this.listeners[event] = listener;
184
255
  }
256
+ /**
257
+ * Connect to the server and begin a new session.
258
+ * @returns A promise that resolves when the connection is established and the session begins.
259
+ */
185
260
  connect() {
186
261
  return new Promise((resolve) => {
187
262
  if (this.socket) {
@@ -260,9 +335,17 @@ class RealtimeTranscriber {
260
335
  };
261
336
  });
262
337
  }
338
+ /**
339
+ * Send audio data to the server.
340
+ * @param audio - The audio data to send to the server.
341
+ */
263
342
  sendAudio(audio) {
264
343
  this.send(audio);
265
344
  }
345
+ /**
346
+ * Create a writable stream that can be used to send audio data to the server.
347
+ * @returns A writable stream that can be used to send audio data to the server.
348
+ */
266
349
  stream() {
267
350
  return new WritableStream({
268
351
  write: (chunk) => {
@@ -290,6 +373,11 @@ class RealtimeTranscriber {
290
373
  }
291
374
  this.socket.send(data);
292
375
  }
376
+ /**
377
+ * Close the connection to the server.
378
+ * @param waitForSessionTermination - If true, the method will wait for the session to be terminated before closing the connection.
379
+ * While waiting for the session to be terminated, you will receive the final transcript and session information.
380
+ */
293
381
  async close(waitForSessionTermination = true) {
294
382
  if (this.socket) {
295
383
  if (this.socket.readyState === this.socket.OPEN) {
@@ -355,6 +443,8 @@ function getPath(path) {
355
443
  return null;
356
444
  if (path.startsWith("https"))
357
445
  return null;
446
+ if (path.startsWith("data:"))
447
+ return null;
358
448
  if (path.startsWith("file://"))
359
449
  return path.substring(7);
360
450
  if (path.startsWith("file:"))
@@ -396,8 +486,13 @@ class TranscriptService extends BaseService {
396
486
  audioUrl = await this.files.upload(path);
397
487
  }
398
488
  else {
399
- // audio is not a local path, assume it's a URL
400
- audioUrl = audio;
489
+ if (audio.startsWith("data:")) {
490
+ audioUrl = await this.files.upload(audio);
491
+ }
492
+ else {
493
+ // audio is not a local path, and not a data-URI, assume it's a normal URL
494
+ audioUrl = audio;
495
+ }
401
496
  }
402
497
  }
403
498
  else {
@@ -548,13 +643,43 @@ class TranscriptService extends BaseService {
548
643
  return await response.text();
549
644
  }
550
645
  /**
551
- * Retrieve redactions of a transcript.
646
+ * Retrieve the redacted audio URL of a transcript.
552
647
  * @param id - The identifier of the transcript.
553
- * @returns A promise that resolves to the subtitles text.
648
+ * @returns A promise that resolves to the details of the redacted audio.
649
+ * @deprecated Use `redactedAudio` instead.
554
650
  */
555
651
  redactions(id) {
652
+ return this.redactedAudio(id);
653
+ }
654
+ /**
655
+ * Retrieve the redacted audio URL of a transcript.
656
+ * @param id - The identifier of the transcript.
657
+ * @returns A promise that resolves to the details of the redacted audio.
658
+ */
659
+ redactedAudio(id) {
556
660
  return this.fetchJson(`/v2/transcript/${id}/redacted-audio`);
557
661
  }
662
+ /**
663
+ * Retrieve the redacted audio file of a transcript.
664
+ * @param id - The identifier of the transcript.
665
+ * @returns A promise that resolves to the fetch HTTP response of the redacted audio file.
666
+ */
667
+ async redactedAudioFile(id) {
668
+ const { redacted_audio_url, status } = await this.redactedAudio(id);
669
+ if (status !== "redacted_audio_ready") {
670
+ throw new Error(`Redacted audio status is ${status}`);
671
+ }
672
+ const response = await fetch(redacted_audio_url);
673
+ if (!response.ok) {
674
+ throw new Error(`Failed to fetch redacted audio: ${response.statusText}`);
675
+ }
676
+ return {
677
+ arrayBuffer: response.arrayBuffer.bind(response),
678
+ blob: response.blob.bind(response),
679
+ body: response.body,
680
+ bodyUsed: response.bodyUsed,
681
+ };
682
+ }
558
683
  }
559
684
  function deprecateConformer2(params) {
560
685
  if (!params)
@@ -578,8 +703,14 @@ class FileService extends BaseService {
578
703
  */
579
704
  async upload(input) {
580
705
  let fileData;
581
- if (typeof input === "string")
582
- fileData = await readFile();
706
+ if (typeof input === "string") {
707
+ if (input.startsWith("data:")) {
708
+ fileData = dataUrlToBlob(input);
709
+ }
710
+ else {
711
+ fileData = await readFile();
712
+ }
713
+ }
583
714
  else
584
715
  fileData = input;
585
716
  const data = await this.fetchJson("/v2/upload", {
@@ -593,6 +724,17 @@ class FileService extends BaseService {
593
724
  return data.upload_url;
594
725
  }
595
726
  }
727
+ function dataUrlToBlob(dataUrl) {
728
+ const arr = dataUrl.split(",");
729
+ const mime = arr[0].match(/:(.*?);/)[1];
730
+ const bstr = atob(arr[1]);
731
+ let n = bstr.length;
732
+ const u8arr = new Uint8Array(n);
733
+ while (n--) {
734
+ u8arr[n] = bstr.charCodeAt(n);
735
+ }
736
+ return new Blob([u8arr], { type: mime });
737
+ }
596
738
 
597
739
  const defaultBaseUrl = "https://api.assemblyai.com";
598
740
  class AssemblyAI {
@@ -602,8 +744,9 @@ class AssemblyAI {
602
744
  */
603
745
  constructor(params) {
604
746
  params.baseUrl = params.baseUrl || defaultBaseUrl;
605
- if (params.baseUrl && params.baseUrl.endsWith("/"))
747
+ if (params.baseUrl && params.baseUrl.endsWith("/")) {
606
748
  params.baseUrl = params.baseUrl.slice(0, -1);
749
+ }
607
750
  this.files = new FileService(params);
608
751
  this.transcripts = new TranscriptService(params, this.files);
609
752
  this.lemur = new LemurService(params);