sycoraxai-voice-assistants
Version:
A voice assistant package for React applications supporting multiple providers
131 lines (111 loc) • 5.02 kB
text/typescript
import { Room, RoomEvent } from 'livekit-client';
import { RetellWebClient } from 'retell-client-js-sdk';
import { ConnectionDetails, LiveKitVoiceAssistant, RetellVoiceAssistant, VoiceAssistantConfig, LiveKitConnectionDetails, RetellConnectionDetails, GeneralConnectionDetails } from './types';
import { SimpleVoiceAssistant } from './components/SimpleVoiceAssistant';
import { AgentVisualizer } from './components/AgentVisualizer';
import { ControlBar } from './components/ControlBar';
import { LiveKitProvider } from './components/LiveKitProvider';
import { VoiceAssistant } from './components/VoiceAssistant';
import { TranscriptionView } from './components/TranscriptionView';
import { RetellProvider } from './components/RetellProvider';
import { RetellSimpleVoiceAssistant } from './components/RetellSimpleVoiceAssistant';
export class LiveKitVoiceAssistantImpl implements LiveKitVoiceAssistant {
public room: Room;
private config: VoiceAssistantConfig;
constructor(config: VoiceAssistantConfig = {}) {
this.room = new Room();
this.config = config;
if (config.onDeviceFailure) {
this.room.on(RoomEvent.MediaDevicesError, config.onDeviceFailure);
}
}
public async connect(connectionDetails: LiveKitConnectionDetails): Promise<void> {
console.log("CONNECTING TO LIVEKIT WITH CONNECTION DETAILS ", connectionDetails);
await this.room.connect(connectionDetails.serverUrl, connectionDetails.participantToken);
await this.room.localParticipant.setMicrophoneEnabled(true);
}
public disconnect(): void {
this.room.disconnect();
}
}
export class RetellVoiceAssistantImpl implements RetellVoiceAssistant {
public client: RetellWebClient;
public isCallActive: boolean = false;
public agentStatus: 'idle' | 'connecting' | 'listening' | 'speaking' = 'idle';
private config: VoiceAssistantConfig;
constructor(config: VoiceAssistantConfig = {}) {
this.config = config;
this.client = new RetellWebClient();
this.setupEventListeners();
}
private setupEventListeners(): void {
this.client.on('call_started', () => {
console.log('Retell call started');
this.agentStatus = 'listening';
this.isCallActive = true;
this.config.onCallStarted?.();
});
this.client.on('call_ended', () => {
console.log('Retell call ended');
this.agentStatus = 'idle';
this.isCallActive = false;
this.config.onCallEnded?.();
});
this.client.on('agent_start_talking', () => {
console.log('Retell agent started talking');
this.agentStatus = 'speaking';
this.config.onAgentStartTalking?.();
});
this.client.on('agent_stop_talking', () => {
console.log('Retell agent stopped talking');
this.agentStatus = 'listening';
this.config.onAgentStopTalking?.();
});
this.client.on('error', (error: Error) => {
console.error('Retell error:', error);
this.client.stopCall();
this.isCallActive = false;
this.agentStatus = 'idle';
this.config.onError?.(error);
});
}
public async connect(connectionDetails: RetellConnectionDetails): Promise<void> {
this.agentStatus = 'connecting';
console.log("STARTING RETELL CALL WITH CONNECTION DETAILS ", connectionDetails);
await this.client.startCall({
accessToken: connectionDetails.access_token,
sampleRate: connectionDetails.sample_rate || 24000,
captureDeviceId: connectionDetails.capture_device_id || 'default',
emitRawAudioSamples: connectionDetails.emit_raw_audio_samples || false,
});
}
public disconnect(): void {
if (this.isCallActive) {
this.client.stopCall();
this.isCallActive = false;
this.agentStatus = 'idle';
}
}
}
export function createLiveKitVoiceAssistant(config?: VoiceAssistantConfig): LiveKitVoiceAssistant {
return new LiveKitVoiceAssistantImpl(config);
}
export function createRetellVoiceAssistant(config?: VoiceAssistantConfig): RetellVoiceAssistant {
return new RetellVoiceAssistantImpl(config);
}
export function createVoiceAssistant(provider: 'livekit', config?: VoiceAssistantConfig): LiveKitVoiceAssistant;
export function createVoiceAssistant(provider: 'retell', config?: VoiceAssistantConfig): RetellVoiceAssistant;
export function createVoiceAssistant(provider: string, config?: VoiceAssistantConfig): LiveKitVoiceAssistant | RetellVoiceAssistant {
switch (provider) {
case 'livekit':
return createLiveKitVoiceAssistant(config);
case 'retell':
return createRetellVoiceAssistant(config);
default:
throw new Error(`Provider ${provider} is not supported`);
}
}
// Export types
export type { ConnectionDetails, VoiceAssistantConfig, LiveKitVoiceAssistant, RetellVoiceAssistant, LiveKitConnectionDetails, RetellConnectionDetails, GeneralConnectionDetails };
// Export components
export { SimpleVoiceAssistant, AgentVisualizer, ControlBar, LiveKitProvider, VoiceAssistant, TranscriptionView, RetellProvider, RetellSimpleVoiceAssistant };