| """
|
| FormScout headless CLI entrypoint.
|
| Usage: python -m formscout.run sample.mp4
|
| """
|
| from __future__ import annotations
|
|
|
| import sys
|
| import json
|
| from pathlib import Path
|
|
|
| from formscout.pipeline import Director
|
| from formscout.rubric import score_test
|
|
|
|
|
| def main():
|
| if len(sys.argv) < 2:
|
| print("Usage: python -m formscout.run <video_path> [test_name] [side]")
|
| sys.exit(1)
|
|
|
| video_path = sys.argv[1]
|
| test_name = sys.argv[2] if len(sys.argv) > 2 else "deep_squat"
|
| side = sys.argv[3] if len(sys.argv) > 3 else "na"
|
|
|
| print(f"FormScout β processing: {video_path}")
|
| print(f" Test: {test_name}, Side: {side}")
|
| print()
|
|
|
| director = Director()
|
| state = director.run(video_path, test_name=test_name, side=side)
|
|
|
|
|
| if state.errors:
|
| print("ERRORS:")
|
| for e in state.errors:
|
| print(f" β {e}")
|
| print()
|
|
|
| if state.warnings:
|
| print("WARNINGS:")
|
| for w in state.warnings:
|
| print(f" β {w}")
|
| print()
|
|
|
| if state.ingest:
|
| print(f"Ingest: {len(state.ingest.frames)} frames, {state.ingest.fps:.1f}fps, "
|
| f"{state.ingest.duration:.1f}s, {state.ingest.width}x{state.ingest.height}")
|
|
|
| if state.pose2d:
|
| n_detected = sum(1 for kps in state.pose2d.keypoints if kps)
|
| print(f"Pose2D: {n_detected}/{len(state.pose2d.keypoints)} frames with detections, "
|
| f"confidence={state.pose2d.confidence:.2f}")
|
|
|
| if state.body3d:
|
| print(f"Body3D: used={state.body3d.used}")
|
|
|
| if state.features:
|
| print(f"Biomechanics: view={state.features.view}, "
|
| f"confidence={state.features.confidence:.2f}")
|
| if state.features.angles:
|
| print(f" Angles: {json.dumps({k: round(v, 1) for k, v in state.features.angles.items()}, indent=4)}")
|
| if state.features.alignments:
|
| print(f" Alignments: {json.dumps(state.features.alignments, indent=4)}")
|
|
|
|
|
| if state.features and test_name == "deep_squat":
|
| score_result = score_test(state.features)
|
| print(f"\nSCORE: {score_result.score}/3")
|
| print(f" Rationale: {score_result.rationale}")
|
| print(f" Confidence: {score_result.confidence:.2f}")
|
| if score_result.needs_human:
|
| print(" β NEEDS HUMAN REVIEW")
|
|
|
|
|
| if state.judge:
|
| print(f"\nJUDGE: score={state.judge.score}, needs_human={state.judge.needs_human}")
|
| print(f" Rationale: {state.judge.rationale}")
|
| if state.judge.compensation_tags:
|
| print(f" Compensations: {state.judge.compensation_tags}")
|
| if state.judge.corrective_hint:
|
| print(f" Corrective: {state.judge.corrective_hint}")
|
|
|
|
|
| if __name__ == "__main__":
|
| main()
|
|
|