Files
FishServer/fish_api/README.md

91 lines
4.5 KiB
Markdown
Raw Normal View History

# Fish API
FastAPI 网关:分块接收 **SVO2**FishMeasure**MP4**FishAction在后台调用现有脚本对外提供文档约定的 **GET** 轮询接口,并托管预览视频 URL。
## 依赖环境
- Python 3.11+uv 可管理 3.13 等版本)
- **FishMeasure**:需与本机 `FishMeasure/` 一致的环境ZED SDK、`pyzed`、CUDA、YOLO/SAM 权重等)
- **FishAction**:需可运行 `FishAction/predict_video_x3d_3class.py`PyTorch、PyTorchVideo、checkpoint
若 FishMeasure 与 FishAction 使用不同虚拟环境,可设置:
- `PYTHON_FISH_MEASURE` — 运行 `predict_weigth_from_svo2.py` 的解释器路径
- `PYTHON_FISH_ACTION` — 运行 `predict_video_x3d_3class.py` 的解释器路径
**单一 Conda 环境**:若 FishMeasure 与 FishAction 已与网关停在同一个 env例如仓库根目录 [`packaging/conda-fishserver.yaml`](../packaging/conda-fishserver.yaml) 定义的 `fishserver`),则**不要**设置上述两个变量,子进程会使用当前 `uvicorn` 的 Python。可用 [`scripts/run_fishserver.sh`](../scripts/run_fishserver.sh) 启动。
## 配置(环境变量)
| 变量 | 说明 | 默认 |
|------|------|------|
| `PUBLIC_BASE_URL` | 返回 JSON 中 `video_left` / `video_right` 的前缀(勿带末尾 `/` | `http://127.0.0.1:8000` |
| `INGEST_API_KEY` | 非空时,`/api/v1/ingest/*` 需请求头 `X-API-Key` | 空(不校验) |
| `STREAM_TMP_DIR` | 分块上传临时目录 | `<repo>/fish_api/.data/ingest` |
| `MEDIA_ROOT` | 对外托管的 `latest_left.mp4` / `latest_right.mp4` | `<repo>/fish_api/.data/media` |
| `FISH_MEASURE_ROOT` | `FishMeasure` 根目录 | 自动相对仓库 |
| `FISH_ACTION_ROOT` | `FishAction` 根目录 | 自动相对仓库 |
| `MEASURE_OUTPUT_ROOT` | 传给 `--save-output` 的目录 | `FishMeasure/output_weight_estimator` |
| `YOLO_MODEL` / `WEIGHT_CHECKPOINT` / `ACTION_CHECKPOINT` | 模型路径 | 与仓库内脚本默认一致 |
| `SAM_DEVICE` | `cuda``cpu` | `cuda` |
| `DEFAULT_FISH_SPECIES` | GET 中 `result[].type` | `大黄鱼` |
可在 `fish_api/.env` 中填写上述变量(`pydantic-settings` 会读取)。
## 安装与启动
```bash
cd fish_api
uv sync
# 可选:包含 httpx便于本地用 FastAPI TestClient 做冒烟测试
# uv sync --group dev
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000
```
OpenAPI`http://127.0.0.1:8000/docs`
## 对外 GET由其它系统轮询
- `GET /api/v1/biomass/real/camera/` — 双目 / 称重结果(最新一次成功快照)
- `GET /api/v1/biomass/health/result/` — 行为 / 健康(最新一次成功快照)
失败时返回 `code: 500``msg` 为错误信息,`data` 为空结构。
## 流式输入(分块上传)
1. `POST /api/v1/ingest/svo/session``POST /api/v1/ingest/mp4/session``session_id`
2. `PUT /api/v1/ingest/{svo|mp4}/session/{session_id}?offset=0`(多次)
- **追加语义**`offset` 必须等于当前已写入字节数(从 0 开始顺序上传)
3. `POST /api/v1/ingest/{svo|mp4}/session/{session_id}/finalize``202 Accepted`,后台开始跑对应算法
示例(小文件一次性,`$API_KEY` 可选):
```bash
BASE=http://127.0.0.1:8000
H=()
# H=(-H "X-API-Key: your-secret")
sid=$(curl -sS "${H[@]}" -X POST "$BASE/api/v1/ingest/svo/session" | jq -r .session_id)
curl -sS "${H[@]}" -T sample.svo2 -X PUT "$BASE/api/v1/ingest/svo/session/$sid?offset=0"
curl -sS "${H[@]}" -X POST "$BASE/api/v1/ingest/svo/session/$sid/finalize"
curl -sS "$BASE/api/v1/biomass/real/camera/"
```
MP4 将 `svo` 换成 `mp4`,本地文件换成 `clip.mp4`,轮询 `GET /api/v1/biomass/health/result/`
**说明**`curl -T` 发送 PUT 时 offset 为 0 且一次性传完整文件适合单块场景;多块时请自行递增 `offset`
## 行为与健康映射
- X3D 输出 `feeding` / `normal` / `scared` → 中文 **吃饵** / **正常游行** / **惊吓**
- 健康:`scared`**不健康**,其余 → **健康**(启发式,可后续换专用模型)
## 视频 URL
FishMeasure 跑完后在输出目录查找 `*preview*.mp4`,复制到 `MEDIA_ROOT/latest_left.mp4``latest_right.mp4`(仅一个文件时左右 URL 可能相同)。确保 `PUBLIC_BASE_URL` 与前端/文档中的域名端口一致(例如 `http://192.168.3.33:8888`另起反向代理时,应把该值配成对外可达的 API 根)。
## 演进建议
- RTSP`ffmpeg` 切段写入 MP4 后调用现有 `finalize` 逻辑
- 任务状态:`finalize` 返回 `job_id`,增加 `GET /jobs/{id}` 查询进度