my-llm-api / frontend /ChatInterface.jsx
Khushhal1's picture
Upload 2 files
891fe6c verified
Raw
History Blame Contribute Delete
3.43 kB
import React, { useState, useEffect, useRef } from 'react';
const ChatInterface = () => {
const [messages, setMessages] = useState([
{ role: 'assistant', content: 'Hello! I am your custom LLM. How can I help you today?' }
]);
const [input, setInput] = useState('');
const [isLoading, setIsLoading] = useState(false);
const messagesEndRef = useRef(null);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
};
useEffect(scrollToBottom, [messages]);
const handleSubmit = async (e) => {
e.preventDefault();
if (!input.trim()) return;
const userMessage = { role: 'user', content: input };
setMessages(prev => [...prev, userMessage]);
setInput('');
setIsLoading(true);
try {
const response = await fetch('/api/chat', { // Proxied to HF/FastAPI
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages: [...messages, userMessage].map(m => ({
role: m.role,
content: m.content
}))
}),
});
const data = await response.json();
setMessages(prev => [...prev, {
role: 'assistant',
content: data.choices[0].message.content
}]);
} catch (error) {
console.error('Error:', error);
setMessages(prev => [...prev, {
role: 'assistant',
content: 'Sorry, I encountered an error. Please check your backend connection.'
}]);
} finally {
setIsLoading(false);
}
};
return (
<div className="flex flex-col h-screen max-w-4xl mx-auto p-4 font-sans text-gray-800">
<header className="py-6 border-b">
<h1 className="text-2xl font-bold text-indigo-600">Custom LLM Studio</h1>
<p className="text-sm text-gray-500">Connected to HF Spaces / FastAPI Backend</p>
</header>
<div className="flex-1 overflow-y-auto py-6 space-y-4">
{messages.map((m, i) => (
<div key={i} className={`flex ${m.role === 'user' ? 'justify-end' : 'justify-start'}`}>
<div className={`max-w-[80%] rounded-2xl px-4 py-2 ${
m.role === 'user'
? 'bg-indigo-600 text-white rounded-tr-none'
: 'bg-gray-100 text-gray-800 rounded-tl-none'
}`}>
<p className="whitespace-pre-wrap">{m.content}</p>
</div>
</div>
))}
{isLoading && (
<div className="flex justify-start">
<div className="bg-gray-100 rounded-2xl px-4 py-2 rounded-tl-none animate-pulse">
Typing...
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
<form onSubmit={handleSubmit} className="py-6 border-t flex gap-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type your message..."
className="flex-1 border rounded-full px-6 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"
disabled={isLoading}
/>
<button
type="submit"
className="bg-indigo-600 text-white rounded-full px-6 py-2 font-semibold hover:bg-indigo-700 disabled:opacity-50 transition"
disabled={isLoading}
>
Send
</button>
</form>
</div>
);
};
export default ChatInterface;