anycoder-2884d574 / components /ChatInterface.jsx
Det9999's picture
Upload components/ChatInterface.jsx with huggingface_hub
80fa8ac verified
import { useState, useRef, useEffect } from 'react';
import { Send, Bot, User, Music, Sparkles } from 'lucide-react';
export default function ChatInterface({
messages,
onSendMessage,
isLoading,
spotifyData
}) {
const [input, setInput] = useState('');
const messagesEndRef = useRef(null);
const inputRef = useRef(null);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};
useEffect(() => {
scrollToBottom();
}, [messages]);
const handleSubmit = (e) => {
e.preventDefault();
if (!input.trim() || isLoading) return;
onSendMessage(input);
setInput('');
};
return (
<div className="flex flex-col h-full bg-[#121212] rounded-xl border border-white/10 overflow-hidden">
{/* Chat Header */}
<div className="p-4 bg-gradient-to-r from-[#1a1a1a] to-[#121212] border-b border-white/10 flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="p-1.5 bg-purple-500/20 rounded-lg text-purple-400">
<Sparkles className="w-5 h-5" />
</div>
<div>
<h2 className="font-bold text-sm">AI Music Assistant</h2>
<p className="text-xs text-gray-400">
{spotifyData ? 'Connected to Spotify' : 'Waiting for Spotify data...'}
</p>
</div>
</div>
{isLoading && (
<div className="flex items-center gap-2 text-xs text-spotify-green animate-pulse">
<div className="w-2 h-2 bg-spotify-green rounded-full"></div>
Thinking...
</div>
)}
</div>
{/* Messages Area */}
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-center space-y-4 opacity-50">
<Music className="w-12 h-12 text-gray-600" />
<div>
<p className="text-lg font-medium">Start the conversation</p>
<p className="text-sm text-gray-400">Ask for recommendations based on your taste</p>
</div>
</div>
) : (
messages.map((msg, idx) => (
<div
key={idx}
className={`flex gap-3 ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}
>
{msg.role === 'assistant' && (
<div className="flex-shrink-0 mt-1">
<div className="w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-indigo-600 flex items-center justify-center">
<Bot className="w-4 h-4 text-white" />
</div>
</div>
)}
<div
className={`max-w-[85%] rounded-2xl px-4 py-3 text-sm leading-relaxed ${
msg.role === 'user'
? 'bg-spotify-green text-black font-medium rounded-tr-sm'
: 'bg-[#282828] text-gray-100 rounded-tl-sm border border-white/5'
}`}
>
{msg.role === 'assistant' ? (
<div className="prose prose-invert prose-sm max-w-none">
{/* Simple markdown-like rendering for newlines */}
{msg.content.split('\n').map((line, i) => (
<p key={i} className="mb-2 last:mb-0">{line}</p>
))}
</div>
) : (
msg.content
)}
</div>
{msg.role === 'user' && (
<div className="flex-shrink-0 mt-1">
<div className="w-8 h-8 rounded-full bg-gray-600 flex items-center justify-center">
<User className="w-4 h-4 text-white" />
</div>
</div>
)}
</div>
))
)}
<div ref={messagesEndRef} />
</div>
{/* Input Area */}
<div className="p-4 bg-[#121212] border-t border-white/10">
<form onSubmit={handleSubmit} className="relative">
<input
ref={inputRef}
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Ask for music recommendations..."
disabled={isLoading}
className="w-full bg-[#282828] text-white pl-4 pr-12 py-3 rounded-full border border-transparent focus:border-spotify-green focus:bg-[#3e3e3e] focus:outline-none transition-all disabled:opacity-50 disabled:cursor-not-allowed"
/>
<button
type="submit"
disabled={!input.trim() || isLoading}
className="absolute right-2 top-1/2 -translate-y-1/2 p-2 bg-white text-black rounded-full hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
<Send className="w-4 h-4" />
</button>
</form>
<p className="text-[10px] text-gray-500 mt-2 text-center">
AI can make mistakes. Verify important info.
</p>
</div>
</div>
);
}