Skip to main content
Glama

Voice Mode

by mbailey
route.ts•2.96 kB
import { AccessToken, AccessTokenOptions, VideoGrant } from "livekit-server-sdk"; import { NextResponse, NextRequest } from "next/server"; // NOTE: Environment variables can be defined in `.env.local` or passed from voice-mode config const API_KEY = process.env.LIVEKIT_API_KEY || "devkey"; const API_SECRET = process.env.LIVEKIT_API_SECRET || "secret"; // TODO: Fix environment variable loading - hardcoded for now const LIVEKIT_URL = "wss://x1:8443"; // process.env.LIVEKIT_URL || "ws://localhost:7880"; // Password protection - set this in your .env.local file const ACCESS_PASSWORD = process.env.LIVEKIT_ACCESS_PASSWORD || "voicemode123"; // don't cache the results export const revalidate = 0; export type ConnectionDetails = { serverUrl: string; roomName: string; participantName: string; participantToken: string; }; export async function GET(request: NextRequest) { try { // Check for password in query params or Authorization header const url = new URL(request.url); const password = url.searchParams.get('password') || request.headers.get('x-access-password'); if (password !== ACCESS_PASSWORD) { return new NextResponse("Unauthorized", { status: 401 }); } // These checks are now optional since we have defaults // but we can still validate they're not empty strings if (!LIVEKIT_URL) { throw new Error("LIVEKIT_URL is empty"); } if (!API_KEY) { throw new Error("LIVEKIT_API_KEY is empty"); } if (!API_SECRET) { throw new Error("LIVEKIT_API_SECRET is empty"); } // Generate participant token const participantIdentity = `voice_assistant_user_${Math.floor(Math.random() * 10_000)}`; const roomName = `voice_assistant_room_${Math.floor(Math.random() * 10_000)}`; const participantToken = await createParticipantToken( { identity: participantIdentity }, roomName ); // Log the URL being used for debugging console.log("LIVEKIT_URL from env:", process.env.LIVEKIT_URL); console.log("Using LIVEKIT_URL:", LIVEKIT_URL); // Return connection details const data: ConnectionDetails = { serverUrl: LIVEKIT_URL, roomName, participantToken: participantToken, participantName: participantIdentity, }; const headers = new Headers({ "Cache-Control": "no-store", }); return NextResponse.json(data, { headers }); } catch (error) { if (error instanceof Error) { console.error(error); return new NextResponse(error.message, { status: 500 }); } } } function createParticipantToken(userInfo: AccessTokenOptions, roomName: string) { const at = new AccessToken(API_KEY, API_SECRET, { ...userInfo, ttl: "15m", }); const grant: VideoGrant = { room: roomName, roomJoin: true, canPublish: true, canPublishData: true, canSubscribe: true, }; at.addGrant(grant); return at.toJwt(); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mbailey/voicemode'

If you have feedback or need assistance with the MCP directory API, please join our Discord server