It's not Vercel, it's the loop. You read the entire stream into text on the server and only then return it. Locally it probably only looked like streaming because the client animates the text.
Pass the stream through instead:
export async function POST(req: Request) {
const { messages } = await req.json();
const stream = await openai.chat.completions.create({ model, messages, stream: true });
const encoder = new TextEncoder();
const body = new ReadableStream({
async start(controller) {
for await (const chunk of stream) {
controller.enqueue(encoder.encode(chunk.choices[0]?.delta?.content ?? ""));
}
controller.close();
},
});
return new Response(body, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
}And on the client, read res.body.getReader() instead of await res.text(), otherwise the browser waits for the end as well.