phase 2
This commit is contained in:
@@ -57,6 +57,13 @@ def write_config(update: ConfigUpdate):
|
||||
return _runtime_config
|
||||
|
||||
|
||||
@router.get("/config/profiles")
|
||||
def list_profiles():
|
||||
"""List available detection profiles."""
|
||||
from detect.profiles import _PROFILES
|
||||
return [{"name": name} for name in _PROFILES]
|
||||
|
||||
|
||||
@router.get("/config/stages", response_model=list[StageConfigInfo])
|
||||
def list_stage_configs():
|
||||
"""Return the stage palette with config field metadata for the editor."""
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
"""
|
||||
Pipeline run endpoints.
|
||||
|
||||
POST /detect/run — launch pipeline on selected source
|
||||
POST /detect/stop/{job_id} — cancel a running pipeline
|
||||
POST /detect/clear/{job_id} — clear events from Redis
|
||||
POST /detect/run — launch pipeline on selected source
|
||||
POST /detect/stop/{job_id} — cancel a running pipeline
|
||||
POST /detect/pause/{job_id} — pause after current stage
|
||||
POST /detect/resume/{job_id} — resume a paused pipeline
|
||||
POST /detect/step/{job_id} — run one stage then pause
|
||||
POST /detect/clear/{job_id} — clear events from Redis
|
||||
GET /detect/status/{job_id} — pipeline run status
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -33,6 +37,7 @@ class RunRequest(BaseModel):
|
||||
skip_vlm: bool = False
|
||||
skip_cloud: bool = False
|
||||
log_level: str = "INFO" # INFO | DEBUG
|
||||
pause_after_stage: bool = False
|
||||
|
||||
|
||||
class RunResponse(BaseModel):
|
||||
@@ -92,9 +97,13 @@ def run_pipeline(req: RunRequest):
|
||||
source_asset_id=req.source_asset_id,
|
||||
)
|
||||
|
||||
from detect.graph import PipelineCancelled, set_cancel_check, clear_cancel_check
|
||||
from detect.graph import (
|
||||
PipelineCancelled, set_cancel_check, clear_cancel_check,
|
||||
init_pause, clear_pause,
|
||||
)
|
||||
|
||||
set_cancel_check(job_id, lambda: job_id in _cancelled_jobs)
|
||||
init_pause(job_id, pause_after_stage=req.pause_after_stage)
|
||||
|
||||
def _run():
|
||||
try:
|
||||
@@ -123,6 +132,7 @@ def run_pipeline(req: RunRequest):
|
||||
_running_jobs.pop(job_id, None)
|
||||
_cancelled_jobs.discard(job_id)
|
||||
clear_cancel_check(job_id)
|
||||
clear_pause(job_id)
|
||||
emit.clear_run_context()
|
||||
|
||||
thread = threading.Thread(target=_run, daemon=True, name=f"pipeline-{job_id}")
|
||||
@@ -145,6 +155,75 @@ def stop_pipeline(job_id: str):
|
||||
return {"status": "stopping", "job_id": job_id}
|
||||
|
||||
|
||||
@router.post("/pause/{job_id}")
|
||||
def pause(job_id: str):
|
||||
"""Pause a running pipeline after the current stage completes."""
|
||||
from detect.graph import pause_pipeline
|
||||
|
||||
if job_id not in _running_jobs:
|
||||
raise HTTPException(status_code=404, detail=f"No running pipeline: {job_id}")
|
||||
|
||||
pause_pipeline(job_id)
|
||||
return {"status": "pausing", "job_id": job_id}
|
||||
|
||||
|
||||
@router.post("/resume/{job_id}")
|
||||
def resume(job_id: str):
|
||||
"""Resume a paused pipeline."""
|
||||
from detect.graph import resume_pipeline
|
||||
|
||||
if job_id not in _running_jobs:
|
||||
raise HTTPException(status_code=404, detail=f"No running pipeline: {job_id}")
|
||||
|
||||
resume_pipeline(job_id)
|
||||
return {"status": "running", "job_id": job_id}
|
||||
|
||||
|
||||
@router.post("/step/{job_id}")
|
||||
def step(job_id: str):
|
||||
"""Run one stage then pause again."""
|
||||
from detect.graph import step_pipeline
|
||||
|
||||
if job_id not in _running_jobs:
|
||||
raise HTTPException(status_code=404, detail=f"No running pipeline: {job_id}")
|
||||
|
||||
step_pipeline(job_id)
|
||||
return {"status": "stepping", "job_id": job_id}
|
||||
|
||||
|
||||
@router.post("/pause-after-stage/{job_id}")
|
||||
def toggle_pause_after_stage(job_id: str, enabled: bool = True):
|
||||
"""Toggle pause-after-each-stage mode."""
|
||||
from detect.graph import set_pause_after_stage
|
||||
|
||||
if job_id not in _running_jobs:
|
||||
raise HTTPException(status_code=404, detail=f"No running pipeline: {job_id}")
|
||||
|
||||
set_pause_after_stage(job_id, enabled)
|
||||
return {"status": "ok", "pause_after_stage": enabled, "job_id": job_id}
|
||||
|
||||
|
||||
@router.get("/status/{job_id}")
|
||||
def pipeline_status(job_id: str):
|
||||
"""Get pipeline run status."""
|
||||
from detect.graph import is_paused
|
||||
|
||||
running = job_id in _running_jobs
|
||||
paused = is_paused(job_id)
|
||||
cancelling = job_id in _cancelled_jobs
|
||||
|
||||
if cancelling:
|
||||
status = "cancelling"
|
||||
elif paused:
|
||||
status = "paused"
|
||||
elif running:
|
||||
status = "running"
|
||||
else:
|
||||
status = "idle"
|
||||
|
||||
return {"status": status, "job_id": job_id}
|
||||
|
||||
|
||||
@router.post("/clear/{job_id}")
|
||||
def clear_pipeline(job_id: str):
|
||||
"""Clear events for a job from Redis."""
|
||||
|
||||
Reference in New Issue
Block a user