Spaces:
Running
Running
File size: 6,741 Bytes
fcbbe44 |
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
import React, { useState, useRef, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Send, Bot, User, Loader2 } from 'lucide-react';
interface Message {
id: string;
content: string;
role: 'user' | 'assistant';
timestamp: Date;
}
const ChatBot = () => {
const [messages, setMessages] = useState<Message[]>([
{
id: '1',
content: 'Hello! I\'m your AI assistant powered by V1Q. How can I help you today?',
role: 'assistant',
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(),
content: input,
role: 'user',
timestamp: new Date()
};
setMessages(prev => [...prev, userMessage]);
setInput('');
setIsLoading(true);
try {
// Simulate API call to V1Q model
await new Promise(resolve => setTimeout(resolve, 1000 + Math.random() * 2000));
const assistantMessage: Message = {
id: (Date.now() + 1).toString(),
content: generateResponse(input),
role: 'assistant',
timestamp: new Date()
};
setMessages(prev => [...prev, assistantMessage]);
} catch (error) {
console.error('Error sending message:', error);
const errorMessage: Message = {
id: (Date.now() + 1).toString(),
content: 'Sorry, I encountered an error. Please try again.',
role: 'assistant',
timestamp: new Date()
};
setMessages(prev => [...prev, errorMessage]);
} finally {
setIsLoading(false);
}
};
const generateResponse = (userInput: string): string => {
// Simple response generation for demo purposes
const responses = [
"That's an interesting question! Let me help you with that.",
"I understand what you're asking. Here's what I think...",
"Great question! Based on my knowledge, I can tell you that...",
"I'd be happy to help you with that. Here's my response...",
"That's a thoughtful inquiry. Let me provide you with some insights..."
];
return responses[Math.floor(Math.random() * responses.length)] +
` Regarding "${userInput}", I'm processing this with the V1Q model to provide you with the most accurate response possible.`;
};
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
};
return (
<div className="max-w-4xl mx-auto h-[600px] flex flex-col">
<Card className="flex-1 flex flex-col">
<CardHeader className="border-b">
<CardTitle className="flex items-center gap-2">
<Bot className="h-6 w-6 text-primary" />
AI Assistant (V1Q)
</CardTitle>
</CardHeader>
<CardContent className="flex-1 flex flex-col p-0">
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((message) => (
<div
key={message.id}
className={`flex gap-3 ${
message.role === 'user' ? 'justify-end' : 'justify-start'
}`}
>
<div
className={`flex gap-3 max-w-[80%] ${
message.role === 'user' ? 'flex-row-reverse' : 'flex-row'
}`}
>
<div className="flex-shrink-0">
{message.role === 'user' ? (
<div className="w-8 h-8 bg-primary rounded-full flex items-center justify-center">
<User className="h-4 w-4 text-primary-foreground" />
</div>
) : (
<div className="w-8 h-8 bg-secondary rounded-full flex items-center justify-center">
<Bot className="h-4 w-4 text-secondary-foreground" />
</div>
)}
</div>
<div
className={`rounded-lg p-3 ${
message.role === 'user'
? 'bg-primary text-primary-foreground'
: 'bg-muted text-muted-foreground'
}`}
>
<p className="text-sm">{message.content}</p>
<p className="text-xs opacity-70 mt-1">
{message.timestamp.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit'
})}
</p>
</div>
</div>
</div>
))}
{isLoading && (
<div className="flex gap-3 justify-start">
<div className="flex gap-3 max-w-[80%]">
<div className="w-8 h-8 bg-secondary rounded-full flex items-center justify-center">
<Bot className="h-4 w-4 text-secondary-foreground" />
</div>
<div className="rounded-lg p-3 bg-muted">
<div className="flex items-center gap-2">
<Loader2 className="h-4 w-4 animate-spin" />
<span className="text-sm text-muted-foreground">Thinking...</span>
</div>
</div>
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
<div className="p-4 border-t">
<div className="flex gap-2">
<Input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={handleKeyPress}
placeholder="Type your message here..."
disabled={isLoading}
className="flex-1"
/>
<Button
onClick={sendMessage}
disabled={!input.trim() || isLoading}
size="icon"
>
<Send className="h-4 w-4" />
</Button>
</div>
</div>
</CardContent>
</Card>
</div>
);
};
export default ChatBot |