@vapi-ai/web 1.0.266 → 1.0.267

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/vapi.ts CHANGED
@@ -1,19 +1,17 @@
1
- import { Call, CreateAssistantDTO } from "./api";
1
+ import { Call, CreateAssistantDTO } from './api';
2
2
  import DailyIframe, {
3
3
  DailyCall,
4
4
  DailyEventObjectAppMessage,
5
5
  DailyEventObjectParticipant,
6
6
  DailyEventObjectRemoteParticipantsAudioLevel,
7
- } from "@daily-co/daily-js";
7
+ } from '@daily-co/daily-js';
8
8
 
9
- import type { ChatCompletionMessageParam } from "openai/resources";
10
- import EventEmitter from "events";
11
- import { client } from "./client";
9
+ import type { ChatCompletionMessageParam } from 'openai/resources';
10
+ import EventEmitter from 'events';
11
+ import { client } from './client';
12
12
 
13
13
  function destroyAudioPlayer(participantId: string) {
14
- const player = document.querySelector(
15
- `audio[data-participant-id="${participantId}"]`
16
- );
14
+ const player = document.querySelector(`audio[data-participant-id="${participantId}"]`);
17
15
  player?.remove();
18
16
  }
19
17
  async function startPlayer(player: HTMLAudioElement, track: any) {
@@ -25,7 +23,7 @@ async function startPlayer(player: HTMLAudioElement, track: any) {
25
23
  }
26
24
  }
