@vapi-ai/web 1.0.141 → 1.0.142

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/dist/vapi.d.ts CHANGED
@@ -3,13 +3,8 @@ import { CreateAssistantDTO } from "./api";
3
3
  import EventEmitter from "events";
4
4
  export default class Vapi extends EventEmitter {
5
5
  private started;
6
- private ws;
7
- private mediaRecorder;
8
- private player;
6
+ private call;
9
7
  constructor(apiToken: string, apiBaseUrl?: string);
10
8
  start(assistant: CreateAssistantDTO | string): void;
11
- private startRecording;
12
- private onMessage;
13
- clear(): void;
14
9
  stop(): void;
15
10
  }
package/dist/vapi.js CHANGED
@@ -3,95 +3,44 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const player_1 = require("./player");
6
+ const daily_js_1 = __importDefault(require("@daily-co/daily-js"));
7
7
  const events_1 = __importDefault(require("events"));
8
8
  const client_1 = require("./client");
9
- const base64_arraybuffer_1 = require("base64-arraybuffer");
10
9
  class Vapi extends events_1.default {
11
10
  constructor(apiToken, apiBaseUrl) {
12
11
  super();
13
12
  this.started = false;
14
- this.ws = null;
15
- this.mediaRecorder = null;
13
+ this.call = null;
16
14
  client_1.client.baseUrl = apiBaseUrl !== null && apiBaseUrl !== void 0 ? apiBaseUrl : "https://api.vapi.ai";
17
15
  client_1.client.setSecurityData(apiToken);
18
- this.player = new player_1.ContinuousPlayer();
19
- this.player.on("speech-start", () => this.emit("speech-start"));
20
- this.player.on("speech-end", () => this.emit("speech-end"));
21
16
  }
22
17
  start(assistant) {
23
18
  if (this.started) {
24
19
  return;
25
20
  }
26
21
  this.started = true;
27
- this.player.start();
28
22
  client_1.client.call
29
23
  .callControllerCreateWebCall({
30
24
  assistant: typeof assistant === "string" ? undefined : assistant,
31
25
  assistantId: typeof assistant === "string" ? assistant : undefined,
32
26
  })
33
27
  .then(({ data }) => {
34
- const { callId, url } = data;
35
- const socket = new WebSocket(url);
36
- this.ws = socket;
37
- socket.onopen = () => {
38
- socket.send(JSON.stringify({ event: "start", callId }));
39
- };
40
- socket.onmessage = (event) => {
41
- if (!socket)
42
- return;
43
- this.onMessage(socket, event);
44
- };
45
- socket.onclose = () => {
46
- this.stop();
47
- };
28
+ const { url } = data;
29
+ this.call = daily_js_1.default.createCallObject({
30
+ url,
31
+ audioSource: true,
32
+ videoSource: false,
33
+ });
48
34
  })
49
35
  .catch((error) => {
50
36
  console.error(error);
51
37
  });
52
38
  }
53
- startRecording() {
54
- navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
55
- this.mediaRecorder = new MediaRecorder(stream, {
56
- mimeType: "audio/webm;codecs=opus",
57
- });
58
- this.mediaRecorder.ondataavailable = (event) => {
59
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
60
- this.ws.send(event.data);
61
- }
62
- };
63
- this.mediaRecorder.start(100);
64
- });
65
- }
66
- onMessage(ws, event) {
67
- const data = JSON.parse(event.data);
68
- switch (data.event) {
69
- case "connected":
70
- this.startRecording();
71
- this.emit("started");
72
- break;
73
- case "clear":
74
- this.clear();
75
- break;
76
- case "media":
77
- const audioData = (0, base64_arraybuffer_1.decode)(data.media.payload);
78
- this.player.playChunk(audioData);
79
- }
80
- }
81
- clear() {
82
- this.player.clear();
83
- }
84
39
  stop() {
40
+ var _a;
85
41
  this.started = false;
86
- if (this.ws) {
87
- this.ws.close();
88
- }
89
- this.ws = null;
90
- if (this.mediaRecorder) {
91
- this.mediaRecorder.stop();
92
- }
93
- this.mediaRecorder = null;
94
- this.emit("stopped");
42
+ (_a = this.call) === null || _a === void 0 ? void 0 : _a.destroy();
43
+ this.call = null;
95
44
  }
96
45
  }
97
46
  exports.default = Vapi;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vapi-ai/web",
3
- "version": "1.0.141",
3
+ "version": "1.0.142",
4
4
  "description": "",
5
5
  "main": "dist/vapi.js",
6
6
  "types": "dist/vapi.d.ts",
