Config ui section is coming along

This commit is contained in:
Jaret Burkett
2025-02-19 07:52:24 -07:00
parent b13fcc1039
commit cef7d9e594
17 changed files with 1323 additions and 120 deletions

102
ui/src/app/api/gpu/route.ts Normal file
View File

@@ -0,0 +1,102 @@
import { NextResponse } from 'next/server';
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
export async function GET() {
try {
// Check if nvidia-smi is available
const hasNvidiaSmi = await checkNvidiaSmi();
if (!hasNvidiaSmi) {
return NextResponse.json({
hasNvidiaSmi: false,
gpus: [],
error: 'nvidia-smi not found or not accessible',
});
}
// Get GPU stats
const gpuStats = await getGpuStats();
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(): Promise<boolean> {
try {
await execAsync('which nvidia-smi');
return true;
} catch (error) {
return false;
}
}
async function getGpuStats() {
// Get detailed GPU information in JSON format
const { stdout } = await execAsync(
'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 --format=csv,noheader,nounits',
);
// 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,
] = 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),
},
};
});
return gpus;
}

View File

@@ -1,12 +1,21 @@
import { NextResponse } from 'next/server';
import { PrismaClient } from '@prisma/client';
import { defaultTrainFolder } from '@/paths';
const prisma = new PrismaClient();
export async function GET() {
try {
const settings = await prisma.settings.findMany();
return NextResponse.json(settings.reduce((acc, curr) => ({ ...acc, [curr.key]: curr.value }), {}));
const settingsObject = settings.reduce((acc: any, setting) => {
acc[setting.key] = setting.value;
return acc;
}, {});
// if TRAINING_FOLDER is not set, use default
if (!settingsObject.TRAINING_FOLDER || settingsObject.TRAINING_FOLDER === '') {
settingsObject.TRAINING_FOLDER = defaultTrainFolder;
}
return NextResponse.json(settingsObject);
} catch (error) {
return NextResponse.json({ error: 'Failed to fetch settings' }, { status: 500 });
}

View File

@@ -27,7 +27,7 @@ export async function GET(request: Request) {
export async function POST(request: Request) {
try {
const body = await request.json();
const { id, name, run_data } = body;
const { id, name, job_config, gpu_id } = body;
if (id) {
// Update existing training
@@ -35,7 +35,8 @@ export async function POST(request: Request) {
where: { id },
data: {
name,
run_data: JSON.stringify(run_data),
gpu_id,
job_config: JSON.stringify(job_config),
},
});
return NextResponse.json(training);
@@ -44,7 +45,8 @@ export async function POST(request: Request) {
const training = await prisma.training.create({
data: {
name,
run_data: JSON.stringify(run_data),
gpu_id,
job_config: JSON.stringify(job_config),
},
});
return NextResponse.json(training);