personai-api

PersonAI API

AI-powered fitness coach backend — real-time biomechanical analysis, rep counting, and form error detection.

The frontend (Next.js) performs pose detection via MediaPipe and streams 33 body keypoints over WebSocket to the backend. The backend focuses exclusively on angle computation, FSM-based state tracking, form error detection, and real-time calorie estimation — a lightweight, separation-of-concerns architecture with zero computer vision dependencies on the server.

English | 繁體中文

Architecture

┌─────────────────────────┐         WebSocket (JSON)         ┌──────────────────────────┐
│        Frontend         │ ──────────────────────────────▶  │        Backend           │
│       (Next.js)         │                                  │     (FastAPI)            │
│                         │  33 keypoints / frame            │                          │
│  Webcam                 │ ◀──────────────────────────────  │  One-Euro Filter         │
│    ↓                    │      Analysis result JSON        │    ↓                     │
│  MediaPipe Pose         │                                  │  Angle calculation       │
│    ↓                    │                                  │    ↓                     │
│  Keypoint extraction    │                                  │  FSM state machine       │
│    ↓                    │                                  │    ↓                     │
│  JSON dispatch          │                                  │  Error detection +       │
│                         │                                  │  calorie tracking        │
└─────────────────────────┘                                  └──────────────────────────┘

Features

  • Real-time motion analysis — frame-by-frame keypoint processing via WebSocket, returning angles, rep counts, and error alerts
  • Finite State Machine (FSM) — precise phase tracking (IDLE → DESCENDING → BOTTOM → ASCENDING) with hysteresis to prevent miscounts
  • Form error detection — squat: knee valgus, excessive forward lean; push-up: hip sagging, hip piking
  • One-Euro Filter — adaptive low-pass smoothing that reduces landmark jitter while maintaining low latency
  • METs calorie estimation — metabolic equivalent-based real-time calorie accumulation by exercise type and body weight
  • InBody body composition — BMI / BMR / lean body mass calculations with Katch-McArdle formula
  • Workout statistics — Pandas-powered grouped reports and daily summaries

Supported Exercises

ExerciseWebSocket PathFSM StatesDetected Errors
Squat/ws/analyze/squatIDLE → DESCENDING → BOTTOM → ASCENDINGKnee valgus, insufficient depth, excessive forward lean
Push-up/ws/analyze/pushupUP → DESCENDING → BOTTOM → ASCENDINGHip sagging, hip piking, insufficient depth

Getting Started

Prerequisites

  • Python >= 3.11

Installation

git clone https://github.com/YinCheng0106/personai-api.git
cd personai-api
pip install -e .

Start Development Server

fastapi dev src/personai_api/main.py

The server starts at http://localhost:8000 by default. Interactive API docs are available at /docs.

API Endpoints

REST API

MethodPathDescription
GET/serverServer health check
GET/user/{user_id}Get user profile with BMI
POST/inbody/{user_id}Save / update InBody body composition data
GET/inbody/{user_id}Get physiological summary (BMI, BMR, LBM)
POST/inbody/{user_id}/caloriesCalculate exercise calorie expenditure
GET/wk/{user_id}Get workout record list
POST/wk/{user_id}/recordSave a workout record
GET/wk/{user_id}/summaryWorkout statistics (grouped by exercise type)
GET/wk/{user_id}/dailyDaily summary (for heatmaps and charts)

User ID format: lowercase u + 3 digits, e.g. u001

WebSocket API

WS /ws/analyze/{exercise_type}?weight_kg=70

Real-time biomechanical analysis. Each connection maintains its own independent FSM state and rep counter.

Query Parameters:

ParameterTypeDefaultDescription
exercise_typestringExercise type: squat or pushup
weight_kgfloat70.0User body weight (kg) for calorie calculation

Request — Keypoints Frame:

{
"keypoints": [
{ "x": 0.5, "y": 0.3, "z": 0.0, "visibility": 0.99 },
{ "x": 0.6, "y": 0.4, "z": 0.0, "visibility": 0.95 }
],
"timestamp": 1234567890.123
}

The keypoints array must contain all 33 MediaPipe Pose landmarks. timestamp is optional.

Response — Analysis Result:

{
"rep_count": 5,
"state": "descending",
"angles": {
"left_knee": 95.2,
"right_knee": 97.8,
"left_hip": 85.1,
"right_hip": 86.3
},
"errors": ["膝蓋內扣:請將膝蓋對齊腳尖方向"],
"confidence": 0.85,
"is_visible": true,
"calories": 12.5
}

Control Command — Reset Counter:

{ "action": "reset" }

Response: { "action": "reset", "status": "ok" }

Project Structure

src/personai_api/
├── main.py                             # FastAPI app entrypoint
├── __about__.py                        # Version number
├── models/
│   ├── biomechanics_schema.py          # WebSocket I/O schemas
│   ├── inbody_schema.py                # InBody physiological data schemas
│   ├── server_schema.py                # Server status schema
│   ├── user_schema.py                  # User schema
│   └── workout_schema.py              # Workout record schemas
├── routers/
│   ├── analyze.py                      # WebSocket real-time analysis endpoint
│   ├── inbody.py                       # InBody physiological data API
│   ├── server.py                       # Server health check
│   ├── user.py                         # User profile API
│   └── workout.py                      # Workout record API
└── services/
    ├── biomechanics.py                 # Angle calculation, filters, FSM
    └── inbody.py                       # BMR/BMI calculation, METs calories, Pandas reports

Core Algorithms

One-Euro Filter

An adaptive low-pass filter based on Casiez et al. (CHI 2012). It applies strong smoothing when signals change slowly (reducing jitter) and reduces smoothing when signals change rapidly (reducing latency). Each landmark's x and y coordinates have their own filter instance (33 landmarks x 2 = 66 filters).

FSM (Finite State Machine)

Hysteresis thresholds prevent state oscillation, ensuring accurate rep counting:

Squat:   IDLE ──knee<155°──▶ DESCENDING ──knee≤100°──▶ BOTTOM ──knee>105°──▶ ASCENDING ──knee≥160°──▶ IDLE (+1 rep)
Push-up: UP ──elbow<155°──▶ DESCENDING ──elbow≤90°──▶ BOTTOM ──elbow>95°──▶ ASCENDING ──elbow≥160°──▶ UP (+1 rep)

METs Calorie Calculation

Calories (kcal) = METs × Weight (kg) × Duration (hr)
ExerciseLightModerateVigorous
Squat3.55.08.0
Push-up3.85.58.0

Source: Ainsworth BE, et al. "Compendium of Physical Activities" (2011)

Development

# Type checking
hatch run types:check

# Run tests
hatch run pytest

# Run a specific test
hatch run pytest tests/test_specific.py::test_name

Tech Stack

TechnologyPurpose
FastAPIAsync web framework + WebSocket
PydanticData validation and serialization
NumPyVector angle calculation and matrix operations
PandasWorkout data statistical reports
HatchBuild system and environment management

License

MIT License

簡介

AI 智慧健身教練後端服務 — 即時生物力學分析、動作計數與姿勢錯誤偵測

主題

fastapifitness

版本

無版本資料

語言

Python100.0 %
© 2026 YinCheng. 版權所有.