@@ -22,15 +22,11 @@
22
22
  },
23
23
  "homepage": "https://github.com/VapiAI/snippet#readme",
24
24
  "dependencies": {
25
- "async": "^3.2.4",
26
- "base64-arraybuffer": "^1.0.2",
27
- "events": "^3.3.0",
28
- "standardized-audio-context": "^25.3.57"
25
+ "@daily-co/daily-js": "^0.52.0",
26
+ "events": "^3.3.0"
29
27
  },
30
28
  "devDependencies": {
31
- "@types/async": "^3.2.21",
32
29
  "@types/node": "^20.6.0",
33
- "@types/ws": "^8.5.5",
34
30
  "swagger-typescript-api": "^13.0.3"
35
31
  }
36
32
  }
package/vapi.ts CHANGED
@@ -1,23 +1,17 @@
1
- import { ContinuousPlayer } from "./player";
1
+ import DailyIframe, { DailyCall } from "@daily-co/daily-js";
2
+
2
3
  import { CreateAssistantDTO } from "./api";
3
4
  import EventEmitter from "events";
4
5
  import { client } from "./client";
5
- import { decode } from "base64-arraybuffer";
6
6
 
7
7
  export default class Vapi extends EventEmitter {
8
8
  private started: boolean = false;
9
- private ws: WebSocket | null = null;
10
- private mediaRecorder: MediaRecorder | null = null;
11
- private player: ContinuousPlayer;
9
+ private call: DailyCall | null = null;
12
10
 
13
11
  constructor(apiToken: string, apiBaseUrl?: string) {
14
12
  super();
15
13
  client.baseUrl = apiBaseUrl ?? "https://api.vapi.ai";
16
14
  client.setSecurityData(apiToken);
17
- this.player = new ContinuousPlayer();
18
-
19
- this.player.on("speech-start", () => this.emit("speech-start"));
20
- this.player.on("speech-end", () => this.emit("speech-end"));
21
15
  }
22
16
 
23
17
  start(assistant: CreateAssistantDTO | string): void {
@@ -26,7 +20,6 @@ export default class Vapi extends EventEmitter {
26
20
  }
27
21
 
28
22
  this.started = true;
29
- this.player.start();
30
23
 
31
24
  client.call
32
25
  .callControllerCreateWebCall({
@@ -34,73 +27,22 @@ export default class Vapi extends EventEmitter {
34
27
  assistantId: typeof assistant === "string" ? assistant : undefined,
35
28
  })
36
29
  .then(({ data }) => {
37
- const { callId, url } = data;
38
- const socket = new WebSocket(url);
30
+ const { url } = data;
39
31
 
40
- this.ws = socket;
41
-
42
- socket.onopen = () => {
43
- socket.send(JSON.stringify({ event: "start", callId }));
44
- };
45
- socket.onmessage = (event) => {
46
- if (!socket) return;
47
- this.onMessage(socket, event);
48
- };
49
- socket.onclose = () => {
50
- this.stop();
51
- };
32
+ this.call = DailyIframe.createCallObject({
33
+ url,
34
+ audioSource: true,
35
+ videoSource: false,
36
+ });
52
37
  })
53
38
  .catch((error) => {
54
39
  console.error(error);
55
40
  });
56
41
  }
57
42
 
58
- private startRecording(): void {
59
- navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
60
- this.mediaRecorder = new MediaRecorder(stream, {
61
- mimeType: "audio/webm;codecs=opus",
62
- });
63
-
64
- this.mediaRecorder.ondataavailable = (event: BlobEvent) => {
65
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
66
- this.ws.send(event.data);
67
- }
68
- };
69
- this.mediaRecorder.start(100);
70
- });
71
- }
72
-
73
- private onMessage(ws: WebSocket, event: MessageEvent): void {
74
- const data = JSON.parse(event.data);
75
-
76
- switch (data.event) {
77
- case "connected":
78
- this.startRecording();
79
- this.emit("started");
80
- break;
81
- case "clear":
82
- this.clear();
83
- break;
84
- case "media":
85
- const audioData = decode(data.media.payload);
86
- this.player.playChunk(audioData);
87
- }
88
- }
89
-
90
- clear(): void {
91
- this.player.clear();
92
- }
93
-
94
43
  stop(): void {
95
44
  this.started = false;
96
- if (this.ws) {
97
- this.ws.close();
98
- }
99
- this.ws = null;
100
- if (this.mediaRecorder) {
101
- this.mediaRecorder.stop();
102
- }
103
- this.mediaRecorder = null;
104
- this.emit("stopped");
45
+ this.call?.destroy();
46
+ this.call = null;
105
47
  }
