1import OpenAI from 'openai';
2
3const openai = new OpenAI();
4
5// Server: Next.js Route Handler
6export async function POST(req: Request) {
7 const { messages } = await req.json();
8
9 // 1. Open a streaming completion
10 const stream = await openai.chat.completions.create({
11 model: 'gpt-4o-mini',
12 messages,
13 stream: true,
14 stream_options: { include_usage: true },
15 });
16
17 // 2. Wrap in a ReadableStream of SSE events
18 const encoder = new TextEncoder();
19 const sse = new ReadableStream({
20 async start(controller) {
21 try {
22 for await (const chunk of stream) {
23 const delta = chunk.choices[0]?.delta?.content ?? '';
24 if (delta) controller.enqueue(encoder.encode(`data: ${JSON.stringify({ delta })}\n\n`));
25 // 3. Final chunk has usage
26 if (chunk.usage) controller.enqueue(encoder.encode(`data: ${JSON.stringify({ usage: chunk.usage })}\n\n`));
27 }
28 // 4. Signal done
29 controller.enqueue(encoder.encode('data: [DONE]\n\n'));
30 } catch (err) {
31 controller.enqueue(encoder.encode(`event: error\ndata: ${JSON.stringify({ message: String(err) })}\n\n`));
32 } finally {
33 controller.close();
34 }
35 },
36 });
37
38 // 5. Headers that defeat buffering
39 return new Response(sse, {
40 headers: {
41 'Content-Type': 'text/event-stream',
42 'Cache-Control': 'no-cache, no-transform',
43 'X-Accel-Buffering': 'no',
44 'Connection': 'keep-alive',
45 },
46 });
47}