Taimwe commited on
Commit
d876c52
·
verified ·
1 Parent(s): 0bc8b51

Add jobs router

Browse files
Files changed (1) hide show
  1. app/routers/jobs.py +78 -0
app/routers/jobs.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Training job routes."""
2
+ from fastapi import APIRouter, Depends, HTTPException
3
+ from sqlalchemy.orm import Session
4
+
5
+ from .. import models, schemas
6
+ from ..database import get_db
7
+ from ..deps import get_current_user
8
+ from ..services import training
9
+
10
+ router = APIRouter(prefix="/jobs", tags=["jobs"])
11
+
12
+
13
+ @router.post("", response_model=schemas.JobOut, status_code=201)
14
+ def create_job(body: schemas.JobCreate, user=Depends(get_current_user), db: Session = Depends(get_db)):
15
+ epochs = int((body.config or {}).get("epochs", 20))
16
+ job = models.TrainingJob(
17
+ name=body.name or f"run-{models._id()[:6]}",
18
+ owner=user.username,
19
+ base_model=body.base_model,
20
+ dataset=body.dataset,
21
+ job_type=body.job_type,
22
+ status="queued",
23
+ config=body.config or {},
24
+ metrics={},
25
+ total_epochs=epochs,
26
+ current_epoch=0,
27
+ )
28
+ db.add(job)
29
+ db.commit()
30
+ db.refresh(job)
31
+ training.launch(job.id)
32
+ return job
33
+
34
+
35
+ @router.get("", response_model=list[schemas.JobOut])
36
+ def list_jobs(user=Depends(get_current_user), db: Session = Depends(get_db)):
37
+ return (
38
+ db.query(models.TrainingJob)
39
+ .filter(models.TrainingJob.owner == user.username)
40
+ .order_by(models.TrainingJob.created_at.desc())
41
+ .all()
42
+ )
43
+
44
+
45
+ @router.get("/{job_id}", response_model=schemas.JobOut)
46
+ def get_job(job_id: str, user=Depends(get_current_user), db: Session = Depends(get_db)):
47
+ j = db.get(models.TrainingJob, job_id)
48
+ if j is None:
49
+ raise HTTPException(404, "Job not found")
50
+ if j.owner != user.username:
51
+ raise HTTPException(403, "Not your job")
52
+ return j
53
+
54
+
55
+ @router.get("/{job_id}/metrics", response_model=list[schemas.MetricPoint])
56
+ def get_metrics(job_id: str, user=Depends(get_current_user), db: Session = Depends(get_db)):
57
+ j = db.get(models.TrainingJob, job_id)
58
+ if j is None:
59
+ raise HTTPException(404, "Job not found")
60
+ if j.owner != user.username:
61
+ raise HTTPException(403, "Not your job")
62
+ losses = (j.metrics or {}).get("loss") or []
63
+ return [schemas.MetricPoint(epoch=i + 1, loss=float(v)) for i, v in enumerate(losses)]
64
+
65
+
66
+ @router.post("/{job_id}/cancel", response_model=schemas.JobOut)
67
+ def cancel_job(job_id: str, user=Depends(get_current_user), db: Session = Depends(get_db)):
68
+ j = db.get(models.TrainingJob, job_id)
69
+ if j is None:
70
+ raise HTTPException(404, "Job not found")
71
+ if j.owner != user.username:
72
+ raise HTTPException(403, "Not your job")
73
+ training.cancel(job_id)
74
+ if not training.is_running(job_id) and j.status not in ("completed", "failed", "cancelled"):
75
+ j.status = "cancelled"
76
+ db.commit()
77
+ db.refresh(j)
78
+ return j