Vector Motion
AI/ML

Training Progress Card - ML Model Training

Track machine learning model training progress, epochs, and convergence. Monitor training loss and validation metrics in real-time.

Training Progress Card

The Training Progress Card displays real-time training progress including epochs, loss, and estimated time remaining.

Preview

Installation

npx shadcn@latest add https://vectormotion.vercel.app/registry/training-progress-card.json
Training Progress Card
'use client'import React from 'react';import { Loader2, Timer, TrendingDown } from 'lucide-react';import { motion } from 'motion/react';import { clsx, type ClassValue } from "clsx"import { twMerge } from "tailwind-merge"import { ResponsiveContainer, PieChart, Pie, Cell, Tooltip } from 'recharts';function cn(...inputs: ClassValue[]) {  return twMerge(clsx(inputs))}interface ProgressData {  name: string;  value: number;  fill: string;  [key: string]: any;}interface TrainingProgressCardProps {  className?: string;  title?: string;  status?: string;  epochLabel?: string;  data?: ProgressData[];  progressValue?: string;  lossValue?: string;  elapsedTime?: string;  remainingTime?: string;}const DEFAULT_DATA: ProgressData[] = [  { name: 'Completed', value: 42, fill: '#3b82f6' }, // Blue-500  { name: 'Remaining', value: 58, fill: '#e4e4e7' }, // Zinc-200];const DEFAULT_TITLE = "Training";const DEFAULT_STATUS = "Running";const DEFAULT_EPOCH_LABEL = "Epoch 42/100";const DEFAULT_PROGRESS_VALUE = "42%";const DEFAULT_LOSS_VALUE = "0.34";const DEFAULT_ELAPSED_TIME = "2h 14m";const DEFAULT_REMAINING_TIME = "~3h 05m";export const TrainingProgressCard: React.FC<TrainingProgressCardProps> = ({  className = "",  title = DEFAULT_TITLE,  status = DEFAULT_STATUS,  epochLabel = DEFAULT_EPOCH_LABEL,  data = DEFAULT_DATA,  progressValue = DEFAULT_PROGRESS_VALUE,  lossValue = DEFAULT_LOSS_VALUE,  elapsedTime = DEFAULT_ELAPSED_TIME,  remainingTime = DEFAULT_REMAINING_TIME,}) => {  return (    <motion.div      initial={{ opacity: 0, y: 20 }}      animate={{ opacity: 1, y: 0 }}      transition={{ duration: 0.5, delay: 0.1 }}      className={cn(        "relative overflow-hidden rounded-2xl border border-border bg-card text-card-foreground shadow-sm transition-all hover:border-blue-300 dark:hover:border-blue-700 hover:shadow-md flex flex-col h-full",        className      )}    >      <div className="p-5 flex flex-col h-full relative z-10">        <div className="mb-2 flex items-start justify-between">          <div>            <div className="flex items-center gap-2 mb-1">              <span className="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs font-medium bg-blue-50 text-blue-600 dark:bg-blue-900/20 dark:text-blue-400 border border-blue-100 dark:border-blue-800">                <Loader2 className="w-3 h-3 animate-spin" />                {status}              </span>            </div>            <h3 className="font-bold text-lg text-foreground">              {title}            </h3>            <p className="text-sm text-muted-foreground font-medium">              {epochLabel}            </p>          </div>          <div className="rounded-lg border-2 border-blue-100 dark:border-blue-800 p-2 text-blue-500 dark:text-blue-400 flex items-center justify-center">            <Timer className="h-5 w-5" />          </div>        </div>        <div className="flex-1 w-full min-h-[140px] relative">          <ResponsiveContainer width="100%" height="100%">            <PieChart>              <Pie                data={data}                cx="50%"                cy="50%"                innerRadius={45}                outerRadius={65}                startAngle={90}                endAngle={-270}                paddingAngle={0}                dataKey="value"                stroke="none"                cornerRadius={5}              >                {data.map((entry, index) => (                  <Cell key={`cell-${index}`} fill={entry.fill} />                ))}              </Pie>              <Tooltip cursor={false} content={() => null} />            </PieChart>          </ResponsiveContainer>          <div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none">            <span className="text-3xl font-bold text-foreground">{progressValue}</span>            <div className="flex items-center gap-0.5 text-xs text-muted-foreground">              <span>Loss: {lossValue}</span>              <TrendingDown className="w-3 h-3 text-emerald-500" />            </div>          </div>        </div>        <div className="mt-2 grid grid-cols-2 gap-2">          <div className="p-2 rounded bg-muted border border-border text-center">            <div className="text-[10px] text-muted-foreground text-left">Elapsed</div>            <div className="text-sm font-bold text-foreground text-left">{elapsedTime}</div>            <div className="w-full h-1 bg-zinc-200 dark:bg-zinc-700 rounded-full mt-1 overflow-hidden">              <div className="h-full bg-blue-400 w-1/2" />            </div>          </div>          <div className="p-2 rounded bg-muted border border-border text-center">            <div className="text-[10px] text-muted-foreground text-left">Remaining</div>            <div className="text-sm font-bold text-foreground text-left">{remainingTime}</div>            <div className="w-full h-1 bg-zinc-200 dark:bg-zinc-700 rounded-full mt-1 overflow-hidden">              <div className="h-full bg-zinc-400 w-3/4" />            </div>          </div>        </div>        <div className="absolute -bottom-4 -right-4 z-0 opacity-5 pointer-events-none">          <Loader2 className="w-40 h-40 text-blue-500" />        </div>      </div>    </motion.div>  );};

Props

Prop

Type

Usage

This component is a demo card displaying training progress with animated visualizations and dark mode support.