forge-arena / ui /src /pages /ForgeQueue.jsx
Amogh-kal1's picture
Upload folder using huggingface_hub
db75f77 verified
import { useCallback } from 'react'
import {
BarChart, Bar, XAxis, YAxis, Tooltip, CartesianGrid,
ResponsiveContainer, Cell, PieChart, Pie, Legend,
} from 'recharts'
import { RefreshCw, Zap, Database, TrendingUp, Clock } from 'lucide-react'
import Card from '../components/ui/Card'
import Button from '../components/ui/Button'
import Spinner from '../components/ui/Spinner'
import { usePolling } from '../hooks/usePolling'
import { getForgeQueue, getForgeStats } from '../api/client'
const NEON = '#00d4ff'
const GREEN = '#00ff88'
const RED = '#ff3366'
const ORANGE = '#ff9900'
function CustomTooltip({ active, payload, label }) {
if (!active || !payload?.length) return null
return (
<div className="custom-tooltip">
<p className="text-muted mb-1">{label}</p>
{payload.map(p => (
<p key={p.name} style={{ color: p.color }}>{p.name}: <b>{p.value}</b></p>
))}
</div>
)
}
const QUEUE_ZONES = [
{ key: 'learnable_count', label: 'Learnable', color: GREEN, desc: '0.20 ≤ pass@k ≤ 0.85' },
{ key: 'too_easy_count', label: 'Too Easy', color: NEON, desc: 'pass@k > 0.85' },
{ key: 'too_hard_count', label: 'Too Hard', color: RED, desc: 'pass@k < 0.20' },
{ key: 'pending_estimation_count', label: 'Pending Estimation', color: ORANGE, desc: 'awaiting pass@k estimate' },
]
export default function ForgeQueue() {
const qFetcher = useCallback(() => getForgeQueue(), [])
const sFetcher = useCallback(() => getForgeStats(), [])
const { data: queue, loading: qLoad, refresh: qRefresh } = usePolling(qFetcher, 4000)
const { data: stats, loading: sLoad } = usePolling(sFetcher, 4000)
const barData = QUEUE_ZONES.map(z => ({
name: z.label,
count: queue?.[z.key] ?? 0,
color: z.color,
}))
const pieData = QUEUE_ZONES
.map(z => ({ name: z.label, value: queue?.[z.key] ?? 0, color: z.color }))
.filter(d => d.value > 0)
const totalTasks = (queue?.seed_task_count ?? 0) + (queue?.generated_task_count ?? 0)
return (
<div className="p-6 space-y-5 animate-fade-in">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg font-semibold text-primary">Forge Queue</h2>
<p className="text-xs text-muted font-mono mt-0.5">Curriculum scheduler - adaptive task difficulty management</p>
</div>
<Button onClick={qRefresh} variant="secondary" size="sm">
<RefreshCw size={13} /> refresh
</Button>
</div>
{/* Zone cards */}
<div className="grid grid-cols-4 gap-4">
{QUEUE_ZONES.map(z => (
<Card key={z.key} className="p-4" glow>
<div className="flex items-center justify-between mb-2">
<span className="text-xs font-mono text-muted">{z.label}</span>
{queue?.replenishment_triggered && z.key === 'learnable_count' && (
<span className="text-xs font-mono text-orange-neon flex items-center gap-1"><Zap size={10}/> replenishing</span>
)}
</div>
<div className="text-3xl font-mono font-bold" style={{ color: z.color }}>
{queue ? queue[z.key] ?? 0 : <Spinner size="sm" />}
</div>
<div className="text-xs text-muted mt-1">{z.desc}</div>
</Card>
))}
</div>
{/* Source cards */}
<div className="grid grid-cols-4 gap-4">
{[
{ icon: Database, label: 'Seed Tasks', key: 'seed_task_count', color: NEON },
{ icon: Zap, label: 'Generated Tasks', key: 'generated_task_count', color: GREEN },
{ icon: TrendingUp, label: 'Acceptance Rate', key: null, color: ORANGE },
{ icon: Clock, label: 'Total Episodes', key: null, color: '#7080aa' },
].map(({ icon: Icon, label, key, color }) => {
let value
if (key) value = queue?.[key] ?? (qLoad ? null : 0)
else if (label === 'Acceptance Rate') value = stats?.generator_acceptance_rate != null ? `${(stats.generator_acceptance_rate * 100).toFixed(1)}%` : (sLoad ? null : 'n/a')
else value = stats?.total_episodes ?? (sLoad ? null : 0)
return (
<Card key={label} className="p-4">
<div className="flex items-center gap-2 mb-2">
<Icon size={13} style={{ color }} />
<span className="text-xs text-muted">{label}</span>
</div>
<div className="text-2xl font-mono font-bold" style={{ color }}>
{value ?? <Spinner size="sm" />}
</div>
</Card>
)
})}
</div>
<div className="grid grid-cols-2 gap-5">
{/* Bar chart */}
<Card className="p-5" glow>
<h3 className="text-sm font-semibold text-secondary mb-4">Queue Counts by Zone</h3>
{barData.some(d => d.count > 0) ? (
<ResponsiveContainer width="100%" height={220}>
<BarChart data={barData} margin={{ left: -20 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#1c1c3a" />
<XAxis dataKey="name" tick={{ fill: '#7080aa', fontSize: 10, fontFamily: 'JetBrains Mono' }} />
<YAxis tick={{ fill: '#7080aa', fontSize: 10, fontFamily: 'JetBrains Mono' }} />
<Tooltip content={<CustomTooltip />} />
<Bar dataKey="count" radius={[3, 3, 0, 0]}>
{barData.map((d, i) => (
<Cell key={i} fill={d.color} style={{ filter: `drop-shadow(0 0 6px ${d.color}60)` }} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
) : (
<div className="flex items-center justify-center h-52 text-muted text-sm">
{qLoad ? <Spinner /> : 'no data'}
</div>
)}
</Card>
{/* Pie */}
<Card className="p-5" glow>
<h3 className="text-sm font-semibold text-secondary mb-4">Zone Distribution</h3>
{pieData.length > 0 ? (
<>
<ResponsiveContainer width="100%" height={180}>
<PieChart>
<Pie data={pieData} cx="50%" cy="50%" innerRadius={48} outerRadius={72} dataKey="value" paddingAngle={4}>
{pieData.map((d, i) => (
<Cell key={i} fill={d.color} style={{ filter: `drop-shadow(0 0 8px ${d.color}60)` }} />
))}
</Pie>
<Tooltip content={<CustomTooltip />} />
</PieChart>
</ResponsiveContainer>
<div className="flex flex-wrap justify-center gap-3 mt-2">
{pieData.map(d => (
<span key={d.name} className="flex items-center gap-1 text-xs font-mono text-secondary">
<span className="w-2 h-2 rounded-full" style={{ background: d.color }} />
{d.name}: {d.value}
</span>
))}
</div>
</>
) : (
<div className="flex items-center justify-center h-52 text-muted text-sm">
{qLoad ? <Spinner /> : 'no data'}
</div>
)}
</Card>
</div>
{/* Learnable threshold reference */}
<Card className="p-4">
<h3 className="text-xs font-mono text-muted uppercase tracking-widest mb-3">Difficulty Thresholds</h3>
<div className="relative h-6 bg-base rounded-full overflow-hidden border border-border">
<div className="absolute inset-y-0 left-0 w-[20%] bg-red-neon/20 flex items-center justify-center">
<span className="text-[9px] font-mono text-red-neon">too-hard</span>
</div>
<div className="absolute inset-y-0 left-[20%] right-[15%] bg-green-neon/15 flex items-center justify-center">
<span className="text-[9px] font-mono text-green-neon">learnable zone (0.20 – 0.85)</span>
</div>
<div className="absolute inset-y-0 right-0 w-[15%] bg-neon/15 flex items-center justify-center">
<span className="text-[9px] font-mono text-neon">too-easy</span>
</div>
{/* Markers */}
<div className="absolute inset-y-0" style={{ left: '20%', width: 1, background: '#00ff88', boxShadow: '0 0 4px #00ff88' }} />
<div className="absolute inset-y-0" style={{ left: '85%', width: 1, background: '#00ff88', boxShadow: '0 0 4px #00ff88' }} />
</div>
<div className="flex justify-between text-[9px] font-mono text-muted mt-1">
<span>0.00</span><span>0.20</span><span className="ml-auto mr-4">0.85</span><span>1.00</span>
</div>
</Card>
</div>
)
}