feat(onboarding): replace hardcoded system info with live /api/system/hardware data
This commit is contained in:
parent
c18ccbb773
commit
883ae7ff8c
3 changed files with 85 additions and 15 deletions
|
|
@ -2,20 +2,14 @@ import { Badge } from "@/components/ui/badge";
|
|||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { useTrainingConfigStore } from "@/features/training";
|
||||
import { useHardwareInfo } from "@/hooks";
|
||||
import { isAdapterMethod } from "@/types/training";
|
||||
import { GpuIcon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { useShallow } from "zustand/react/shallow";
|
||||
|
||||
const SYSTEM_INFO = {
|
||||
gpu: "NVIDIA RTX 4090",
|
||||
vram: "24 GB",
|
||||
pytorch: "2.5.1+cu124",
|
||||
cuda: "12.4",
|
||||
transformers: "4.47.1",
|
||||
};
|
||||
|
||||
export function SummaryStep() {
|
||||
const hw = useHardwareInfo();
|
||||
const {
|
||||
modelType,
|
||||
selectedModel,
|
||||
|
|
@ -88,24 +82,24 @@ export function SummaryStep() {
|
|||
</div>
|
||||
<div className="flex flex-col flex-1">
|
||||
<span className="text-xs text-muted-foreground">GPU</span>
|
||||
<span className="text-sm font-medium">{SYSTEM_INFO.gpu}</span>
|
||||
<span className="text-sm font-medium">{hw.gpuName ?? "—"}</span>
|
||||
</div>
|
||||
<Badge variant="secondary">{SYSTEM_INFO.vram}</Badge>
|
||||
<Badge variant="secondary">{hw.vramTotalGb != null ? `${hw.vramTotalGb} GB` : "—"}</Badge>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="space-y-1 text-sm">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">torch</span>
|
||||
<span className="font-mono text-xs">{SYSTEM_INFO.pytorch}</span>
|
||||
<span className="text-muted-foreground">unsloth</span>
|
||||
<span className="font-mono text-xs">{hw.unsloth ?? "—"}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">cuda</span>
|
||||
<span className="font-mono text-xs">{SYSTEM_INFO.cuda}</span>
|
||||
<span className="text-muted-foreground">torch</span>
|
||||
<span className="font-mono text-xs">{hw.torch ?? "—"}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">transformers</span>
|
||||
<span className="font-mono text-xs">
|
||||
{SYSTEM_INFO.transformers}
|
||||
{hw.transformers ?? "—"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
export { useDebouncedValue } from "./use-debounced-value";
|
||||
export { useGpuInfo } from "./use-gpu-info";
|
||||
export { useGpuUtilization } from "./use-gpu-utilization";
|
||||
export { useHardwareInfo } from "./use-hardware-info";
|
||||
export { useHfModelSearch } from "./use-hf-model-search";
|
||||
export { useHfDatasetSearch } from "./use-hf-dataset-search";
|
||||
export { useHfDatasetSplits } from "./use-hf-dataset-splits";
|
||||
|
|
|
|||
75
studio/frontend/src/hooks/use-hardware-info.ts
Normal file
75
studio/frontend/src/hooks/use-hardware-info.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import { authFetch } from "@/features/auth";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export interface HardwareInfo {
|
||||
gpuName: string | null;
|
||||
vramTotalGb: number | null;
|
||||
torch: string | null;
|
||||
cuda: string | null;
|
||||
transformers: string | null;
|
||||
unsloth: string | null;
|
||||
}
|
||||
|
||||
const DEFAULT: HardwareInfo = {
|
||||
gpuName: null,
|
||||
vramTotalGb: null,
|
||||
torch: null,
|
||||
cuda: null,
|
||||
transformers: null,
|
||||
unsloth: null,
|
||||
};
|
||||
|
||||
// Module-level cache so multiple components share one fetch.
|
||||
let cached: HardwareInfo | null = null;
|
||||
let fetchPromise: Promise<HardwareInfo> | null = null;
|
||||
|
||||
async function fetchOnce(): Promise<HardwareInfo> {
|
||||
if (cached) return cached;
|
||||
if (fetchPromise) return fetchPromise;
|
||||
|
||||
fetchPromise = (async () => {
|
||||
try {
|
||||
const res = await authFetch("/api/system/hardware");
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const data = await res.json();
|
||||
const info: HardwareInfo = {
|
||||
gpuName: data?.gpu?.gpu_name ?? null,
|
||||
vramTotalGb: data?.gpu?.vram_total_gb ?? null,
|
||||
torch: data?.versions?.torch ?? null,
|
||||
cuda: data?.versions?.cuda ?? null,
|
||||
transformers: data?.versions?.transformers ?? null,
|
||||
unsloth: data?.versions?.unsloth ?? null,
|
||||
};
|
||||
cached = info;
|
||||
return info;
|
||||
} catch {
|
||||
// Reset promise so subsequent calls retry (e.g. backend wasn't ready)
|
||||
fetchPromise = null;
|
||||
return DEFAULT;
|
||||
}
|
||||
})();
|
||||
|
||||
return fetchPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch hardware info from `GET /api/system/hardware`.
|
||||
*
|
||||
* The result is cached at module level — only one network request is made
|
||||
* regardless of how many components call this hook.
|
||||
*/
|
||||
export function useHardwareInfo(): HardwareInfo {
|
||||
const [info, setInfo] = useState<HardwareInfo>(cached ?? DEFAULT);
|
||||
|
||||
useEffect(() => {
|
||||
if (cached) return;
|
||||
|
||||
let cancelled = false;
|
||||
fetchOnce().then((hw) => {
|
||||
if (!cancelled) setInfo(hw);
|
||||
});
|
||||
return () => { cancelled = true; };
|
||||
}, []);
|
||||
|
||||
return info;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue