Show retrain progress in Android
This commit is contained in:
@@ -144,6 +144,13 @@ def create_app(settings: Settings | None = None) -> FastAPI:
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
@app.post("/api/training/jobs/{job_id}/progress")
|
||||
async def training_progress(job_id: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
try:
|
||||
return training.progress(job_id, payload)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
@app.post("/api/training/jobs/{job_id}/complete")
|
||||
async def training_complete(job_id: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
try:
|
||||
|
||||
@@ -139,6 +139,25 @@ class TrainingCoordinator:
|
||||
self._save_state(state)
|
||||
return {"complete": True, "name": name, "sha256": sha256}
|
||||
|
||||
def progress(self, job_id: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
payload = payload or {}
|
||||
with self._lock:
|
||||
state = self._load_state()
|
||||
job = self._job_by_id(state, job_id)
|
||||
if job is None:
|
||||
raise ValueError(f"training job not found: {job_id}")
|
||||
if isinstance(payload.get("worker"), dict):
|
||||
state["worker"] = self._worker_from_payload(payload["worker"])
|
||||
job["status"] = str(payload.get("status") or job.get("status") or "running")
|
||||
job["phase"] = str(payload.get("phase") or job.get("phase") or "running")
|
||||
job["message"] = str(payload.get("message") or job.get("message") or "")
|
||||
job["progress_percent"] = _coerce_percent(payload.get("progress_percent"), job.get("progress_percent", 0))
|
||||
job["updated_at"] = _now()
|
||||
if isinstance(payload.get("details"), dict):
|
||||
job["details"] = payload["details"]
|
||||
self._save_state(state)
|
||||
return {"ok": True, "job": job, "status": self._public_status(state)}
|
||||
|
||||
def complete(self, job_id: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
payload = payload or {}
|
||||
with self._lock:
|
||||
@@ -148,6 +167,8 @@ class TrainingCoordinator:
|
||||
raise ValueError(f"training job not found: {job_id}")
|
||||
success = bool(payload.get("success", payload.get("status") == "completed"))
|
||||
job["status"] = "completed" if success else "failed"
|
||||
job["phase"] = "completed" if success else "failed"
|
||||
job["progress_percent"] = 100 if success else _coerce_percent(payload.get("progress_percent"), job.get("progress_percent", 0))
|
||||
job["completed_at"] = _now()
|
||||
job["message"] = str(payload.get("message") or "")
|
||||
if isinstance(payload.get("summary"), dict):
|
||||
@@ -257,6 +278,17 @@ def _parse_time(value: str) -> datetime | None:
|
||||
return None
|
||||
|
||||
|
||||
def _coerce_percent(value: Any, default: Any = 0) -> int:
|
||||
try:
|
||||
number = int(float(value))
|
||||
except (TypeError, ValueError):
|
||||
try:
|
||||
number = int(float(default))
|
||||
except (TypeError, ValueError):
|
||||
number = 0
|
||||
return max(0, min(number, 100))
|
||||
|
||||
|
||||
def _remove_tree(path: Path) -> None:
|
||||
if not path.exists():
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user