whole process
This commit is contained in:
@@ -25,7 +25,7 @@ FastAPI 网关:分块接收 **SVO2**(FishMeasure)与 **MP4**(FishAction
|
||||
| `MEDIA_ROOT` | 对外托管每次测量生成的 `*_left.mp4` / `*_right.mp4` | `<repo>/fish_api/.data/media` |
|
||||
| `FISH_MEASURE_ROOT` | `FishMeasure` 根目录 | 自动相对仓库 |
|
||||
| `FISH_ACTION_ROOT` | `FishAction` 根目录 | 自动相对仓库 |
|
||||
| `MEASURE_OUTPUT_ROOT` | 传给 `--save-output` 的目录 | `FishMeasure/output_weight_estimator` |
|
||||
| `MEASURE_OUTPUT_ROOT` | 传给 `--save-output` 的目录 | `<repo>/fish_api/.data/measure_output` |
|
||||
| `YOLO_MODEL` / `WEIGHT_CHECKPOINT` / `ACTION_CHECKPOINT` | 模型路径 | 与仓库内脚本默认一致 |
|
||||
| `SAM_DEVICE` | `cuda` 或 `cpu` | `cuda` |
|
||||
可在 `fish_api/.env` 中填写上述变量(`pydantic-settings` 会读取)。
|
||||
@@ -37,7 +37,8 @@ cd fish_api
|
||||
uv sync
|
||||
# 可选:包含 httpx,便于本地用 FastAPI TestClient 做冒烟测试
|
||||
# uv sync --group dev
|
||||
bash start_fresh.sh # 清空 SQLite / 缓存后启动;保留缓存用 start_no_fresh.sh
|
||||
bash start_fresh.sh # 默认仅重置 client_id 投递进度,保留 SQLite 历史与快照
|
||||
# CLEAR_SQLITE_DATABASE=1 bash start_fresh.sh # 需要时才彻底清 SQLite
|
||||
# 或:uv run uvicorn app.main:app --host 0.0.0.0 --port 8000(需自行 prestart)
|
||||
```
|
||||
|
||||
@@ -85,6 +86,17 @@ MP4 将 `svo` 换成 `mp4`,本地文件换成 `clip.mp4`,轮询 `GET /api/v1
|
||||
|
||||
FishMeasure 跑完后在输出目录查找 `*preview*.mp4`,复制到 `MEDIA_ROOT/`,文件名为 `{UTC时间戳}_{svo_stem}_left.mp4` / `_right.mp4`(每次测量不覆盖;仅一个预览文件时可能左右 URL 指向同一逻辑源经 SBS 拆分)。确保 `PUBLIC_BASE_URL` 与前端/文档中的域名端口一致。
|
||||
|
||||
## Weight Rule (Current)
|
||||
|
||||
最终体重 `pred_weight_g` 由以下规则链决定(按优先级从高到低):
|
||||
|
||||
1. **440g 全池均值保护**(规则 B):若 `avg_g_filtered`(所有 candidates 均值)> `--mean-pool-fallback-max-if-over-g`(默认 440g),则 `pred_weight_g = max_predicted_weight_g_after_filter`,`pred_weight_rule = "max_after_filter_high_mean_pool_over_g"`。
|
||||
2. **400g mean-all fallback**(规则 A,仅 `--average-all-after-filter` 开启时):若全池 mean > `--average-all-fallback-max-if-mean-over-g`(默认 400g),则 `pred_weight_g = max_predicted_weight_g_after_filter`,`pred_weight_rule = "max_after_filter_high_mean_all"`。
|
||||
3. **`--average-all-after-filter`**(默认关):全部 candidates 均值作为最终值,`pred_weight_rule = "mean_all_filtered"`。
|
||||
4. **Top-K 聚合**(默认路径):按 `--top-by-length`(默认开)选 top-K 帧,candidates < 5 用 max 否则用 mean,`pred_weight_rule = "top_k_aggregate"`。
|
||||
|
||||
DGCNN 明细中同时输出 `mean_all_pred_g_after_filters`、`avg_topk_mean_pred_g` 等供对比参考。
|
||||
|
||||
## 演进建议
|
||||
|
||||
- RTSP:用 `ffmpeg` 切段写入 MP4 后调用现有 `finalize` 逻辑
|
||||
|
||||
@@ -750,6 +750,28 @@ def remove_sqlite_database_files(settings: Settings) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def reset_delivery_client_progress(settings: Settings) -> None:
|
||||
"""仅重置客户端投递游标(保留历史快照与 watch 缓存)。"""
|
||||
init_db(settings)
|
||||
conn = _connect(settings.sqlite_path)
|
||||
try:
|
||||
# 清空所有客户端游标,避免沿用旧 client_id 的消费进度。
|
||||
conn.execute("UPDATE delivery_client_cursor SET last_delivered_id = 0")
|
||||
# 确保默认客户端行存在(历史库升级场景)。
|
||||
for kind in ("measure", "health"):
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO delivery_client_cursor (client_id, kind, last_delivered_id)
|
||||
VALUES (?, ?, 0)
|
||||
ON CONFLICT(client_id, kind) DO NOTHING
|
||||
""",
|
||||
(DEFAULT_CLIENT_ID, kind),
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def clear_watch_cache_and_snapshots(settings: Settings) -> None:
|
||||
"""清空 watch 已处理路径与对应快照,便于重新跑推理(与 measure/action_watch 的 use_state_file 开关一致)。"""
|
||||
init_db(settings)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""启动前清空状态:SQLite(客户端数据)、watch 旧 JSON。
|
||||
"""启动前清空状态:默认仅重置客户端游标,保留 SQLite 历史快照。
|
||||
|
||||
由 start_fresh.sh 在 uvicorn 之前调用。
|
||||
- 默认保留 SQLite 历史数据,仅重置 client_id 投递游标(fresh 语义)
|
||||
- 设置 CLEAR_SQLITE_DATABASE=1 可强制清空 SQLite(主库 + wal/shm)
|
||||
- 默认保留 measure_output 以复用中间步骤(点云等)
|
||||
- 设置 CLEAR_MEASURE_OUTPUT=1 清空测量输出目录
|
||||
- 设置 CLEAR_ACTION_OUTPUT=1 清空行为输出目录
|
||||
@@ -11,7 +13,7 @@ from __future__ import annotations
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from app.db import _safe_rm_tree, remove_sqlite_database_files
|
||||
from app.db import _safe_rm_tree, remove_sqlite_database_files, reset_delivery_client_progress
|
||||
from app.settings import get_settings
|
||||
|
||||
|
||||
@@ -29,12 +31,23 @@ def _rm_legacy_json(path: Path | None) -> None:
|
||||
def run_prestart_fresh() -> None:
|
||||
s = get_settings()
|
||||
|
||||
# 始终清空 SQLite(客户端数据)
|
||||
remove_sqlite_database_files(s)
|
||||
print(
|
||||
f"[prestart-fresh] removed SQLite at {s.sqlite_path} (and -wal/-shm if present).",
|
||||
flush=True,
|
||||
clear_sqlite_database = os.environ.get("CLEAR_SQLITE_DATABASE", "").strip() in (
|
||||
"1",
|
||||
"true",
|
||||
"yes",
|
||||
)
|
||||
if clear_sqlite_database:
|
||||
remove_sqlite_database_files(s)
|
||||
print(
|
||||
f"[prestart-fresh] removed SQLite at {s.sqlite_path} (and -wal/-shm if present).",
|
||||
flush=True,
|
||||
)
|
||||
else:
|
||||
reset_delivery_client_progress(s)
|
||||
print(
|
||||
f"[prestart-fresh] kept SQLite history, reset delivery client progress in {s.sqlite_path}.",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
# 检查是否清空中间输出目录(默认保留以复用点云等中间步骤)
|
||||
clear_measure_output = os.environ.get("CLEAR_MEASURE_OUTPUT", "").strip() in ("1", "true", "yes")
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# 清空 SQLite(客户端数据)后启动 Fish API(uvicorn)。
|
||||
# 默认重置 client_id 投递游标后启动 Fish API(uvicorn),保留 SQLite 历史快照。
|
||||
# 默认保留 measure_output 中间步骤(点云等)以加速重新处理。
|
||||
#
|
||||
# bash fish_api/start_fresh.sh
|
||||
# PORT=8001 HOST=0.0.0.0 bash fish_api/start_fresh.sh
|
||||
#
|
||||
# 强制清空 SQLite(谨慎):
|
||||
# CLEAR_SQLITE_DATABASE=1 bash fish_api/start_fresh.sh
|
||||
#
|
||||
# 强制清空中间输出目录(重新生成点云等):
|
||||
# CLEAR_MEASURE_OUTPUT=1 bash fish_api/start_fresh.sh
|
||||
# CLEAR_MEASURE_OUTPUT=1 CLEAR_ACTION_OUTPUT=1 bash fish_api/start_fresh.sh
|
||||
|
||||
Reference in New Issue
Block a user