Stream OpenAI responses to the browser for real-time text display
Quick Answer
OpenAI's `stream: true` returns a token stream; forward it to the client via SSE (Server-Sent Events) so tokens render in real-time as they arrive.
1import OpenAI from 'openai';
2import { Request, Response } from 'express';
3
4const client = new OpenAI({
5 apiKey: process.env.OPENAI_API_KEY,
6});
7
8export async function streamHandler(req: Request, res: Response) {
9 const { message } = req.body;
10
11 res.setHeader('Content-Type', 'text/event-stream');
12 res.setHeader('Cache-Control', 'no-cache');
13 res.setHeader('Connection', 'keep-alive');
14
15 try {
16 const stream = await client.chat.completions.create({
17 model: 'gpt-4o-mini',
18 messages: [
19 {
20 role: 'system',
21 content: 'You are a helpful assistant.',
22 },
23 {
24 role: 'user',
25 content: message,
26 },
27 ],
28 stream: true,
29 });
30
31 for await (const chunk of stream) {
32 if (chunk.choices[0]?.delta?.content) {
33 res.write(
34 `data: ${JSON.stringify({ token: chunk.choices[0].delta.content })}\n\n`
35 );
36 }
37 }
38
39 res.write('data: [DONE]\n\n');
40 res.end();
41 } catch (error) {
42 res.write(`data: ${JSON.stringify({ error: 'Stream failed' })}\n\n`);
43 res.end();
44 }
45}
46
47// Client-side usage
48/*
49const response = await fetch('/api/stream', {
50 method: 'POST',
51 headers: { 'Content-Type': 'application/json' },
52 body: JSON.stringify({ message: 'Hello!' }),
53});
54
55const reader = response.body?.getReader();
56const decoder = new TextDecoder();
57
58while (true) {
59 const { done, value } = await reader.read();
60 if (done) break;
61 const text = decoder.decode(value);
62 const lines = text.split('\n');
63 for (const line of lines) {
64 if (line.startsWith('data: ')) {
65 const json = JSON.parse(line.slice(6));
66 if (json.token) console.log(json.token);
67 }
68 }
69}
70*/Streaming OpenAI responses provides a much better user experience than waiting for the full response. Instead of a long loading state, users see text appear token-by-token. This snippet sets up an API route that streams OpenAI's response via SSE, which works seamlessly with `fetch` on the client side.
SSE is simpler, one-directional, and works over HTTP. WebSockets are bidirectional but more complex. For streaming AI responses, SSE is sufficient and more lightweight.
Yes. On the client, call `reader.cancel()` and the server detects the disconnection, stopping token generation.
This free typescript code snippet for streaming ai responses (real-time ui) is production-ready and copy-paste friendly. Whether you are building a web app, API, or frontend interface, this advanced-level example will help you implement streaming ai responses (real-time ui) quickly and correctly.
All snippets in the Snippetly library follow typescript best practices and are tested for real-world use. You can adapt this code to work with React, Vue, Node.js, or any project that uses typescript.
Organise your team's code snippets with Snippetly. Share knowledge and boost productivity across your organisation.