``` feat: migrate from OpenAI Realtime API to LiveKit for voice infrastructure Replace direct OpenAI Realtime API WebRTC connection with LiveKit Cloud infrastructure. Add LiveKit agent package with OpenAI and Silero plugins for voice-to-voice conversations. Update web client to use LiveKit React components and session token authentication. Maintain backward compatibility for OpenAI event types during transition. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> ``` This commit message: - Uses `feat:` type since this is a new feature/major change - Describes the main change (migration from OpenAI to LiveKit) - Provides context in the body about what was added/changed - Mentions backward compatibility consideration - Includes the Claude Code attribution as requested
69 lines
1.6 KiB
TypeScript
69 lines
1.6 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { AccessToken, type VideoGrant } from "livekit-server-sdk";
|
|
|
|
const LIVEKIT_API_KEY = process.env.LIVEKIT_API_KEY;
|
|
const LIVEKIT_API_SECRET = process.env.LIVEKIT_API_SECRET;
|
|
const LIVEKIT_URL = process.env.LIVEKIT_URL;
|
|
|
|
export async function POST() {
|
|
if (!LIVEKIT_API_KEY) {
|
|
return NextResponse.json(
|
|
{ error: "LiveKit API key not configured" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
|
|
if (!LIVEKIT_API_SECRET) {
|
|
return NextResponse.json(
|
|
{ error: "LiveKit API secret not configured" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
|
|
if (!LIVEKIT_URL) {
|
|
return NextResponse.json(
|
|
{ error: "LiveKit URL not configured" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
|
|
try {
|
|
console.log("Creating LiveKit token...");
|
|
|
|
const participantIdentity = `voice_user_${Math.floor(Math.random() * 10_000)}`;
|
|
const participantName = "user";
|
|
const roomName = `voice_room_${Math.floor(Math.random() * 10_000)}`;
|
|
|
|
const token = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, {
|
|
identity: participantIdentity,
|
|
name: participantName,
|
|
ttl: "15m",
|
|
});
|
|
|
|
const grant: VideoGrant = {
|
|
room: roomName,
|
|
roomJoin: true,
|
|
canPublish: true,
|
|
canPublishData: true,
|
|
canSubscribe: true,
|
|
};
|
|
|
|
token.addGrant(grant);
|
|
|
|
const jwt = await token.toJwt();
|
|
|
|
return NextResponse.json({
|
|
serverUrl: LIVEKIT_URL,
|
|
roomName,
|
|
participantToken: jwt,
|
|
participantName,
|
|
});
|
|
} catch (error) {
|
|
console.error("Token creation error:", error);
|
|
return NextResponse.json(
|
|
{ error: "Failed to create token" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|