106
48
  }
@@ -1,97 +0,0 @@
1
- import async, { QueueObject } from "async";
2
-
3
- import EventEmitter from "events";
4
-
5
- declare global {
6
- interface Window {
7
- ManagedMediaSource: any;
8
- }
9
- }
10
-
11
- // ManagedMediaSource needed for iOS Safari
12
- function getMediaSource() {
13
- if (window.ManagedMediaSource) {
14
- return new window.ManagedMediaSource();
15
- }
16
- if (window.MediaSource) {
17
- return new window.MediaSource();
18
- }
19
-
20
- return null;
21
- }
22
-
23
- class AtomicMediaSource extends EventEmitter {
24
- mediaSource: any;
25
- sourceBuffer: SourceBuffer | null = null;
26
- private operationsQueue: QueueObject<() => Promise<void>>;
27
-
28
- constructor() {
29
- super();
30
- this.mediaSource = getMediaSource();
31
- this.operationsQueue = this.createOperationQueue();
32
-
33
- if (!this.mediaSource) {
34
- console.error("MediaSource is not supported in your browser.");
35
- // Display a message to the user, or handle this situation in another way
36
- return;
37
- }
38
-
39
- this.mediaSource.addEventListener("sourceopen", () => {
40
- this.mediaSource.duration = Number.POSITIVE_INFINITY;
41
- this.sourceBuffer = this.mediaSource.addSourceBuffer(
42
- 'audio/webm; codecs="opus"'
43
- );
44
- if (this.sourceBuffer) {
45
- this.sourceBuffer.mode = "sequence";
46
- }
47
- });
48
- }
49
-
50
- public appendBuffer(buffer: ArrayBuffer) {
51
- this.operationsQueue.push(() => {
52
- return new Promise((resolve, reject) => {
53
- if (this.sourceBuffer) {
54
- this.sourceBuffer.addEventListener(
55
- "updateend",
56
- () => {
57
- resolve();
58
- },
59
- { once: true }
60
- );
61
- this.sourceBuffer.appendBuffer(buffer);
62
- } else {
63
- reject();
64
- }
65
- });
66
- });
67
- }
68
-
69
- public clearBuffer() {
70
- // this.operationsQueue.push(() => {
71
- // return new Promise((resolve, reject) => {
72
- // if (this.sourceBuffer) {
73
- // this.sourceBuffer.addEventListener(
74
- // "updateend",
75
- // () => {
76
- // resolve();
77
- // },
78
- // { once: true }
79
- // );
80
- // if (this.sourceBuffer.buffered.length > 0) {
81
- // this.sourceBuffer.remove(0, this.sourceBuffer.buffered.end(0));
82
- // }
83
- // } else {
84
- // reject();
85
- // }
86
- // });
87
- // });
88
- }
89
-
90
- private createOperationQueue() {
91
- return async.queue<() => Promise<void>>((task, callback) => {
92
- task().then(() => callback());
93
- }, 1);
94
- }
95
- }
96
-
97
- export default AtomicMediaSource;
package/player.ts DELETED
@@ -1,46 +0,0 @@
1
- import AtomicMediaSource from "./AtomicMediaSource";
2
- import EventEmitter from "events";
3
-
4
- export class ContinuousPlayer extends EventEmitter {
5
- private atomic: AtomicMediaSource;
6
- private audio: HTMLAudioElement;
7
-
8
- constructor() {
9
- super();
10
-
11
- this.audio = document.createElement("audio");
12
-
13
- this.audio.addEventListener("playing", () => this.emit("speech-start"));
14
- this.audio.addEventListener("play", () => this.emit("speech-start"));
15
- this.audio.addEventListener("canplay", () => {
16
- this.audio.play();
17
- });
18
-
19
- this.audio.addEventListener("waiting", () => this.emit("speech-end"));
20
-
21
- this.atomic = new AtomicMediaSource();
22
-
23
- this.audio.src = URL.createObjectURL(this.atomic.mediaSource);
24
- document.body.appendChild(this.audio);
25
- }
26
-
27
- start() {
28
- this.audio.play();
29
- }
30
-
31
- playChunk(audioData: ArrayBuffer) {
32
- this.atomic.sourceBuffer?.addEventListener(
33
- "updateend",
34
- () => {
35
- this.audio.play().catch((error) => console.error("Play error:", error));
36
- },
37
- { once: true }
38
- );
39
- this.atomic.appendBuffer(audioData);
40
- }
41
-
42
- clear() {
43
- this.audio.pause();
44
- this.atomic.clearBuffer();
45
- }
46
- }
package/silent.mp3 DELETED
Binary file