From 5e06cc39472d8181eeeadf1a1f1e236a81157acc Mon Sep 17 00:00:00 2001 From: Kirill Dubovitskiy Date: Wed, 6 Aug 2025 03:35:11 -0700 Subject: [PATCH] wip: generate short lived token on the backend to send to the frontend for realtime session creation --- package.json | 2 +- sources/app/api.ts | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 47dc0a4..4441978 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "build": "tsc --noEmit", "start": "tsx ./sources/main.ts", - "dev": "tsx --env-file=.env.example ./sources/main.ts", + "dev": "tsx --env-file=.env --env-file=.env.example ./sources/main.ts", "test": "vitest run", "migrate": "dotenv -e .env.example -- prisma migrate dev", "generate": "prisma generate", diff --git a/sources/app/api.ts b/sources/app/api.ts index c584b29..6892a26 100644 --- a/sources/app/api.ts +++ b/sources/app/api.ts @@ -253,6 +253,65 @@ export async function startApi(): Promise<{ app: FastifyInstance; io: Server }> return reply.send({ success: true }); }); + // OpenAI Realtime ephemeral token generation + typed.post('/v1/openai/realtime-token', { + preHandler: app.authenticate, + schema: { + response: { + 200: z.object({ + token: z.string() + }), + 500: z.object({ + error: z.string() + }) + } + } + }, async (request, reply) => { + try { + // Check if OpenAI API key is configured on server + const OPENAI_API_KEY = process.env.OPENAI_API_KEY; + if (!OPENAI_API_KEY) { + return reply.code(500).send({ + error: 'OpenAI API key not configured on server' + }); + } + + // Generate ephemeral token from OpenAI + const response = await fetch('https://api.openai.com/v1/realtime/sessions', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${OPENAI_API_KEY}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: 'gpt-4o-realtime-preview-2024-12-17', + voice: 'verse', + }), + }); + + if (!response.ok) { + throw new Error(`OpenAI API error: ${response.status}`); + } + + const data = await response.json() as { + client_secret: { + value: string; + expires_at: number; + }; + id: string; + }; + + return reply.send({ + token: data.client_secret.value + }); + } catch (error) { + log({ module: 'openai', level: 'error' }, 'Failed to generate ephemeral token', error); + return reply.code(500).send({ + error: 'Failed to generate ephemeral token' + }); + } + }); + // Sessions API typed.get('/v1/sessions', { preHandler: app.authenticate,