diff --git a/web/public/locales/en/views/system.json b/web/public/locales/en/views/system.json index 1ba46153e..3b0a395e9 100644 --- a/web/public/locales/en/views/system.json +++ b/web/public/locales/en/views/system.json @@ -51,6 +51,7 @@ "gpuMemory": "GPU Memory", "gpuEncoder": "GPU Encoder", "gpuDecoder": "GPU Decoder", + "gpuTemperature": "GPU Temperature", "gpuInfo": { "vainfoOutput": { "title": "Vainfo Output", @@ -77,6 +78,7 @@ }, "npuUsage": "NPU Usage", "npuMemory": "NPU Memory", + "npuTemperature": "NPU Temperature", "intelGpuWarning": { "title": "Intel GPU Stats Warning", "message": "GPU stats unavailable", diff --git a/web/src/types/stats.ts b/web/src/types/stats.ts index 1fd38a1c3..8b22849be 100644 --- a/web/src/types/stats.ts +++ b/web/src/types/stats.ts @@ -61,11 +61,13 @@ export type GpuStats = { enc?: string; dec?: string; pstate?: string; + temp?: number; }; export type NpuStats = { npu: number; mem: string; + temp?: number; }; export type GpuInfo = "vainfo" | "nvinfo"; diff --git a/web/src/views/system/GeneralMetrics.tsx b/web/src/views/system/GeneralMetrics.tsx index 8c358e55a..e7dfbc2cf 100644 --- a/web/src/views/system/GeneralMetrics.tsx +++ b/web/src/views/system/GeneralMetrics.tsx @@ -368,6 +368,40 @@ export default function GeneralMetrics({ return Object.keys(series).length > 0 ? Object.values(series) : undefined; }, [statsHistory]); + const gpuTempSeries = useMemo(() => { + if (!statsHistory) { + return []; + } + + const series: { + [key: string]: { name: string; data: { x: number; y: number }[] }; + } = {}; + let hasValidGpu = false; + + statsHistory.forEach((stats, statsIdx) => { + if (!stats) { + return; + } + + Object.entries(stats.gpu_usages || {}).forEach(([key, stats]) => { + if (!(key in series)) { + series[key] = { name: key, data: [] }; + } + + if (stats.temp !== undefined) { + hasValidGpu = true; + series[key].data.push({ x: statsIdx + 1, y: stats.temp }); + } + }); + }); + + if (!hasValidGpu) { + return []; + } + + return Object.keys(series).length > 0 ? Object.values(series) : undefined; + }, [statsHistory]); + // Check if Intel GPU has all 0% usage values (known bug) const showIntelGpuWarning = useMemo(() => { if (!statsHistory || statsHistory.length < 3) { @@ -448,6 +482,40 @@ export default function GeneralMetrics({ return Object.keys(series).length > 0 ? Object.values(series) : []; }, [statsHistory]); + const npuTempSeries = useMemo(() => { + if (!statsHistory) { + return []; + } + + const series: { + [key: string]: { name: string; data: { x: number; y: number }[] }; + } = {}; + let hasValidNpu = false; + + statsHistory.forEach((stats, statsIdx) => { + if (!stats) { + return; + } + + Object.entries(stats.npu_usages || {}).forEach(([key, stats]) => { + if (!(key in series)) { + series[key] = { name: key, data: [] }; + } + + if (stats.temp !== undefined) { + hasValidNpu = true; + series[key].data.push({ x: statsIdx + 1, y: stats.temp }); + } + }); + }); + + if (!hasValidNpu) { + return []; + } + + return Object.keys(series).length > 0 ? Object.values(series) : undefined; + }, [statsHistory]); + // other processes stats const hardwareType = useMemo(() => { @@ -670,6 +738,7 @@ export default function GeneralMetrics({ className={cn( "mt-4 grid grid-cols-1 gap-2 sm:grid-cols-2", gpuEncSeries?.length && "md:grid-cols-4", + gpuTempSeries?.length && "md:grid-cols-3", )} > {statsHistory[0]?.gpu_usages && ( @@ -804,6 +873,30 @@ export default function GeneralMetrics({ ) : ( )} + {statsHistory.length != 0 ? ( + <> + {gpuTempSeries && gpuTempSeries?.length != 0 && ( +
+
+ {t("general.hardwareInfo.gpuTemperature")} +
+ {gpuTempSeries.map((series) => ( + + ))} +
+ )} + + ) : ( + + )} {statsHistory[0]?.npu_usages && ( <> @@ -827,6 +920,30 @@ export default function GeneralMetrics({ ) : ( )} + {statsHistory.length != 0 ? ( + <> + {npuTempSeries && npuTempSeries?.length != 0 && ( +
+
+ {t("general.hardwareInfo.npuTemperature")} +
+ {npuTempSeries.map((series) => ( + + ))} +
+ )} + + ) : ( + + )} )}