Files
FishServer/fish_api/app/measure_debug_cli.py

128 lines
4.3 KiB
Python
Raw Permalink 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.
"""CLI对单条 fish 跑 FishMeasure 子进程(不写 SQLite、不发布 /media
使用 ``run_measure_batch_subprocess``(合并点云)。线上 ``measure_watch`` 为逐段 ``run_full_measure``,齐套后再 aggregate final。
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from typing import Any, Dict, List
from app.services.measure import run_measure_batch_subprocess
from app.settings import get_settings
def _sorted_svo2_in_folder(folder: Path) -> List[Path]:
"""与 measure_watch.iter_svo2_folders 中单目录内 .svo2 列表一致(按文件名排序)。"""
return sorted(
[p for p in folder.iterdir() if p.is_file() and p.suffix.lower() == ".svo2"],
key=lambda p: p.name,
)
def _print_weight_summary(output_root: Path) -> None:
combined = output_root / "weight_prediction.json"
if not combined.is_file():
print(f"[measure-debug] no combined file: {combined}", file=sys.stderr)
return
try:
with open(combined, encoding="utf-8") as f:
data: Dict[str, Any] = json.load(f)
except (OSError, json.JSONDecodeError) as e:
print(f"[measure-debug] failed to read {combined}: {e}", file=sys.stderr)
return
summary = data.get("dgcnn_summary") or data.get("weight_summary") or {}
pred_g = data.get("pred_weight_g")
rule = data.get("pred_weight_rule")
print("[measure-debug] --- weight_prediction.json (summary) ---")
if pred_g is not None:
print(f" pred_weight_g: {pred_g}")
if rule is not None:
print(f" pred_weight_rule: {rule}")
if summary:
top_k = summary.get("top_k")
tbl = summary.get("top_by_length")
print(f" dgcnn_summary.top_k: {top_k}")
print(f" dgcnn_summary.top_by_length: {tbl}")
mean_all = data.get("mean_all_pred_g_after_filters")
if mean_all is not None:
print(f" mean_all_pred_g_after_filters: {mean_all}")
def main() -> None:
parser = argparse.ArgumentParser(
description="Run FishMeasure for one fish folder (same subprocess as fish_api)."
)
parser.add_argument(
"--fish-id",
default="1",
help='Fish id used for output dir measure_output/fish{N} (default: 1).',
)
parser.add_argument(
"--batch-folder",
type=Path,
default=None,
help="Folder containing .svo2 files (overrides MEASURE_WATCH_DIR/fish{N}).",
)
parser.add_argument(
"--watch-dir",
type=Path,
default=None,
help="Override MEASURE_WATCH_DIR when resolving fish{N}/ (ignored if --batch-folder is set).",
)
parser.add_argument(
"--output-root",
type=Path,
default=None,
help="Override save-output directory (default: MEASURE_OUTPUT_ROOT/fish{N}).",
)
args = parser.parse_args()
settings = get_settings()
fish_id = str(args.fish_id).strip() or "1"
if args.batch_folder is not None:
batch_folder = args.batch_folder.expanduser().resolve()
else:
watch = args.watch_dir if args.watch_dir is not None else settings.measure_watch_dir
if watch is None:
print(
"未配置输入目录:请设置 --batch-folder或在 .env 中设置 MEASURE_WATCH_DIR",
file=sys.stderr,
)
raise SystemExit(2)
watch = watch.expanduser().resolve()
batch_folder = watch / f"fish{fish_id}"
if not batch_folder.is_dir():
print(f"不是目录或不存在: {batch_folder}", file=sys.stderr)
raise SystemExit(2)
svo_paths = _sorted_svo2_in_folder(batch_folder)
if not svo_paths:
print(f"目录下无 .svo2 文件: {batch_folder}", file=sys.stderr)
raise SystemExit(2)
if args.output_root is not None:
out_root = args.output_root.expanduser().resolve()
else:
out_root = settings.measure_output_root / f"fish{fish_id}"
out_root.mkdir(parents=True, exist_ok=True)
print(f"[measure-debug] batch_folder={batch_folder}")
print(f"[measure-debug] output_root={out_root}")
print(f"[measure-debug] {len(svo_paths)} SVO(s): {', '.join(p.name for p in svo_paths)}")
run_measure_batch_subprocess(svo_paths, settings, output_root=out_root)
_print_weight_summary(out_root)
print("[measure-debug] done.")
if __name__ == "__main__":
main()