Streaming AI Responses
LLM response bisa panjang dan lambat. Streaming menampilkan token satu per satu saat dihasilkan — seperti ChatGPT typing effect. UX jauh lebih baik daripada loading spinner 10 detik.
Backend: Stream dari OpenAI
// Express endpoint
app.post("/api/chat", async (req, res) => {
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
const stream = await openai.chat.completions.create({
model: "gpt-4o",
messages: req.body.messages,
stream: true, // Enable streaming
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || "";
if (content) {
res.write(`data: ${JSON.stringify({ content })}\n\n`);
}
}
res.write("data: [DONE]\n\n");
res.end();
});
Frontend: Consume Stream
async function streamChat(messages, onToken) {
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages }),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const text = decoder.decode(value);
const lines = text.split("\n").filter(Boolean);
for (const line of lines) {
if (line.startsWith("data: ") && line !== "data: [DONE]") {
const { content } = JSON.parse(line.slice(6));
onToken(content); // append ke UI
}
}
}
}
Vercel AI SDK (Simpler)
// Backend (Next.js Route Handler)
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export async function POST(req) {
const { messages } = await req.json();
const result = streamText({
model: openai("gpt-4o"),
messages,
});
return result.toDataStreamResponse();
}
// Frontend (React)
import { useChat } from "ai/react";
function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div>
{messages.map(m => <p key={m.id}>{m.content}</p>)}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
</form>
</div>
);
}