When an AI model generates an extensive response (e.g., 500 words of complex code or legal analysis), traditional synchronous HTTP requests force the user to stare at a blank screen or loading spinner for 10 to 20 seconds. This creates a terrible user experience. In contrast, Real-Time Streaming delivers tokens to the user interface the instant they are calculated by the GPU, reducing Time-to-First-Token (TTFT) to under 300 milliseconds!
| Technology | Communication Protocol | Complexity & Reconnection | Best Used For |
|---|---|---|---|
| Server-Sent Events (SSE) | Unidirectional (Server → Client) over standard HTTP/1.1 or HTTP/2. Content-Type: text/event-stream. |
Low Complexity. Built into modern web browsers (EventSource). Automatic reconnection, fire-and-forget, lightweight. |
The Industry Standard for AI Text Streaming (used by ChatGPT, Claude, and Gemini interfaces). |
| WebSockets | Full-Duplex (Bidirectional: Client ↔ Server) persistent TCP connection via ws:// or wss:// protocol. |
High Complexity. Requires dedicated WebSocket server, manual heartbeat pings, and reconnection logic. | Real-time speech-to-speech audio streams, multi-user multiplayer canvas collaboration, gaming. |
Accept: text/event-stream.ReadableStream and updates the UI state in real-time.// server_sse.js
const express = require('express');
const OpenAI = require('openai');
require('dotenv').config();
const app = express();
app.use(express.json());
const openai = new OpenAI();
app.post('/api/chat-stream', async (req, res) => {
const { prompt } = req.body;
// Set mandatory SSE Streaming Headers
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders(); // Establish stream immediately
try {
const stream = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
stream: true, // Enable streaming chunk response
});
for await (const chunk of stream) {
const token = chunk.choices[0]?.delta?.content || '';
if (token) {
// Send standard SSE event format
res.write('data: ' + JSON.stringify({ token }) + '
');
}
}
res.write('data: [DONE]
');
res.end();
} catch (err) {
console.error("Streaming error:", err);
res.write('data: ' + JSON.stringify({ error: err.message }) + '
');
res.end();
}
});
app.listen(3001, () => console.log("SSE Server running on port 3001"));
// client_stream.js (Browser / React)
async function streamAIResponse(userPrompt, onChunkReceived) {
const response = await fetch('/api/chat-stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: userPrompt })
});
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let fullResponse = "";
while (true) {
const { value, done } = await reader.read();
if (done) break;
const chunkText = decoder.decode(value);
const lines = chunkText.split('
');
for (const line of lines) {
if (line.startsWith('data: ')) {
const dataStr = line.replace('data: ', '').trim();
if (dataStr === '[DONE]') {
console.log("Streaming completed successfully!");
return fullResponse;
}
try {
const parsed = JSON.parse(dataStr);
if (parsed.token) {
fullResponse += parsed.token;
onChunkReceived(parsed.token, fullResponse);
}
} catch (e) {
// Ignore partial chunks
}
}
}
}
return fullResponse;
}
// Example usage: Update UI dynamically as tokens arrive
// streamAIResponse("Write a quick Python sort function", (token, fullText) => {
// document.getElementById("output").innerText = fullText;
// });
Broaden your foundational and advanced AI knowledge across our curriculum:
Handling basic HTTP requests and API keys securely on the backend.
Streaming partial JSON objects and structured tool calls in real-time.
Client-side token generation loops without any server roundtrip latency.
Code an interactive streaming chatbot in React and Node.js.