fitscript-env / README.md
coffeine16's picture
clean initial commit
0446283
---
title: FitScript Environment Server
emoji: πŸ‹οΈ
colorFrom: blue
colorTo: green
sdk: docker
pinned: false
app_port: 8000
base_path: /web
tags:
- openenv
---
# FitScript Environment
## Environment Description
FitScript is an **AI fitness prescription environment** built on the OpenEnv framework. It simulates the real-world task of generating, evaluating, and refining personalized workout plans β€” work typically performed by personal trainers, physiotherapists, and sports coaches.
Given a structured client profile (age, fitness level, goal, available equipment, injuries, days available), an agent must produce a JSON workout plan that satisfies evidence-based exercise-science criteria. The environment grades each submitted plan deterministically and provides step-by-step feedback so the agent can iterate and improve.
## Motivation
Fitness prescription is a genuine, commercially valuable human-expert task with several properties that make it ideal for RL benchmark training:
- **Objective grading** β€” exercise science has deterministic rules: volume, frequency, contraindications, and progression targets are verifiable without human labelers.
- **Natural difficulty gradient** β€” tasks range from simple beginner plans to complex periodized powerlifting programs.
- **Safety constraints** β€” contraindicated exercises for injured clients introduce hard safety penalties, training agents to respect real-world constraints.
- **Dense reward signal** β€” partial scores at every step prevent sparse-reward pathology.
## Action Space
Each step the agent submits a `FitscriptAction`:
| Field | Type | Description |
|-------|------|-------------|
| `action_type` | `str` | One of `"generate_plan"`, `"modify_plan"`, `"explain_exercise"` |
| `plan` | `str` | JSON string of the structured workout plan (exercises, sets, reps, rest) |
| `reasoning` | `str \| None` | Optional agent justification for the plan choices |
**Plan JSON schema (basic / injury tasks):**
```json
{
"days": [
{
"name": "Day 1 - Lower Body",
"focus": "legs",
"exercises": [
{"name": "Squat", "sets": 3, "reps": 10, "rest_seconds": 60}
]
}
]
}
```
**Plan JSON schema (periodized program task):**
```json
{
"weeks": [
{
"week": 1,
"intensity": 72.5,
"total_sets": 80,
"days": [
{
"name": "Day 1 - Squat",
"exercises": [
{"name": "Back Squat", "sets": 5, "reps": 5, "intensity_pct": 72.5}
]
}
]
}
]
}
```
## Observation Space
Each step returns a `FitscriptObservation`:
| Field | Type | Description |
|-------|------|-------------|
| `client_profile` | `dict` | Age, fitness level, goal, equipment, injuries, days/week |
| `feedback` | `str` | Human-readable grader feedback on the submitted plan |
| `score_breakdown` | `dict[str, float]` | Per-criterion partial scores |
| `task_id` | `str` | Active task identifier |
| `step_count` | `int` | Current step within the episode |
| `done` | `bool` | `True` when task complete or max steps reached |
| `reward` | `float` | Step reward in `[0.0, 1.0]` |
## Task Descriptions
### Task 1 β€” EASY: Basic Plan Generation (`basic_plan`)
**Client:** 35-year-old beginner, no injuries, 3 days/week, home, no equipment.
**Grader criteria (0.25 each):**
1. Plan contains exactly 3 workout days.
2. All exercises are bodyweight-only (no equipment required).
3. Each day has 4–8 exercises with `sets` and `reps` defined.
4. Beginner-appropriate: reps ≀ 15, no advanced movements (muscle-ups, pistol squats, etc.).
**Score formula:** `(criteria_met / 4)` β†’ `[0.0, 1.0]`
**Episode ends:** plan submitted OR after 3 steps.
---
### Task 2 β€” MEDIUM: Injury-Safe Plan Modification (`injury_safe_modification`)
**Client:** 30-year-old intermediate, lower-back injury, pre-generated plan contains back squats, deadlifts, and bent-over rows.
**Grader criteria (0.25 each):**
1. Deadlifts removed or replaced (Romanian deadlift / leg press / hip thrust).
2. Back squats replaced (goblet squat / wall sit / leg press).
3. Bent-over rows replaced (seated cable row / machine row).
4. Plan retains same muscle-group targets despite modifications.
**Score formula:** `(criteria_met / 4)` β†’ `[0.0, 1.0]`
**Episode ends:** modification submitted OR after 5 steps.
---
### Task 3 β€” HARD: Periodized 4-Week Program (`periodized_program`)
**Client:** 27-year-old advanced powerlifter, 5 days/week, full gym, competition in 5 weeks, weak points: upper back and lockout strength.
**Grader criteria (0.2 each):**
1. 4 distinct weeks, each with 5 training days.
2. Weeks 1–3 show progressive overload (increasing intensity/RPE).
3. Week 4 is a deload: volume reduced β‰₯ 40% vs week 3.
4. Competition lifts (squat, bench, deadlift) present as primary movements.
5. Bonus: accessory work targets weak points (upper back, lockout).
**Score formula:** `min(1.0, criteria_met * 0.2)` β†’ `[0.0, 1.0]`
**Episode ends:** full 4-week program submitted OR after 8 steps.
---
## Reward Design
- **Per-step reward:** `max(0.0, partial_score βˆ’ safety_penalty)`
- **Safety penalty:** βˆ’0.3 if contraindicated exercises are present for an injured client.
- **Empty plan:** reward = 0.0.
- **Duplicate plan:** reward = 0.0 (no improvement penalty).
- All rewards are clamped to `[0.0, 1.0]`.
## Setup Instructions
### Build the Docker image
```bash
docker build -t FitScript-env:latest -f server/Dockerfile .
```
### Run locally
```bash
uvicorn server.app:app --reload --host 0.0.0.0 --port 8000
```
### Run inference
```bash
export API_BASE_URL=https://api.openai.com/v1
export MODEL_NAME=gpt-4o
export HF_TOKEN=<your_key>
export FITSCRIPT_TASK=basic_plan # or injury_safe_modification / periodized_program
python inference.py
```
### Deploy to Hugging Face Spaces
```bash
# From the directory containing openenv.yaml
openenv push
# With options
openenv push --repo-id my-org/fitscript-env --private
```
The deployed space exposes:
- **Web Interface** at `/web`
- **API Docs** at `/docs`
- **Health Check** at `/health`
- **WebSocket** at `/ws`
### Pre-submission validation
```bash
bash validate.sh <HF_SPACE_URL> <REPO_DIR>
# Step 1: POST /reset returns HTTP 200
# Step 2: docker build succeeds
# Step 3: openenv validate passes
```
## Baseline Scores
> Run `python inference.py` for each task and record the `[END] score=...` line.
| Task | Difficulty | Baseline Score | Model |
|------|-----------|---------------|-------|
| `basic_plan` | Easy | _TBD_ | _fill before submission_ |
| `injury_safe_modification` | Medium | _TBD_ | _fill before submission_ |
| `periodized_program` | Hard | _TBD_ | _fill before submission_ |
## Project Structure
```
FitScript/
β”œβ”€β”€ inference.py # ← Hackathon entry point (REQUIRED)
β”œβ”€β”€ openenv.yaml # OpenEnv manifest with tasks section
β”œβ”€β”€ pyproject.toml # Project metadata and dependencies
β”œβ”€β”€ __init__.py # Module exports
β”œβ”€β”€ client.py # FitscriptEnv client
β”œβ”€β”€ models.py # FitscriptAction and FitscriptObservation
└── server/
β”œβ”€β”€ __init__.py # Server module exports
β”œβ”€β”€ FitScript_environment.py # Core environment + 3 task graders
β”œβ”€β”€ app.py # FastAPI application (HTTP + WebSocket)
└── Dockerfile # Multi-stage container definition
```