Antigravity commited on
Commit
ef886da
·
1 Parent(s): 79fb5cc

Redesign UI with premium interactive glassmorphic dark theme

Browse files
frontend/src/components/Layout.jsx CHANGED
@@ -1,41 +1,59 @@
1
  import { useState } from 'react';
 
2
  import Sidebar from './Sidebar';
3
- import { Menu } from 'lucide-react';
4
- import { motion } from 'framer-motion';
5
 
6
  export default function Layout({ children }) {
7
  const [sidebarOpen, setSidebarOpen] = useState(false);
 
8
 
9
  return (
10
- <div className="flex min-h-screen">
11
  <Sidebar isOpen={sidebarOpen} onClose={() => setSidebarOpen(false)} />
12
 
13
- <main className="flex-1 min-h-screen">
14
  {/* Top bar */}
15
- <header className="flex items-center gap-4 px-4 sm:px-8 py-4 lg:py-6">
16
  <button
17
  onClick={() => setSidebarOpen(true)}
18
- className="lg:hidden p-2 hover:bg-white/5 rounded-xl transition-colors"
19
  >
20
- <Menu size={22} />
21
  </button>
 
22
  <div className="flex-1" />
23
- <div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-emerald-500/10 border border-emerald-500/20">
24
- <span className="w-2 h-2 rounded-full bg-emerald-500 shadow-[0_0_8px_rgba(34,197,94,0.6)]" />
25
- <span className="text-xs font-semibold text-emerald-400">Online</span>
 
 
 
 
 
 
 
 
 
 
 
26
  </div>
27
  </header>
28
 
29
  {/* Content */}
30
- <motion.div
31
- key={location.pathname}
32
- initial={{ opacity: 0, y: 12 }}
33
- animate={{ opacity: 1, y: 0 }}
34
- transition={{ duration: 0.35 }}
35
- className="px-4 sm:px-8 pb-8"
36
- >
37
- {children}
38
- </motion.div>
 
 
 
 
39
  </main>
40
  </div>
41
  );
 
1
  import { useState } from 'react';
2
+ import { useLocation } from 'react-router-dom';
3
  import Sidebar from './Sidebar';
4
+ import { Menu, Zap } from 'lucide-react';
5
+ import { motion, AnimatePresence } from 'framer-motion';
6
 
7
  export default function Layout({ children }) {
8
  const [sidebarOpen, setSidebarOpen] = useState(false);
9
+ const location = useLocation();
10
 
11
  return (
12
+ <div className="relative flex min-h-screen z-10">
13
  <Sidebar isOpen={sidebarOpen} onClose={() => setSidebarOpen(false)} />
14
 
15
+ <main className="flex-1 min-h-screen flex flex-col">
16
  {/* Top bar */}
17
+ <header className="flex items-center gap-4 px-4 sm:px-8 py-4 lg:py-5">
18
  <button
19
  onClick={() => setSidebarOpen(true)}
20
+ className="lg:hidden p-2.5 hover:bg-white/5 rounded-xl transition-all border border-white/[0.06] active:scale-95"
21
  >
22
+ <Menu size={20} />
23
  </button>
24
+
25
  <div className="flex-1" />
26
+
27
+ {/* Status badge */}
28
+ <div className="flex items-center gap-3">
29
+ <div className="hidden sm:flex items-center gap-2 px-3 py-1.5 rounded-xl bg-white/[0.03] border border-white/[0.06] text-xs text-slate-400">
30
+ <Zap size={12} className="text-amber-400" />
31
+ <span>Models Loaded</span>
32
+ </div>
33
+ <div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-emerald-500/10 border border-emerald-500/20">
34
+ <span className="relative flex h-2 w-2">
35
+ <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" />
36
+ <span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500" />
37
+ </span>
38
+ <span className="text-xs font-semibold text-emerald-400">Online</span>
39
+ </div>
40
  </div>
41
  </header>
42
 
43
  {/* Content */}
44
+ <div className="flex-1 px-4 sm:px-8 pb-8">
45
+ <AnimatePresence mode="wait">
46
+ <motion.div
47
+ key={location.pathname}
48
+ initial={{ opacity: 0, y: 16, filter: 'blur(4px)' }}
49
+ animate={{ opacity: 1, y: 0, filter: 'blur(0px)' }}
50
+ exit={{ opacity: 0, y: -8, filter: 'blur(4px)' }}
51
+ transition={{ duration: 0.35, ease: [0.4, 0, 0.2, 1] }}
52
+ >
53
+ {children}
54
+ </motion.div>
55
+ </AnimatePresence>
56
+ </div>
57
  </main>
58
  </div>
59
  );
frontend/src/components/Sidebar.jsx CHANGED
@@ -1,9 +1,9 @@
1
  import { useState } from 'react';
2
- import { NavLink, useLocation } from 'react-router-dom';
3
  import { motion, AnimatePresence } from 'framer-motion';
4
  import {
5
  LayoutDashboard, User, PenTool, Languages, Smile, Brain,
6
- Target, PieChart, Braces, ShoppingCart, Menu, X
7
  } from 'lucide-react';
8
 
9
  const navItems = [
@@ -29,7 +29,7 @@ export default function Sidebar({ isOpen, onClose }) {
29
  initial={{ opacity: 0 }}
30
  animate={{ opacity: 1 }}
31
  exit={{ opacity: 0 }}
32
- className="fixed inset-0 bg-black/60 backdrop-blur-sm z-40 lg:hidden"
33
  onClick={onClose}
34
  />
35
  )}
@@ -38,49 +38,72 @@ export default function Sidebar({ isOpen, onClose }) {
38
  {/* Sidebar */}
39
  <aside className={`
40
  fixed top-0 left-0 h-screen w-[280px] z-50
41
- bg-[#0a0f1c] border-r border-white/8
42
- flex flex-col p-6 gap-6
 
43
  transition-transform duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
44
  lg:translate-x-0 lg:static
45
- ${isOpen ? 'translate-x-0 shadow-2xl' : '-translate-x-full'}
46
  `}>
47
  {/* Brand */}
48
- <div className="flex items-center gap-3 px-2">
49
- <div className="w-10 h-10 rounded-xl bg-gradient-to-br from-cyan-400 to-purple-500 grid place-items-center font-extrabold text-white text-sm">
50
- AI
 
 
 
51
  </div>
52
- <span className="text-lg font-bold tracking-tight">Quantum Hub</span>
53
- <button onClick={onClose} className="lg:hidden ml-auto p-1 hover:bg-white/5 rounded-lg">
54
- <X size={20} />
 
 
 
55
  </button>
56
  </div>
57
 
 
 
 
 
 
 
58
  {/* Nav */}
59
- <nav className="flex flex-col gap-1 flex-1 overflow-y-auto">
60
  {navItems.map(({ path, label, icon: Icon }) => (
61
  <NavLink
62
  key={path}
63
  to={path}
64
  onClick={onClose}
65
  className={({ isActive }) => `
66
- flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-medium
67
- transition-all duration-200
68
  ${isActive
69
- ? 'bg-cyan-500/10 text-cyan-400'
70
- : 'text-slate-400 hover:bg-white/5 hover:text-slate-200'
71
  }
72
  `}
73
  >
74
- <Icon size={18} />
75
- <span>{label}</span>
 
 
 
 
 
 
 
76
  </NavLink>
77
  ))}
78
  </nav>
79
 
80
  {/* Footer */}
81
- <div className="px-3 py-3 rounded-xl bg-white/3 border border-white/5 text-center">
82
- <p className="text-xs text-slate-500">Powered by</p>
83
- <p className="text-xs font-semibold gradient-text">Quantum AI Engine</p>
 
 
 
84
  </div>
85
  </aside>
86
  </>
 
1
  import { useState } from 'react';
2
+ import { NavLink } from 'react-router-dom';
3
  import { motion, AnimatePresence } from 'framer-motion';
4
  import {
5
  LayoutDashboard, User, PenTool, Languages, Smile, Brain,
6
+ Target, PieChart, Braces, ShoppingCart, X, Sparkles
7
  } from 'lucide-react';
8
 
9
  const navItems = [
 
29
  initial={{ opacity: 0 }}
30
  animate={{ opacity: 1 }}
31
  exit={{ opacity: 0 }}
32
+ className="fixed inset-0 bg-black/70 backdrop-blur-md z-40 lg:hidden"
33
  onClick={onClose}
34
  />
35
  )}
 
38
  {/* Sidebar */}
39
  <aside className={`
40
  fixed top-0 left-0 h-screen w-[280px] z-50
41
+ bg-[#060a15]/95 backdrop-blur-xl
42
+ border-r border-white/[0.06]
43
+ flex flex-col py-6 px-4 gap-4
44
  transition-transform duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
45
  lg:translate-x-0 lg:static
46
+ ${isOpen ? 'translate-x-0 shadow-[4px_0_40px_rgba(0,0,0,0.5)]' : '-translate-x-full'}
47
  `}>
48
  {/* Brand */}
49
+ <div className="flex items-center gap-3 px-3 mb-2">
50
+ <div className="relative">
51
+ <div className="w-11 h-11 rounded-2xl bg-gradient-to-br from-cyan-500 via-blue-500 to-purple-600 grid place-items-center font-black text-white text-sm shadow-lg shadow-cyan-500/20">
52
+ AI
53
+ </div>
54
+ <div className="absolute -top-0.5 -right-0.5 w-3 h-3 bg-emerald-400 rounded-full border-2 border-[#060a15] animate-pulse" />
55
  </div>
56
+ <div className="flex flex-col">
57
+ <span className="text-base font-bold tracking-tight">Quantum Hub</span>
58
+ <span className="text-[10px] text-cyan-500/80 font-semibold uppercase tracking-widest">AI Platform</span>
59
+ </div>
60
+ <button onClick={onClose} className="lg:hidden ml-auto p-1.5 hover:bg-white/5 rounded-xl transition-colors">
61
+ <X size={18} />
62
  </button>
63
  </div>
64
 
65
+ {/* Divider */}
66
+ <div className="h-px bg-gradient-to-r from-transparent via-white/10 to-transparent mx-2" />
67
+
68
+ {/* Label */}
69
+ <p className="text-[10px] font-bold uppercase tracking-[0.2em] text-slate-500 px-4 mt-1">Services</p>
70
+
71
  {/* Nav */}
72
+ <nav className="flex flex-col gap-0.5 flex-1 overflow-y-auto px-1">
73
  {navItems.map(({ path, label, icon: Icon }) => (
74
  <NavLink
75
  key={path}
76
  to={path}
77
  onClick={onClose}
78
  className={({ isActive }) => `
79
+ flex items-center gap-3 px-4 py-2.5 rounded-xl text-[13px] font-medium
80
+ transition-all duration-200 group relative
81
  ${isActive
82
+ ? 'bg-gradient-to-r from-cyan-500/10 to-purple-500/5 text-cyan-400 shadow-sm shadow-cyan-500/5'
83
+ : 'text-slate-400 hover:bg-white/[0.04] hover:text-slate-200'
84
  }
85
  `}
86
  >
87
+ {({ isActive }) => (
88
+ <>
89
+ {isActive && (
90
+ <div className="absolute left-0 top-1/2 -translate-y-1/2 w-[3px] h-5 bg-gradient-to-b from-cyan-400 to-purple-500 rounded-full" />
91
+ )}
92
+ <Icon size={16} className={`transition-transform duration-200 ${isActive ? '' : 'group-hover:scale-110'}`} />
93
+ <span>{label}</span>
94
+ </>
95
+ )}
96
  </NavLink>
97
  ))}
98
  </nav>
99
 
100
  {/* Footer */}
101
+ <div className="mx-2 p-4 rounded-2xl bg-gradient-to-br from-cyan-500/[0.07] to-purple-500/[0.04] border border-white/[0.05]">
102
+ <div className="flex items-center gap-2 mb-1">
103
+ <Sparkles size={14} className="text-cyan-400" />
104
+ <p className="text-[11px] font-bold text-cyan-400">Pro Features</p>
105
+ </div>
106
+ <p className="text-[11px] text-slate-500 leading-relaxed">9 AI engines ready to process your data.</p>
107
  </div>
108
  </aside>
109
  </>
frontend/src/components/UI.jsx CHANGED
@@ -1,11 +1,23 @@
1
  import { motion } from 'framer-motion';
2
- import { Loader2 } from 'lucide-react';
 
3
 
4
- export function PageHeader({ title, subtitle }) {
5
  return (
6
  <div className="mb-8">
7
- <h1 className="text-2xl sm:text-3xl font-bold tracking-tight">{title}</h1>
8
- {subtitle && <p className="text-slate-400 mt-1 text-sm sm:text-base">{subtitle}</p>}
 
 
 
 
 
 
 
 
 
 
 
9
  </div>
10
  );
11
  }
@@ -13,9 +25,10 @@ export function PageHeader({ title, subtitle }) {
13
  export function ResultBox({ children, className = '' }) {
14
  return (
15
  <motion.div
16
- initial={{ opacity: 0, y: 16 }}
17
- animate={{ opacity: 1, y: 0 }}
18
- className={`mt-6 p-5 sm:p-6 rounded-2xl bg-gradient-to-br from-cyan-500/5 to-purple-500/5 border border-cyan-500/10 ${className}`}
 
19
  >
20
  {children}
21
  </motion.div>
@@ -26,44 +39,100 @@ export function ErrorBox({ message }) {
26
  if (!message) return null;
27
  return (
28
  <motion.div
29
- initial={{ opacity: 0 }}
30
- animate={{ opacity: 1 }}
31
- className="mt-4 p-4 rounded-xl bg-red-500/10 border border-red-500/20 text-red-400 text-sm"
32
  >
33
- ⚠️ {message}
 
34
  </motion.div>
35
  );
36
  }
37
 
38
  export function SubmitButton({ loading, children, onClick, type = 'submit' }) {
39
  return (
40
- <button
41
  type={type}
42
  onClick={onClick}
43
  disabled={loading}
44
- className="btn-quantum w-full py-3.5 px-6 text-base font-bold rounded-xl flex items-center justify-center gap-2 disabled:opacity-60"
 
45
  >
46
- {loading ? <Loader2 className="animate-spin" size={20} /> : null}
47
- {loading ? 'Processing...' : children}
48
- </button>
 
 
 
 
49
  );
50
  }
51
 
52
  export function UploadZone({ accept, name, onChange, label, sublabel }) {
 
 
 
 
 
 
 
 
 
 
53
  return (
54
- <label className="block cursor-pointer">
55
- <div className="border-2 border-dashed border-white/10 rounded-2xl p-8 text-center hover:border-cyan-500/30 hover:bg-cyan-500/3 transition-all">
56
- <div className="text-3xl mb-3 gradient-text">☁️</div>
57
- <p className="font-semibold text-sm">{label || 'Click to upload'}</p>
58
- <p className="text-xs text-slate-500 mt-1">{sublabel || 'Drag and drop supported'}</p>
59
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  <input
61
  type="file"
62
  accept={accept}
63
  name={name}
64
- onChange={onChange}
65
  className="hidden"
66
  />
67
  </label>
68
  );
69
  }
 
 
 
 
 
 
 
 
 
 
1
  import { motion } from 'framer-motion';
2
+ import { Loader2, AlertTriangle, CloudUpload, CheckCircle2 } from 'lucide-react';
3
+ import { useState } from 'react';
4
 
5
+ export function PageHeader({ title, subtitle, icon: Icon }) {
6
  return (
7
  <div className="mb-8">
8
+ <motion.div
9
+ initial={{ opacity: 0, x: -12 }}
10
+ animate={{ opacity: 1, x: 0 }}
11
+ transition={{ duration: 0.4 }}
12
+ >
13
+ {Icon && (
14
+ <div className="w-12 h-12 rounded-2xl bg-gradient-to-br from-cyan-500/20 to-purple-500/10 border border-white/[0.06] grid place-items-center mb-4">
15
+ <Icon size={22} className="text-cyan-400" />
16
+ </div>
17
+ )}
18
+ <h1 className="text-2xl sm:text-3xl font-extrabold tracking-tight">{title}</h1>
19
+ {subtitle && <p className="text-slate-400 mt-2 text-sm sm:text-base leading-relaxed max-w-xl">{subtitle}</p>}
20
+ </motion.div>
21
  </div>
22
  );
23
  }
 
25
  export function ResultBox({ children, className = '' }) {
26
  return (
27
  <motion.div
28
+ initial={{ opacity: 0, y: 20, scale: 0.98 }}
29
+ animate={{ opacity: 1, y: 0, scale: 1 }}
30
+ transition={{ duration: 0.5, ease: [0.4, 0, 0.2, 1] }}
31
+ className={`mt-6 p-6 sm:p-7 rounded-2xl bg-gradient-to-br from-cyan-500/[0.06] to-purple-500/[0.04] border border-cyan-500/10 backdrop-blur-sm ${className}`}
32
  >
33
  {children}
34
  </motion.div>
 
39
  if (!message) return null;
40
  return (
41
  <motion.div
42
+ initial={{ opacity: 0, y: 8 }}
43
+ animate={{ opacity: 1, y: 0 }}
44
+ className="mt-4 p-4 rounded-2xl bg-red-500/[0.08] border border-red-500/20 text-red-400 text-sm flex items-start gap-3"
45
  >
46
+ <AlertTriangle size={18} className="mt-0.5 flex-shrink-0" />
47
+ <span>{message}</span>
48
  </motion.div>
49
  );
50
  }
51
 
52
  export function SubmitButton({ loading, children, onClick, type = 'submit' }) {
53
  return (
54
+ <motion.button
55
  type={type}
56
  onClick={onClick}
57
  disabled={loading}
58
+ whileTap={{ scale: 0.97 }}
59
+ className="btn-quantum w-full py-4 px-6 text-base font-bold rounded-2xl flex items-center justify-center gap-2.5 disabled:opacity-50 disabled:cursor-not-allowed"
60
  >
61
+ {loading ? (
62
+ <>
63
+ <Loader2 className="animate-spin" size={20} />
64
+ <span>Processing...</span>
65
+ </>
66
+ ) : children}
67
+ </motion.button>
68
  );
69
  }
70
 
71
  export function UploadZone({ accept, name, onChange, label, sublabel }) {
72
+ const [fileName, setFileName] = useState('');
73
+ const [isDragging, setIsDragging] = useState(false);
74
+
75
+ const handleChange = (e) => {
76
+ if (e.target.files[0]) {
77
+ setFileName(e.target.files[0].name);
78
+ }
79
+ onChange?.(e);
80
+ };
81
+
82
  return (
83
+ <label
84
+ className="block cursor-pointer"
85
+ onDragOver={(e) => { e.preventDefault(); setIsDragging(true); }}
86
+ onDragLeave={() => setIsDragging(false)}
87
+ onDrop={() => setIsDragging(false)}
88
+ >
89
+ <motion.div
90
+ whileHover={{ scale: 1.01 }}
91
+ className={`
92
+ border-2 border-dashed rounded-2xl p-10 text-center
93
+ transition-all duration-300
94
+ ${isDragging
95
+ ? 'border-cyan-400/50 bg-cyan-500/[0.06] shadow-lg shadow-cyan-500/5'
96
+ : fileName
97
+ ? 'border-emerald-500/30 bg-emerald-500/[0.04]'
98
+ : 'border-white/[0.08] hover:border-cyan-500/20 hover:bg-white/[0.02]'
99
+ }
100
+ `}
101
+ >
102
+ {fileName ? (
103
+ <div className="flex flex-col items-center gap-2">
104
+ <CheckCircle2 size={32} className="text-emerald-400" />
105
+ <p className="text-sm font-semibold text-emerald-400">{fileName}</p>
106
+ <p className="text-xs text-slate-500">Click to change file</p>
107
+ </div>
108
+ ) : (
109
+ <div className="flex flex-col items-center gap-3">
110
+ <div className="w-14 h-14 rounded-2xl bg-gradient-to-br from-cyan-500/10 to-purple-500/5 border border-white/[0.06] grid place-items-center">
111
+ <CloudUpload size={24} className="text-cyan-400" />
112
+ </div>
113
+ <div>
114
+ <p className="font-semibold text-sm text-slate-200">{label || 'Click to upload'}</p>
115
+ <p className="text-xs text-slate-500 mt-1">{sublabel || 'Drag and drop supported'}</p>
116
+ </div>
117
+ </div>
118
+ )}
119
+ </motion.div>
120
  <input
121
  type="file"
122
  accept={accept}
123
  name={name}
124
+ onChange={handleChange}
125
  className="hidden"
126
  />
127
  </label>
128
  );
129
  }
130
+
131
+ export function SectionLabel({ children }) {
132
+ return (
133
+ <p className="text-[11px] font-bold uppercase tracking-[0.15em] text-purple-400 mb-3 flex items-center gap-2">
134
+ <span className="w-1.5 h-1.5 rounded-full bg-purple-400 animate-pulse" />
135
+ {children}
136
+ </p>
137
+ );
138
+ }
frontend/src/index.css CHANGED
@@ -2,30 +2,83 @@
2
 
3
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
4
 
 
5
  :root {
6
- --bg-deep: #050a14;
7
- --sidebar-bg: #0a0f1c;
8
- --card-bg: rgba(15, 23, 42, 0.6);
9
- --glass-border: rgba(255, 255, 255, 0.08);
10
- --accent-cyan: #00d4ff;
 
11
  --accent-purple: #a855f7;
12
- --text-primary: #f0f2f5;
 
 
13
  --text-secondary: #64748b;
 
 
 
14
  }
15
 
16
  * {
17
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
18
  }
19
 
 
 
 
 
20
  body {
21
  background: var(--bg-deep);
22
  color: var(--text-primary);
23
  overflow-x: hidden;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
- /* Custom scrollbar */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  ::-webkit-scrollbar {
28
- width: 6px;
29
  }
30
 
31
  ::-webkit-scrollbar-track {
@@ -33,75 +86,199 @@ body {
33
  }
34
 
35
  ::-webkit-scrollbar-thumb {
36
- background: rgba(255, 255, 255, 0.1);
37
- border-radius: 3px;
38
  }
39
 
40
  ::-webkit-scrollbar-thumb:hover {
41
- background: rgba(255, 255, 255, 0.2);
42
  }
43
 
44
- /* Glass Card */
45
  .glass-card {
 
46
  background: var(--card-bg);
47
- backdrop-filter: blur(20px);
48
- -webkit-backdrop-filter: blur(20px);
49
  border: 1px solid var(--glass-border);
50
- border-radius: 20px;
51
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
 
54
  .glass-card:hover {
55
- border-color: rgba(255, 255, 255, 0.15);
 
56
  }
57
 
58
- /* Gradient text */
59
  .gradient-text {
60
- background: linear-gradient(135deg, #00d4ff, #a855f7);
61
  -webkit-background-clip: text;
62
  -webkit-text-fill-color: transparent;
63
  background-clip: text;
64
  }
65
 
66
- /* Quantum button */
 
 
 
 
 
 
 
67
  .btn-quantum {
68
- background: linear-gradient(135deg, #00d4ff 0%, #a855f7 100%);
 
69
  color: white;
70
  border: none;
71
- border-radius: 14px;
72
  font-weight: 700;
73
  cursor: pointer;
74
- transition: all 0.3s;
75
- box-shadow: 0 8px 25px -8px rgba(0, 212, 255, 0.4);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  }
77
 
78
  .btn-quantum:hover {
79
- transform: translateY(-2px);
80
- box-shadow: 0 12px 35px -8px rgba(0, 212, 255, 0.5);
81
  }
82
 
83
  .btn-quantum:active {
84
- transform: translateY(0);
85
  }
86
 
87
- /* Custom input styles */
88
  .quantum-input {
89
  width: 100%;
90
  background: rgba(0, 0, 0, 0.3);
91
  border: 1px solid var(--glass-border);
92
- border-radius: 14px;
93
- padding: 14px 18px;
94
  color: var(--text-primary);
95
- font-size: 1rem;
96
- transition: all 0.3s;
97
  outline: none;
98
  }
99
 
100
  .quantum-input:focus {
101
  border-color: var(--accent-cyan);
102
- box-shadow: 0 0 0 4px rgba(0, 212, 255, 0.1);
 
103
  }
104
 
105
  .quantum-input::placeholder {
106
- color: var(--text-secondary);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
 
2
 
3
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
4
 
5
+ /* ===== DESIGN SYSTEM ===== */
6
  :root {
7
+ --bg-deep: #030712;
8
+ --bg-surface: #0a0f1e;
9
+ --card-bg: rgba(15, 23, 42, 0.5);
10
+ --glass-border: rgba(255, 255, 255, 0.06);
11
+ --glass-border-hover: rgba(255, 255, 255, 0.12);
12
+ --accent-cyan: #06b6d4;
13
  --accent-purple: #a855f7;
14
+ --accent-blue: #3b82f6;
15
+ --accent-pink: #ec4899;
16
+ --text-primary: #f1f5f9;
17
  --text-secondary: #64748b;
18
+ --text-muted: #475569;
19
+ --glow-cyan: rgba(6, 182, 212, 0.15);
20
+ --glow-purple: rgba(168, 85, 247, 0.15);
21
  }
22
 
23
  * {
24
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
25
  }
26
 
27
+ html {
28
+ scroll-behavior: smooth;
29
+ }
30
+
31
  body {
32
  background: var(--bg-deep);
33
  color: var(--text-primary);
34
  overflow-x: hidden;
35
+ min-height: 100vh;
36
+ }
37
+
38
+ /* ===== ANIMATED BACKGROUND ===== */
39
+ body::before {
40
+ content: '';
41
+ position: fixed;
42
+ top: 0;
43
+ left: 0;
44
+ width: 100vw;
45
+ height: 100vh;
46
+ background:
47
+ radial-gradient(ellipse 600px 400px at 15% 20%, rgba(6, 182, 212, 0.08) 0%, transparent 70%),
48
+ radial-gradient(ellipse 500px 500px at 85% 80%, rgba(168, 85, 247, 0.06) 0%, transparent 70%),
49
+ radial-gradient(ellipse 400px 300px at 50% 50%, rgba(59, 130, 246, 0.04) 0%, transparent 70%);
50
+ pointer-events: none;
51
+ z-index: 0;
52
+ animation: bgPulse 8s ease-in-out infinite alternate;
53
+ }
54
+
55
+ @keyframes bgPulse {
56
+ 0% {
57
+ opacity: 0.7;
58
+ }
59
+
60
+ 100% {
61
+ opacity: 1;
62
+ }
63
  }
64
 
65
+ /* Noise texture overlay */
66
+ body::after {
67
+ content: '';
68
+ position: fixed;
69
+ top: 0;
70
+ left: 0;
71
+ width: 100%;
72
+ height: 100%;
73
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.04'/%3E%3C/svg%3E");
74
+ opacity: 0.4;
75
+ pointer-events: none;
76
+ z-index: 0;
77
+ }
78
+
79
+ /* ===== SCROLLBAR ===== */
80
  ::-webkit-scrollbar {
81
+ width: 5px;
82
  }
83
 
84
  ::-webkit-scrollbar-track {
 
86
  }
87
 
88
  ::-webkit-scrollbar-thumb {
89
+ background: rgba(255, 255, 255, 0.08);
90
+ border-radius: 10px;
91
  }
92
 
93
  ::-webkit-scrollbar-thumb:hover {
94
+ background: rgba(255, 255, 255, 0.15);
95
  }
96
 
97
+ /* ===== GLASS CARD ===== */
98
  .glass-card {
99
+ position: relative;
100
  background: var(--card-bg);
101
+ backdrop-filter: blur(24px) saturate(1.2);
102
+ -webkit-backdrop-filter: blur(24px) saturate(1.2);
103
  border: 1px solid var(--glass-border);
104
+ border-radius: 24px;
105
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
106
+ overflow: hidden;
107
+ }
108
+
109
+ .glass-card::before {
110
+ content: '';
111
+ position: absolute;
112
+ top: 0;
113
+ left: 0;
114
+ right: 0;
115
+ height: 1px;
116
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
117
  }
118
 
119
  .glass-card:hover {
120
+ border-color: var(--glass-border-hover);
121
+ box-shadow: 0 8px 40px -12px rgba(0, 0, 0, 0.4), 0 0 20px var(--glow-cyan);
122
  }
123
 
124
+ /* ===== GRADIENT TEXT ===== */
125
  .gradient-text {
126
+ background: linear-gradient(135deg, var(--accent-cyan), var(--accent-purple));
127
  -webkit-background-clip: text;
128
  -webkit-text-fill-color: transparent;
129
  background-clip: text;
130
  }
131
 
132
+ .gradient-text-warm {
133
+ background: linear-gradient(135deg, #f97316, #ec4899);
134
+ -webkit-background-clip: text;
135
+ -webkit-text-fill-color: transparent;
136
+ background-clip: text;
137
+ }
138
+
139
+ /* ===== QUANTUM BUTTON ===== */
140
  .btn-quantum {
141
+ position: relative;
142
+ background: linear-gradient(135deg, var(--accent-cyan) 0%, var(--accent-purple) 100%);
143
  color: white;
144
  border: none;
145
+ border-radius: 16px;
146
  font-weight: 700;
147
  cursor: pointer;
148
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
149
+ box-shadow: 0 4px 20px -4px rgba(6, 182, 212, 0.4);
150
+ overflow: hidden;
151
+ z-index: 1;
152
+ }
153
+
154
+ .btn-quantum::before {
155
+ content: '';
156
+ position: absolute;
157
+ inset: 0;
158
+ background: linear-gradient(135deg, var(--accent-purple) 0%, var(--accent-cyan) 100%);
159
+ opacity: 0;
160
+ transition: opacity 0.4s;
161
+ z-index: -1;
162
+ }
163
+
164
+ .btn-quantum:hover::before {
165
+ opacity: 1;
166
  }
167
 
168
  .btn-quantum:hover {
169
+ transform: translateY(-3px);
170
+ box-shadow: 0 12px 40px -8px rgba(6, 182, 212, 0.5), 0 0 20px rgba(168, 85, 247, 0.2);
171
  }
172
 
173
  .btn-quantum:active {
174
+ transform: translateY(-1px);
175
  }
176
 
177
+ /* ===== INPUTS ===== */
178
  .quantum-input {
179
  width: 100%;
180
  background: rgba(0, 0, 0, 0.3);
181
  border: 1px solid var(--glass-border);
182
+ border-radius: 16px;
183
+ padding: 16px 20px;
184
  color: var(--text-primary);
185
+ font-size: 0.95rem;
186
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
187
  outline: none;
188
  }
189
 
190
  .quantum-input:focus {
191
  border-color: var(--accent-cyan);
192
+ box-shadow: 0 0 0 4px rgba(6, 182, 212, 0.1), 0 0 20px rgba(6, 182, 212, 0.05);
193
+ background: rgba(0, 0, 0, 0.4);
194
  }
195
 
196
  .quantum-input::placeholder {
197
+ color: var(--text-muted);
198
+ }
199
+
200
+ /* Select dropdown */
201
+ select.quantum-input {
202
+ appearance: none;
203
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
204
+ background-position: right 12px center;
205
+ background-repeat: no-repeat;
206
+ background-size: 20px;
207
+ padding-right: 40px;
208
+ }
209
+
210
+ select.quantum-input option {
211
+ background: #0f172a;
212
+ color: white;
213
+ }
214
+
215
+ /* ===== FLOATING ORB ANIMATION ===== */
216
+ @keyframes float {
217
+
218
+ 0%,
219
+ 100% {
220
+ transform: translateY(0px) rotate(0deg);
221
+ }
222
+
223
+ 50% {
224
+ transform: translateY(-20px) rotate(3deg);
225
+ }
226
+ }
227
+
228
+ @keyframes glow {
229
+
230
+ 0%,
231
+ 100% {
232
+ opacity: 0.5;
233
+ }
234
+
235
+ 50% {
236
+ opacity: 1;
237
+ }
238
+ }
239
+
240
+ @keyframes shimmer {
241
+ 0% {
242
+ background-position: -200% 0;
243
+ }
244
+
245
+ 100% {
246
+ background-position: 200% 0;
247
+ }
248
+ }
249
+
250
+ .animate-float {
251
+ animation: float 6s ease-in-out infinite;
252
+ }
253
+
254
+ .animate-glow {
255
+ animation: glow 3s ease-in-out infinite;
256
+ }
257
+
258
+ /* Shimmer loading effect */
259
+ .shimmer {
260
+ background: linear-gradient(90deg, transparent 25%, rgba(255, 255, 255, 0.05) 50%, transparent 75%);
261
+ background-size: 200% 100%;
262
+ animation: shimmer 2s infinite;
263
+ }
264
+
265
+ /* ===== STAT COUNTER ===== */
266
+ .stat-glow {
267
+ position: relative;
268
+ }
269
+
270
+ .stat-glow::after {
271
+ content: '';
272
+ position: absolute;
273
+ inset: -2px;
274
+ border-radius: 20px;
275
+ background: linear-gradient(135deg, var(--accent-cyan), var(--accent-purple));
276
+ opacity: 0;
277
+ z-index: -1;
278
+ transition: opacity 0.3s;
279
+ filter: blur(8px);
280
+ }
281
+
282
+ .stat-glow:hover::after {
283
+ opacity: 0.3;
284
  }
frontend/src/pages/AssociationRules.jsx CHANGED
@@ -1,7 +1,8 @@
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
  import { ShoppingCart } from 'lucide-react';
4
- import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone } from '../components/UI';
 
5
 
6
  export default function AssociationRules() {
7
  const [file, setFile] = useState(null);
@@ -17,14 +18,12 @@ export default function AssociationRules() {
17
  e.preventDefault();
18
  if (!file) return setError('Please upload a file');
19
  setLoading(true); setError(''); setResult(null);
20
-
21
  const fd = new FormData();
22
  fd.append('file', file);
23
  fd.append('metric', metric);
24
  fd.append('min_support', minSupport);
25
  fd.append('min_threshold', minThreshold);
26
  fd.append('has_header', hasHeader);
27
-
28
  try {
29
  const res = await axios.post('/api/apriori', fd);
30
  setResult(res.data);
@@ -35,31 +34,30 @@ export default function AssociationRules() {
35
 
36
  return (
37
  <div className="max-w-4xl mx-auto">
38
- <PageHeader title="Association Rules" subtitle="Discover hidden relationships in transactional datasets using Apriori." />
39
 
40
- <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-5">
41
  <UploadZone accept=".csv,.xlsx" onChange={(e) => setFile(e.target.files[0])} label="Upload Transaction Data" sublabel=".CSV or .XLSX (each row = transaction)" />
42
- {file && <p className="text-sm text-cyan-400 text-center font-medium">📊 {file.name}</p>}
43
 
44
  <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
45
  <div>
46
- <label className="block text-sm font-semibold text-slate-300 mb-2">Metric</label>
47
  <select value={metric} onChange={(e) => setMetric(e.target.value)} className="quantum-input">
48
  <option value="lift">Lift</option>
49
  <option value="confidence">Confidence</option>
50
  </select>
51
  </div>
52
  <div>
53
- <label className="block text-sm font-semibold text-slate-300 mb-2">Min Support</label>
54
  <input type="number" value={minSupport} onChange={(e) => setMinSupport(e.target.value)} step="0.01" min="0.01" max="1" className="quantum-input" />
55
  </div>
56
  <div>
57
- <label className="block text-sm font-semibold text-slate-300 mb-2">Min Threshold</label>
58
  <input type="number" value={minThreshold} onChange={(e) => setMinThreshold(e.target.value)} step="0.1" min="0.1" className="quantum-input" />
59
  </div>
60
  <div className="flex items-end">
61
- <label className="flex items-center gap-3 cursor-pointer text-sm text-slate-300">
62
- <input type="checkbox" checked={hasHeader} onChange={(e) => setHasHeader(e.target.checked)} className="w-4 h-4 rounded" />
63
  File has header row
64
  </label>
65
  </div>
@@ -74,37 +72,41 @@ export default function AssociationRules() {
74
 
75
  {result && (
76
  <ResultBox>
77
- <p className="text-xs font-bold uppercase tracking-widest text-purple-400 mb-4">
78
- Mining Results: {result.count} rules discovered
79
- </p>
80
- <div className="overflow-x-auto -mx-2">
81
  <table className="w-full text-sm">
82
  <thead>
83
- <tr className="text-left text-xs uppercase tracking-wider text-slate-500 border-b border-white/10">
84
- <th className="p-3">Antecedents (If)</th>
85
- <th className="p-3">Consequents (Then)</th>
86
- <th className="p-3">Support</th>
87
- <th className="p-3">Confidence</th>
88
- <th className="p-3">Lift</th>
89
  </tr>
90
  </thead>
91
  <tbody>
92
  {result.rules?.map((rule, i) => (
93
- <tr key={i} className="border-b border-white/5 hover:bg-white/3">
94
- <td className="p-3">
95
- <span className="px-2 py-0.5 rounded text-xs font-semibold bg-blue-500/20 text-blue-400">
 
 
 
 
 
 
96
  {rule.antecedents.join(', ')}
97
  </span>
98
  </td>
99
- <td className="p-3">
100
- <span className="px-2 py-0.5 rounded text-xs font-semibold bg-purple-500/20 text-purple-400">
101
  {rule.consequents.join(', ')}
102
  </span>
103
  </td>
104
- <td className="p-3 text-slate-300">{rule.support.toFixed(4)}</td>
105
- <td className="p-3 text-slate-300">{rule.confidence.toFixed(4)}</td>
106
- <td className="p-3 text-slate-300">{rule.lift.toFixed(4)}</td>
107
- </tr>
108
  ))}
109
  </tbody>
110
  </table>
 
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
  import { ShoppingCart } from 'lucide-react';
4
+ import { motion } from 'framer-motion';
5
+ import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone, SectionLabel } from '../components/UI';
6
 
7
  export default function AssociationRules() {
8
  const [file, setFile] = useState(null);
 
18
  e.preventDefault();
19
  if (!file) return setError('Please upload a file');
20
  setLoading(true); setError(''); setResult(null);
 
21
  const fd = new FormData();
22
  fd.append('file', file);
23
  fd.append('metric', metric);
24
  fd.append('min_support', minSupport);
25
  fd.append('min_threshold', minThreshold);
26
  fd.append('has_header', hasHeader);
 
27
  try {
28
  const res = await axios.post('/api/apriori', fd);
29
  setResult(res.data);
 
34
 
35
  return (
36
  <div className="max-w-4xl mx-auto">
37
+ <PageHeader icon={ShoppingCart} title="Association Rules" subtitle="Discover hidden relationships in transactional datasets using the Apriori algorithm." />
38
 
39
+ <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-6">
40
  <UploadZone accept=".csv,.xlsx" onChange={(e) => setFile(e.target.files[0])} label="Upload Transaction Data" sublabel=".CSV or .XLSX (each row = transaction)" />
 
41
 
42
  <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
43
  <div>
44
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Metric</label>
45
  <select value={metric} onChange={(e) => setMetric(e.target.value)} className="quantum-input">
46
  <option value="lift">Lift</option>
47
  <option value="confidence">Confidence</option>
48
  </select>
49
  </div>
50
  <div>
51
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Min Support</label>
52
  <input type="number" value={minSupport} onChange={(e) => setMinSupport(e.target.value)} step="0.01" min="0.01" max="1" className="quantum-input" />
53
  </div>
54
  <div>
55
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Min Threshold</label>
56
  <input type="number" value={minThreshold} onChange={(e) => setMinThreshold(e.target.value)} step="0.1" min="0.1" className="quantum-input" />
57
  </div>
58
  <div className="flex items-end">
59
+ <label className="flex items-center gap-3 cursor-pointer text-sm text-slate-300 bg-white/[0.02] border border-white/[0.05] rounded-2xl px-4 py-3 w-full hover:bg-white/[0.04] transition-colors">
60
+ <input type="checkbox" checked={hasHeader} onChange={(e) => setHasHeader(e.target.checked)} className="w-4 h-4 rounded accent-cyan-500" />
61
  File has header row
62
  </label>
63
  </div>
 
72
 
73
  {result && (
74
  <ResultBox>
75
+ <SectionLabel>Mining Results: {result.count} rules discovered</SectionLabel>
76
+ <div className="overflow-x-auto -mx-2 rounded-2xl border border-white/[0.05]">
 
 
77
  <table className="w-full text-sm">
78
  <thead>
79
+ <tr className="text-left text-[11px] uppercase tracking-wider text-slate-500 bg-white/[0.02]">
80
+ <th className="p-4">Antecedents</th>
81
+ <th className="p-4">Consequents</th>
82
+ <th className="p-4">Support</th>
83
+ <th className="p-4">Confidence</th>
84
+ <th className="p-4">Lift</th>
85
  </tr>
86
  </thead>
87
  <tbody>
88
  {result.rules?.map((rule, i) => (
89
+ <motion.tr
90
+ key={i}
91
+ initial={{ opacity: 0 }}
92
+ animate={{ opacity: 1 }}
93
+ transition={{ delay: i * 0.05 }}
94
+ className="border-t border-white/[0.04] hover:bg-white/[0.02] transition-colors"
95
+ >
96
+ <td className="p-4">
97
+ <span className="px-2.5 py-1 rounded-lg text-xs font-semibold bg-blue-500/15 text-blue-400">
98
  {rule.antecedents.join(', ')}
99
  </span>
100
  </td>
101
+ <td className="p-4">
102
+ <span className="px-2.5 py-1 rounded-lg text-xs font-semibold bg-purple-500/15 text-purple-400">
103
  {rule.consequents.join(', ')}
104
  </span>
105
  </td>
106
+ <td className="p-4 text-slate-300 font-mono text-xs">{rule.support.toFixed(4)}</td>
107
+ <td className="p-4 text-slate-300 font-mono text-xs">{rule.confidence.toFixed(4)}</td>
108
+ <td className="p-4 text-cyan-400 font-mono text-xs font-bold">{rule.lift.toFixed(4)}</td>
109
+ </motion.tr>
110
  ))}
111
  </tbody>
112
  </table>
frontend/src/pages/CognitiveQA.jsx CHANGED
@@ -1,7 +1,8 @@
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
- import { Brain, Volume2 } from 'lucide-react';
4
- import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone } from '../components/UI';
 
5
 
6
  export default function CognitiveQA() {
7
  const [tab, setTab] = useState('text');
@@ -15,7 +16,6 @@ export default function CognitiveQA() {
15
  const handleSubmit = async (e) => {
16
  e.preventDefault();
17
  setLoading(true); setError(''); setResult(null);
18
-
19
  try {
20
  let res;
21
  if (tab === 'text') {
@@ -41,11 +41,11 @@ export default function CognitiveQA() {
41
 
42
  return (
43
  <div className="max-w-3xl mx-auto">
44
- <PageHeader title="Cognitive QA" subtitle="Knowledge extraction engine with vocal synthesis output." />
45
 
46
- <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-5">
47
  <div>
48
- <label className="block text-sm font-semibold text-slate-300 mb-2">Context Repository</label>
49
  <textarea
50
  value={context}
51
  onChange={(e) => setContext(e.target.value)}
@@ -55,30 +55,35 @@ export default function CognitiveQA() {
55
  />
56
  </div>
57
 
58
- <div className="flex gap-2 border-b border-white/10 pb-3">
59
  {['text', 'voice'].map(t => (
60
  <button
61
  key={t}
62
  type="button"
63
  onClick={() => setTab(t)}
64
- className={`px-4 py-2 rounded-xl text-sm font-semibold transition-all ${tab === t ? 'bg-cyan-500/10 text-cyan-400' : 'text-slate-400 hover:bg-white/5'
 
 
65
  }`}
66
  >
67
- {t === 'text' ? 'Type Question' : 'Voice Question'}
68
  </button>
69
  ))}
70
  </div>
71
 
72
  {tab === 'text' ? (
73
  <div>
74
- <label className="block text-sm font-semibold text-slate-300 mb-2">Query</label>
75
- <input
76
- type="text"
77
- value={question}
78
- onChange={(e) => setQuestion(e.target.value)}
79
- placeholder="Ask a question about the context..."
80
- className="quantum-input"
81
- />
 
 
 
82
  </div>
83
  ) : (
84
  <UploadZone accept="audio/*" onChange={(e) => setFile(e.target.files[0])} label="Record Your Query" sublabel="Upload audio for voice-to-voice QA" />
@@ -93,35 +98,46 @@ export default function CognitiveQA() {
93
 
94
  {result && (
95
  <ResultBox>
96
- <p className="text-xs font-bold uppercase tracking-widest text-purple-400 mb-4">Reasoning Output</p>
97
 
98
- <div className="flex flex-col sm:flex-row items-start sm:items-center gap-4 p-5 rounded-xl bg-black/20 border-l-4 border-cyan-400">
99
  <div className="flex-1">
100
- <span className="text-xs font-bold text-cyan-400 uppercase">Extracted Answer</span>
101
- <p className="text-xl font-bold text-slate-100 mt-1">{result.answer}</p>
 
 
 
 
 
 
 
102
  </div>
103
  {result.audio_url && (
104
- <button
105
  type="button"
106
  onClick={playAudio}
107
- className="w-14 h-14 rounded-full bg-gradient-to-br from-cyan-500 to-purple-500 grid place-items-center text-white hover:scale-110 transition-transform flex-shrink-0"
 
 
108
  >
109
  <Volume2 size={22} />
110
- </button>
111
  )}
112
  </div>
113
 
114
  {result.score > 0 && (
115
- <div className="mt-4">
116
- <div className="h-2 bg-white/5 rounded-full overflow-hidden">
117
- <div
118
- className="h-full bg-gradient-to-r from-cyan-500 to-purple-500 rounded-full transition-all duration-1000"
119
- style={{ width: `${result.score}%` }}
 
 
120
  />
121
  </div>
122
- <div className="flex justify-between text-sm text-slate-400 mt-1">
123
- <span>Confidence</span>
124
- <span>{result.score}%</span>
125
  </div>
126
  </div>
127
  )}
 
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
+ import { Brain, Volume2, MessageSquare } from 'lucide-react';
4
+ import { motion } from 'framer-motion';
5
+ import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone, SectionLabel } from '../components/UI';
6
 
7
  export default function CognitiveQA() {
8
  const [tab, setTab] = useState('text');
 
16
  const handleSubmit = async (e) => {
17
  e.preventDefault();
18
  setLoading(true); setError(''); setResult(null);
 
19
  try {
20
  let res;
21
  if (tab === 'text') {
 
41
 
42
  return (
43
  <div className="max-w-3xl mx-auto">
44
+ <PageHeader icon={Brain} title="Cognitive QA" subtitle="Knowledge extraction engine with vocal synthesis output using DistilBERT." />
45
 
46
+ <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-6">
47
  <div>
48
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Context Repository</label>
49
  <textarea
50
  value={context}
51
  onChange={(e) => setContext(e.target.value)}
 
55
  />
56
  </div>
57
 
58
+ <div className="flex gap-1 p-1 rounded-2xl bg-white/[0.03] border border-white/[0.05]">
59
  {['text', 'voice'].map(t => (
60
  <button
61
  key={t}
62
  type="button"
63
  onClick={() => setTab(t)}
64
+ className={`flex-1 px-4 py-2.5 rounded-xl text-sm font-semibold transition-all ${tab === t
65
+ ? 'bg-gradient-to-r from-cyan-500/15 to-purple-500/10 text-cyan-400 shadow-sm'
66
+ : 'text-slate-500 hover:text-slate-300'
67
  }`}
68
  >
69
+ {t === 'text' ? '⌨️ Type Question' : '🎙 Voice Question'}
70
  </button>
71
  ))}
72
  </div>
73
 
74
  {tab === 'text' ? (
75
  <div>
76
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Query Expression</label>
77
+ <div className="relative">
78
+ <MessageSquare size={16} className="absolute left-4 top-1/2 -translate-y-1/2 text-cyan-500/60" />
79
+ <input
80
+ type="text"
81
+ value={question}
82
+ onChange={(e) => setQuestion(e.target.value)}
83
+ placeholder="Ask a question about the context..."
84
+ className="quantum-input pl-11"
85
+ />
86
+ </div>
87
  </div>
88
  ) : (
89
  <UploadZone accept="audio/*" onChange={(e) => setFile(e.target.files[0])} label="Record Your Query" sublabel="Upload audio for voice-to-voice QA" />
 
98
 
99
  {result && (
100
  <ResultBox>
101
+ <SectionLabel>Reasoning Output</SectionLabel>
102
 
103
+ <div className="flex flex-col sm:flex-row items-start sm:items-center gap-4 p-5 rounded-2xl bg-black/20 border-l-4 border-cyan-400">
104
  <div className="flex-1">
105
+ <span className="text-[10px] font-bold text-cyan-400 uppercase tracking-widest">Extracted Answer</span>
106
+ <motion.p
107
+ initial={{ opacity: 0 }}
108
+ animate={{ opacity: 1 }}
109
+ transition={{ delay: 0.2 }}
110
+ className="text-lg sm:text-xl font-bold text-slate-100 mt-2 leading-relaxed"
111
+ >
112
+ {result.answer}
113
+ </motion.p>
114
  </div>
115
  {result.audio_url && (
116
+ <motion.button
117
  type="button"
118
  onClick={playAudio}
119
+ whileHover={{ scale: 1.1 }}
120
+ whileTap={{ scale: 0.95 }}
121
+ className="w-14 h-14 rounded-full bg-gradient-to-br from-cyan-500 to-purple-600 grid place-items-center text-white shadow-lg shadow-cyan-500/20 flex-shrink-0"
122
  >
123
  <Volume2 size={22} />
124
+ </motion.button>
125
  )}
126
  </div>
127
 
128
  {result.score > 0 && (
129
+ <div className="mt-5">
130
+ <div className="h-2 bg-white/[0.04] rounded-full overflow-hidden">
131
+ <motion.div
132
+ initial={{ width: 0 }}
133
+ animate={{ width: `${result.score}%` }}
134
+ transition={{ duration: 1.2, ease: [0.4, 0, 0.2, 1] }}
135
+ className="h-full bg-gradient-to-r from-cyan-500 to-purple-500 rounded-full shadow-sm shadow-cyan-500/30"
136
  />
137
  </div>
138
+ <div className="flex justify-between text-xs text-slate-500 mt-1.5 font-medium">
139
+ <span>Confidence Score</span>
140
+ <span className="text-cyan-400">{result.score}%</span>
141
  </div>
142
  </div>
143
  )}
frontend/src/pages/Dashboard.jsx CHANGED
@@ -2,37 +2,77 @@ import { Link } from 'react-router-dom';
2
  import { motion } from 'framer-motion';
3
  import {
4
  User, PenTool, Languages, Smile, Brain,
5
- Target, PieChart, Braces, ShoppingCart
 
6
  } from 'lucide-react';
7
- import { PageHeader } from '../components/UI';
8
 
9
  const services = [
10
- { path: '/gender', label: 'Gender Discovery', desc: 'Vision Transformer for high-precision gender classification.', icon: User, color: 'from-pink-500 to-rose-500' },
11
- { path: '/textgen', label: 'Text Synthesis', desc: 'Creative language generation powered by GPT-2 architecture.', icon: PenTool, color: 'from-cyan-500 to-blue-500' },
12
- { path: '/translate', label: 'Neural Translate', desc: 'Advanced English-to-Urdu translation using sequence models.', icon: Languages, color: 'from-emerald-500 to-teal-500' },
13
- { path: '/sentiment', label: 'Empathy Engine', desc: 'Analyze emotional valence in text and vocal inputs.', icon: Smile, color: 'from-amber-500 to-orange-500' },
14
- { path: '/qa', label: 'Cognitive QA', desc: 'Extract precise knowledge from context with DistilBERT.', icon: Brain, color: 'from-violet-500 to-purple-500' },
15
- { path: '/zsl', label: 'Zero-Shot Lab', desc: 'BART-based classification for any unseen categories.', icon: Target, color: 'from-red-500 to-pink-500' },
16
- { path: '/clustering', label: 'Data Clusters', desc: 'Automated pattern discovery using K-Means clustering.', icon: PieChart, color: 'from-sky-500 to-indigo-500' },
17
- { path: '/dbscan', label: 'DBSCAN Lab', desc: 'Density-based clustering for complex patterns and outliers.', icon: Braces, color: 'from-lime-500 to-emerald-500' },
18
- { path: '/apriori', label: 'Market Analytics', desc: 'Generate association rules from transactional data.', icon: ShoppingCart, color: 'from-fuchsia-500 to-violet-500' },
 
 
 
 
 
 
19
  ];
20
 
21
  const container = {
22
  hidden: {},
23
- show: { transition: { staggerChildren: 0.06 } }
24
  };
25
 
26
  const item = {
27
- hidden: { opacity: 0, y: 20 },
28
- show: { opacity: 1, y: 0, transition: { duration: 0.4 } }
29
  };
30
 
31
  export default function Dashboard() {
32
  return (
33
  <div>
34
- <PageHeader title="Quantum Analytics" subtitle="Select a specialized AI engine to begin processing." />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
 
36
  <motion.div
37
  variants={container}
38
  initial="hidden"
@@ -43,18 +83,26 @@ export default function Dashboard() {
43
  <motion.div key={s.path} variants={item}>
44
  <Link
45
  to={s.path}
46
- className="glass-card p-6 flex flex-col gap-4 group hover:translate-y-[-6px] block"
47
  >
48
- <div className={`w-12 h-12 rounded-xl bg-gradient-to-br ${s.color} grid place-items-center opacity-80 group-hover:opacity-100 transition-all group-hover:scale-110`}>
49
- <s.icon size={22} className="text-white" />
 
 
 
 
50
  </div>
51
- <div>
52
- <h3 className="text-lg font-bold mb-1">{s.label}</h3>
53
- <p className="text-sm text-slate-400 leading-relaxed">{s.desc}</p>
 
 
54
  </div>
55
- <div className="mt-auto pt-2">
56
- <span className="text-xs font-bold uppercase tracking-widest text-cyan-400 group-hover:underline">
57
- Launch Engine
 
 
58
  </span>
59
  </div>
60
  </Link>
 
2
  import { motion } from 'framer-motion';
3
  import {
4
  User, PenTool, Languages, Smile, Brain,
5
+ Target, PieChart, Braces, ShoppingCart,
6
+ ArrowRight, Sparkles, Activity
7
  } from 'lucide-react';
 
8
 
9
  const services = [
10
+ { path: '/gender', label: 'Gender Discovery', desc: 'Vision Transformer for high-precision gender classification from facial images.', icon: User, gradient: 'from-pink-500 to-rose-500', glow: 'shadow-pink-500/20' },
11
+ { path: '/textgen', label: 'Text Synthesis', desc: 'Creative language generation powered by GPT-2 neural architecture.', icon: PenTool, gradient: 'from-cyan-500 to-blue-500', glow: 'shadow-cyan-500/20' },
12
+ { path: '/translate', label: 'Neural Translate', desc: 'Advanced EnglishUrdu translation using sequence-to-sequence models.', icon: Languages, gradient: 'from-emerald-500 to-teal-500', glow: 'shadow-emerald-500/20' },
13
+ { path: '/sentiment', label: 'Empathy Engine', desc: 'Analyze emotional valence and sentiment in text and vocal inputs.', icon: Smile, gradient: 'from-amber-500 to-orange-500', glow: 'shadow-amber-500/20' },
14
+ { path: '/qa', label: 'Cognitive QA', desc: 'Extract precise answers from context documents with DistilBERT.', icon: Brain, gradient: 'from-violet-500 to-purple-500', glow: 'shadow-violet-500/20' },
15
+ { path: '/zsl', label: 'Zero-Shot Lab', desc: 'BART-based classification for any unseen categories without training.', icon: Target, gradient: 'from-red-500 to-pink-500', glow: 'shadow-red-500/20' },
16
+ { path: '/clustering', label: 'Data Clusters', desc: 'Automated pattern discovery using K-Means unsupervised clustering.', icon: PieChart, gradient: 'from-sky-500 to-indigo-500', glow: 'shadow-sky-500/20' },
17
+ { path: '/dbscan', label: 'DBSCAN Lab', desc: 'Density-based spatial clustering for complex patterns and outliers.', icon: Braces, gradient: 'from-lime-500 to-emerald-500', glow: 'shadow-lime-500/20' },
18
+ { path: '/apriori', label: 'Market Analytics', desc: 'Generate association rules from transactional data with Apriori algorithm.', icon: ShoppingCart, gradient: 'from-fuchsia-500 to-violet-500', glow: 'shadow-fuchsia-500/20' },
19
+ ];
20
+
21
+ const stats = [
22
+ { label: 'AI Models', value: '9', icon: Sparkles, color: 'text-cyan-400' },
23
+ { label: 'NLP Engines', value: '5', icon: Brain, color: 'text-purple-400' },
24
+ { label: 'ML Pipelines', value: '3', icon: Activity, color: 'text-emerald-400' },
25
  ];
26
 
27
  const container = {
28
  hidden: {},
29
+ show: { transition: { staggerChildren: 0.05, delayChildren: 0.15 } }
30
  };
31
 
32
  const item = {
33
+ hidden: { opacity: 0, y: 24, scale: 0.96 },
34
+ show: { opacity: 1, y: 0, scale: 1, transition: { duration: 0.45, ease: [0.4, 0, 0.2, 1] } }
35
  };
36
 
37
  export default function Dashboard() {
38
  return (
39
  <div>
40
+ {/* Hero Section */}
41
+ <motion.div
42
+ initial={{ opacity: 0, y: -10 }}
43
+ animate={{ opacity: 1, y: 0 }}
44
+ className="mb-10"
45
+ >
46
+ <div className="flex items-center gap-3 mb-3">
47
+ <div className="w-10 h-10 rounded-xl bg-gradient-to-br from-cyan-500 to-purple-600 grid place-items-center">
48
+ <Sparkles size={18} className="text-white" />
49
+ </div>
50
+ <div>
51
+ <h1 className="text-2xl sm:text-3xl font-extrabold tracking-tight">Quantum Analytics</h1>
52
+ </div>
53
+ </div>
54
+ <p className="text-slate-400 text-sm sm:text-base max-w-lg leading-relaxed">
55
+ Select a specialized AI engine to begin processing. Each service is powered by state-of-the-art deep learning models.
56
+ </p>
57
+ </motion.div>
58
+
59
+ {/* Stats Bar */}
60
+ <motion.div
61
+ initial={{ opacity: 0, y: 12 }}
62
+ animate={{ opacity: 1, y: 0 }}
63
+ transition={{ delay: 0.1 }}
64
+ className="grid grid-cols-3 gap-3 sm:gap-4 mb-8"
65
+ >
66
+ {stats.map((s, i) => (
67
+ <div key={i} className="glass-card stat-glow p-4 sm:p-5 text-center group cursor-default">
68
+ <s.icon size={20} className={`${s.color} mx-auto mb-2 group-hover:scale-110 transition-transform`} />
69
+ <p className="text-xl sm:text-2xl font-black">{s.value}</p>
70
+ <p className="text-[11px] text-slate-500 font-medium uppercase tracking-wider mt-1">{s.label}</p>
71
+ </div>
72
+ ))}
73
+ </motion.div>
74
 
75
+ {/* Service Cards Grid */}
76
  <motion.div
77
  variants={container}
78
  initial="hidden"
 
83
  <motion.div key={s.path} variants={item}>
84
  <Link
85
  to={s.path}
86
+ className="glass-card p-6 flex flex-col gap-4 group block hover:translate-y-[-6px] transition-all duration-300"
87
  >
88
+ {/* Icon */}
89
+ <div className="flex items-center justify-between">
90
+ <div className={`w-12 h-12 rounded-2xl bg-gradient-to-br ${s.gradient} grid place-items-center shadow-lg ${s.glow} opacity-90 group-hover:opacity-100 group-hover:scale-110 transition-all duration-300`}>
91
+ <s.icon size={20} className="text-white" />
92
+ </div>
93
+ <ArrowRight size={16} className="text-slate-600 group-hover:text-cyan-400 group-hover:translate-x-1 transition-all duration-300" />
94
  </div>
95
+
96
+ {/* Content */}
97
+ <div className="flex-1">
98
+ <h3 className="text-base font-bold mb-1.5 group-hover:text-cyan-300 transition-colors">{s.label}</h3>
99
+ <p className="text-[13px] text-slate-500 leading-relaxed">{s.desc}</p>
100
  </div>
101
+
102
+ {/* Footer */}
103
+ <div className="pt-3 border-t border-white/[0.05]">
104
+ <span className="text-[11px] font-bold uppercase tracking-[0.15em] text-cyan-500/70 group-hover:text-cyan-400 transition-colors">
105
+ Launch Engine
106
  </span>
107
  </div>
108
  </Link>
frontend/src/pages/DataClusters.jsx CHANGED
@@ -1,7 +1,8 @@
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
  import { PieChart } from 'lucide-react';
4
- import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone } from '../components/UI';
 
5
 
6
  export default function DataClusters() {
7
  const [file, setFile] = useState(null);
@@ -14,11 +15,9 @@ export default function DataClusters() {
14
  e.preventDefault();
15
  if (!file) return setError('Please upload a file');
16
  setLoading(true); setError(''); setResult(null);
17
-
18
  const fd = new FormData();
19
  fd.append('file', file);
20
  fd.append('clusters', clusters);
21
-
22
  try {
23
  const res = await axios.post('/api/clustering', fd);
24
  setResult(res.data);
@@ -29,23 +28,14 @@ export default function DataClusters() {
29
 
30
  return (
31
  <div className="max-w-3xl mx-auto">
32
- <PageHeader title="Data Clusters" subtitle="Unsupervised grouping of multivariate datasets using K-Means." />
33
 
34
- <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-5">
35
  <UploadZone accept=".csv,.xlsx" onChange={(e) => setFile(e.target.files[0])} label="Upload Data Structure" sublabel=".CSV or .XLSX datasets" />
36
- {file && <p className="text-sm text-cyan-400 text-center font-medium">📊 {file.name}</p>}
37
-
38
  <div>
39
- <label className="block text-sm font-semibold text-slate-300 mb-2">Cluster Centroids (K)</label>
40
- <input
41
- type="number"
42
- value={clusters}
43
- onChange={(e) => setClusters(e.target.value)}
44
- min="2" max="10"
45
- className="quantum-input w-32"
46
- />
47
  </div>
48
-
49
  <SubmitButton loading={loading}>
50
  <PieChart size={18} /> Map Clusters
51
  </SubmitButton>
@@ -55,17 +45,19 @@ export default function DataClusters() {
55
 
56
  {result && (
57
  <ResultBox>
58
- <p className="text-xs font-bold uppercase tracking-widest text-purple-400 mb-4">Clustering Visualization</p>
59
- <div className="bg-white p-4 rounded-2xl">
60
  <img src={`data:image/png;base64,${result.plot}`} alt="Cluster Plot" className="w-full rounded-xl" />
61
- </div>
62
  {result.cluster_info && (
63
  <div className="mt-5 grid grid-cols-2 sm:grid-cols-3 gap-3">
64
- {Object.entries(result.cluster_info).map(([k, v]) => (
65
- <div key={k} className="p-3 rounded-xl bg-white/3 border-l-3 border-purple-500">
66
- <span className="text-xs font-bold text-purple-400 uppercase">Cluster {k}</span>
67
- <p className="text-lg font-extrabold mt-1">{v} Entities</p>
68
- </div>
 
 
69
  ))}
70
  </div>
71
  )}
 
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
  import { PieChart } from 'lucide-react';
4
+ import { motion } from 'framer-motion';
5
+ import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone, SectionLabel } from '../components/UI';
6
 
7
  export default function DataClusters() {
8
  const [file, setFile] = useState(null);
 
15
  e.preventDefault();
16
  if (!file) return setError('Please upload a file');
17
  setLoading(true); setError(''); setResult(null);
 
18
  const fd = new FormData();
19
  fd.append('file', file);
20
  fd.append('clusters', clusters);
 
21
  try {
22
  const res = await axios.post('/api/clustering', fd);
23
  setResult(res.data);
 
28
 
29
  return (
30
  <div className="max-w-3xl mx-auto">
31
+ <PageHeader icon={PieChart} title="Data Clusters" subtitle="Unsupervised grouping of multivariate datasets using K-Means algorithm." />
32
 
33
+ <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-6">
34
  <UploadZone accept=".csv,.xlsx" onChange={(e) => setFile(e.target.files[0])} label="Upload Data Structure" sublabel=".CSV or .XLSX datasets" />
 
 
35
  <div>
36
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Cluster Centroids (K)</label>
37
+ <input type="number" value={clusters} onChange={(e) => setClusters(e.target.value)} min="2" max="10" className="quantum-input w-32" />
 
 
 
 
 
 
38
  </div>
 
39
  <SubmitButton loading={loading}>
40
  <PieChart size={18} /> Map Clusters
41
  </SubmitButton>
 
45
 
46
  {result && (
47
  <ResultBox>
48
+ <SectionLabel>Clustering Visualization</SectionLabel>
49
+ <motion.div initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }} className="bg-white p-4 rounded-2xl">
50
  <img src={`data:image/png;base64,${result.plot}`} alt="Cluster Plot" className="w-full rounded-xl" />
51
+ </motion.div>
52
  {result.cluster_info && (
53
  <div className="mt-5 grid grid-cols-2 sm:grid-cols-3 gap-3">
54
+ {Object.entries(result.cluster_info).map(([k, v], i) => (
55
+ <motion.div key={k} initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: i * 0.1 }}
56
+ className="stat-glow p-4 rounded-2xl bg-white/[0.02] border border-white/[0.05]">
57
+ <span className="text-[10px] font-bold text-purple-400 uppercase tracking-widest">Cluster {k}</span>
58
+ <p className="text-xl font-black mt-1">{v}</p>
59
+ <span className="text-[11px] text-slate-500">Entities</span>
60
+ </motion.div>
61
  ))}
62
  </div>
63
  )}
frontend/src/pages/DbscanLab.jsx CHANGED
@@ -1,7 +1,8 @@
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
  import { Braces } from 'lucide-react';
4
- import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone } from '../components/UI';
 
5
 
6
  export default function DbscanLab() {
7
  const [file, setFile] = useState(null);
@@ -15,12 +16,10 @@ export default function DbscanLab() {
15
  e.preventDefault();
16
  if (!file) return setError('Please upload a file');
17
  setLoading(true); setError(''); setResult(null);
18
-
19
  const fd = new FormData();
20
  fd.append('file', file);
21
  fd.append('eps', eps);
22
  fd.append('min_samples', minSamples);
23
-
24
  try {
25
  const res = await axios.post('/api/dbscan', fd);
26
  setResult(res.data);
@@ -31,23 +30,20 @@ export default function DbscanLab() {
31
 
32
  return (
33
  <div className="max-w-3xl mx-auto">
34
- <PageHeader title="DBSCAN Lab" subtitle="Density-based clustering to identify complex patterns and outliers." />
35
 
36
- <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-5">
37
  <UploadZone accept=".csv,.xlsx" onChange={(e) => setFile(e.target.files[0])} label="Upload Data Structure" sublabel=".CSV or .XLSX datasets" />
38
- {file && <p className="text-sm text-cyan-400 text-center font-medium">📊 {file.name}</p>}
39
-
40
  <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
41
  <div>
42
- <label className="block text-sm font-semibold text-slate-300 mb-2">Epsilon (eps)</label>
43
  <input type="number" value={eps} onChange={(e) => setEps(e.target.value)} step="0.01" min="0.01" className="quantum-input" />
44
  </div>
45
  <div>
46
- <label className="block text-sm font-semibold text-slate-300 mb-2">Min Samples</label>
47
  <input type="number" value={minSamples} onChange={(e) => setMinSamples(e.target.value)} min="1" className="quantum-input" />
48
  </div>
49
  </div>
50
-
51
  <SubmitButton loading={loading}>
52
  <Braces size={18} /> Run DBSCAN
53
  </SubmitButton>
@@ -57,17 +53,19 @@ export default function DbscanLab() {
57
 
58
  {result && (
59
  <ResultBox>
60
- <p className="text-xs font-bold uppercase tracking-widest text-purple-400 mb-4">DBSCAN Visualization</p>
61
- <div className="bg-white p-4 rounded-2xl">
62
  <img src={`data:image/png;base64,${result.plot}`} alt="DBSCAN Plot" className="w-full rounded-xl" />
63
- </div>
64
  {result.cluster_info && (
65
  <div className="mt-5 grid grid-cols-2 sm:grid-cols-3 gap-3">
66
- {Object.entries(result.cluster_info).map(([k, v]) => (
67
- <div key={k} className="p-3 rounded-xl bg-white/3 border-l-3 border-purple-500">
68
- <span className="text-xs font-bold text-purple-400 uppercase">{k === '-1' ? 'Noise' : `Cluster ${k}`}</span>
69
- <p className="text-lg font-extrabold mt-1">{v} Entities</p>
70
- </div>
 
 
71
  ))}
72
  </div>
73
  )}
 
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
  import { Braces } from 'lucide-react';
4
+ import { motion } from 'framer-motion';
5
+ import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone, SectionLabel } from '../components/UI';
6
 
7
  export default function DbscanLab() {
8
  const [file, setFile] = useState(null);
 
16
  e.preventDefault();
17
  if (!file) return setError('Please upload a file');
18
  setLoading(true); setError(''); setResult(null);
 
19
  const fd = new FormData();
20
  fd.append('file', file);
21
  fd.append('eps', eps);
22
  fd.append('min_samples', minSamples);
 
23
  try {
24
  const res = await axios.post('/api/dbscan', fd);
25
  setResult(res.data);
 
30
 
31
  return (
32
  <div className="max-w-3xl mx-auto">
33
+ <PageHeader icon={Braces} title="DBSCAN Lab" subtitle="Density-based spatial clustering to identify complex patterns and outliers." />
34
 
35
+ <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-6">
36
  <UploadZone accept=".csv,.xlsx" onChange={(e) => setFile(e.target.files[0])} label="Upload Data Structure" sublabel=".CSV or .XLSX datasets" />
 
 
37
  <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
38
  <div>
39
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Epsilon (eps)</label>
40
  <input type="number" value={eps} onChange={(e) => setEps(e.target.value)} step="0.01" min="0.01" className="quantum-input" />
41
  </div>
42
  <div>
43
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Min Samples</label>
44
  <input type="number" value={minSamples} onChange={(e) => setMinSamples(e.target.value)} min="1" className="quantum-input" />
45
  </div>
46
  </div>
 
47
  <SubmitButton loading={loading}>
48
  <Braces size={18} /> Run DBSCAN
49
  </SubmitButton>
 
53
 
54
  {result && (
55
  <ResultBox>
56
+ <SectionLabel>DBSCAN Visualization</SectionLabel>
57
+ <motion.div initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }} className="bg-white p-4 rounded-2xl">
58
  <img src={`data:image/png;base64,${result.plot}`} alt="DBSCAN Plot" className="w-full rounded-xl" />
59
+ </motion.div>
60
  {result.cluster_info && (
61
  <div className="mt-5 grid grid-cols-2 sm:grid-cols-3 gap-3">
62
+ {Object.entries(result.cluster_info).map(([k, v], i) => (
63
+ <motion.div key={k} initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: i * 0.1 }}
64
+ className="stat-glow p-4 rounded-2xl bg-white/[0.02] border border-white/[0.05]">
65
+ <span className="text-[10px] font-bold text-purple-400 uppercase tracking-widest">{k === '-1' ? 'Noise Points' : `Cluster ${k}`}</span>
66
+ <p className="text-xl font-black mt-1">{v}</p>
67
+ <span className="text-[11px] text-slate-500">Entities</span>
68
+ </motion.div>
69
  ))}
70
  </div>
71
  )}
frontend/src/pages/EmpathyEngine.jsx CHANGED
@@ -1,7 +1,8 @@
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
- import { Smile, Frown, Meh, Mic } from 'lucide-react';
4
- import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone } from '../components/UI';
 
5
 
6
  export default function EmpathyEngine() {
7
  const [tab, setTab] = useState('text');
@@ -14,7 +15,6 @@ export default function EmpathyEngine() {
14
  const handleSubmit = async (e) => {
15
  e.preventDefault();
16
  setLoading(true); setError(''); setResult(null);
17
-
18
  try {
19
  let res;
20
  if (tab === 'text') {
@@ -30,43 +30,38 @@ export default function EmpathyEngine() {
30
  } finally { setLoading(false); }
31
  };
32
 
33
- const sentimentIcon = (label) => {
34
  const l = (label || '').toLowerCase();
35
- if (l === 'positive') return <Smile size={48} className="text-emerald-400" />;
36
- if (l === 'negative') return <Frown size={48} className="text-red-400" />;
37
- return <Meh size={48} className="text-cyan-400" />;
38
- };
39
-
40
- const sentimentColor = (label) => {
41
- const l = (label || '').toLowerCase();
42
- if (l === 'positive') return 'text-emerald-400';
43
- if (l === 'negative') return 'text-red-400';
44
- return 'text-cyan-400';
45
  };
46
 
47
  return (
48
  <div className="max-w-2xl mx-auto">
49
- <PageHeader title="Empathy Engine" subtitle="Contextual sentiment analysis for text and vocal recordings." />
50
 
51
- <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-5">
52
  {/* Tabs */}
53
- <div className="flex gap-2 border-b border-white/10 pb-3">
54
  {['text', 'voice'].map(t => (
55
  <button
56
  key={t}
57
  type="button"
58
  onClick={() => setTab(t)}
59
- className={`px-4 py-2 rounded-xl text-sm font-semibold transition-all ${tab === t ? 'bg-cyan-500/10 text-cyan-400' : 'text-slate-400 hover:bg-white/5'
 
 
60
  }`}
61
  >
62
- {t === 'text' ? 'Text Analysis' : 'Vocal Analysis'}
63
  </button>
64
  ))}
65
  </div>
66
 
67
  {tab === 'text' ? (
68
  <div>
69
- <label className="block text-sm font-semibold text-slate-300 mb-2">Input Text</label>
70
  <textarea
71
  value={text}
72
  onChange={(e) => setText(e.target.value)}
@@ -75,40 +70,64 @@ export default function EmpathyEngine() {
75
  />
76
  </div>
77
  ) : (
78
- <div>
79
- <UploadZone accept="audio/*" onChange={(e) => setFile(e.target.files[0])} label="Upload Voice Recording" sublabel="WAV or MP3 format" />
80
- {file && <p className="text-sm text-cyan-400 text-center mt-2 font-medium">🎙 {file.name}</p>}
81
- </div>
82
  )}
83
 
84
  <SubmitButton loading={loading}>
85
- <Mic size={18} /> Analyze Sentiment
86
  </SubmitButton>
87
  </form>
88
 
89
  <ErrorBox message={error} />
90
 
91
- {result && (
92
- <ResultBox>
93
- <p className="text-xs font-bold uppercase tracking-widest text-purple-400 mb-4">Engine Output</p>
94
- {result.transcript && (
95
- <div className="mb-4 p-3 rounded-xl bg-black/20 text-sm">
96
- <span className="text-xs font-bold text-cyan-400 uppercase">Transcription</span>
97
- <p className="mt-1 text-slate-300">"{result.transcript}"</p>
98
- </div>
99
- )}
100
- <div className="flex items-center gap-6 p-4 rounded-xl bg-white/3">
101
- <div className="flex-1">
102
- <span className="text-sm text-slate-400">Detected Sentiment</span>
103
- <p className={`text-3xl font-extrabold capitalize ${sentimentColor(result.result)}`}>
104
- {result.result}
105
- </p>
106
- <span className="text-sm text-slate-500">{result.score}% confidence</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  </div>
108
- {sentimentIcon(result.result)}
109
- </div>
110
- </ResultBox>
111
- )}
112
  </div>
113
  );
114
  }
 
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
+ import { Smile, Frown, Meh, Mic, HeartPulse } from 'lucide-react';
4
+ import { motion } from 'framer-motion';
5
+ import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone, SectionLabel } from '../components/UI';
6
 
7
  export default function EmpathyEngine() {
8
  const [tab, setTab] = useState('text');
 
15
  const handleSubmit = async (e) => {
16
  e.preventDefault();
17
  setLoading(true); setError(''); setResult(null);
 
18
  try {
19
  let res;
20
  if (tab === 'text') {
 
30
  } finally { setLoading(false); }
31
  };
32
 
33
+ const sentimentConfig = (label) => {
34
  const l = (label || '').toLowerCase();
35
+ if (l === 'positive') return { icon: Smile, color: 'text-emerald-400', bg: 'bg-emerald-500/10', border: 'border-emerald-500/20' };
36
+ if (l === 'negative') return { icon: Frown, color: 'text-red-400', bg: 'bg-red-500/10', border: 'border-red-500/20' };
37
+ return { icon: Meh, color: 'text-cyan-400', bg: 'bg-cyan-500/10', border: 'border-cyan-500/20' };
 
 
 
 
 
 
 
38
  };
39
 
40
  return (
41
  <div className="max-w-2xl mx-auto">
42
+ <PageHeader icon={HeartPulse} title="Empathy Engine" subtitle="Contextual sentiment analysis for text and vocal recordings." />
43
 
44
+ <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-6">
45
  {/* Tabs */}
46
+ <div className="flex gap-1 p-1 rounded-2xl bg-white/[0.03] border border-white/[0.05]">
47
  {['text', 'voice'].map(t => (
48
  <button
49
  key={t}
50
  type="button"
51
  onClick={() => setTab(t)}
52
+ className={`flex-1 px-4 py-2.5 rounded-xl text-sm font-semibold transition-all ${tab === t
53
+ ? 'bg-gradient-to-r from-cyan-500/15 to-purple-500/10 text-cyan-400 shadow-sm'
54
+ : 'text-slate-500 hover:text-slate-300'
55
  }`}
56
  >
57
+ {t === 'text' ? '📝 Text Analysis' : '🎙 Vocal Analysis'}
58
  </button>
59
  ))}
60
  </div>
61
 
62
  {tab === 'text' ? (
63
  <div>
64
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Input Text</label>
65
  <textarea
66
  value={text}
67
  onChange={(e) => setText(e.target.value)}
 
70
  />
71
  </div>
72
  ) : (
73
+ <UploadZone accept="audio/*" onChange={(e) => setFile(e.target.files[0])} label="Upload Voice Recording" sublabel="WAV or MP3 format" />
 
 
 
74
  )}
75
 
76
  <SubmitButton loading={loading}>
77
+ <HeartPulse size={18} /> Analyze Sentiment
78
  </SubmitButton>
79
  </form>
80
 
81
  <ErrorBox message={error} />
82
 
83
+ {result && (() => {
84
+ const cfg = sentimentConfig(result.result);
85
+ const Icon = cfg.icon;
86
+ return (
87
+ <ResultBox>
88
+ <SectionLabel>Engine Output</SectionLabel>
89
+
90
+ {result.transcript && (
91
+ <div className="mb-5 p-4 rounded-2xl bg-black/20 border border-white/[0.05]">
92
+ <span className="text-[10px] font-bold text-cyan-400 uppercase tracking-widest">Transcription</span>
93
+ <p className="mt-1.5 text-slate-300 text-sm leading-relaxed">"{result.transcript}"</p>
94
+ </div>
95
+ )}
96
+
97
+ <div className={`flex items-center gap-6 p-5 rounded-2xl ${cfg.bg} border ${cfg.border}`}>
98
+ <div className="flex-1">
99
+ <span className="text-xs text-slate-400 font-medium">Detected Sentiment</span>
100
+ <motion.p
101
+ initial={{ scale: 0.5 }}
102
+ animate={{ scale: 1 }}
103
+ transition={{ type: 'spring', stiffness: 200 }}
104
+ className={`text-3xl font-black capitalize ${cfg.color}`}
105
+ >
106
+ {result.result}
107
+ </motion.p>
108
+ <div className="mt-2 flex items-center gap-2">
109
+ <div className="h-1.5 flex-1 bg-black/20 rounded-full overflow-hidden">
110
+ <motion.div
111
+ initial={{ width: 0 }}
112
+ animate={{ width: `${result.score}%` }}
113
+ transition={{ duration: 1, delay: 0.3 }}
114
+ className="h-full bg-gradient-to-r from-cyan-500 to-purple-500 rounded-full"
115
+ />
116
+ </div>
117
+ <span className="text-xs text-slate-400 font-semibold">{result.score}%</span>
118
+ </div>
119
+ </div>
120
+ <motion.div
121
+ initial={{ rotate: -20, scale: 0 }}
122
+ animate={{ rotate: 0, scale: 1 }}
123
+ transition={{ type: 'spring', delay: 0.2 }}
124
+ >
125
+ <Icon size={52} className={cfg.color} />
126
+ </motion.div>
127
  </div>
128
+ </ResultBox>
129
+ );
130
+ })()}
 
131
  </div>
132
  );
133
  }
frontend/src/pages/GenderDiscovery.jsx CHANGED
@@ -1,7 +1,8 @@
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
- import { Upload } from 'lucide-react';
4
- import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone } from '../components/UI';
 
5
 
6
  export default function GenderDiscovery() {
7
  const [file, setFile] = useState(null);
@@ -22,10 +23,8 @@ export default function GenderDiscovery() {
22
  e.preventDefault();
23
  if (!file) return setError('Please select an image');
24
  setLoading(true); setError(''); setResult('');
25
-
26
  const fd = new FormData();
27
  fd.append('image', file);
28
-
29
  try {
30
  const res = await axios.post('/api/gender', fd);
31
  setResult(res.data.result);
@@ -36,21 +35,29 @@ export default function GenderDiscovery() {
36
 
37
  return (
38
  <div className="max-w-2xl mx-auto">
39
- <PageHeader title="Gender Discovery" subtitle="Upload a visual specimen for neural gender classification." />
40
-
41
- <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-5">
42
- <UploadZone accept="image/*" name="image" onChange={handleFile} label="Upload Image" sublabel="PNG, JPG or WEBP (max 10MB)" />
43
 
44
- {preview && (
45
- <div className="rounded-2xl overflow-hidden border border-white/10">
46
- <img src={preview} alt="Preview" className="w-full h-56 object-cover" />
47
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  )}
49
 
50
- {file && <p className="text-sm text-cyan-400 text-center font-medium">📎 {file.name}</p>}
51
-
52
  <SubmitButton loading={loading}>
53
- <Upload size={18} /> Run Discovery Engine
54
  </SubmitButton>
55
  </form>
56
 
@@ -58,11 +65,21 @@ export default function GenderDiscovery() {
58
 
59
  {result && (
60
  <ResultBox>
61
- <p className="text-xs font-bold uppercase tracking-widest text-purple-400 mb-2">Engine Output</p>
62
- <div className="flex justify-between items-center">
63
- <span className="text-slate-400">Detected Gender</span>
64
- <span className="text-3xl font-extrabold">{result}</span>
 
 
 
 
 
 
 
65
  </div>
 
 
 
66
  </ResultBox>
67
  )}
68
  </div>
 
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
+ import { Upload, User, Scan } from 'lucide-react';
4
+ import { motion } from 'framer-motion';
5
+ import { PageHeader, ResultBox, ErrorBox, SubmitButton, UploadZone, SectionLabel } from '../components/UI';
6
 
7
  export default function GenderDiscovery() {
8
  const [file, setFile] = useState(null);
 
23
  e.preventDefault();
24
  if (!file) return setError('Please select an image');
25
  setLoading(true); setError(''); setResult('');
 
26
  const fd = new FormData();
27
  fd.append('image', file);
 
28
  try {
29
  const res = await axios.post('/api/gender', fd);
30
  setResult(res.data.result);
 
35
 
36
  return (
37
  <div className="max-w-2xl mx-auto">
38
+ <PageHeader icon={User} title="Gender Discovery" subtitle="Upload a visual specimen for neural gender classification using Vision Transformer." />
 
 
 
39
 
40
+ <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-6">
41
+ {!preview ? (
42
+ <UploadZone accept="image/*" name="image" onChange={handleFile} label="Upload Image" sublabel="PNG, JPG or WEBP (max 10MB)" />
43
+ ) : (
44
+ <motion.div
45
+ initial={{ opacity: 0, scale: 0.95 }}
46
+ animate={{ opacity: 1, scale: 1 }}
47
+ className="relative rounded-2xl overflow-hidden border border-white/10 group"
48
+ >
49
+ <img src={preview} alt="Preview" className="w-full h-60 object-cover" />
50
+ <div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity flex items-end p-4">
51
+ <label className="text-xs text-white/80 cursor-pointer hover:text-white font-medium">
52
+ Click to change →
53
+ <input type="file" accept="image/*" onChange={handleFile} className="hidden" />
54
+ </label>
55
+ </div>
56
+ </motion.div>
57
  )}
58
 
 
 
59
  <SubmitButton loading={loading}>
60
+ <Scan size={18} /> Run Discovery Engine
61
  </SubmitButton>
62
  </form>
63
 
 
65
 
66
  {result && (
67
  <ResultBox>
68
+ <SectionLabel>Engine Output</SectionLabel>
69
+ <div className="flex items-center justify-between p-5 rounded-2xl bg-white/[0.02] border border-white/[0.05]">
70
+ <span className="text-sm text-slate-400 font-medium">Detected Gender</span>
71
+ <motion.span
72
+ initial={{ scale: 0.5, opacity: 0 }}
73
+ animate={{ scale: 1, opacity: 1 }}
74
+ transition={{ type: 'spring', stiffness: 200 }}
75
+ className="text-3xl font-black gradient-text"
76
+ >
77
+ {result}
78
+ </motion.span>
79
  </div>
80
+ <p className="text-xs text-slate-500 mt-3 flex items-center gap-1.5">
81
+ <Scan size={12} /> Vision model identifies facial features for classification
82
+ </p>
83
  </ResultBox>
84
  )}
85
  </div>
frontend/src/pages/NeuralTranslate.jsx CHANGED
@@ -1,7 +1,7 @@
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
- import { Languages, Copy, Check } from 'lucide-react';
4
- import { PageHeader, ResultBox, ErrorBox, SubmitButton } from '../components/UI';
5
 
6
  export default function NeuralTranslate() {
7
  const [text, setText] = useState('');
@@ -30,20 +30,24 @@ export default function NeuralTranslate() {
30
 
31
  return (
32
  <div className="max-w-2xl mx-auto">
33
- <PageHeader title="Neural Translate" subtitle="Advanced English-to-Urdu translation using sequence models." />
34
 
35
- <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-5">
36
  <div>
37
- <label className="block text-sm font-semibold text-slate-300 mb-2">English Text</label>
 
 
 
 
38
  <textarea
39
  value={text}
40
  onChange={(e) => setText(e.target.value)}
41
  placeholder="Type or paste English text here..."
42
- className="quantum-input min-h-[140px] resize-y"
43
  />
44
  </div>
45
  <SubmitButton loading={loading}>
46
- <Languages size={18} /> Translate to Urdu
47
  </SubmitButton>
48
  </form>
49
 
@@ -51,14 +55,17 @@ export default function NeuralTranslate() {
51
 
52
  {result && (
53
  <ResultBox>
54
- <div className="flex items-center justify-between mb-3">
55
- <p className="text-xs font-bold uppercase tracking-widest text-purple-400">Urdu Translation</p>
56
- <button onClick={copyText} className="flex items-center gap-1.5 text-xs text-slate-400 hover:text-white transition-colors bg-white/5 px-3 py-1.5 rounded-lg">
57
- {copied ? <Check size={14} /> : <Copy size={14} />}
 
 
 
58
  {copied ? 'Copied!' : 'Copy'}
59
  </button>
60
  </div>
61
- <p className="text-xl text-slate-200 leading-relaxed text-right font-medium" dir="rtl">{result}</p>
62
  </ResultBox>
63
  )}
64
  </div>
 
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
+ import { Languages, Copy, Check, ArrowRight } from 'lucide-react';
4
+ import { PageHeader, ResultBox, ErrorBox, SubmitButton, SectionLabel } from '../components/UI';
5
 
6
  export default function NeuralTranslate() {
7
  const [text, setText] = useState('');
 
30
 
31
  return (
32
  <div className="max-w-2xl mx-auto">
33
+ <PageHeader icon={Languages} title="Neural Translate" subtitle="Advanced EnglishUrdu translation using sequence-to-sequence models." />
34
 
35
+ <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-6">
36
  <div>
37
+ <div className="flex items-center gap-2 mb-2.5">
38
+ <span className="text-xs font-bold bg-blue-500/10 text-blue-400 px-2 py-0.5 rounded-lg">English</span>
39
+ <ArrowRight size={14} className="text-slate-600" />
40
+ <span className="text-xs font-bold bg-emerald-500/10 text-emerald-400 px-2 py-0.5 rounded-lg">Urdu</span>
41
+ </div>
42
  <textarea
43
  value={text}
44
  onChange={(e) => setText(e.target.value)}
45
  placeholder="Type or paste English text here..."
46
+ className="quantum-input min-h-[150px] resize-y"
47
  />
48
  </div>
49
  <SubmitButton loading={loading}>
50
+ <Languages size={18} /> Translate
51
  </SubmitButton>
52
  </form>
53
 
 
55
 
56
  {result && (
57
  <ResultBox>
58
+ <div className="flex items-center justify-between mb-4">
59
+ <SectionLabel>Urdu Translation</SectionLabel>
60
+ <button
61
+ onClick={copyText}
62
+ className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-xl bg-white/[0.04] border border-white/[0.06] text-slate-400 hover:text-white hover:border-white/10 transition-all"
63
+ >
64
+ {copied ? <Check size={13} className="text-emerald-400" /> : <Copy size={13} />}
65
  {copied ? 'Copied!' : 'Copy'}
66
  </button>
67
  </div>
68
+ <p className="text-xl text-slate-200 leading-loose font-medium text-right" dir="rtl">{result}</p>
69
  </ResultBox>
70
  )}
71
  </div>
frontend/src/pages/TextSynthesis.jsx CHANGED
@@ -1,7 +1,7 @@
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
- import { PenTool, Copy, Check } from 'lucide-react';
4
- import { PageHeader, ResultBox, ErrorBox, SubmitButton } from '../components/UI';
5
 
6
  export default function TextSynthesis() {
7
  const [prompt, setPrompt] = useState('');
@@ -30,20 +30,20 @@ export default function TextSynthesis() {
30
 
31
  return (
32
  <div className="max-w-2xl mx-auto">
33
- <PageHeader title="Text Synthesis" subtitle="Creative language generation powered by GPT-2 architecture." />
34
 
35
- <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-5">
36
  <div>
37
- <label className="block text-sm font-semibold text-slate-300 mb-2">Synthesis Prompt</label>
38
  <textarea
39
  value={prompt}
40
  onChange={(e) => setPrompt(e.target.value)}
41
  placeholder="Enter a seed sentence for the AI to expand upon..."
42
- className="quantum-input min-h-[140px] resize-y"
43
  />
44
  </div>
45
  <SubmitButton loading={loading}>
46
- <PenTool size={18} /> Synthesize Text
47
  </SubmitButton>
48
  </form>
49
 
@@ -51,14 +51,17 @@ export default function TextSynthesis() {
51
 
52
  {result && (
53
  <ResultBox>
54
- <div className="flex items-center justify-between mb-3">
55
- <p className="text-xs font-bold uppercase tracking-widest text-purple-400">Generated Output</p>
56
- <button onClick={copyText} className="flex items-center gap-1.5 text-xs text-slate-400 hover:text-white transition-colors bg-white/5 px-3 py-1.5 rounded-lg">
57
- {copied ? <Check size={14} /> : <Copy size={14} />}
 
 
 
58
  {copied ? 'Copied!' : 'Copy'}
59
  </button>
60
  </div>
61
- <p className="text-slate-200 leading-relaxed">{result}</p>
62
  </ResultBox>
63
  )}
64
  </div>
 
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
+ import { PenTool, Copy, Check, Wand2 } from 'lucide-react';
4
+ import { PageHeader, ResultBox, ErrorBox, SubmitButton, SectionLabel } from '../components/UI';
5
 
6
  export default function TextSynthesis() {
7
  const [prompt, setPrompt] = useState('');
 
30
 
31
  return (
32
  <div className="max-w-2xl mx-auto">
33
+ <PageHeader icon={PenTool} title="Text Synthesis" subtitle="Creative language generation powered by GPT-2 neural architecture." />
34
 
35
+ <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-6">
36
  <div>
37
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Synthesis Prompt</label>
38
  <textarea
39
  value={prompt}
40
  onChange={(e) => setPrompt(e.target.value)}
41
  placeholder="Enter a seed sentence for the AI to expand upon..."
42
+ className="quantum-input min-h-[150px] resize-y"
43
  />
44
  </div>
45
  <SubmitButton loading={loading}>
46
+ <Wand2 size={18} /> Synthesize Text
47
  </SubmitButton>
48
  </form>
49
 
 
51
 
52
  {result && (
53
  <ResultBox>
54
+ <div className="flex items-center justify-between mb-4">
55
+ <SectionLabel>Generated Output</SectionLabel>
56
+ <button
57
+ onClick={copyText}
58
+ className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-xl bg-white/[0.04] border border-white/[0.06] text-slate-400 hover:text-white hover:border-white/10 transition-all"
59
+ >
60
+ {copied ? <Check size={13} className="text-emerald-400" /> : <Copy size={13} />}
61
  {copied ? 'Copied!' : 'Copy'}
62
  </button>
63
  </div>
64
+ <p className="text-slate-200 leading-relaxed text-[15px]">{result}</p>
65
  </ResultBox>
66
  )}
67
  </div>
frontend/src/pages/ZeroShotLab.jsx CHANGED
@@ -1,7 +1,8 @@
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
- import { Target } from 'lucide-react';
4
- import { PageHeader, ResultBox, ErrorBox, SubmitButton } from '../components/UI';
 
5
 
6
  export default function ZeroShotLab() {
7
  const [text, setText] = useState('');
@@ -22,13 +23,21 @@ export default function ZeroShotLab() {
22
  } finally { setLoading(false); }
23
  };
24
 
 
 
 
 
 
 
 
 
25
  return (
26
  <div className="max-w-2xl mx-auto">
27
- <PageHeader title="Zero-Shot Lab" subtitle="BART-based classification for any unseen categories." />
28
 
29
- <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-5">
30
  <div>
31
- <label className="block text-sm font-semibold text-slate-300 mb-2">Input Text</label>
32
  <textarea
33
  value={text}
34
  onChange={(e) => setText(e.target.value)}
@@ -38,7 +47,7 @@ export default function ZeroShotLab() {
38
  />
39
  </div>
40
  <div>
41
- <label className="block text-sm font-semibold text-slate-300 mb-2">Candidate Labels</label>
42
  <input
43
  type="text"
44
  value={labels}
@@ -47,7 +56,7 @@ export default function ZeroShotLab() {
47
  className="quantum-input"
48
  required
49
  />
50
- <p className="text-xs text-slate-500 mt-1">Separate labels with commas</p>
51
  </div>
52
  <SubmitButton loading={loading}>
53
  <Target size={18} /> Classify Text
@@ -58,24 +67,41 @@ export default function ZeroShotLab() {
58
 
59
  {result && (
60
  <ResultBox>
61
- <p className="text-xs font-bold uppercase tracking-widest text-purple-400 mb-4">Classification Results</p>
62
- <div className="mb-4 p-4 rounded-xl bg-black/20 text-center">
63
- <span className="text-sm text-slate-400">Best Match</span>
64
- <p className="text-2xl font-extrabold text-cyan-400 mt-1">{result.best_label}</p>
 
 
 
 
 
 
 
 
65
  <span className="text-sm text-slate-500">{result.best_score}% confidence</span>
66
  </div>
67
- <div className="space-y-2">
 
68
  {result.results?.map((r, i) => (
69
- <div key={i} className="flex items-center gap-3">
70
- <span className="text-sm text-slate-300 w-28 truncate capitalize">{r.label}</span>
71
- <div className="flex-1 h-2 bg-white/5 rounded-full overflow-hidden">
72
- <div
73
- className="h-full bg-gradient-to-r from-cyan-500 to-purple-500 rounded-full transition-all duration-700"
74
- style={{ width: `${r.score}%` }}
 
 
 
 
 
 
 
 
75
  />
76
  </div>
77
- <span className="text-xs text-slate-400 w-12 text-right">{r.score}%</span>
78
- </div>
79
  ))}
80
  </div>
81
  </ResultBox>
 
1
  import { useState } from 'react';
2
  import axios from 'axios';
3
+ import { Target, BarChart3 } from 'lucide-react';
4
+ import { motion } from 'framer-motion';
5
+ import { PageHeader, ResultBox, ErrorBox, SubmitButton, SectionLabel } from '../components/UI';
6
 
7
  export default function ZeroShotLab() {
8
  const [text, setText] = useState('');
 
23
  } finally { setLoading(false); }
24
  };
25
 
26
+ const barColors = [
27
+ 'from-cyan-500 to-blue-500',
28
+ 'from-purple-500 to-pink-500',
29
+ 'from-emerald-500 to-teal-500',
30
+ 'from-amber-500 to-orange-500',
31
+ 'from-red-500 to-rose-500',
32
+ ];
33
+
34
  return (
35
  <div className="max-w-2xl mx-auto">
36
+ <PageHeader icon={Target} title="Zero-Shot Lab" subtitle="BART-based classification for any unseen categories without fine-tuning." />
37
 
38
+ <form onSubmit={handleSubmit} className="glass-card p-6 sm:p-8 space-y-6">
39
  <div>
40
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Input Text</label>
41
  <textarea
42
  value={text}
43
  onChange={(e) => setText(e.target.value)}
 
47
  />
48
  </div>
49
  <div>
50
+ <label className="block text-sm font-semibold text-slate-300 mb-2.5">Candidate Labels</label>
51
  <input
52
  type="text"
53
  value={labels}
 
56
  className="quantum-input"
57
  required
58
  />
59
+ <p className="text-xs text-slate-500 mt-1.5">Separate labels with commas</p>
60
  </div>
61
  <SubmitButton loading={loading}>
62
  <Target size={18} /> Classify Text
 
67
 
68
  {result && (
69
  <ResultBox>
70
+ <SectionLabel>Classification Results</SectionLabel>
71
+
72
+ <div className="mb-5 p-5 rounded-2xl bg-gradient-to-br from-cyan-500/[0.08] to-purple-500/[0.04] border border-cyan-500/10 text-center">
73
+ <span className="text-xs text-slate-400 font-medium">Best Match</span>
74
+ <motion.p
75
+ initial={{ scale: 0.5 }}
76
+ animate={{ scale: 1 }}
77
+ transition={{ type: 'spring', stiffness: 200 }}
78
+ className="text-2xl font-black gradient-text mt-1"
79
+ >
80
+ {result.best_label}
81
+ </motion.p>
82
  <span className="text-sm text-slate-500">{result.best_score}% confidence</span>
83
  </div>
84
+
85
+ <div className="space-y-3">
86
  {result.results?.map((r, i) => (
87
+ <motion.div
88
+ key={i}
89
+ initial={{ opacity: 0, x: -20 }}
90
+ animate={{ opacity: 1, x: 0 }}
91
+ transition={{ delay: i * 0.1 }}
92
+ className="flex items-center gap-3"
93
+ >
94
+ <span className="text-sm text-slate-300 w-28 truncate capitalize font-medium">{r.label}</span>
95
+ <div className="flex-1 h-3 bg-white/[0.04] rounded-full overflow-hidden">
96
+ <motion.div
97
+ initial={{ width: 0 }}
98
+ animate={{ width: `${r.score}%` }}
99
+ transition={{ duration: 0.8, delay: 0.3 + i * 0.1 }}
100
+ className={`h-full bg-gradient-to-r ${barColors[i % barColors.length]} rounded-full`}
101
  />
102
  </div>
103
+ <span className="text-xs text-slate-400 w-14 text-right font-semibold">{r.score}%</span>
104
+ </motion.div>
105
  ))}
106
  </div>
107
  </ResultBox>