Voice AI Features: - LiveKit Agents integration for real-time voice calls - Julia AI agent (Python) deployed to LiveKit Cloud - Token server for authentication - Debug screen with voice call testing - Voice call screen with full-screen UI Agent Configuration: - STT: Deepgram Nova-2 - LLM: OpenAI GPT-4o - TTS: Deepgram Aura Asteria (female voice) - Turn Detection: LiveKit Multilingual Model - VAD: Silero - Noise Cancellation: LiveKit BVC Files added: - julia-agent/ - Complete agent code and token server - app/voice-call.tsx - Full-screen voice call UI - services/livekitService.ts - LiveKit client service - contexts/VoiceTranscriptContext.tsx - Transcript state - polyfills/livekit-globals.ts - WebRTC polyfills 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
104 lines
2.5 KiB
TypeScript
104 lines
2.5 KiB
TypeScript
/**
|
|
* LiveKit Voice AI Service
|
|
* Connects to LiveKit Cloud with Julia AI agent
|
|
* Uses dedicated Julia Token Server for token generation
|
|
*/
|
|
|
|
// Julia Token Server (dedicated endpoint for LiveKit tokens)
|
|
const JULIA_TOKEN_SERVER = 'https://wellnuo.smartlaunchhub.com/julia';
|
|
|
|
// Voice configuration
|
|
export const VOICE_ID = 'Asteria';
|
|
export const VOICE_NAME = 'Asteria';
|
|
|
|
// API Response types
|
|
export interface LiveKitTokenResponse {
|
|
success: boolean;
|
|
data?: {
|
|
token: string;
|
|
roomName: string;
|
|
wsUrl: string;
|
|
};
|
|
error?: string;
|
|
}
|
|
|
|
/**
|
|
* Get a LiveKit access token from Julia Token Server
|
|
* No authentication required - token server is dedicated for voice AI
|
|
*/
|
|
export async function getToken(userId: string): Promise<LiveKitTokenResponse> {
|
|
try {
|
|
console.log('[LiveKit] Getting token for user:', userId);
|
|
|
|
// Request LiveKit token from Julia Token Server
|
|
const response = await fetch(`${JULIA_TOKEN_SERVER}/token`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ userId }),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
console.error('[LiveKit] Token request failed:', response.status, errorData);
|
|
return {
|
|
success: false,
|
|
error: errorData.error || `Failed to get token: ${response.status}`,
|
|
};
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (!data.success) {
|
|
return {
|
|
success: false,
|
|
error: data.error || 'Token generation failed',
|
|
};
|
|
}
|
|
|
|
console.log('[LiveKit] Token received:', {
|
|
room: data.data.roomName,
|
|
identity: data.data.identity,
|
|
url: data.data.wsUrl,
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
token: data.data.token,
|
|
roomName: data.data.roomName,
|
|
wsUrl: data.data.wsUrl,
|
|
},
|
|
};
|
|
} catch (error) {
|
|
console.error('[LiveKit] Get token error:', error);
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : 'Failed to get token',
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if LiveKit service is available
|
|
*/
|
|
export async function checkServerHealth(): Promise<boolean> {
|
|
try {
|
|
const response = await fetch(`${JULIA_TOKEN_SERVER}/health`, {
|
|
method: 'GET',
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
console.log('[LiveKit] Health check:', data);
|
|
return data.status === 'ok';
|
|
}
|
|
|
|
return false;
|
|
} catch (error) {
|
|
console.error('[LiveKit] Health check failed:', error);
|
|
return false;
|
|
}
|
|
}
|