SantoshKumar1310's picture
Upload folder using huggingface_hub
49e53ae verified
'use client';
import { useState, useRef, useEffect } from 'react';
import { Send, Bot, User, Sparkles, Loader2, X, Maximize2, Minimize2 } from 'lucide-react';
interface Message {
id: string;
role: 'user' | 'assistant';
content: string;
timestamp: Date;
}
interface AIChatPanelProps {
onClose?: () => void;
isExpanded?: boolean;
onToggleExpand?: () => void;
}
export default function AIChatPanel({ onClose, isExpanded, onToggleExpand }: AIChatPanelProps) {
const [messages, setMessages] = useState<Message[]>([
{
id: '1',
role: 'assistant',
content: "Hello! I'm the QuantumShield AI Assistant. I can help you analyze transactions, understand fraud patterns, and explain how our quantum-enhanced detection works. What would you like to know?",
timestamp: new Date()
}
]);
const [input, setInput] = useState('');
const [isLoading, setIsLoading] = useState(false);
const messagesEndRef = useRef<HTMLDivElement>(null);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};
useEffect(() => {
scrollToBottom();
}, [messages]);
const sendMessage = async () => {
if (!input.trim() || isLoading) return;
const userMessage: Message = {
id: Date.now().toString(),
role: 'user',
content: input,
timestamp: new Date()
};
setMessages(prev => [...prev, userMessage]);
setInput('');
setIsLoading(true);
try {
const response = await fetch('http://localhost:8000/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: input,
conversation_history: messages.map(m => ({
role: m.role,
content: m.content
}))
})
});
if (!response.ok) throw new Error('Chat request failed');
const data = await response.json();
const assistantMessage: Message = {
id: (Date.now() + 1).toString(),
role: 'assistant',
content: data.response,
timestamp: new Date()
};
setMessages(prev => [...prev, assistantMessage]);
} catch (error) {
const errorMessage: Message = {
id: (Date.now() + 1).toString(),
role: 'assistant',
content: "I'm having trouble connecting to the server. Please make sure the backend is running on port 8000.",
timestamp: new Date()
};
setMessages(prev => [...prev, errorMessage]);
} finally {
setIsLoading(false);
}
};
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
};
const suggestedQuestions = [
"How does quantum detection work?",
"What are VQC, QAOA, and QNN?",
"Explain the fraud scoring system"
];
return (
<div className="card-dark rounded-3xl p-6 card-hover h-full flex flex-col">
{/* Header */}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center">
<Sparkles className="w-5 h-5 text-white" />
</div>
<div>
<h3 className="text-xl font-bold text-white">AI ASSISTANT</h3>
<p className="text-xs text-white/60">Quantum Analysis Expert</p>
</div>
</div>
<div className="flex items-center gap-2">
{onToggleExpand && (
<button
onClick={onToggleExpand}
className="p-2 text-white/60 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
>
{isExpanded ? <Minimize2 className="w-4 h-4" /> : <Maximize2 className="w-4 h-4" />}
</button>
)}
{onClose && (
<button
onClick={onClose}
className="p-2 text-white/60 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
>
<X className="w-4 h-4" />
</button>
)}
</div>
</div>
{/* Messages */}
<div className="flex-1 overflow-y-auto space-y-4 mb-4 min-h-[200px] max-h-[400px] scrollbar-thin pr-2">
{messages.map((message) => (
<div
key={message.id}
className={`flex gap-3 ${message.role === 'user' ? 'flex-row-reverse' : ''}`}
>
<div className={`w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0 ${
message.role === 'user'
? 'bg-blue-500'
: 'bg-gradient-to-br from-purple-500 to-pink-500'
}`}>
{message.role === 'user' ? (
<User className="w-4 h-4 text-white" />
) : (
<Bot className="w-4 h-4 text-white" />
)}
</div>
<div className={`max-w-[80%] rounded-2xl px-4 py-3 ${
message.role === 'user'
? 'bg-blue-500 text-white'
: 'bg-white/10 text-white'
}`}>
<p className="text-sm whitespace-pre-wrap">{message.content}</p>
<p className={`text-xs mt-1 ${message.role === 'user' ? 'text-blue-200' : 'text-white/40'}`}>
{message.timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
</p>
</div>
</div>
))}
{isLoading && (
<div className="flex gap-3">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center">
<Bot className="w-4 h-4 text-white" />
</div>
<div className="bg-white/10 rounded-2xl px-4 py-3">
<div className="flex items-center gap-2">
<Loader2 className="w-4 h-4 text-white animate-spin" />
<span className="text-sm text-white/60">Analyzing...</span>
</div>
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
{/* Suggested Questions */}
{messages.length <= 2 && (
<div className="flex flex-wrap gap-2 mb-4">
{suggestedQuestions.map((question, index) => (
<button
key={index}
onClick={() => setInput(question)}
className="text-xs px-3 py-1.5 bg-white/10 hover:bg-white/20 text-white/80 rounded-full transition-colors"
>
{question}
</button>
))}
</div>
)}
{/* Input */}
<div className="flex gap-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={handleKeyPress}
placeholder="Ask about fraud detection..."
className="flex-1 bg-white/10 border-0 rounded-xl px-4 py-3 text-white placeholder-white/40 focus:ring-2 focus:ring-blue-500 focus:outline-none"
disabled={isLoading}
/>
<button
onClick={sendMessage}
disabled={!input.trim() || isLoading}
className="px-4 py-3 bg-gradient-to-r from-blue-500 to-purple-600 rounded-xl text-white font-medium hover:opacity-90 transition-opacity disabled:opacity-50 disabled:cursor-not-allowed"
>
<Send className="w-5 h-5" />
</button>
</div>
</div>
);
}