'use client';
import { useState } from 'react';
export default function StreamingChat() {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
const [streamingContent, setStreamingContent] = useState('');
const [isStreaming, setIsStreaming] = useState(false);
const sendMessage = async () => {
if (!input.trim()) return;
const userMessage = { role: 'user', content: input };
setMessages(prev => [...prev, userMessage]);
setInput('');
setIsStreaming(true);
setStreamingContent('');
try {
const response = await fetch('/api/chat/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages: [...messages, userMessage],
}),
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
let fullContent = '';
while (true) {
const { done, value } = await reader!.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6));
if (!data.done) {
fullContent += data.chunk;
setStreamingContent(fullContent);
} else {
// Streaming complete
setMessages(prev => [
...prev,
{ role: 'assistant', content: fullContent }
]);
setStreamingContent('');
}
}
}
}
} catch (error) {
console.error('Streaming error:', error);
} finally {
setIsStreaming(false);
}
};
return (
<div className="flex flex-col h-screen">
<div className="flex-1 overflow-y-auto p-4">
{messages.map((msg, idx) => (
<div key={idx} className="mb-4">
<div className="font-bold">{msg.role}:</div>
<div>{msg.content}</div>
</div>
))}
{streamingContent && (
<div className="mb-4">
<div className="font-bold">assistant:</div>
<div className="animate-pulse">{streamingContent}</div>
</div>
)}
</div>
<div className="border-t p-4">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
disabled={isStreaming}
className="w-full border rounded px-3 py-2"
placeholder="Type a message..."
/>
</div>
</div>
);
}