apolinario commited on
Commit
231dcea
·
1 Parent(s): 531b15c

track the org jobs

Browse files
ui/src/app/api/hf-jobs/route.ts CHANGED
@@ -16,7 +16,8 @@ export async function POST(request: NextRequest) {
16
  return NextResponse.json({ error: 'Token and job ID required' }, { status: 400 });
17
  }
18
 
19
- const jobStatus = await checkHFJobStatus(token, jobConfig.hf_job_id);
 
20
  return NextResponse.json({ status: jobStatus });
21
  } catch (error: any) {
22
  console.error('Job status check error:', error);
@@ -904,13 +905,19 @@ async function submitHFJobUV(token: string, hardware: string, scriptPath: string
904
  });
905
  }
906
 
907
- async function checkHFJobStatus(token: string, jobId: string): Promise<any> {
908
  return new Promise((resolve, reject) => {
909
  console.log(`Checking HF Job status for: ${jobId}`);
910
-
911
- const childProcess = spawn('hf', [
912
- 'jobs', 'inspect', jobId
913
- ], {
 
 
 
 
 
 
914
  env: {
915
  ...process.env,
916
  HF_TOKEN: token
 
16
  return NextResponse.json({ error: 'Token and job ID required' }, { status: 400 });
17
  }
18
 
19
+ const jobNamespaceOverride = jobConfig?.hf_job_namespace;
20
+ const jobStatus = await checkHFJobStatus(token, jobConfig.hf_job_id, jobNamespaceOverride);
21
  return NextResponse.json({ status: jobStatus });
22
  } catch (error: any) {
23
  console.error('Job status check error:', error);
 
905
  });
906
  }
907
 
908
+ async function checkHFJobStatus(token: string, jobId: string, jobNamespace?: string): Promise<any> {
909
  return new Promise((resolve, reject) => {
910
  console.log(`Checking HF Job status for: ${jobId}`);
911
+ const args = ['jobs', 'inspect'];
912
+
913
+ if (jobNamespace) {
914
+ console.log(`Using namespace override for status check: ${jobNamespace}`);
915
+ args.push('--namespace', jobNamespace);
916
+ }
917
+
918
+ args.push(jobId);
919
+
920
+ const childProcess = spawn('hf', args, {
921
  env: {
922
  ...process.env,
923
  HF_TOKEN: token
ui/src/components/HFJobStatus.tsx CHANGED
@@ -7,10 +7,25 @@ import { Button } from '@headlessui/react';
7
  interface HFJobStatusProps {
8
  hfJobId: string;
9
  hfJobUrl?: string;
 
10
  }
11
 
12
- export default function HFJobStatus({ hfJobId, hfJobUrl }: HFJobStatusProps) {
13
- const { status, loading, error } = useHFJobStatus(hfJobId);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  if (error) {
16
  return (
@@ -122,4 +137,4 @@ export default function HFJobStatus({ hfJobId, hfJobUrl }: HFJobStatusProps) {
122
  )}
123
  </div>
124
  );
125
- }
 
7
  interface HFJobStatusProps {
8
  hfJobId: string;
9
  hfJobUrl?: string;
10
+ hfJobNamespace?: string;
11
  }
12
 
13
+ const extractNamespaceFromUrl = (url?: string) => {
14
+ if (!url) {
15
+ return undefined;
16
+ }
17
+ try {
18
+ const match = url.match(/\/jobs\/([^\/]+)\//);
19
+ return match?.[1];
20
+ } catch (error) {
21
+ console.warn('Failed to derive HF job namespace from URL:', error);
22
+ return undefined;
23
+ }
24
+ };
25
+
26
+ export default function HFJobStatus({ hfJobId, hfJobUrl, hfJobNamespace }: HFJobStatusProps) {
27
+ const derivedNamespace = hfJobNamespace || extractNamespaceFromUrl(hfJobUrl);
28
+ const { status, loading, error } = useHFJobStatus(hfJobId, derivedNamespace);
29
 
30
  if (error) {
31
  return (
 
137
  )}
138
  </div>
139
  );
140
+ }
ui/src/components/HFJobsWorkflow.tsx CHANGED
@@ -409,6 +409,7 @@ export default function HFJobsWorkflow({ jobConfig, onComplete, hackathonEligibl
409
  is_hf_job: true,
410
  training_backend: 'hf-jobs',
411
  hf_job_submitted: true,
 
412
  },
413
  info: response.data.message || 'HF Job submitted',
414
  status: 'submitted',
@@ -437,6 +438,7 @@ export default function HFJobsWorkflow({ jobConfig, onComplete, hackathonEligibl
437
  is_hf_job: true,
438
  training_backend: 'hf-jobs',
439
  hf_job_submitted: true,
 
440
  },
441
  info: response.data.message || 'HF Job submitted',
442
  status: 'submitted',
 
409
  is_hf_job: true,
410
  training_backend: 'hf-jobs',
411
  hf_job_submitted: true,
412
+ hf_job_namespace: jobNamespace,
413
  },
414
  info: response.data.message || 'HF Job submitted',
415
  status: 'submitted',
 
438
  is_hf_job: true,
439
  training_backend: 'hf-jobs',
440
  hf_job_submitted: true,
441
+ hf_job_namespace: jobNamespace,
442
  },
443
  info: response.data.message || 'HF Job submitted',
444
  status: 'submitted',
ui/src/components/JobOverview.tsx CHANGED
@@ -109,6 +109,7 @@ export default function JobOverview({ job }: JobOverviewProps) {
109
  <HFJobStatus
110
  hfJobId={jobConfig.hf_job_id}
111
  hfJobUrl={jobConfig.hf_job_url}
 
112
  />
113
  ) : isHFJob && !hfJobSubmitted ? (
114
  <span className="px-3 py-1 rounded-full text-sm bg-yellow-500/10 text-yellow-500">
 
109
  <HFJobStatus
110
  hfJobId={jobConfig.hf_job_id}
111
  hfJobUrl={jobConfig.hf_job_url}
112
+ hfJobNamespace={jobConfig.hf_job_namespace}
113
  />
114
  ) : isHFJob && !hfJobSubmitted ? (
115
  <span className="px-3 py-1 rounded-full text-sm bg-yellow-500/10 text-yellow-500">
ui/src/components/JobsTable.tsx CHANGED
@@ -99,6 +99,7 @@ export default function JobsTable({ onlyActive = false }: JobsTableProps) {
99
  <HFJobStatus
100
  hfJobId={jobConfig.hf_job_id}
101
  hfJobUrl={jobConfig.hf_job_url}
 
102
  />
103
  );
104
  } else {
 
99
  <HFJobStatus
100
  hfJobId={jobConfig.hf_job_id}
101
  hfJobUrl={jobConfig.hf_job_url}
102
+ hfJobNamespace={jobConfig.hf_job_namespace}
103
  />
104
  );
105
  } else {
ui/src/hooks/useHFJobStatus.tsx CHANGED
@@ -12,7 +12,7 @@ interface HFJobStatus {
12
  url: string;
13
  }
14
 
15
- export function useHFJobStatus(hfJobId: string | null, refreshInterval = 30000) {
16
  const [status, setStatus] = useState<HFJobStatus | null>(null);
17
  const [loading, setLoading] = useState(false);
18
  const [error, setError] = useState<string | null>(null);
@@ -31,7 +31,10 @@ export function useHFJobStatus(hfJobId: string | null, refreshInterval = 30000)
31
  const response = await apiClient.post('/api/hf-jobs', {
32
  action: 'checkStatus',
33
  token,
34
- jobConfig: { hf_job_id: hfJobId },
 
 
 
35
  });
36
 
37
  if (response.data.status) {
@@ -52,7 +55,7 @@ export function useHFJobStatus(hfJobId: string | null, refreshInterval = 30000)
52
  const interval = setInterval(fetchStatus, refreshInterval);
53
 
54
  return () => clearInterval(interval);
55
- }, [hfJobId, token, refreshInterval]);
56
 
57
  return { status, loading, error, refetch: () => {
58
  if (hfJobId && token) {
 
12
  url: string;
13
  }
14
 
15
+ export function useHFJobStatus(hfJobId: string | null, hfJobNamespace?: string, refreshInterval = 30000) {
16
  const [status, setStatus] = useState<HFJobStatus | null>(null);
17
  const [loading, setLoading] = useState(false);
18
  const [error, setError] = useState<string | null>(null);
 
31
  const response = await apiClient.post('/api/hf-jobs', {
32
  action: 'checkStatus',
33
  token,
34
+ jobConfig: {
35
+ hf_job_id: hfJobId,
36
+ hf_job_namespace: hfJobNamespace,
37
+ },
38
  });
39
 
40
  if (response.data.status) {
 
55
  const interval = setInterval(fetchStatus, refreshInterval);
56
 
57
  return () => clearInterval(interval);
58
+ }, [hfJobId, hfJobNamespace, token, refreshInterval]);
59
 
60
  return { status, loading, error, refetch: () => {
61
  if (hfJobId && token) {
ui/src/types.ts CHANGED
@@ -199,6 +199,14 @@ export interface JobConfig {
199
  job: string;
200
  config: ConfigObject;
201
  meta: MetaConfig;
 
 
 
 
 
 
 
 
202
  }
203
 
204
  export interface ConfigDoc {
 
199
  job: string;
200
  config: ConfigObject;
201
  meta: MetaConfig;
202
+ is_hf_job?: boolean;
203
+ hf_job_id?: string;
204
+ hf_job_url?: string | null;
205
+ hf_job_namespace?: string;
206
+ dataset_repo?: string;
207
+ hardware?: string;
208
+ training_backend?: string;
209
+ hf_job_submitted?: boolean;
210
  }
211
 
212
  export interface ConfigDoc {