Problem Statement: I am building a chatbot in Next.js using ai and @ai-sdk/google. The chatbot should stream responses from Gemini (gemini-1.5-flash-8b) to the frontend. I confirmed that the response is streamed in the backend by logging the chunks:
for await (const textPart of result.textStream) {
console.log(textPart);
}
However, when I return the response to the frontend, the streaming effect is lost, and I receive the full response all at once.
What I Have Tried:
Backend (API Route in Next.js):
import { createGoogleGenerativeAI } from "@ai-sdk/google";
import { streamText } from "ai";
import { NextRequest, NextResponse } from "next/server";
const google = createGoogleGenerativeAI({
apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
});
const model = google("gemini-1.5-flash-8b");
export async function POST(req: NextRequest) {
try {
const { messages } = await req.json();
console.log(messages);
const result = streamText({
model: model,
system: "You are a helpful assistant.",
prompt: messages[0].content,
});
for await (const textPart of result.textStream) {
console.log(textPart); // Confirms streaming works in backend
}
return result.toDataStreamResponse(); // Returns the response
} catch (error) {
console.error(error);
return new NextResponse("Error processing request", { status: 500 });
}
}
Frontend (useChat Hook from ai/react):
"use client";
import React from "react";
import { Input } from "./ui/input";
import { useChat } from "ai/react";
import { Button } from "./ui/button";
import { Send } from "lucide-react";
import MessageList from "./MessageList";
const ChatComponent = () => {
const { input, handleInputChange, handleSubmit, messages } = useChat();
return (
<div className="relative max-h-screen overflow-scroll" id="message-container">
<div className="sticky top-0 inset-x-0 p-2 bg-white h-fit">
<h3 className="text-xl font-bold">Chat</h3>
</div>
<MessageList messages={messages} />
<form onSubmit={handleSubmit} className="sticky bottom-0 inset-x-0 px-2 py-4 bg-white">
<div className="flex">
<Input value={input} onChange={handleInputChange} placeholder="Ask any question" className="w-full" />
<Button className="bg-blue-600 ml-2">
<Send className="h-4 w-4" />
</Button>
</div>
</form>
</div>
);
};
export default ChatComponent; Expected Behavior: I want the frontend to display the response text as it arrives, rather than waiting for the entire response to be received.
Actual Behavior: The backend correctly logs the response as a stream. The frontend receives the response, but only after all of it is processed. The real-time streaming effect is lost. Question: How can I ensure the response is streamed to the frontend in real time using streamText? Do I need to manually handle the stream in the frontend instead of relying on useChat?
Problem Statement: I am building a chatbot in Next.js using ai and @ai-sdk/google. The chatbot should stream responses from Gemini (gemini-1.5-flash-8b) to the frontend. I confirmed that the response is streamed in the backend by logging the chunks:
for await (const textPart of result.textStream) {
console.log(textPart);
}
However, when I return the response to the frontend, the streaming effect is lost, and I receive the full response all at once.
What I Have Tried:
Backend (API Route in Next.js):
import { createGoogleGenerativeAI } from "@ai-sdk/google";
import { streamText } from "ai";
import { NextRequest, NextResponse } from "next/server";
const google = createGoogleGenerativeAI({
apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
});
const model = google("gemini-1.5-flash-8b");
export async function POST(req: NextRequest) {
try {
const { messages } = await req.json();
console.log(messages);
const result = streamText({
model: model,
system: "You are a helpful assistant.",
prompt: messages[0].content,
});
for await (const textPart of result.textStream) {
console.log(textPart); // Confirms streaming works in backend
}
return result.toDataStreamResponse(); // Returns the response
} catch (error) {
console.error(error);
return new NextResponse("Error processing request", { status: 500 });
}
}
Frontend (useChat Hook from ai/react):
"use client";
import React from "react";
import { Input } from "./ui/input";
import { useChat } from "ai/react";
import { Button } from "./ui/button";
import { Send } from "lucide-react";
import MessageList from "./MessageList";
const ChatComponent = () => {
const { input, handleInputChange, handleSubmit, messages } = useChat();
return (
<div className="relative max-h-screen overflow-scroll" id="message-container">
<div className="sticky top-0 inset-x-0 p-2 bg-white h-fit">
<h3 className="text-xl font-bold">Chat</h3>
</div>
<MessageList messages={messages} />
<form onSubmit={handleSubmit} className="sticky bottom-0 inset-x-0 px-2 py-4 bg-white">
<div className="flex">
<Input value={input} onChange={handleInputChange} placeholder="Ask any question" className="w-full" />
<Button className="bg-blue-600 ml-2">
<Send className="h-4 w-4" />
</Button>
</div>
</form>
</div>
);
};
export default ChatComponent; Expected Behavior: I want the frontend to display the response text as it arrives, rather than waiting for the entire response to be received.
Actual Behavior: The backend correctly logs the response as a stream. The frontend receives the response, but only after all of it is processed. The real-time streaming effect is lost. Question: How can I ensure the response is streamed to the frontend in real time using streamText? Do I need to manually handle the stream in the frontend instead of relying on useChat?
It seems you shouldnt be using useChat(), instead use useCompletion(), more info here. Hope it helps, let me know if it worked
