golem-flask-backend / src /components /DashboardPanels.tsx
mememechez's picture
Deploy final cleaned source code
ca28016
raw
history blame
42.4 kB
'use client';
import React, { useRef, useEffect, useState, useMemo } from 'react';
import { Card } from './ui/card';
import { Button } from './ui/button';
import { Input } from './ui/input';
import { Label } from './ui/label';
import { Slider } from './ui/slider';
import { Switch } from './ui/switch';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select';
import { ScrollArea } from './ui/scroll-area';
import { Badge } from './ui/badge';
import { Separator } from './ui/separator';
import { Tabs, TabsContent, TabsList, TabsTrigger } from './ui/tabs';
import NeonAnalyzerChart from './visualizations/NeonAnalyzerChart';
// Chart Panel Component
export const ChartPanel: React.FC<{
metrics?: { epoch: number; loss: number; accuracy: number; val_loss?: number; val_accuracy?: number }[];
jobStatus?: string;
isLoading: boolean;
freeze: () => void;
resume: () => void;
exportMetrics: () => void;
currentEpoch?: number;
totalEpochs?: number;
currentAccuracy?: number;
currentLoss?: number;
backendConnected?: boolean | null;
}> = ({
metrics = [],
jobStatus = 'idle',
isLoading,
freeze,
resume,
exportMetrics,
currentEpoch = 0,
totalEpochs = 0,
currentAccuracy = 0,
currentLoss = 0,
backendConnected = null,
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const [size, setSize] = useState({ width: 800, height: 600 });
useEffect(() => {
const handleResize = () => {
if (containerRef.current) {
const rect = containerRef.current.getBoundingClientRect();
setSize({
width: Math.max(300, rect.width - 40), // Minimum width with padding
height: Math.max(200, rect.height - 120) // Account for header and padding
});
}
};
handleResize();
const resizeObserver = new ResizeObserver(handleResize);
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
return () => {
resizeObserver.disconnect();
window.removeEventListener('resize', handleResize);
};
}, []);
// Format metrics for the chart
const traces = [
{
data: metrics.map(m => m.accuracy),
color: '#39ff14', // Neon green
label: 'Accuracy'
},
{
data: metrics.map(m => m.loss),
color: '#ff00ff', // Neon pink
label: 'Loss'
},
{
data: metrics.map(m => m.val_accuracy || 0),
color: '#00ffe7', // Neon cyan
label: 'Val Acc'
}
];
// Ensure traces have valid data
const validTraces = traces.filter(trace => trace.data.length > 0);
const hasValidData = validTraces.length > 0 && validTraces[0].data.length > 0;
// Status display text and colors
const statusText = typeof jobStatus === 'string' && jobStatus.length > 0 ? jobStatus.toUpperCase() : 'IDLE';
const isRunning = jobStatus === 'running';
const isCompleted = jobStatus === 'completed';
const isFailed = jobStatus === 'failed';
// Get status-specific styling
const getStatusStyling = () => {
if (backendConnected === false) {
return {
badgeClass: 'bg-[#ff6600]/10 text-[#ff6600] border-[#ff6600]/30',
headerClass: 'text-[#ff6600]',
text: 'OFFLINE'
};
} else if (backendConnected === null) {
return {
badgeClass: 'bg-[#ffff00]/10 text-[#ffff00] border-[#ffff00]/30',
headerClass: 'text-[#ffff00]',
text: 'CONNECTING'
};
} else if (isRunning) {
return {
badgeClass: 'bg-[#39ff14]/10 text-[#39ff14] border-[#39ff14]/30',
headerClass: 'text-[#39ff14]',
text: 'LIVE TRAINING'
};
} else if (isCompleted) {
return {
badgeClass: 'bg-[#00ffe7]/10 text-[#00ffe7] border-[#00ffe7]/30',
headerClass: 'text-[#00ffe7]',
text: 'COMPLETED'
};
} else if (isFailed) {
return {
badgeClass: 'bg-[#ff0080]/10 text-[#ff0080] border-[#ff0080]/30',
headerClass: 'text-[#ff0080]',
text: 'FAILED'
};
} else {
return {
badgeClass: 'bg-[#00ffe7]/10 text-[#00ffe7] border-[#00ffe7]/30',
headerClass: 'text-[#00ffe7]',
text: 'READY'
};
}
};
const statusStyling = getStatusStyling();
return (
<div ref={containerRef} className="flex flex-col h-full w-full min-h-[700px] bg-[#0a0f1c] rounded-lg border border-[#00ffe7]/30 shadow-lg shadow-[#00ffe7]/20 max-w-full overflow-hidden">
{/* Header */}
<div className="flex items-center justify-between p-2 border-b border-[#00ffe7]/20 flex-shrink-0">
<div className="flex items-center space-x-4 min-w-0 flex-1">
<h2 className="text-xl font-bold font-mono text-[#ffff00] truncate">SPECTRUM ANALYZER</h2>
<Badge variant="outline" className={`text-xs font-semibold ${statusStyling.badgeClass}`}>
{statusStyling.text}
</Badge>
{backendConnected && currentEpoch > 0 && (
<div className="text-xs font-mono text-[#00ffe7]/80 hidden sm:block">
EPOCH: {currentEpoch}/{totalEpochs} | ACC: {(currentAccuracy || 0).toFixed(1)}% | LOSS: {(currentLoss || 0).toFixed(4)}
</div>
)}
</div>
<div className="flex items-center space-x-2 flex-shrink-0">
<Button variant="outline" className="neon-button border-[#00ffe7]/50 text-[#00ffe7] bg-black/40 hover:bg-[#00ffe7]/10 hover:shadow-[0_0_16px_#00ffe7] transition-all duration-300 font-mono text-xs tracking-wide h-9 px-3">
FREEZE
</Button>
<Button variant="outline" className="neon-button border-[#00ffe7]/50 text-[#00ffe7] bg-black/40 hover:bg-[#00ffe7]/10 hover:shadow-[0_0_16px_#00ffe7] transition-all duration-300 font-mono text-xs tracking-wide h-9 px-3" disabled={!hasValidData}>
EXPORT
</Button>
</div>
</div>
{/* Chart Content */}
<div className="flex-1 p-4 overflow-hidden">
{backendConnected === false ? (
<div className="flex items-center justify-center h-full">
<div className="text-center">
<div className="w-16 h-16 mx-auto mb-4 border-2 border-[#ff6600]/30 rounded-full flex items-center justify-center animate-pulse">
<span className="text-[#ff6600] text-2xl">⚠️</span>
</div>
<p className="text-[#ff6600] font-mono text-sm">Backend Offline</p>
</div>
</div>
) : backendConnected === null ? (
<div className="flex items-center justify-center h-full">
<div className="text-center">
<div className="w-16 h-16 mx-auto mb-4 border-2 border-[#ffff00]/30 rounded-full flex items-center justify-center animate-pulse">
<span className="text-[#ffff00] text-2xl">🔄</span>
</div>
<p className="text-[#ffff00] font-mono text-sm">Connecting to training backend...</p>
</div>
</div>
) : hasValidData ? (
<NeonAnalyzerChart
width={size.width}
height={size.height}
traces={validTraces}
backgroundColor="rgba(10, 15, 28, 0.95)"
gridColor="rgba(0, 255, 231, 0.2)"
overlays={[
{ text: 'Training Metrics', color: '#39ff14', x: 120, y: 40, fontSize: 24 }
]}
/>
) : (
<div className="flex items-center justify-center h-full">
<div className="text-center">
<div className="w-16 h-16 mx-auto mb-4 border-2 border-[#00ffe7]/30 rounded-full flex items-center justify-center">
<span className="text-[#00ffe7] text-2xl">📊</span>
</div>
<p className="text-[#00ffe7] font-mono text-sm">No training data available</p>
</div>
</div>
)}
</div>
</div>
);
};
// Terminal Panel Component
export const TerminalPanel: React.FC<{
logs: Array<{ time: string; level: string; message: string }> | string[];
isPolling?: boolean;
clearLogs: () => void;
exportLogs: () => void;
stopJob: () => void;
}> = ({ logs, isPolling = false, clearLogs, exportLogs, stopJob }) => {
const visibleLogs = useMemo(() => logs.slice(-50), [logs]);
const renderLogLine = (log, index) => {
if (typeof log === 'string') {
return (
<div key={index} className="font-mono text-xs text-[#39ff14] leading-relaxed break-words whitespace-pre-wrap">
{log}
</div>
);
}
return (
<div key={index} className="font-mono text-xs leading-relaxed break-words">
<span className="text-[#39ff14]/70">{log.timestamp}</span>
<span className="text-[#39ff14]/50 mx-2">[{log.level}]</span>
<span className="text-[#39ff14]">{log.message}</span>
</div>
);
};
return (
<Card className="neon-card glass terminal-panel h-full w-full bg-black/98 border-[#39ff14]/20 shadow-[0_0_16px_#39ff1444,inset_0_0_16px_rgba(0,0,0,0.8)] backdrop-blur-sm overflow-hidden max-w-full flex flex-col" style={{ fontFamily: 'Share Tech Mono, Space Mono, VT323, monospace', borderRadius: '12px' }}>
<div className="terminal-header p-3 border-b border-[#39ff14]/30 flex-shrink-0">
<div className="flex items-center justify-between min-w-0">
<div className="flex items-center space-x-3 min-w-0 flex-1">
<div className="w-2 h-2 rounded-full shadow-[0_0_12px_#39ff14] bg-[#39ff14]/50 flex-shrink-0"></div>
<h3 className="text-[#39ff14] font-mono text-sm font-medium tracking-wide text-shadow-neon truncate">NEURAL LOG</h3>
<Badge variant="outline" className="border-[#39ff14]/50 bg-[#39ff14]/10 text-xs shadow-[0_0_8px_#39ff14] text-[#39ff14]/70 flex-shrink-0">
{isPolling ? 'ACTIVE' : 'STANDBY'}
</Badge>
</div>
<div className="flex items-center space-x-2 flex-shrink-0">
<span className="text-[#39ff14]/70 font-mono text-xs">LINES: {visibleLogs.length}</span>
<Button
size="sm"
variant="outline"
className="border-[#39ff14]/30 text-[#39ff14] text-xs hover:bg-[#39ff14]/10 hover:shadow-[0_0_8px_#39ff14] h-5 px-2"
onClick={clearLogs}
>
CLEAR
</Button>
<Button
size="sm"
variant="outline"
className="border-[#39ff14]/30 text-[#39ff14] text-xs hover:bg-[#39ff14]/10 hover:shadow-[0_0_8px_#39ff14] h-5 px-2"
onClick={exportLogs}
>
EXPORT
</Button>
<Button
size="sm"
variant="outline"
className="border-[#ff0080]/30 text-[#ff0080] text-xs hover:bg-[#ff0080]/10 hover:shadow-[0_0_8px_#ff0080] h-5 px-2"
onClick={stopJob}
>
STOP
</Button>
</div>
</div>
</div>
<div className="flex-1 min-h-0 overflow-hidden">
<ScrollArea className="h-full pr-2">
<div className="p-3 space-y-1 max-w-full">
{visibleLogs.length === 0 ? (
<div className="flex items-center justify-center h-32">
<div className="text-center">
<div className="w-12 h-12 mx-auto mb-3 border border-[#39ff14]/30 rounded-full flex items-center justify-center">
<span className="text-[#39ff14] text-xl">📟</span>
</div>
<p className="font-mono text-xs text-[#39ff14]/70">No logs available</p>
<p className="font-mono text-xs text-[#39ff14]/50 mt-1">Start training to see real-time output</p>
</div>
</div>
) : (
visibleLogs.map((log, index) => renderLogLine(log, index))
)}
</div>
</ScrollArea>
</div>
</Card>
);
};
// Controls Panel Component
export const ControlsPanel: React.FC<{
onTrainingStart?: (jobId: string) => void;
isTraining?: boolean;
currentJobId?: string | null;
jobStatus?: import('@/lib/training-api').JobStatus | null;
backendConnected?: boolean | null;
}> = ({ onTrainingStart, isTraining = false, currentJobId, jobStatus, backendConnected = null }) => {
// Form state for training parameters
const [formData, setFormData] = React.useState({
modelName: 'ZPE_Quantum_Neural_Net',
totalEpochs: 60,
batchSize: 32,
learningRate: 0.001,
weightDecay: 0.0001,
baseConfigId: '',
sequenceLength: 32,
labelSmoothing: 0.1,
mixupAlpha: 1.0,
// ZPE Parameters
momentumParams: [0.9, 0.85, 0.8, 0.75, 0.7, 0.65],
strengthParams: [0.35, 0.3, 0.25, 0.2, 0.15, 0.1],
noiseParams: [0.3, 0.25, 0.2, 0.15, 0.1, 0.05],
couplingParams: [0.85, 0.8, 0.75, 0.7, 0.65, 0.6],
});
const [isSubmitting, setIsSubmitting] = React.useState(false);
// Import the API
const { trainingAPI } = React.useMemo(() => {
// We'll import this dynamically to avoid SSR issues
return require('@/lib/training-api');
}, []);
// Handle form field updates
const updateField = (field: string, value: any) => {
setFormData(prev => ({ ...prev, [field]: value }));
};
// Handle ZPE parameter updates
const updateZPEParam = (paramType: 'momentumParams' | 'strengthParams' | 'noiseParams' | 'couplingParams', index: number, value: number) => {
setFormData(prev => ({
...prev,
[paramType]: prev[paramType].map((v, i) => i === index ? value : v)
}));
};
// Handle training submission
const handleStartTraining = async () => {
if (isSubmitting || isTraining || !backendConnected) return;
try {
setIsSubmitting(true);
console.log('🚀 Submitting training request with params:', formData);
// Prepare parameters for backend API
const trainingParams = {
model_name: formData.modelName,
total_epochs: formData.totalEpochs,
batch_size: formData.batchSize,
learning_rate: formData.learningRate,
sequence_length: formData.sequenceLength,
label_smoothing: formData.labelSmoothing,
mixup_alpha: formData.mixupAlpha,
base_config_id: formData.baseConfigId || undefined,
weightDecay: formData.weightDecay,
momentumParams: formData.momentumParams,
strengthParams: formData.strengthParams,
noiseParams: formData.noiseParams,
couplingParams: formData.couplingParams,
};
// Call the backend API
const response = await trainingAPI.startTraining(trainingParams);
if (response.status === 'training_started' && response.job_id) {
console.log('✅ Training started successfully:', response.job_id);
onTrainingStart?.(response.job_id);
} else {
throw new Error('Unexpected response from training API');
}
} catch (error) {
console.error('❌ Training start failed:', error);
alert(`Training failed to start: ${error instanceof Error ? error.message : 'Unknown error'}`);
} finally {
setIsSubmitting(false);
}
};
return (
<Card className="neon-card glass controls-panel h-full w-full bg-black/98 border-[#00ffe7]/30 backdrop-blur-sm flex flex-col overflow-hidden" style={{ borderRadius: '12px', minWidth: '0' }}>
<div className="controls-header p-3 border-b border-[#00ffe7]/30 flex-shrink-0">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3 min-w-0 flex-1">
<div className="w-3 h-3 bg-[#00ffe7] rounded-full animate-pulse shadow-[0_0_12px_#00ffe7] flex-shrink-0"></div>
<h3 className="text-[#00ffe7] font-mono text-sm font-medium tracking-wide text-shadow-neon truncate">NEURAL CONTROLS</h3>
<Badge variant="outline" className={`border-[#00ffe7]/50 bg-[#00ffe7]/10 text-xs shadow-[0_0_8px_#00ffe7] flex-shrink-0 ${
backendConnected === false ? 'text-[#ff6600] border-[#ff6600]/50 bg-[#ff6600]/10' :
isTraining ? 'text-[#39ff14] border-[#39ff14]/50 bg-[#39ff14]/10' : 'text-[#00ffe7]'
}`}>
{backendConnected === false ? 'OFFLINE' : isTraining ? 'TRAINING' : 'READY'}
</Badge>
</div>
</div>
</div>
{/* Backend Offline Banner */}
{backendConnected === false && (
<div className="bg-[#ff6600]/10 border-y border-[#ff6600]/30 p-3 flex-shrink-0">
<div className="flex items-center gap-2 min-w-0">
<span className="text-[#ff6600] text-sm flex-shrink-0">⚠️</span>
<div className="min-w-0 flex-1">
<p className="text-[#ff6600] font-mono text-xs font-semibold truncate">Training Backend Offline</p>
<p className="text-[#ff6600]/70 font-mono text-xs truncate">Connect to backend server to enable training</p>
</div>
</div>
</div>
)}
<Tabs defaultValue="neural" className="flex-1 flex flex-col min-h-0 overflow-hidden">
<TabsList className="grid w-full grid-cols-4 bg-black/60 border-[#00ffe7]/30 mx-3 mt-3 flex-shrink-0">
<TabsTrigger value="neural" className="text-xs text-[#00ffe7] data-[state=active]:bg-[#00ffe7]/20 truncate">Neural</TabsTrigger>
<TabsTrigger value="hyper" className="text-xs text-[#00ffe7] data-[state=active]:bg-[#00ffe7]/20 truncate">Hyper</TabsTrigger>
<TabsTrigger value="model" className="text-xs text-[#00ffe7] data-[state=active]:bg-[#00ffe7]/20 truncate">Model</TabsTrigger>
<TabsTrigger value="config" className="text-xs text-[#00ffe7] data-[state=active]:bg-[#00ffe7]/20 truncate">Config</TabsTrigger>
</TabsList>
<TabsContent value="neural" className="flex-1 min-h-0 overflow-hidden">
<ScrollArea className="h-full w-full pr-2">
<div className="p-3 space-y-4">
<h4 className="text-[#00ffe7] font-mono text-sm font-medium mb-2 tracking-wide text-shadow-neon">NEURAL TRAINING</h4>
<div className="space-y-3">
<div className="flex items-center justify-between">
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">AUTO TRAIN</Label>
<Switch className="data-[state=checked]:bg-[#39ff14] data-[state=checked]:shadow-[0_0_8px_#39ff14]" disabled={!backendConnected} />
</div>
<div className="flex items-center justify-between">
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">EARLY STOPPING</Label>
<Switch className="data-[state=checked]:bg-[#39ff14] data-[state=checked]:shadow-[0_0_8px_#39ff14]" disabled={!backendConnected} />
</div>
<div className="flex items-center justify-between">
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">GRADIENT CLIPPING</Label>
<Switch className="data-[state=checked]:bg-[#39ff14] data-[state=checked]:shadow-[0_0_8px_#39ff14]" disabled={!backendConnected} />
</div>
</div>
{/* Real-time Training Stats */}
{isTraining && jobStatus && backendConnected && (
<div className="mt-4 p-3 border border-[#39ff14]/30 rounded-lg bg-[#39ff14]/5">
<h5 className="text-[#39ff14] font-mono text-xs tracking-wide mb-2">TRAINING STATUS</h5>
<div className="space-y-1 text-xs font-mono">
<div className="flex justify-between">
<span className="text-[#00ffe7]/70">Epoch:</span>
<span className="text-[#39ff14]">{jobStatus.current_epoch}/{jobStatus.total_epochs}</span>
</div>
<div className="flex justify-between">
<span className="text-[#00ffe7]/70">Accuracy:</span>
<span className="text-[#39ff14]">{(jobStatus.accuracy || 0).toFixed(2)}%</span>
</div>
<div className="flex justify-between">
<span className="text-[#00ffe7]/70">Loss:</span>
<span className="text-[#39ff14]">{(jobStatus.loss || 0).toFixed(4)}</span>
</div>
</div>
</div>
)}
</div>
</ScrollArea>
</TabsContent>
<TabsContent value="hyper" className="flex-1 min-h-0 overflow-hidden">
<ScrollArea className="h-full w-full pr-2">
<div className="p-3 space-y-4">
<h4 className="text-[#00ffe7] font-mono text-sm font-medium mb-2 tracking-wide text-shadow-neon">HYPERPARAMETERS</h4>
<div className="space-y-3">
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">LEARNING RATE</Label>
<div className="flex items-center space-x-2 mt-1">
<Slider
value={[formData.learningRate * 1000]}
max={10}
min={0.1}
step={0.1}
className="flex-1"
onValueChange={(value) => updateField('learningRate', value[0] / 1000)}
disabled={!backendConnected}
/>
<Input
className="neon-border glass focus:border-[var(--neon-cyan)] focus:shadow-[0_0_16px_var(--neon-cyan)] w-16 h-6 bg-black border-[#39ff14]/30 text-[#39ff14] text-xs text-center"
value={formData.learningRate}
onChange={(e) => updateField('learningRate', parseFloat(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
</div>
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">BATCH SIZE</Label>
<Select value={formData.batchSize.toString()} onValueChange={(value) => updateField('batchSize', parseInt(value))} disabled={!backendConnected}>
<SelectTrigger className="neon-border glass w-full h-8 bg-black border-[#39ff14]/30 text-[#39ff14] text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-black border-[#39ff14]/30">
<SelectItem value="16">16</SelectItem>
<SelectItem value="32">32</SelectItem>
<SelectItem value="64">64</SelectItem>
<SelectItem value="128">128</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">EPOCHS</Label>
<Input
className="neon-border glass focus:border-[#00ffe7] focus:shadow-[0_0_16px_#00ffe7] w-full h-8 bg-black border-[#39ff14]/30 text-[#39ff14] text-xs"
value={formData.totalEpochs}
onChange={(e) => updateField('totalEpochs', parseInt(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">WEIGHT DECAY</Label>
<Input
className="neon-border glass focus:border-[#00ffe7] focus:shadow-[0_0_16px_#00ffe7] w-full h-8 bg-black border-[#39ff14]/30 text-[#39ff14] text-xs"
value={formData.weightDecay}
onChange={(e) => updateField('weightDecay', parseFloat(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
</div>
</div>
</ScrollArea>
</TabsContent>
<TabsContent value="model" className="flex-1 min-h-0 overflow-hidden">
<ScrollArea className="h-full w-full pr-2">
<div className="p-3 space-y-4">
<h4 className="text-[#00ffe7] font-mono text-sm font-medium mb-2 tracking-wide text-shadow-neon">MODEL CONFIG</h4>
<div className="space-y-3">
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">MODEL TYPE</Label>
<Select defaultValue="zpe" disabled={!backendConnected}>
<SelectTrigger className="neon-border glass w-full h-8 bg-black border-[#39ff14]/30 text-[#39ff14] text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-black border-[#39ff14]/30">
<SelectItem value="zpe">ZPE DeepNet</SelectItem>
<SelectItem value="quantum">Quantum Enhanced</SelectItem>
<SelectItem value="classical">Classical CNN</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">OPTIMIZER</Label>
<Select defaultValue="adam" disabled={!backendConnected}>
<SelectTrigger className="neon-border glass w-full h-8 bg-black border-[#39ff14]/30 text-[#39ff14] text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-black border-[#39ff14]/30">
<SelectItem value="adam">Adam</SelectItem>
<SelectItem value="sgd">SGD</SelectItem>
<SelectItem value="adamw">AdamW</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">LOSS FUNCTION</Label>
<Select defaultValue="crossentropy" disabled={!backendConnected}>
<SelectTrigger className="neon-border glass w-full h-8 bg-black border-[#39ff14]/30 text-[#39ff14] text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-black border-[#39ff14]/30">
<SelectItem value="crossentropy">Cross Entropy</SelectItem>
<SelectItem value="mse">Mean Squared Error</SelectItem>
<SelectItem value="huber">Huber Loss</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</div>
</ScrollArea>
</TabsContent>
<TabsContent value="config" className="flex-1 min-h-0 max-w-full overflow-hidden">
<Tabs defaultValue="general" className="flex-1 flex flex-col min-h-0 max-w-full">
<TabsList className="grid w-full grid-cols-3 bg-black/60 border-[#00ffe7]/30 mx-1 mt-2 flex-shrink-0 max-w-full">
<TabsTrigger value="general" className="text-xs text-[#00ffe7] data-[state=active]:bg-[#00ffe7]/20 truncate px-1">General</TabsTrigger>
<TabsTrigger value="zpe" className="text-xs text-[#00ffe7] data-[state=active]:bg-[#00ffe7]/20 truncate px-1">ZPE</TabsTrigger>
<TabsTrigger value="quantum" className="text-xs text-[#00ffe7] data-[state=active]:bg-[#00ffe7]/20 truncate px-1">Quantum</TabsTrigger>
</TabsList>
<div className="flex-1 min-h-0 overflow-hidden">
<TabsContent value="general" className="h-full m-0">
<div className="h-full overflow-y-scroll" style={{
maxHeight: '500px',
paddingRight: '12px',
scrollbarWidth: 'thick',
scrollbarColor: '#00ffe7 #0a0f1c'
}}>
<div className="p-4 space-y-4 flex flex-col items-center pb-20">
<div className="w-full max-w-md">
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">MODEL NAME</Label>
<Input
className="neon-border glass focus:border-[#00ffe7] focus:shadow-[0_0_16px_#00ffe7] w-full h-8 bg-black/40 border-[#00ffe7]/30 text-[#00ffe7] text-xs mt-1 font-mono"
value={formData.modelName}
onChange={(e) => updateField('modelName', e.target.value)}
disabled={!backendConnected}
/>
</div>
<div className="w-full max-w-md grid grid-cols-2 gap-2">
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">TOTAL EPOCHS</Label>
<Input
className="neon-border glass focus:border-[#00ffe7] focus:shadow-[0_0_16px_#00ffe7] w-full h-8 bg-black/40 border-[#00ffe7]/30 text-[#00ffe7] text-xs mt-1 font-mono text-center"
value={formData.totalEpochs}
onChange={(e) => updateField('totalEpochs', parseInt(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">BATCH SIZE</Label>
<Input
className="neon-border glass focus:border-[#00ffe7] focus:shadow-[0_0_16px_#00ffe7] w-full h-8 bg-black/40 border-[#00ffe7]/30 text-[#00ffe7] text-xs mt-1 font-mono text-center"
value={formData.batchSize}
onChange={(e) => updateField('batchSize', parseInt(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
</div>
<div className="w-full max-w-md grid grid-cols-2 gap-2">
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">LEARNING RATE</Label>
<Input
className="neon-border glass focus:border-[#00ffe7] focus:shadow-[0_0_16px_#00ffe7] w-full h-8 bg-black/40 border-[#00ffe7]/30 text-[#00ffe7] text-xs mt-1 font-mono text-center"
value={formData.learningRate}
onChange={(e) => updateField('learningRate', parseFloat(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
<div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">WEIGHT DECAY</Label>
<Input
className="neon-border glass focus:border-[#00ffe7] focus:shadow-[0_0_16px_#00ffe7] w-full h-8 bg-black/40 border-[#00ffe7]/30 text-[#00ffe7] text-xs mt-1 font-mono text-center"
value={formData.weightDecay}
onChange={(e) => updateField('weightDecay', parseFloat(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
</div>
<div className="w-full max-w-md">
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">BASE CONFIG ID (OPTIONAL)</Label>
<Input
className="neon-border glass focus:border-[#00ffe7] focus:shadow-[0_0_16px_#00ffe7] w-full h-8 bg-black/40 border-[#00ffe7]/30 text-[#00ffe7]/60 text-xs mt-1 font-mono"
value={formData.baseConfigId}
onChange={(e) => updateField('baseConfigId', e.target.value)}
placeholder="e.g., config_123456"
disabled={!backendConnected}
/>
</div>
<div className="w-full max-w-md flex flex-col gap-2 pt-3 pb-12">
<Button
className={`neon-button transition-all duration-300 text-xs h-8 font-mono tracking-wide w-full ${
backendConnected ?
'bg-[#39ff14]/20 border-[#39ff14]/50 text-[#39ff14] hover:bg-[#39ff14]/30 hover:shadow-[0_0_16px_#39ff14]' :
'bg-[#666]/20 border-[#666]/50 text-[#666] cursor-not-allowed'
}`}
onClick={handleStartTraining}
disabled={isSubmitting || isTraining || !backendConnected}
>
{!backendConnected ? 'BACKEND OFFLINE' :
isSubmitting ? 'STARTING...' :
isTraining ? 'TRAINING IN PROGRESS' :
'START NEW TRAINING SESSION'}
</Button>
<Button
variant="outline"
className={`neon-button transition-all duration-300 text-xs h-8 font-mono tracking-wide w-full ${
backendConnected ?
'border-[#00ffe7]/50 text-[#00ffe7] bg-black/40 hover:bg-[#00ffe7]/10 hover:shadow-[0_0_16px_#00ffe7]' :
'border-[#666]/50 text-[#666] bg-black/40 cursor-not-allowed'
}`}
disabled={!formData.baseConfigId || !backendConnected}
>
CONTINUE FROM CHECKPOINT (.PTH)
</Button>
</div>
</div>
</div>
</TabsContent>
<TabsContent value="zpe" className="h-full m-0">
<div className="h-full overflow-y-scroll" style={{
maxHeight: '500px',
paddingRight: '12px',
scrollbarWidth: 'thick',
scrollbarColor: '#00ffe7 #0a0f1c'
}}>
<div className="p-4 space-y-6 flex flex-col items-center pb-20">
<h4 className="text-[#00ffe7] font-mono text-sm font-medium tracking-wide text-shadow-neon text-center">ZPE CONFIGURATION</h4>
<div className="w-full max-w-md space-y-4">
<div className="flex items-center justify-center gap-2 mb-2">
<div className="w-2 h-2 bg-[#39ff14] rounded-full animate-pulse shadow-[0_0_8px_#39ff14] flex-shrink-0"></div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">MOMENTUM (6 LAYERS)</Label>
</div>
<div className="grid grid-cols-3 gap-2 w-full">
{formData.momentumParams.map((value, index) => (
<div key={index} className="min-w-0">
<Label className="text-[#00ffe7] font-mono text-xs block mb-1 text-center">L{index + 1}</Label>
<Input
className="neon-border glass focus:border-[#39ff14] focus:shadow-[0_0_8px_#39ff14] w-full h-8 bg-black/40 border-[#39ff14]/30 text-[#39ff14] text-xs font-mono text-center"
value={value}
onChange={(e) => updateZPEParam('momentumParams', index, parseFloat(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
))}
</div>
</div>
<div className="w-full max-w-md space-y-4">
<div className="flex items-center justify-center gap-2 mb-2">
<div className="w-2 h-2 bg-[#ff00ff] rounded-full animate-pulse shadow-[0_0_8px_#ff00ff] flex-shrink-0"></div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">STRENGTH (6 LAYERS)</Label>
</div>
<div className="grid grid-cols-3 gap-2 w-full">
{formData.strengthParams.map((value, index) => (
<div key={index} className="min-w-0">
<Label className="text-[#00ffe7] font-mono text-xs block mb-1 text-center">L{index + 1}</Label>
<Input
className="neon-border glass focus:border-[#ff00ff] focus:shadow-[0_0_8px_#ff00ff] w-full h-8 bg-black/40 border-[#ff00ff]/30 text-[#ff00ff] text-xs font-mono text-center"
value={value}
onChange={(e) => updateZPEParam('strengthParams', index, parseFloat(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
))}
</div>
</div>
<div className="w-full max-w-md space-y-4">
<div className="flex items-center justify-center gap-2 mb-2">
<div className="w-2 h-2 bg-[#ffa500] rounded-full animate-pulse shadow-[0_0_8px_#ffa500] flex-shrink-0"></div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">NOISE PARAMETERS</Label>
</div>
<div className="grid grid-cols-3 gap-2 w-full">
{formData.noiseParams.map((value, index) => (
<div key={index} className="min-w-0">
<Label className="text-[#00ffe7] font-mono text-xs block mb-1 text-center">N{index + 1}</Label>
<Input
className="neon-border glass focus:border-[#ffa500] focus:shadow-[0_0_8px_#ffa500] w-full h-8 bg-black/40 border-[#ffa500]/30 text-[#ffa500] text-xs font-mono text-center"
value={value}
onChange={(e) => updateZPEParam('noiseParams', index, parseFloat(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
))}
</div>
</div>
<div className="w-full max-w-md space-y-4 pb-12">
<div className="flex items-center justify-center gap-2 mb-2">
<div className="w-2 h-2 bg-[#00ffff] rounded-full animate-pulse shadow-[0_0_8px_#00ffff] flex-shrink-0"></div>
<Label className="text-[#39ff14] font-mono text-xs tracking-wide">COUPLING STRENGTH</Label>
</div>
<div className="grid grid-cols-3 gap-2 w-full">
{formData.couplingParams.map((value, index) => (
<div key={index} className="min-w-0">
<Label className="text-[#00ffe7] font-mono text-xs block mb-1 text-center">C{index + 1}</Label>
<Input
className="neon-border glass focus:border-[#00ffff] focus:shadow-[0_0_8px_#00ffff] w-full h-8 bg-black/40 border-[#00ffff]/30 text-[#00ffff] text-xs font-mono text-center"
value={value}
onChange={(e) => updateZPEParam('couplingParams', index, parseFloat(e.target.value) || 0)}
disabled={!backendConnected}
/>
</div>
))}
</div>
</div>
</div>
</div>
</TabsContent>
<TabsContent value="quantum" className="h-full m-0">
<div className="h-full overflow-y-scroll" style={{
maxHeight: '500px',
paddingRight: '12px',
scrollbarWidth: 'thick',
scrollbarColor: '#00ffe7 #0a0f1c'
}}>
<div className="p-4 space-y-4 flex flex-col items-center pb-20">
<h4 className="text-[#00ffe7] font-mono text-sm font-medium tracking-wide text-shadow-neon text-center">QUANTUM CONFIGURATION</h4>
<div className="flex items-center justify-center h-32">
<div className="text-center">
<div className="w-12 h-12 mx-auto mb-3 border border-[#00ffe7]/30 rounded-full flex items-center justify-center">
<span className="text-[#00ffe7] text-xl">⚛️</span>
</div>
<p className="text-[#00ffe7]/70 font-mono text-xs">Quantum parameters coming soon...</p>
</div>
</div>
</div>
</div>
</TabsContent>
</div>
</Tabs>
</TabsContent>
</Tabs>
</Card>
);
};
// Job History Panel Component
export const JobHistoryPanel: React.FC = () => {
return (
<Card className="neon-card glass h-full w-full bg-black/98 border-[#00ffe7]/30 backdrop-blur-sm flex flex-col" style={{ borderRadius: '12px' }}>
<div className="p-3 border-b border-[#00ffe7]/30 flex-shrink-0">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="w-2 h-2 bg-[#3b82f6] rounded-full"></div>
<h3 className="text-[#9ca3af] font-mono text-sm font-medium tracking-wide">Job History</h3>
</div>
</div>
<div className="text-xs text-[#6b7280] mt-1">View previous, past and ongoing training jobs.</div>
</div>
<ScrollArea className="flex-1 min-h-0">
<div className="p-3">
<div className="text-center text-[#9ca3af] text-xs py-8">
No training jobs found.
</div>
</div>
</ScrollArea>
</Card>
);
};