Spaces:
Runtime error
Runtime error
File size: 5,164 Bytes
80fa8ac |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
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>
);
} |