Files
FishServer/fish_api/README.md
2026-04-08 19:32:23 +08:00

91 lines
4.5 KiB
Markdown
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.
# 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}` 查询进度