Files
FishServer/fish_api/app/routers/biomass.py
2026-04-10 18:16:15 +08:00

124 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import Optional
from fastapi import APIRouter, Depends, Header, Query
from starlette.responses import JSONResponse
from app.db import normalize_client_id, pop_next_health, pop_next_measure
from app.settings import Settings, get_settings
router = APIRouter(prefix="/api/v1/biomass", tags=["biomass"])
# 是否有新快照被本次 GET 消费1/0body 保持与客户端约定字段一致,不写入 has_new。
HEADER_BIOMASS_NEW = "X-Fish-Biomass-New"
def _new_headers(has_new: bool) -> dict[str, str]:
return {HEADER_BIOMASS_NEW: "1" if has_new else "0"}
def _resolve_client_id(
x_fish_client_id: Optional[str] = Header(None, alias="X-Fish-Client-Id"),
client_id: Optional[str] = Query(
None,
description="客户端标识;与请求头 X-Fish-Client-Id 二选一(优先头)。未带时共用 default 游标",
),
) -> str:
if x_fish_client_id is not None and str(x_fish_client_id).strip():
return normalize_client_id(x_fish_client_id)
if client_id is not None and str(client_id).strip():
return normalize_client_id(client_id)
return normalize_client_id(None)
@router.get("/real/camera/")
async def get_real_camera(
settings: Settings = Depends(get_settings),
client_id: str = Depends(_resolve_client_id),
):
"""双目实时结果:每次 GET 投递该客户端下一条未消费的 FishMeasure 快照(按 client_id 独立游标)。"""
m, has_new, _ = pop_next_measure(settings, client_id)
if not has_new:
return JSONResponse(
content={
"code": 200,
"msg": "成功",
"data": {
"result": [],
"video_left": "",
"video_right": "",
},
},
headers=_new_headers(False),
)
if m.error:
return JSONResponse(
content={
"code": 500,
"msg": m.error,
"data": {
"result": [],
"video_left": "",
"video_right": "",
},
},
headers=_new_headers(True),
)
return JSONResponse(
content={
"code": 200,
"msg": "成功",
"data": {
"result": m.result,
"video_left": m.video_left,
"video_right": m.video_right,
},
},
headers=_new_headers(True),
)
@router.get("/health/result/")
async def get_health_result(
settings: Settings = Depends(get_settings),
client_id: str = Depends(_resolve_client_id),
):
"""行为 / 健康结果:每次 GET 投递该客户端下一条未消费的 FishAction 快照(按 client_id 独立游标)。"""
h, has_new, _ = pop_next_health(settings, client_id)
if not has_new:
return JSONResponse(
content={
"code": 200,
"msg": "成功",
"data": {
"behavior_result": "",
"health_result": "",
},
},
headers=_new_headers(False),
)
if h.error:
return JSONResponse(
content={
"code": 500,
"msg": h.error,
"data": {
"behavior_result": "",
"health_result": "",
},
},
headers=_new_headers(True),
)
return JSONResponse(
content={
"code": 200,
"msg": "成功",
"data": {
"behavior_result": h.behavior_result,
"health_result": h.health_result,
},
},
headers=_new_headers(True),
)