27
25
  async function buildAudioPlayer(track: any, participantId: string) {
28
- const player = document.createElement("audio");
26
+ const player = document.createElement('audio');
29
27
  player.dataset.participantId = participantId;
30
28
  document.body.appendChild(player);
31
29
  await startPlayer(player, track);
@@ -43,56 +41,49 @@ function subscribeToTracks(e: DailyEventObjectParticipant, call: DailyCall) {
43
41
  }
44
42
 
45
43
  export interface AddMessageMessage {
46
- type: "add-message";
44
+ type: 'add-message';
47
45
  message: ChatCompletionMessageParam;
48
46
  }
49
47
 
50
- type VapiClientToServerMessage = AddMessageMessage;
48
+ export interface ControlMessages {
49
+ type: 'control';
50
+ control: 'mute-assistant' | 'unmute-assistant';
51
+ }
52
+
53
+ type VapiClientToServerMessage = AddMessageMessage | ControlMessages;
51
54
 
52
55
  type VapiEventNames =
53
- | "call-end"
54
- | "call-start"
55
- | "volume-level"
56
- | "speech-start"
57
- | "speech-end"
58
- | "message"
59
- | "error";
56
+ | 'call-end'
57
+ | 'call-start'
58
+ | 'volume-level'
59
+ | 'speech-start'
60
+ | 'speech-end'
61
+ | 'message'
62
+ | 'error';
60
63
 
61
64
  type VapiEventListeners = {
62
- "call-end": () => void;
63
- "call-start": () => void;
64
- "volume-level": (volume: number) => void;
65
- "speech-start": () => void;
66
- "speech-end": () => void;
65
+ 'call-end': () => void;
66
+ 'call-start': () => void;
67
+ 'volume-level': (volume: number) => void;
68
+ 'speech-start': () => void;
69
+ 'speech-end': () => void;
67
70
  message: (message: any) => void;
68
71
  error: (error: any) => void;
69
72
  };
70
73
 
71
74
  class VapiEventEmitter extends EventEmitter {
72
- on<E extends VapiEventNames>(
73
- event: E,
74
- listener: VapiEventListeners[E]
75
- ): this {
75
+ on<E extends VapiEventNames>(event: E, listener: VapiEventListeners[E]): this {
76
76
  super.on(event, listener);
77
77
  return this;
78
78
  }
79
- once<E extends VapiEventNames>(
80
- event: E,
81
- listener: VapiEventListeners[E]
82
- ): this {
79
+ once<E extends VapiEventNames>(event: E, listener: VapiEventListeners[E]): this {
83
80
  super.once(event, listener);
84
81
  return this;
85
82
  }
86
- emit<E extends VapiEventNames>(
87
- event: E,
88
- ...args: Parameters<VapiEventListeners[E]>
89
- ): boolean {
83
+ emit<E extends VapiEventNames>(event: E, ...args: Parameters<VapiEventListeners[E]>): boolean {
90
84
  return super.emit(event, ...args);
91
85
  }
92
- removeListener<E extends VapiEventNames>(
93
- event: E,
94
- listener: VapiEventListeners[E]
95
- ): this {
86
+ removeListener<E extends VapiEventNames>(event: E, listener: VapiEventListeners[E]): this {
96
87
  super.removeListener(event, listener);
97
88
  return this;
98
89
  }
@@ -110,7 +101,7 @@ export default class Vapi extends VapiEventEmitter {
110
101
 
111
102
  constructor(apiToken: string, apiBaseUrl?: string) {
112
103
  super();
113
- client.baseUrl = apiBaseUrl ?? "https://api.vapi.ai";
104
+ client.baseUrl = apiBaseUrl ?? 'https://api.vapi.ai';
114
105
  client.setSecurityData(apiToken);
115
106
  }
116
107
 
@@ -131,43 +122,46 @@ export default class Vapi extends VapiEventEmitter {
131
122
  try {
132
123
  const webCall = (
133
124
  await client.call.callControllerCreateWebCall({
134
- assistant: typeof assistant === "string" ? undefined : assistant,
135
- assistantId: typeof assistant === "string" ? assistant : undefined,
125
+ assistant: typeof assistant === 'string' ? undefined : assistant,
126
+ assistantId: typeof assistant === 'string' ? assistant : undefined,
136
127
  })
137
128
  ).data;
138
129
 
130
+ if (this.call) {
131
+ this.cleanup();
132
+ }
139
133
  this.call = DailyIframe.createCallObject({
140
134
  audioSource: true,
141
135
  videoSource: false,
142
136
  });
143
- this.call.iframe()?.style.setProperty("display", "none");
137
+ this.call.iframe()?.style.setProperty('display', 'none');
144
138
 
145
- this.call.on("left-meeting", () => {
146
- this.emit("call-end");
139
+ this.call.on('left-meeting', () => {
140
+ this.emit('call-end');
147
141
  this.cleanup();
148
142
  });
149
143
 
150
- this.call.on("participant-left", (e) => {
144
+ this.call.on('participant-left', (e) => {
151
145
  if (!e) return;
152
146
  destroyAudioPlayer(e.participant.session_id);
153
147
  });
154
148
 
155
- this.call.on("error", () => {
149
+ this.call.on('error', () => {
156
150
  // Ignore error
157
151
  });
158
152
 
159
- this.call.on("track-started", async (e) => {
153
+ this.call.on('track-started', async (e) => {
160
154
  if (!e || !e.participant) return;
161
155
  if (e.participant?.local) return;
162
- if (e.track.kind !== "audio") return;
156
+ if (e.track.kind !== 'audio') return;
163
157
 
164
158
  await buildAudioPlayer(e.track, e.participant.session_id);
165
159
 
166
- if (e?.participant?.user_name !== "Vapi Speaker") return;
167
- this.call?.sendAppMessage("playable");
160
+ if (e?.participant?.user_name !== 'Vapi Speaker') return;
161
+ this.call?.sendAppMessage('playable');
168
162
  });
169
163
 
170
- this.call.on("participant-joined", (e) => {
164
+ this.call.on('participant-joined', (e) => {
171
165
  if (!e || !this.call) return;
172
166
  subscribeToTracks(e, this.call);
173
167
  });
@@ -179,16 +173,16 @@ export default class Vapi extends VapiEventEmitter {
179
173
 
180
174
  this.call.startRemoteParticipantsAudioLevelObserver(100);
181
175
 
182
- this.call.on("remote-participants-audio-level", (e) => {
176
+ this.call.on('remote-participants-audio-level', (e) => {
183
177
  if (e) this.handleRemoteParticipantsAudioLevel(e);
184
178
  });
185
179
 
186
- this.call.on("app-message", (e) => this.onAppMessage(e));
180
+ this.call.on('app-message', (e) => this.onAppMessage(e));
187
181
 
188
182
  this.call.updateInputSettings({
189
183
  audio: {
190
184
  processor: {
191
- type: "noise-cancellation",
185
+ type: 'noise-cancellation',
192
186
  },
193
187
  },
194
188
  });
@@ -196,7 +190,7 @@ export default class Vapi extends VapiEventEmitter {
196
190
  return webCall;
197
191
  } catch (e) {
198
192
  console.error(e);
199
- this.emit("error", e);
193
+ this.emit('error', e);
200
194
  this.cleanup();
201
195
  return null;
202
196
  }
@@ -205,14 +199,14 @@ export default class Vapi extends VapiEventEmitter {
205
199
  private onAppMessage(e?: DailyEventObjectAppMessage) {
206
200
  if (!e) return;
207
201
  try {
208
- if (e.data === "listening") {
209
- return this.emit("call-start");
202
+ if (e.data === 'listening') {
203
+ return this.emit('call-start');
210
204
  } else {
211
205
  try {
212
206
  const parsedMessage = JSON.parse(e.data);
213
- this.emit("message", parsedMessage);
207
+ this.emit('message', parsedMessage);
214
208
  } catch (parseError) {
215
- console.log("Error parsing message data: ", parseError);
209
+ console.log('Error parsing message data: ', parseError);
216
210
  }
217
211
  }
218
212
  } catch (e) {
@@ -220,15 +214,10 @@ export default class Vapi extends VapiEventEmitter {
220
214
  }
221
215
  }
222
216
 
223
- private handleRemoteParticipantsAudioLevel(
224
- e: DailyEventObjectRemoteParticipantsAudioLevel
225
- ) {
226
- const speechLevel = Object.values(e.participantsAudioLevel).reduce(
227
- (a, b) => a + b,
228
- 0
229
- );
217
+ private handleRemoteParticipantsAudioLevel(e: DailyEventObjectRemoteParticipantsAudioLevel) {
218
+ const speechLevel = Object.values(e.participantsAudioLevel).reduce((a, b) => a + b, 0);
230
219
 
231
- this.emit("volume-level", Math.min(1, speechLevel / 0.15));
220
+ this.emit('volume-level', Math.min(1, speechLevel / 0.15));
232
221
 
233
222
  const isSpeaking = speechLevel > 0.01;
234
223
 
@@ -238,11 +227,11 @@ export default class Vapi extends VapiEventEmitter {
238
227
  clearTimeout(this.speakingTimeout);
239
228
  this.speakingTimeout = null;
240
229
  } else {
241
- this.emit("speech-start");
230
+ this.emit('speech-start');
242
231
  }
243
232
 
244
233
  this.speakingTimeout = setTimeout(() => {
245
- this.emit("speech-end");
234
+ this.emit('speech-end');
246
235
  this.speakingTimeout = null;
247
236
  }, 1000);
248
237
  }
@@ -260,7 +249,7 @@ export default class Vapi extends VapiEventEmitter {
260
249
  public setMuted(mute: boolean) {
261
250
  try {
262
251
  if (!this.call) {
263
- throw new Error("Call object is not available.");
252
+ throw new Error('Call object is not available.');
264
253
  }
265
254
  this.call.setLocalAudio(!mute);
266
255
  } catch (error) {
@@ -1,17 +0,0 @@
1
- /// <reference types="node" />
2
- import EventEmitter from "events";
3
- declare global {
4
- interface Window {
5
- ManagedMediaSource: any;
6
- }
7
- }
8
- declare class AtomicMediaSource extends EventEmitter {
9
- mediaSource: any;
10
- sourceBuffer: SourceBuffer | null;
11
- private operationsQueue;
12
- constructor();
13
- appendBuffer(buffer: ArrayBuffer): void;
14
- clearBuffer(): void;
15
- private createOperationQueue;
16
- }
17
- export default AtomicMediaSource;
@@ -1,78 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const async_1 = __importDefault(require("async"));
7
- const events_1 = __importDefault(require("events"));
8
- // ManagedMediaSource needed for iOS Safari
9
- function getMediaSource() {
10
- if (window.ManagedMediaSource) {
11
- return new window.ManagedMediaSource();
12
- }
13
- if (window.MediaSource) {
14
- return new window.MediaSource();
15
- }
16
- return null;
17
- }
18
- class AtomicMediaSource extends events_1.default {
19
- constructor() {
20
- super();
21
- this.sourceBuffer = null;
22
- this.mediaSource = getMediaSource();
23
- this.operationsQueue = this.createOperationQueue();
24
- if (!this.mediaSource) {
25
- console.error("MediaSource is not supported in your browser.");
26
- // Display a message to the user, or handle this situation in another way
27
- return;
28
- }
29
- this.mediaSource.addEventListener("sourceopen", () => {
30
- this.mediaSource.duration = Number.POSITIVE_INFINITY;
31
- this.sourceBuffer = this.mediaSource.addSourceBuffer('audio/webm; codecs="opus"');
32
- if (this.sourceBuffer) {
33
- this.sourceBuffer.mode = "sequence";
34
- }
35
- });
36
- }
37
- appendBuffer(buffer) {
38
- this.operationsQueue.push(() => {
39
- return new Promise((resolve, reject) => {
40
- if (this.sourceBuffer) {
41
- this.sourceBuffer.addEventListener("updateend", () => {
42
- resolve();
43
- }, { once: true });
44
- this.sourceBuffer.appendBuffer(buffer);
45
- }
46
- else {
47
- reject();
48
- }
49
- });
50
- });
51
- }
52
- clearBuffer() {
53
- // this.operationsQueue.push(() => {
54
- // return new Promise((resolve, reject) => {
55
- // if (this.sourceBuffer) {
56
- // this.sourceBuffer.addEventListener(
57
- // "updateend",
58
- // () => {
59
- // resolve();
60
- // },
61
- // { once: true }
62
- // );
63
- // if (this.sourceBuffer.buffered.length > 0) {
64
- // this.sourceBuffer.remove(0, this.sourceBuffer.buffered.end(0));
65
- // }
66
- // } else {
67
- // reject();
68
- // }
69
- // });
70
- // });
71
- }
72
- createOperationQueue() {
73
- return async_1.default.queue((task, callback) => {
74
- task().then(() => callback());
75
- }, 1);
76
- }
77
- }
78
- exports.default = AtomicMediaSource;
package/dist/player.d.ts DELETED
@@ -1,10 +0,0 @@
1
- /// <reference types="node" />
2
- import EventEmitter from "events";
3
- export declare class ContinuousPlayer extends EventEmitter {
4
- private atomic;
5
- private audio;
6
- constructor();
7
- start(): void;
8
- playChunk(audioData: ArrayBuffer): void;
9
- clear(): void;
10
- }
package/dist/player.js DELETED
@@ -1,38 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ContinuousPlayer = void 0;
7
- const AtomicMediaSource_1 = __importDefault(require("./AtomicMediaSource"));
8
- const events_1 = __importDefault(require("events"));
9
- class ContinuousPlayer extends events_1.default {
10
- constructor() {
11
- super();
12
- this.audio = document.createElement("audio");
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
- this.audio.addEventListener("waiting", () => this.emit("speech-end"));
19
- this.atomic = new AtomicMediaSource_1.default();
20
- this.audio.src = URL.createObjectURL(this.atomic.mediaSource);
21
- document.body.appendChild(this.audio);
22
- }
23
- start() {
24
- this.audio.play();
25
- }
26
- playChunk(audioData) {
27
- var _a;
28
- (_a = this.atomic.sourceBuffer) === null || _a === void 0 ? void 0 : _a.addEventListener("updateend", () => {
29
- this.audio.play().catch((error) => console.error("Play error:", error));
30
- }, { once: true });
31
- this.atomic.appendBuffer(audioData);
32
- }
33
- clear() {
34
- this.audio.pause();
35
- this.atomic.clearBuffer();
36
- }
37
- }
38
- exports.ContinuousPlayer = ContinuousPlayer;