Det9999 commited on
Commit
80fa8ac
·
verified ·
1 Parent(s): d65f2e9

Upload components/ChatInterface.jsx with huggingface_hub

Browse files
Files changed (1) hide show
  1. components/ChatInterface.jsx +134 -0
components/ChatInterface.jsx ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useRef, useEffect } from 'react';
2
+ import { Send, Bot, User, Music, Sparkles } from 'lucide-react';
3
+
4
+ export default function ChatInterface({
5
+ messages,
6
+ onSendMessage,
7
+ isLoading,
8
+ spotifyData
9
+ }) {
10
+ const [input, setInput] = useState('');
11
+ const messagesEndRef = useRef(null);
12
+ const inputRef = useRef(null);
13
+
14
+ const scrollToBottom = () => {
15
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
16
+ };
17
+
18
+ useEffect(() => {
19
+ scrollToBottom();
20
+ }, [messages]);
21
+
22
+ const handleSubmit = (e) => {
23
+ e.preventDefault();
24
+ if (!input.trim() || isLoading) return;
25
+ onSendMessage(input);
26
+ setInput('');
27
+ };
28
+
29
+ return (
30
+ <div className="flex flex-col h-full bg-[#121212] rounded-xl border border-white/10 overflow-hidden">
31
+ {/* Chat Header */}
32
+ <div className="p-4 bg-gradient-to-r from-[#1a1a1a] to-[#121212] border-b border-white/10 flex items-center justify-between">
33
+ <div className="flex items-center gap-2">
34
+ <div className="p-1.5 bg-purple-500/20 rounded-lg text-purple-400">
35
+ <Sparkles className="w-5 h-5" />
36
+ </div>
37
+ <div>
38
+ <h2 className="font-bold text-sm">AI Music Assistant</h2>
39
+ <p className="text-xs text-gray-400">
40
+ {spotifyData ? 'Connected to Spotify' : 'Waiting for Spotify data...'}
41
+ </p>
42
+ </div>
43
+ </div>
44
+ {isLoading && (
45
+ <div className="flex items-center gap-2 text-xs text-spotify-green animate-pulse">
46
+ <div className="w-2 h-2 bg-spotify-green rounded-full"></div>
47
+ Thinking...
48
+ </div>
49
+ )}
50
+ </div>
51
+
52
+ {/* Messages Area */}
53
+ <div className="flex-1 overflow-y-auto p-4 space-y-4">
54
+ {messages.length === 0 ? (
55
+ <div className="flex flex-col items-center justify-center h-full text-center space-y-4 opacity-50">
56
+ <Music className="w-12 h-12 text-gray-600" />
57
+ <div>
58
+ <p className="text-lg font-medium">Start the conversation</p>
59
+ <p className="text-sm text-gray-400">Ask for recommendations based on your taste</p>
60
+ </div>
61
+ </div>
62
+ ) : (
63
+ messages.map((msg, idx) => (
64
+ <div
65
+ key={idx}
66
+ className={`flex gap-3 ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}
67
+ >
68
+ {msg.role === 'assistant' && (
69
+ <div className="flex-shrink-0 mt-1">
70
+ <div className="w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-indigo-600 flex items-center justify-center">
71
+ <Bot className="w-4 h-4 text-white" />
72
+ </div>
73
+ </div>
74
+ )}
75
+
76
+ <div
77
+ className={`max-w-[85%] rounded-2xl px-4 py-3 text-sm leading-relaxed ${
78
+ msg.role === 'user'
79
+ ? 'bg-spotify-green text-black font-medium rounded-tr-sm'
80
+ : 'bg-[#282828] text-gray-100 rounded-tl-sm border border-white/5'
81
+ }`}
82
+ >
83
+ {msg.role === 'assistant' ? (
84
+ <div className="prose prose-invert prose-sm max-w-none">
85
+ {/* Simple markdown-like rendering for newlines */}
86
+ {msg.content.split('\n').map((line, i) => (
87
+ <p key={i} className="mb-2 last:mb-0">{line}</p>
88
+ ))}
89
+ </div>
90
+ ) : (
91
+ msg.content
92
+ )}
93
+ </div>
94
+
95
+ {msg.role === 'user' && (
96
+ <div className="flex-shrink-0 mt-1">
97
+ <div className="w-8 h-8 rounded-full bg-gray-600 flex items-center justify-center">
98
+ <User className="w-4 h-4 text-white" />
99
+ </div>
100
+ </div>
101
+ )}
102
+ </div>
103
+ ))
104
+ )}
105
+ <div ref={messagesEndRef} />
106
+ </div>
107
+
108
+ {/* Input Area */}
109
+ <div className="p-4 bg-[#121212] border-t border-white/10">
110
+ <form onSubmit={handleSubmit} className="relative">
111
+ <input
112
+ ref={inputRef}
113
+ type="text"
114
+ value={input}
115
+ onChange={(e) => setInput(e.target.value)}
116
+ placeholder="Ask for music recommendations..."
117
+ disabled={isLoading}
118
+ 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"
119
+ />
120
+ <button
121
+ type="submit"
122
+ disabled={!input.trim() || isLoading}
123
+ 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"
124
+ >
125
+ <Send className="w-4 h-4" />
126
+ </button>
127
+ </form>
128
+ <p className="text-[10px] text-gray-500 mt-2 text-center">
129
+ AI can make mistakes. Verify important info.
130
+ </p>
131
+ </div>
132
+ </div>
133
+ );
134
+ }