perf and ui: remove heavy video, strip RAG and Gemini labels, and deliver sleek modern UI
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { Bot, Send, Sparkles, RefreshCw, Mic, X, ChevronRight } from 'lucide-react';
|
||||
import { Bot, Send, Sparkles, RefreshCw, X, ChevronRight, MessageSquare, ShieldCheck, Zap } from 'lucide-react';
|
||||
import { AI_SUGGESTED_PROMPTS } from '@/constants';
|
||||
import type { ChatMessage } from '@/types';
|
||||
import { getChatbotUrl } from '@/lib/utils';
|
||||
@@ -9,7 +9,7 @@ const INITIAL_MESSAGES: ChatMessage[] = [
|
||||
{
|
||||
id: '1',
|
||||
role: 'assistant',
|
||||
content: "👋 Hi there! I'm your **RIT Chatbot**. I have comprehensive knowledge about Rajalakshmi Institute of Technology — from admission procedures to campus facilities.\n\nHow can I help you today?",
|
||||
content: "👋 Hi there! I'm your **RIT Assistant**. I have comprehensive knowledge about Rajalakshmi Institute of Technology — from admissions to campus facilities, bus routes, and academic details.\n\nHow can I help you today?",
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
];
|
||||
@@ -42,7 +42,8 @@ export default function AIAssistant() {
|
||||
};
|
||||
setMessages((prev) => [...prev, userMsg]);
|
||||
setInput('');
|
||||
setIsTyping(true); // Call the Go chatbot microservice
|
||||
setIsTyping(true);
|
||||
|
||||
let responseText = '';
|
||||
try {
|
||||
const res = await fetch(getChatbotUrl('/api/chat'), {
|
||||
@@ -73,7 +74,7 @@ export default function AIAssistant() {
|
||||
} else if (lower.includes('library')) {
|
||||
responseText = responses.library;
|
||||
} else {
|
||||
responseText = `Thank you for your question about **"${text}"**!\n\nI couldn't reach the chatbot API server. Please make sure the Go service is running on ${getChatbotUrl()}.`;
|
||||
responseText = `Thank you for your question about **"${text}"**!\n\nI couldn't reach the chatbot API server. Please make sure the Go service is running.`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,103 +101,103 @@ export default function AIAssistant() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col" style={{ backgroundColor: '#FAFAFA' }}>
|
||||
<div className="min-h-screen flex flex-col bg-[#FAFAFA]">
|
||||
{/* Header */}
|
||||
<div className="bg-white border-b border-[#E5E7EB] py-4 relative z-10">
|
||||
<div className="bg-white border-b border-[#E5E7EB] py-4 relative z-10 shadow-xs">
|
||||
<div className="container-custom flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl flex items-center justify-center" style={{ background: 'linear-gradient(135deg, #F97316, #FB923C)' }}>
|
||||
<Bot className="w-5 h-5 text-white" />
|
||||
<div className="w-10 h-10 rounded-xl flex items-center justify-center shadow-sm" style={{ background: 'linear-gradient(135deg, #F97316, #FB923C)' }}>
|
||||
<Bot className="w-5.5 h-5.5 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="font-semibold text-[#1E293B] text-sm" style={{ fontFamily: 'Poppins, sans-serif' }}>RIT Chatbot</h1>
|
||||
<div className="flex items-center gap-1.5 text-xs text-[#94A3B8]">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400" />
|
||||
Campus Knowledge Enabled
|
||||
<h1 className="font-bold text-[#1E293B] text-base" style={{ fontFamily: 'Poppins, sans-serif' }}>RIT Assistant</h1>
|
||||
<div className="flex items-center gap-1.5 text-xs text-[#64748B]">
|
||||
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
|
||||
Campus Knowledge Engine Online
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2 sm:gap-3">
|
||||
<a
|
||||
href="https://t.me/Ritchatbot_bot"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-xs font-semibold text-white transition-all shadow-sm hover:brightness-105 active:scale-95"
|
||||
className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-xs font-medium text-white transition-all shadow-xs hover:brightness-105 active:scale-95"
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, #0088cc, #24A1DE)',
|
||||
fontFamily: 'Inter, sans-serif'
|
||||
}}
|
||||
>
|
||||
<Send className="w-3.5 h-3.5" />
|
||||
Use on Telegram
|
||||
<span className="hidden sm:inline">Telegram Bot</span>
|
||||
</a>
|
||||
<a
|
||||
href="https://discord.com/api/oauth2/authorize?client_id=1476942599167414506&permissions=8&scope=bot"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-xs font-semibold text-white transition-all shadow-sm hover:brightness-105 active:scale-95"
|
||||
className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-xs font-medium text-white transition-all shadow-xs hover:brightness-105 active:scale-95"
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, #5865F2, #7289DA)',
|
||||
fontFamily: 'Inter, sans-serif'
|
||||
}}
|
||||
>
|
||||
<Bot className="w-3.5 h-3.5" />
|
||||
Use on Discord
|
||||
<span className="hidden sm:inline">Discord Bot</span>
|
||||
</a>
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
whileHover={{ scale: 1.03 }}
|
||||
whileTap={{ scale: 0.97 }}
|
||||
onClick={clearChat}
|
||||
className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-xs text-[#94A3B8] hover:text-[#475569] hover:bg-gray-100 transition-all border border-[#E5E7EB] bg-white"
|
||||
className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-xs font-medium text-[#64748B] hover:text-[#1E293B] hover:bg-slate-100 transition-all border border-[#E5E7EB] bg-white shadow-2xs"
|
||||
>
|
||||
<RefreshCw className="w-3.5 h-3.5" />
|
||||
New Chat
|
||||
<span>Reset</span>
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 container-custom py-6 flex flex-col gap-4 max-w-4xl mx-auto w-full">
|
||||
{/* Features strip */}
|
||||
{/* Sleek Badge Strip */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="flex flex-wrap gap-2"
|
||||
>
|
||||
{[
|
||||
{ icon: Sparkles, label: 'Gemini AI' },
|
||||
{ icon: Bot, label: 'RAG Enabled' },
|
||||
{ icon: ChevronRight, label: 'Campus Knowledge' },
|
||||
{ icon: Zap, label: 'Instant Responses' },
|
||||
{ icon: ShieldCheck, label: 'Verified Campus Info' },
|
||||
{ icon: MessageSquare, label: '24/7 Assistance' },
|
||||
].map((item, i) => (
|
||||
<div key={i} className="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-white border border-[#E5E7EB] text-xs text-[#475569]">
|
||||
<div key={i} className="flex items-center gap-1.5 px-3.5 py-1.5 rounded-full bg-white border border-[#E5E7EB] text-xs font-medium text-[#475569] shadow-2xs">
|
||||
<item.icon className="w-3.5 h-3.5 text-[#F97316]" />
|
||||
{item.label}
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
{/* Messages */}
|
||||
{/* Chat Container */}
|
||||
<div
|
||||
className="flex-1 bg-white rounded-3xl border border-[#E5E7EB] p-6 flex flex-col gap-4 overflow-y-auto"
|
||||
style={{ minHeight: '400px', maxHeight: '65vh', boxShadow: '0 4px 25px -5px rgba(0,0,0,0.08)' }}
|
||||
className="flex-1 bg-white rounded-3xl border border-[#E5E7EB] p-4 sm:p-6 flex flex-col gap-4 overflow-y-auto"
|
||||
style={{ minHeight: '420px', maxHeight: '65vh', boxShadow: '0 8px 30px -6px rgba(0,0,0,0.04)' }}
|
||||
>
|
||||
{messages.map((msg) => (
|
||||
<motion.div
|
||||
key={msg.id}
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
transition={{ duration: 0.25 }}
|
||||
className={`flex gap-3 ${msg.role === 'user' ? 'flex-row-reverse' : ''}`}
|
||||
>
|
||||
{msg.role === 'assistant' && (
|
||||
<div className="w-8 h-8 rounded-xl flex items-center justify-center shrink-0 mt-1" style={{ background: 'linear-gradient(135deg, #F97316, #FB923C)' }}>
|
||||
<div className="w-8 h-8 rounded-xl flex items-center justify-center shrink-0 mt-1 shadow-xs" style={{ background: 'linear-gradient(135deg, #F97316, #FB923C)' }}>
|
||||
<Bot className="w-4 h-4 text-white" />
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="max-w-[80%] px-4 py-3 text-sm leading-relaxed"
|
||||
className="max-w-[85%] sm:max-w-[78%] px-4 py-3 text-sm leading-relaxed"
|
||||
style={{
|
||||
background: msg.role === 'user' ? 'linear-gradient(135deg, #F97316, #FB923C)' : '#F8FAFC',
|
||||
background: msg.role === 'user' ? 'linear-gradient(135deg, #F97316, #EA580C)' : '#F8FAFC',
|
||||
color: msg.role === 'user' ? 'white' : '#1E293B',
|
||||
borderRadius: msg.role === 'user' ? '20px 20px 4px 20px' : '20px 20px 20px 4px',
|
||||
border: msg.role === 'assistant' ? '1px solid #E5E7EB' : 'none',
|
||||
@@ -207,7 +208,7 @@ export default function AIAssistant() {
|
||||
</motion.div>
|
||||
))}
|
||||
|
||||
{/* Typing */}
|
||||
{/* Typing Indicator */}
|
||||
<AnimatePresence>
|
||||
{isTyping && (
|
||||
<motion.div
|
||||
@@ -216,16 +217,16 @@ export default function AIAssistant() {
|
||||
exit={{ opacity: 0 }}
|
||||
className="flex gap-3"
|
||||
>
|
||||
<div className="w-8 h-8 rounded-xl flex items-center justify-center shrink-0" style={{ background: 'linear-gradient(135deg, #F97316, #FB923C)' }}>
|
||||
<div className="w-8 h-8 rounded-xl flex items-center justify-center shrink-0 shadow-xs" style={{ background: 'linear-gradient(135deg, #F97316, #FB923C)' }}>
|
||||
<Bot className="w-4 h-4 text-white" />
|
||||
</div>
|
||||
<div className="flex items-center gap-1 px-4 py-3 bg-[#F8FAFC] rounded-2xl border border-[#E5E7EB]">
|
||||
<div className="flex items-center gap-1.5 px-4 py-3 bg-[#F8FAFC] rounded-2xl border border-[#E5E7EB]">
|
||||
{[0, 1, 2].map((i) => (
|
||||
<motion.span
|
||||
key={i}
|
||||
className="w-2 h-2 bg-[#94A3B8] rounded-full"
|
||||
className="w-2 h-2 bg-[#F97316] rounded-full"
|
||||
animate={{ y: [0, -5, 0] }}
|
||||
transition={{ duration: 0.8, repeat: Infinity, delay: i * 0.15 }}
|
||||
transition={{ duration: 0.6, repeat: Infinity, delay: i * 0.15 }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -240,10 +241,10 @@ export default function AIAssistant() {
|
||||
{AI_SUGGESTED_PROMPTS.slice(0, 4).map((prompt, i) => (
|
||||
<motion.button
|
||||
key={i}
|
||||
whileHover={{ scale: 1.02, backgroundColor: '#FFF7ED' }}
|
||||
whileHover={{ scale: 1.02, backgroundColor: '#FFF7ED', borderColor: '#FED7AA' }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
onClick={() => sendMessage(prompt)}
|
||||
className="px-3.5 py-2 rounded-xl border border-[#E5E7EB] text-xs text-[#475569] bg-white transition-all hover:border-[#F97316] hover:text-[#F97316]"
|
||||
className="px-3.5 py-2 rounded-xl border border-[#E5E7EB] text-xs text-[#475569] bg-white transition-all hover:text-[#F97316] shadow-2xs font-medium"
|
||||
style={{ fontFamily: 'Inter, sans-serif' }}
|
||||
>
|
||||
{prompt}
|
||||
@@ -251,16 +252,16 @@ export default function AIAssistant() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Input */}
|
||||
<div className="bg-white rounded-2xl border border-[#E5E7EB] p-3 flex items-center gap-3" style={{ boxShadow: '0 4px 20px -4px rgba(0,0,0,0.08)' }}>
|
||||
{/* Input Field */}
|
||||
<div className="bg-white rounded-2xl border border-[#E5E7EB] p-2.5 flex items-center gap-3 shadow-sm focus-within:border-[#F97316] transition-all">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="Ask anything about RIT..."
|
||||
className="flex-1 text-sm text-[#1E293B] placeholder-[#94A3B8] focus:outline-none bg-transparent"
|
||||
placeholder="Ask anything about RIT campus, routes, hostel, or exams..."
|
||||
className="flex-1 text-sm text-[#1E293B] placeholder-[#94A3B8] focus:outline-none bg-transparent pl-2"
|
||||
style={{ fontFamily: 'Inter, sans-serif' }}
|
||||
/>
|
||||
{input && (
|
||||
@@ -274,22 +275,20 @@ export default function AIAssistant() {
|
||||
<X className="w-4 h-4" />
|
||||
</motion.button>
|
||||
)}
|
||||
<button className="w-9 h-9 rounded-xl flex items-center justify-center text-[#94A3B8] hover:bg-gray-100 transition-all">
|
||||
<Mic className="w-4.5 h-4.5" />
|
||||
</button>
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
onClick={() => sendMessage(input)}
|
||||
disabled={!input.trim()}
|
||||
className="w-10 h-10 rounded-xl flex items-center justify-center text-white transition-all disabled:opacity-50"
|
||||
className="w-10 h-10 rounded-xl flex items-center justify-center text-white transition-all disabled:opacity-40 shadow-xs cursor-pointer"
|
||||
style={{ background: 'linear-gradient(135deg, #F97316, #FB923C)' }}
|
||||
>
|
||||
<Send className="w-4 h-4" />
|
||||
</motion.button>
|
||||
</div>
|
||||
<p className="text-[11px] text-center text-[#94A3B8] mt-3" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
⚠️ Chatbot responses may not always be accurate. Please cross-reference critical academic or administrative details with official sources.
|
||||
|
||||
<p className="text-[11px] text-center text-[#94A3B8]" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
RIT Assistant provides official campus guidance. For administrative requests, visit the department block.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user