cli to control zed camera start and stop. 2. measure now use every svo2 file for 1 fish, give intermideate result and final result with confidecne level(*).
This commit is contained in:
125
fish_api/app/routers/zed.py
Normal file
125
fish_api/app/routers/zed.py
Normal file
@@ -0,0 +1,125 @@
|
||||
"""ZED 分段录制 HTTP 控制(响应格式对齐 biomass:code/msg/data;不校验 ingest API Key)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from fastapi import APIRouter, Body, Depends
|
||||
from pydantic import BaseModel, Field
|
||||
from starlette.responses import JSONResponse
|
||||
|
||||
from app.services.zed_recording_control import (
|
||||
start_zed_recording,
|
||||
stop_zed_recording,
|
||||
zed_recording_is_running,
|
||||
)
|
||||
from app.settings import Settings, get_settings
|
||||
from app.state import app_state
|
||||
|
||||
router = APIRouter(prefix="/api/v1/zed/recording", tags=["zed-recording"])
|
||||
|
||||
|
||||
def _ok(data: Dict[str, Any], msg: str = "成功") -> JSONResponse:
|
||||
return JSONResponse(
|
||||
content={
|
||||
"code": 200,
|
||||
"msg": msg,
|
||||
"data": data,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _err(
|
||||
http_status: int,
|
||||
*,
|
||||
code: int,
|
||||
msg: str,
|
||||
data: Optional[Dict[str, Any]] = None,
|
||||
) -> JSONResponse:
|
||||
body: Dict[str, Any] = {"code": code, "msg": msg}
|
||||
if data is not None:
|
||||
body["data"] = data
|
||||
return JSONResponse(status_code=http_status, content=body)
|
||||
|
||||
|
||||
class ZedRecordingStartRequest(BaseModel):
|
||||
"""可选覆盖分段时长;``fish_id`` 由服务端每次启动在库中递增分配。"""
|
||||
|
||||
segment_sec: Optional[float] = Field(
|
||||
None,
|
||||
ge=1.0,
|
||||
description="每段时长(秒);缺省使用 ZED_SVO_SEGMENT_SEC",
|
||||
)
|
||||
|
||||
|
||||
@router.get("/status")
|
||||
async def zed_recording_status() -> JSONResponse:
|
||||
data: Dict[str, Any] = {"running": zed_recording_is_running()}
|
||||
if app_state.zed_recording_fish_id is not None:
|
||||
data["fish_id"] = app_state.zed_recording_fish_id
|
||||
return _ok(data)
|
||||
|
||||
|
||||
@router.post("/start")
|
||||
async def zed_recording_start(
|
||||
body: ZedRecordingStartRequest = Body(default_factory=ZedRecordingStartRequest),
|
||||
settings: Settings = Depends(get_settings),
|
||||
) -> JSONResponse:
|
||||
ok, msg, fish_id, _ = start_zed_recording(
|
||||
settings,
|
||||
segment_sec=body.segment_sec,
|
||||
)
|
||||
if not ok:
|
||||
if msg == "already_running":
|
||||
return _err(
|
||||
409,
|
||||
code=409,
|
||||
msg="已在录制中",
|
||||
data={"ok": False, "message": "已在录制中"},
|
||||
)
|
||||
if msg.startswith("session_db_error:"):
|
||||
return _err(
|
||||
500,
|
||||
code=500,
|
||||
msg="写入录制会话失败",
|
||||
data={"ok": False, "message": msg},
|
||||
)
|
||||
return _err(
|
||||
500,
|
||||
code=500,
|
||||
msg="启动录制失败",
|
||||
data={"ok": False, "message": msg},
|
||||
)
|
||||
|
||||
return _ok(
|
||||
{
|
||||
"ok": True,
|
||||
"message": "录制开始",
|
||||
"fish_id": fish_id,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@router.post("/stop")
|
||||
async def zed_recording_stop(settings: Settings = Depends(get_settings)) -> JSONResponse:
|
||||
ok, msg, fish_id = stop_zed_recording(settings)
|
||||
if not ok:
|
||||
if msg == "not_running":
|
||||
return _ok({"ok": False, "message": "未在录制"}, msg="未在录制")
|
||||
if msg == "stop_timeout":
|
||||
return _err(
|
||||
504,
|
||||
code=504,
|
||||
msg="停止超时",
|
||||
data={"ok": False, "message": "停止超时"},
|
||||
)
|
||||
return _err(
|
||||
500,
|
||||
code=500,
|
||||
msg="停止录制失败",
|
||||
data={"ok": False, "message": msg},
|
||||
)
|
||||
out: Dict[str, Any] = {"ok": True, "message": "录制停止"}
|
||||
if fish_id is not None:
|
||||
out["fish_id"] = fish_id
|
||||
return _ok(out)
|
||||
Reference in New Issue
Block a user