Sergei dde0ecb9cd Add Julia AI voice agent with LiveKit integration
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>
2026-01-17 17:58:31 -08:00

188 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* End-to-end test for Julia AI Voice flow
* Tests: Token generation → Room creation → Agent availability
*/
const { AccessToken, RoomServiceClient } = require('livekit-server-sdk');
const LIVEKIT_API_KEY = 'APIEivUcPW3WSrV';
const LIVEKIT_API_SECRET = 'A65mc5KUKE0VGdZNaMRwe6uJpA9ZQPAxS66akZTOfmL';
const LIVEKIT_URL = 'wss://live-kit-demo-70txlh6a.livekit.cloud';
const LIVEKIT_HTTP_URL = 'https://live-kit-demo-70txlh6a.livekit.cloud';
const AGENT_NAME = 'julia-ai';
async function testTokenGeneration() {
console.log('\n=== Test 1: Token Generation ===');
try {
const token = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, {
identity: 'test-user-' + Date.now(),
ttl: 3600,
});
token.addGrant({
room: 'test-room-' + Date.now(),
roomJoin: true,
canPublish: true,
canSubscribe: true,
canPublishData: true,
});
const jwt = await token.toJwt();
console.log('✅ Token generated successfully');
console.log(' Token length:', jwt.length);
console.log(' Token preview:', jwt.substring(0, 50) + '...');
return true;
} catch (error) {
console.log('❌ Token generation failed:', error.message);
return false;
}
}
async function testRoomServiceConnection() {
console.log('\n=== Test 2: Room Service Connection ===');
try {
const roomService = new RoomServiceClient(LIVEKIT_HTTP_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
// List existing rooms
const rooms = await roomService.listRooms();
console.log('✅ Connected to LiveKit Cloud');
console.log(' Active rooms:', rooms.length);
if (rooms.length > 0) {
console.log(' Room names:', rooms.map(r => r.name).join(', '));
}
return true;
} catch (error) {
console.log('❌ Room Service connection failed:', error.message);
return false;
}
}
async function testCreateRoomWithAgent() {
console.log('\n=== Test 3: Create Room with Agent Request ===');
try {
const roomService = new RoomServiceClient(LIVEKIT_HTTP_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
const roomName = 'julia-test-' + Date.now();
// Create room with agent configuration
const room = await roomService.createRoom({
name: roomName,
emptyTimeout: 60, // 1 minute
maxParticipants: 2,
// Note: Agent dispatch happens automatically when user joins with proper token
});
console.log('✅ Room created successfully');
console.log(' Room name:', room.name);
console.log(' Room SID:', room.sid);
console.log(' Empty timeout:', room.emptyTimeout, 'seconds');
// Clean up - delete the test room
await roomService.deleteRoom(roomName);
console.log(' Room cleaned up');
return true;
} catch (error) {
console.log('❌ Room creation failed:', error.message);
return false;
}
}
async function testTokenServerEndpoint() {
console.log('\n=== Test 4: Token Server Endpoint ===');
try {
// Test health endpoint
const healthResponse = await fetch('https://wellnuo.smartlaunchhub.com/julia/health');
const healthData = await healthResponse.json();
if (healthData.status !== 'ok') {
console.log('❌ Health check failed:', healthData);
return false;
}
console.log('✅ Health endpoint OK');
console.log(' Agent:', healthData.agent);
console.log(' URL:', healthData.url);
// Test token endpoint
const tokenResponse = await fetch('https://wellnuo.smartlaunchhub.com/julia/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userId: 'test-user-' + Date.now() }),
});
const tokenData = await tokenResponse.json();
if (!tokenData.success) {
console.log('❌ Token endpoint failed:', tokenData);
return false;
}
console.log('✅ Token endpoint OK');
console.log(' Room:', tokenData.data.roomName);
console.log(' WebSocket URL:', tokenData.data.wsUrl);
console.log(' Token length:', tokenData.data.token.length);
return true;
} catch (error) {
console.log('❌ Token server test failed:', error.message);
return false;
}
}
async function checkAgentDeployment() {
console.log('\n=== Test 5: Agent Deployment Status ===');
console.log(' Agent Name:', AGENT_NAME);
console.log(' LiveKit Cloud URL:', LIVEKIT_URL);
console.log('');
console.log(' ⚠️ Agent deployment status cannot be checked via API.');
console.log(' ⚠️ Verify at: https://cloud.livekit.io/projects');
console.log('');
console.log(' If agent is deployed, it should automatically join rooms');
console.log(' when a user connects with a valid token.');
return true;
}
async function runAllTests() {
console.log('╔════════════════════════════════════════════════════════════╗');
console.log('║ Julia AI Voice - End-to-End Backend Test ║');
console.log('╚════════════════════════════════════════════════════════════╝');
const results = {
tokenGeneration: await testTokenGeneration(),
roomService: await testRoomServiceConnection(),
createRoom: await testCreateRoomWithAgent(),
tokenServer: await testTokenServerEndpoint(),
agentDeployment: await checkAgentDeployment(),
};
console.log('\n═══════════════════════════════════════════════════════════════');
console.log(' TEST SUMMARY ');
console.log('═══════════════════════════════════════════════════════════════');
let passed = 0;
let failed = 0;
for (const [test, result] of Object.entries(results)) {
const status = result ? '✅ PASS' : '❌ FAIL';
console.log(` ${test}: ${status}`);
if (result) passed++; else failed++;
}
console.log('');
console.log(` Total: ${passed} passed, ${failed} failed`);
console.log('═══════════════════════════════════════════════════════════════');
if (failed === 0) {
console.log('\n🎉 All backend tests passed! Ready for mobile testing.');
} else {
console.log('\n⚠ Some tests failed. Please fix issues before mobile testing.');
}
}
runAllTests().catch(console.error);