From 2b6e66e0cb543eb2048c687b9309ac3b71373fe0 Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Fri, 21 Feb 2025 12:40:17 -0700 Subject: [PATCH] Mor ui work --- ui/prisma/schema.prisma | 2 +- ui/src/app/api/jobs/[jobID]/start/route.ts | 4 +-- ui/src/app/api/jobs/route.ts | 14 ++++---- ui/src/app/jobs/[jobID]/page.tsx | 2 +- ui/src/app/jobs/new/page.tsx | 41 +++++++++++++--------- ui/src/components/JobsTable.tsx | 4 +-- ui/src/hooks/useJobsList.tsx | 9 +++-- 7 files changed, 44 insertions(+), 32 deletions(-) diff --git a/ui/prisma/schema.prisma b/ui/prisma/schema.prisma index b28c43bf..c23826ae 100644 --- a/ui/prisma/schema.prisma +++ b/ui/prisma/schema.prisma @@ -16,7 +16,7 @@ model Settings { model Job { id String @id @default(uuid()) name String @unique - gpu_id Int + gpu_ids String job_config String // JSON string created_at DateTime @default(now()) updated_at DateTime @updatedAt diff --git a/ui/src/app/api/jobs/[jobID]/start/route.ts b/ui/src/app/api/jobs/[jobID]/start/route.ts index b706043f..1ca970ac 100644 --- a/ui/src/app/api/jobs/[jobID]/start/route.ts +++ b/ui/src/app/api/jobs/[jobID]/start/route.ts @@ -70,7 +70,7 @@ export async function GET(request: NextRequest, { params }: { params: { jobID: s return NextResponse.json({ error: 'run.py not found' }, { status: 500 }); } - console.log('Spawning command:', `AITK_JOB_ID=${jobID} CUDA_VISIBLE_DEVICES=${job.gpu_id} ${pythonPath} ${runFilePath} ${configPath}`); + console.log('Spawning command:', `AITK_JOB_ID=${jobID} CUDA_VISIBLE_DEVICES=${job.gpu_ids} ${pythonPath} ${runFilePath} ${configPath}`); // start job const subprocess = spawn(pythonPath, [runFilePath, configPath], { @@ -79,7 +79,7 @@ export async function GET(request: NextRequest, { params }: { params: { jobID: s env: { ...process.env, AITK_JOB_ID: jobID, - CUDA_VISIBLE_DEVICES: `${job.gpu_id}`, + CUDA_VISIBLE_DEVICES: `${job.gpu_ids}`, }, cwd: TOOLKIT_ROOT, }); diff --git a/ui/src/app/api/jobs/route.ts b/ui/src/app/api/jobs/route.ts index 3e0df9f0..4d9b954e 100644 --- a/ui/src/app/api/jobs/route.ts +++ b/ui/src/app/api/jobs/route.ts @@ -9,16 +9,16 @@ export async function GET(request: Request) { try { if (id) { - const training = await prisma.job.findUnique({ + const job = await prisma.job.findUnique({ where: { id }, }); - return NextResponse.json(training); + return NextResponse.json(job); } - const trainings = await prisma.job.findMany({ + const jobs = await prisma.job.findMany({ orderBy: { created_at: 'desc' }, }); - return NextResponse.json(trainings); + return NextResponse.json({ jobs: jobs }); } catch (error) { console.error(error); return NextResponse.json({ error: 'Failed to fetch training data' }, { status: 500 }); @@ -28,7 +28,7 @@ export async function GET(request: Request) { export async function POST(request: Request) { try { const body = await request.json(); - const { id, name, job_config, gpu_id } = body; + const { id, name, job_config, gpu_ids } = body; if (id) { // Update existing training @@ -36,7 +36,7 @@ export async function POST(request: Request) { where: { id }, data: { name, - gpu_id, + gpu_ids, job_config: JSON.stringify(job_config), }, }); @@ -46,7 +46,7 @@ export async function POST(request: Request) { const training = await prisma.job.create({ data: { name, - gpu_id, + gpu_ids, job_config: JSON.stringify(job_config), }, }); diff --git a/ui/src/app/jobs/[jobID]/page.tsx b/ui/src/app/jobs/[jobID]/page.tsx index 4929804f..e28ed956 100644 --- a/ui/src/app/jobs/[jobID]/page.tsx +++ b/ui/src/app/jobs/[jobID]/page.tsx @@ -58,7 +58,7 @@ export default function JobPage({ params }: { params: { jobID: string } }) {

Job Details

ID: {job.id}

Name: {job.name}

-

GPU: {job.gpu_id}

+

GPUs: {job.gpu_ids}

Status: {job.status}

Info: {job.info}

Step: {job.step}

diff --git a/ui/src/app/jobs/new/page.tsx b/ui/src/app/jobs/new/page.tsx index 4473df18..e5247da1 100644 --- a/ui/src/app/jobs/new/page.tsx +++ b/ui/src/app/jobs/new/page.tsx @@ -22,7 +22,7 @@ export default function TrainingForm() { const router = useRouter(); const searchParams = useSearchParams(); const runId = searchParams.get('id'); - const [gpuID, setGpuID] = useState(null); + const [gpuIDs, setGpuIDs] = useState(null); const { settings, isSettingsLoaded } = useSettings(); const { gpuList, isGPUInfoLoaded } = useGPUInfo(); const { datasets, status: datasetFetchStatus } = useDatasetList(); @@ -52,7 +52,7 @@ export default function TrainingForm() { fetch(`/api/jobs?id=${runId}`) .then(res => res.json()) .then(data => { - setGpuID(data.gpu_id); + setGpuIDs(data.gpu_ids); setJobConfig(JSON.parse(data.job_config)); }) .catch(error => console.error('Error fetching training:', error)); @@ -61,8 +61,8 @@ export default function TrainingForm() { useEffect(() => { if (isGPUInfoLoaded) { - if (gpuID === null && gpuList.length > 0) { - setGpuID(gpuList[0]); + if (gpuIDs === null && gpuList.length > 0) { + setGpuIDs(`${gpuList[0]}`); } } }, [gpuList, isGPUInfoLoaded]); @@ -73,8 +73,8 @@ export default function TrainingForm() { } }, [settings, isSettingsLoaded]); - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); + const saveJob = async () => { + if (status === 'saving') return; setStatus('saving'); try { @@ -86,7 +86,7 @@ export default function TrainingForm() { body: JSON.stringify({ id: runId, name: jobConfig.config.name, - gpu_id: gpuID, + gpu_ids: gpuIDs, job_config: jobConfig, }), }); @@ -106,6 +106,11 @@ export default function TrainingForm() { } }; + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + saveJob(); + }; + return ( <> @@ -118,6 +123,15 @@ export default function TrainingForm() {

{runId ? 'Edit Training Job' : 'New Training Job'}

+
+ +
@@ -132,9 +146,9 @@ export default function TrainingForm() { /> setGpuID(parseInt(value))} + onChange={value => setGpuIDs(value)} options={gpuList.map(gpu => ({ value: `${gpu}`, label: `GPU #${gpu}` }))} /> @@ -553,17 +567,10 @@ export default function TrainingForm() { - - {status === 'success' &&

Training saved successfully!

} {status === 'error' &&

Error saving training. Please try again.

} +
); diff --git a/ui/src/components/JobsTable.tsx b/ui/src/components/JobsTable.tsx index 9be85d15..0986fcd1 100644 --- a/ui/src/components/JobsTable.tsx +++ b/ui/src/components/JobsTable.tsx @@ -38,7 +38,7 @@ export default function JobsTable(props: JobsTableProps) { - {jobs.map((job, index) => { + {jobs?.map((job, index) => { const jobConfig: JobConfig = JSON.parse(job.job_config); const totalSteps = jobConfig.config.process[0].train.steps; @@ -68,7 +68,7 @@ export default function JobsTable(props: JobsTableProps) { - {job.gpu_id} + {job.gpu_ids} {job.status} {job.info} diff --git a/ui/src/hooks/useJobsList.tsx b/ui/src/hooks/useJobsList.tsx index 879a6b2b..737fe226 100644 --- a/ui/src/hooks/useJobsList.tsx +++ b/ui/src/hooks/useJobsList.tsx @@ -13,8 +13,13 @@ export default function useJobsList() { .then(res => res.json()) .then(data => { console.log('Jobs:', data); - setJobs(data); - setStatus('success'); + if (data.error) { + console.log('Error fetching jobs:', data.error); + setStatus('error'); + } else { + setJobs(data.jobs); + setStatus('success'); + } }) .catch(error => { console.error('Error fetching datasets:', error);