import { useId } from "react";
import { Gpu } from "lucide-react";
import { useTranslation } from "react-i18next";
import type { ServerMetrics } from "@/main-axios";
import type { GpuDevice, GpuProcess } from "@/types/stats-widgets";
import { MiniStat, RadialGauge, Sparkline, StatRow } from "@/components/charts";
import { MetricCard } from "@/components/metric-card";
import type { GpuHistories, GpuHistory } from "./gpu-history";
const NA = "N/A";
const EMPTY_HISTORY: GpuHistory = { utilization: [], memory: [] };
function formatGiB(mib: number | null): string {
return mib === null ? NA : (mib / 1024).toFixed(1);
}
function formatVram(gpu: GpuDevice): string {
return gpu.memoryUsedMiB === null || gpu.memoryTotalMiB === null
? NA
: `${formatGiB(gpu.memoryUsedMiB)}/${formatGiB(gpu.memoryTotalMiB)}G`;
}
function formatWhole(value: number | null, unit: string): string {
return value === null ? NA : `${Math.round(value)}${unit}`;
}
function formatPower(gpu: GpuDevice): string {
if (gpu.powerDrawWatts === null && gpu.powerLimitWatts === null) return NA;
return `${formatWhole(gpu.powerDrawWatts, "")}/${formatWhole(gpu.powerLimitWatts, "")}W`;
}
function processVram(process: GpuProcess): string {
const vram =
process.memoryUsedMiB === null
? NA
: `${formatGiB(process.memoryUsedMiB)}G`;
return process.gpuIndex === null ? vram : `${vram} · GPU ${process.gpuIndex}`;
}
function executableName(path: string): string {
return path.split(/[\\/]/).pop() || path;
}
/** A captioned 0-100% sparkline, so the two trends under each GPU are told apart. */
function TrendSparkline({
caption,
data,
colorClassName,
}: {
caption: string;
data: number[];
colorClassName?: string;
}) {
const captionId = useId();
return (