Spaces:
Paused
Paused
import { NextResponse } from 'next/server'; | |
import { exec } from 'child_process'; | |
import { promisify } from 'util'; | |
import os from 'os'; | |
const execAsync = promisify(exec); | |
export async function GET() { | |
try { | |
// Get platform | |
const platform = os.platform(); | |
const isWindows = platform === 'win32'; | |
// Check if nvidia-smi is available | |
const hasNvidiaSmi = await checkNvidiaSmi(isWindows); | |
if (!hasNvidiaSmi) { | |
return NextResponse.json({ | |
hasNvidiaSmi: false, | |
gpus: [], | |
error: 'nvidia-smi not found or not accessible', | |
}); | |
} | |
// Get GPU stats | |
const gpuStats = await getGpuStats(isWindows); | |
return NextResponse.json({ | |
hasNvidiaSmi: true, | |
gpus: gpuStats, | |
}); | |
} catch (error) { | |
console.error('Error fetching NVIDIA GPU stats:', error); | |
return NextResponse.json( | |
{ | |
hasNvidiaSmi: false, | |
gpus: [], | |
error: `Failed to fetch GPU stats: ${error instanceof Error ? error.message : String(error)}`, | |
}, | |
{ status: 500 }, | |
); | |
} | |
} | |
async function checkNvidiaSmi(isWindows: boolean): Promise<boolean> { | |
try { | |
if (isWindows) { | |
// Check if nvidia-smi is available on Windows | |
// It's typically located in C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe | |
// but we'll just try to run it directly as it may be in PATH | |
await execAsync('nvidia-smi -L'); | |
} else { | |
// Linux/macOS check | |
await execAsync('which nvidia-smi'); | |
} | |
return true; | |
} catch (error) { | |
return false; | |
} | |
} | |
async function getGpuStats(isWindows: boolean) { | |
// Command is the same for both platforms, but the path might be different | |
const command = | |
'nvidia-smi --query-gpu=index,name,driver_version,temperature.gpu,utilization.gpu,utilization.memory,memory.total,memory.free,memory.used,power.draw,power.limit,clocks.current.graphics,clocks.current.memory,fan.speed --format=csv,noheader,nounits'; | |
// Execute command | |
const { stdout } = await execAsync(command); | |
// Parse CSV output | |
const gpus = stdout | |
.trim() | |
.split('\n') | |
.map(line => { | |
const [ | |
index, | |
name, | |
driverVersion, | |
temperature, | |
gpuUtil, | |
memoryUtil, | |
memoryTotal, | |
memoryFree, | |
memoryUsed, | |
powerDraw, | |
powerLimit, | |
clockGraphics, | |
clockMemory, | |
fanSpeed, | |
] = line.split(', ').map(item => item.trim()); | |
return { | |
index: parseInt(index), | |
name, | |
driverVersion, | |
temperature: parseInt(temperature), | |
utilization: { | |
gpu: parseInt(gpuUtil), | |
memory: parseInt(memoryUtil), | |
}, | |
memory: { | |
total: parseInt(memoryTotal), | |
free: parseInt(memoryFree), | |
used: parseInt(memoryUsed), | |
}, | |
power: { | |
draw: parseFloat(powerDraw), | |
limit: parseFloat(powerLimit), | |
}, | |
clocks: { | |
graphics: parseInt(clockGraphics), | |
memory: parseInt(clockMemory), | |
}, | |
fan: { | |
speed: parseInt(fanSpeed) || 0, // Some GPUs might not report fan speed, default to 0 | |
}, | |
}; | |
}); | |
return gpus; | |
} | |