- Voice agent now extracts deploymentId and beneficiaryNamesDict from participant metadata passed via LiveKit token - WellNuoLLM class accepts dynamic deployment_id and beneficiary_names_dict - API calls now include personalized beneficiary names for better responses - Text chat already has this functionality (verified) - Updated LiveKit agent deployed to cloud Also includes: - Speaker toggle button in voice call UI - Keyboard controller integration for chat - Various UI improvements
118 lines
3.0 KiB
TypeScript
118 lines
3.0 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';
|
|
|
|
// Beneficiary data to pass to voice agent
|
|
export interface BeneficiaryData {
|
|
deploymentId: string;
|
|
beneficiaryNamesDict: Record<string, string>;
|
|
}
|
|
|
|
// 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
|
|
* @param userId - User identifier
|
|
* @param beneficiaryData - Optional beneficiary data to pass to voice agent
|
|
*/
|
|
export async function getToken(
|
|
userId: string,
|
|
beneficiaryData?: BeneficiaryData
|
|
): Promise<LiveKitTokenResponse> {
|
|
try {
|
|
console.log('[LiveKit] Getting token for user:', userId);
|
|
if (beneficiaryData) {
|
|
console.log('[LiveKit] With beneficiary data:', beneficiaryData);
|
|
}
|
|
|
|
// 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, beneficiaryData }),
|
|
});
|
|
|
|
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;
|
|
}
|
|
}
|