Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files
README.md
CHANGED
|
@@ -10,12 +10,15 @@ tags:
|
|
| 10 |
- openenv
|
| 11 |
---
|
| 12 |
|
| 13 |
-
# FitCoach
|
| 14 |
-
|
|
|
|
| 15 |
|
| 16 |
An OpenEnv-compliant RL environment where an LLM agent plays an **orchestrator** coordinating three deterministic specialist actors to produce integrated fitness + nutrition prescriptions.
|
| 17 |
|
| 18 |
-
**Hackathon Themes:** Multi-Agent Interactions (Theme 1
|
|
|
|
|
|
|
| 19 |
|
| 20 |
## What Makes This Environment Interesting
|
| 21 |
|
|
@@ -25,145 +28,280 @@ The agent does NOT generate fitness plans in isolation. It must:
|
|
| 25 |
2. **Detect conflicts** between actors (e.g., high volume vs low calories, injury vs overload demands)
|
| 26 |
3. **Resolve conflicts** and submit a final integrated plan
|
| 27 |
4. **Handle mid-episode complications** (injuries injected mid-episode, goal changes)
|
| 28 |
-
5. **Adapt to adaptive curriculum**
|
| 29 |
|
| 30 |
The actors are **deterministic rule engines**, not LLMs. The LLM being trained is the orchestrator that manages them.
|
| 31 |
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
| Dimension | What It Measures |
|
| 35 |
|---|---|
|
| 36 |
| `equipment_compliance` | Exercises match available equipment only |
|
| 37 |
-
| `macro_accuracy` | Macros within
|
| 38 |
-
| `volume_appropriateness` | Weekly sets in correct range for fitness level
|
| 39 |
| `progressive_overload` | Correct double-progression applied to exercise history |
|
| 40 |
| `plateau_response` | Adapted volume/calories when plateau detected |
|
| 41 |
| `constraint_respect` | No contraindicated exercises or dietary violations |
|
| 42 |
| `coherence` | Nutrition supports training volume (no high volume + low cal) |
|
| 43 |
| `actor_coordination` | Consulted all actors, plan follows their constraints |
|
| 44 |
|
| 45 |
-
Safety penalty:
|
|
|
|
|
|
|
| 46 |
|
| 47 |
## Tasks
|
| 48 |
|
| 49 |
| Task | Difficulty | Description |
|
| 50 |
|---|---|---|
|
| 51 |
| `week1_plan` | Easy | Fresh beginner, vegetarian, dumbbells only. Consult actors, submit valid plan. |
|
| 52 |
-
| `plateau_adaptation` | Medium | 14-day weight plateau. Actors conflict on adaptation. Knee injury injected mid-episode. |
|
| 53 |
| `conflict_resolution` | Hard | 3 simultaneous challenges: plateau + lower-back injury + goal change. All actors conflict. |
|
| 54 |
-
| `curriculum` | Adaptive | Random clients each episode. Difficulty escalates easy
|
|
|
|
|
|
|
| 55 |
|
| 56 |
-
## Quick Start
|
| 57 |
|
| 58 |
```python
|
|
|
|
| 59 |
from FitCoach import FitcoachAction, FitcoachEnv
|
| 60 |
|
| 61 |
with FitcoachEnv(base_url="http://localhost:8000") as env:
|
|
|
|
| 62 |
result = env.reset()
|
| 63 |
-
print(result.observation.client_profile)
|
| 64 |
-
print(result.observation.complications)
|
| 65 |
|
|
|
|
| 66 |
result = env.step(FitcoachAction(
|
| 67 |
action_type="consult_actor",
|
| 68 |
actor_target="fitness_advisor",
|
| 69 |
))
|
| 70 |
-
print(result.observation.actor_response)
|
| 71 |
|
|
|
|
| 72 |
result = env.step(FitcoachAction(
|
| 73 |
action_type="consult_actor",
|
| 74 |
actor_target="nutrition_advisor",
|
| 75 |
))
|
| 76 |
-
print(result.observation.actor_response)
|
| 77 |
|
|
|
|
| 78 |
result = env.step(FitcoachAction(
|
| 79 |
action_type="consult_actor",
|
| 80 |
actor_target="progress_analyst",
|
| 81 |
))
|
| 82 |
-
print(result.observation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
|
| 84 |
-
import json
|
| 85 |
result = env.step(FitcoachAction(
|
| 86 |
action_type="submit_plan",
|
| 87 |
-
workout_plan=json.dumps(
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
"
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
"daily_targets": {"calories": 2650, "protein_g": 144,
|
| 96 |
-
"carbs_g": 352, "fats_g": 74},
|
| 97 |
-
"meals": [{"meal_name": "Breakfast",
|
| 98 |
-
"foods": ["100g oats", "200ml milk", "1 banana"],
|
| 99 |
-
"calories": 450, "protein_g": 18}],
|
| 100 |
-
}),
|
| 101 |
-
reasoning="Resolved volume-calorie conflict by keeping sets at 14..."
|
| 102 |
))
|
| 103 |
print(f"Reward: {result.reward}")
|
| 104 |
-
print(result.observation.score_breakdown)
|
|
|
|
| 105 |
```
|
| 106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
## Episode Flow
|
| 108 |
|
| 109 |
```
|
| 110 |
-
Reset
|
| 111 |
|
| 112 |
-
consult_actor(fitness_advisor)
|
| 113 |
-
consult_actor(nutrition_advisor)
|
| 114 |
-
consult_actor(progress_analyst)
|
| 115 |
|
| 116 |
-
Conflicts detected between actors (shown in observation)
|
| 117 |
|
| 118 |
submit_plan(workout + nutrition + reasoning)
|
| 119 |
|
| 120 |
-
If score < 0.85: actors REJECT with specific fixes
|
| 121 |
-
If score
|
| 122 |
```
|
| 123 |
|
|
|
|
|
|
|
| 124 |
## Actor Pushback System
|
| 125 |
|
| 126 |
-
After the agent submits a plan, each actor **reviews** it against
|
| 127 |
|
| 128 |
-
- **FitnessAdvisor** checks volume range, equipment, banned exercises
|
| 129 |
-
- **NutritionAdvisor** checks calorie/protein targets, banned foods
|
| 130 |
-
- **ProgressAnalyst** checks plateau adaptation
|
| 131 |
|
| 132 |
If any actor rejects, the episode continues and the agent must revise. This transforms the environment from a passive grader into an **active negotiation arena**.
|
| 133 |
|
|
|
|
|
|
|
| 134 |
## Domain Knowledge
|
| 135 |
|
| 136 |
- **Nutrition**: Grounded in IFCT 2017 (Indian Food Composition Tables, NIN Hyderabad) + USDA FoodData. 30+ foods with verified macros per 100g.
|
| 137 |
-
- **Plateau Detection**: 7-day rolling mean + OLS linear regression. Classifies trend as plateau/on_track/overshooting/reversing.
|
| 138 |
-
- **Progressive Overload**: Double-progression rules
|
| 139 |
- **Injury Safety**: Contraindicated exercise lists per injury type with safe alternatives.
|
| 140 |
|
|
|
|
|
|
|
| 141 |
## Running Locally
|
| 142 |
|
| 143 |
```bash
|
| 144 |
-
|
| 145 |
-
FITCOACH_TASK=
|
|
|
|
|
|
|
|
|
|
| 146 |
```
|
| 147 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
## Project Structure
|
| 149 |
|
| 150 |
```
|
| 151 |
FitCoach/
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
|
|
|
| 168 |
```
|
| 169 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
- openenv
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# FitCoach β Multi-Actor Fitness Orchestrator RL Environment
|
| 14 |
+
|
| 15 |
+
YouTube demo: https://www.youtube.com/watch?v=2GxX_Ie5_7o
|
| 16 |
|
| 17 |
An OpenEnv-compliant RL environment where an LLM agent plays an **orchestrator** coordinating three deterministic specialist actors to produce integrated fitness + nutrition prescriptions.
|
| 18 |
|
| 19 |
+
**Hackathon Themes:** Multi-Agent Interactions (Theme 1 β Halluminate sub-theme) | Professional Tasks (Theme 3.1) | Self-Improvement (Theme 4 β Snorkel AI sub-theme)
|
| 20 |
+
|
| 21 |
+
---
|
| 22 |
|
| 23 |
## What Makes This Environment Interesting
|
| 24 |
|
|
|
|
| 28 |
2. **Detect conflicts** between actors (e.g., high volume vs low calories, injury vs overload demands)
|
| 29 |
3. **Resolve conflicts** and submit a final integrated plan
|
| 30 |
4. **Handle mid-episode complications** (injuries injected mid-episode, goal changes)
|
| 31 |
+
5. **Adapt to adaptive curriculum** β random clients each episode, difficulty escalates with performance
|
| 32 |
|
| 33 |
The actors are **deterministic rule engines**, not LLMs. The LLM being trained is the orchestrator that manages them.
|
| 34 |
|
| 35 |
+
---
|
| 36 |
+
|
| 37 |
+
## Action Schema
|
| 38 |
+
|
| 39 |
+
Every action is a `FitcoachAction` with these fields:
|
| 40 |
+
|
| 41 |
+
| Field | Type | When required | Description |
|
| 42 |
+
|---|---|---|---|
|
| 43 |
+
| `action_type` | str | always | `"consult_actor"` or `"submit_plan"` |
|
| 44 |
+
| `actor_target` | str \| null | when consulting | `"fitness_advisor"`, `"nutrition_advisor"`, or `"progress_analyst"` |
|
| 45 |
+
| `workout_plan` | str (JSON) | when submitting | JSON string of workout structure |
|
| 46 |
+
| `nutrition_plan` | str (JSON) | when submitting | JSON string of nutrition structure |
|
| 47 |
+
| `reasoning` | str \| null | recommended on submit | How conflicts were resolved |
|
| 48 |
+
|
| 49 |
+
> β οΈ Note: `workout_plan` and `nutrition_plan` are JSON **strings**, not nested objects. Use `json.dumps(...)` when constructing them in Python.
|
| 50 |
+
|
| 51 |
+
---
|
| 52 |
+
|
| 53 |
+
## Reward Dimensions (8 total, scored 0β1)
|
| 54 |
|
| 55 |
| Dimension | What It Measures |
|
| 56 |
|---|---|
|
| 57 |
| `equipment_compliance` | Exercises match available equipment only |
|
| 58 |
+
| `macro_accuracy` | Macros within Β±15% of IFCT 2017 formula targets |
|
| 59 |
+
| `volume_appropriateness` | Weekly sets in correct range for fitness level Γ goal |
|
| 60 |
| `progressive_overload` | Correct double-progression applied to exercise history |
|
| 61 |
| `plateau_response` | Adapted volume/calories when plateau detected |
|
| 62 |
| `constraint_respect` | No contraindicated exercises or dietary violations |
|
| 63 |
| `coherence` | Nutrition supports training volume (no high volume + low cal) |
|
| 64 |
| `actor_coordination` | Consulted all actors, plan follows their constraints |
|
| 65 |
|
| 66 |
+
Safety penalty: **β0.3** for any hard constraint violation (injury-banned exercise or dietary violation).
|
| 67 |
+
|
| 68 |
+
---
|
| 69 |
|
| 70 |
## Tasks
|
| 71 |
|
| 72 |
| Task | Difficulty | Description |
|
| 73 |
|---|---|---|
|
| 74 |
| `week1_plan` | Easy | Fresh beginner, vegetarian, dumbbells only. Consult actors, submit valid plan. |
|
| 75 |
+
| `plateau_adaptation` | Medium | 14-day weight plateau. Actors conflict on adaptation. Knee injury injected mid-episode at step 4. |
|
| 76 |
| `conflict_resolution` | Hard | 3 simultaneous challenges: plateau + lower-back injury + goal change. All actors conflict. |
|
| 77 |
+
| `curriculum` | Adaptive | Random clients each episode. Difficulty escalates easy β medium β hard with performance. |
|
| 78 |
+
|
| 79 |
+
---
|
| 80 |
|
| 81 |
+
## Quick Start (Python)
|
| 82 |
|
| 83 |
```python
|
| 84 |
+
import json
|
| 85 |
from FitCoach import FitcoachAction, FitcoachEnv
|
| 86 |
|
| 87 |
with FitcoachEnv(base_url="http://localhost:8000") as env:
|
| 88 |
+
# 1. Reset to start an episode
|
| 89 |
result = env.reset()
|
| 90 |
+
print("Client:", result.observation.client_profile)
|
| 91 |
+
print("Complications:", result.observation.complications)
|
| 92 |
|
| 93 |
+
# 2. Consult fitness_advisor
|
| 94 |
result = env.step(FitcoachAction(
|
| 95 |
action_type="consult_actor",
|
| 96 |
actor_target="fitness_advisor",
|
| 97 |
))
|
| 98 |
+
print("Fitness:", result.observation.actor_response["message"])
|
| 99 |
|
| 100 |
+
# 3. Consult nutrition_advisor
|
| 101 |
result = env.step(FitcoachAction(
|
| 102 |
action_type="consult_actor",
|
| 103 |
actor_target="nutrition_advisor",
|
| 104 |
))
|
| 105 |
+
print("Nutrition:", result.observation.actor_response["message"])
|
| 106 |
|
| 107 |
+
# 4. Consult progress_analyst
|
| 108 |
result = env.step(FitcoachAction(
|
| 109 |
action_type="consult_actor",
|
| 110 |
actor_target="progress_analyst",
|
| 111 |
))
|
| 112 |
+
print("Progress:", result.observation.actor_response["message"])
|
| 113 |
+
print("Conflicts detected:", result.observation.active_conflicts)
|
| 114 |
+
|
| 115 |
+
# 5. Submit final plan (note: workout_plan and nutrition_plan are JSON STRINGS)
|
| 116 |
+
workout = {
|
| 117 |
+
"days": [
|
| 118 |
+
{
|
| 119 |
+
"name": "Day 1 - Upper",
|
| 120 |
+
"focus": "chest, back",
|
| 121 |
+
"exercises": [
|
| 122 |
+
{"name": "Dumbbell Bench Press", "sets": 3, "reps": "8-12",
|
| 123 |
+
"rest_seconds": 90, "weight_kg": 15},
|
| 124 |
+
{"name": "Pull-up", "sets": 3, "reps": "6-10",
|
| 125 |
+
"rest_seconds": 90, "weight_kg": 0},
|
| 126 |
+
],
|
| 127 |
+
},
|
| 128 |
+
{
|
| 129 |
+
"name": "Day 2 - Lower",
|
| 130 |
+
"focus": "legs",
|
| 131 |
+
"exercises": [
|
| 132 |
+
{"name": "Dumbbell Squat", "sets": 3, "reps": "8-12",
|
| 133 |
+
"rest_seconds": 90, "weight_kg": 15},
|
| 134 |
+
{"name": "Dumbbell Romanian Deadlift", "sets": 3, "reps": "10-12",
|
| 135 |
+
"rest_seconds": 90, "weight_kg": 15},
|
| 136 |
+
],
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"name": "Day 3 - Push/Pull",
|
| 140 |
+
"focus": "shoulders, arms",
|
| 141 |
+
"exercises": [
|
| 142 |
+
{"name": "Dumbbell Shoulder Press", "sets": 2, "reps": "8-12",
|
| 143 |
+
"rest_seconds": 90, "weight_kg": 10},
|
| 144 |
+
{"name": "Dumbbell Row", "sets": 2, "reps": "8-12",
|
| 145 |
+
"rest_seconds": 90, "weight_kg": 12},
|
| 146 |
+
],
|
| 147 |
+
},
|
| 148 |
+
],
|
| 149 |
+
"weekly_volume_sets": 16,
|
| 150 |
+
"notes": "16 sets/week β top of beginner muscle-gain range",
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
nutrition = {
|
| 154 |
+
"daily_targets": {
|
| 155 |
+
"calories": 2650, "protein_g": 144, "carbs_g": 352, "fats_g": 74,
|
| 156 |
+
},
|
| 157 |
+
"meals": [
|
| 158 |
+
{"meal_name": "Breakfast",
|
| 159 |
+
"foods": ["100g oats", "200ml milk", "1 banana", "30g whey protein"],
|
| 160 |
+
"calories": 600, "protein_g": 40},
|
| 161 |
+
{"meal_name": "Lunch",
|
| 162 |
+
"foods": ["150g paneer", "100g brown rice", "100g spinach"],
|
| 163 |
+
"calories": 700, "protein_g": 35},
|
| 164 |
+
{"meal_name": "Snack",
|
| 165 |
+
"foods": ["100g rajma", "1 roti", "30g almonds"],
|
| 166 |
+
"calories": 550, "protein_g": 20},
|
| 167 |
+
{"meal_name": "Dinner",
|
| 168 |
+
"foods": ["150g chana", "150g brown rice", "100g curd"],
|
| 169 |
+
"calories": 650, "protein_g": 35},
|
| 170 |
+
],
|
| 171 |
+
}
|
| 172 |
|
|
|
|
| 173 |
result = env.step(FitcoachAction(
|
| 174 |
action_type="submit_plan",
|
| 175 |
+
workout_plan=json.dumps(workout),
|
| 176 |
+
nutrition_plan=json.dumps(nutrition),
|
| 177 |
+
reasoning=(
|
| 178 |
+
"Beginner vegetarian muscle gain. Used dumbbells + pull-up bar only. "
|
| 179 |
+
"16 sets/week = top of beginner range. Calories 2650 = TDEE 2400 + 250 "
|
| 180 |
+
"surplus per nutrition_advisor. Protein 144g = 2.0g/kg. No plateau, "
|
| 181 |
+
"no adaptation needed."
|
| 182 |
+
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
))
|
| 184 |
print(f"Reward: {result.reward}")
|
| 185 |
+
print("Score breakdown:", result.observation.score_breakdown)
|
| 186 |
+
print("Feedback:", result.observation.feedback)
|
| 187 |
```
|
| 188 |
|
| 189 |
+
---
|
| 190 |
+
|
| 191 |
+
## Using the Hugging Face Playground
|
| 192 |
+
|
| 193 |
+
The Space ships with a Gradio playground for manual testing. Here's the exact flow:
|
| 194 |
+
|
| 195 |
+
1. **Press `Reset`** first. The Status box will populate with the client profile.
|
| 196 |
+
2. **Consult each actor** (3 separate Step calls):
|
| 197 |
+
- Set `Action Type = consult_actor`
|
| 198 |
+
- Set `Actor Target = fitness_advisor` (then `nutrition_advisor`, then `progress_analyst`)
|
| 199 |
+
- Leave `Workout Plan`, `Nutrition Plan`, `Reasoning` empty
|
| 200 |
+
- Press `Step`
|
| 201 |
+
3. **Submit your plan**:
|
| 202 |
+
- Set `Action Type = submit_plan`
|
| 203 |
+
- Leave `Actor Target` empty
|
| 204 |
+
- Paste a valid JSON object into `Workout Plan` (e.g., the `workout` dict from above, JSON-serialized)
|
| 205 |
+
- Paste a valid JSON object into `Nutrition Plan`
|
| 206 |
+
- Add `Reasoning` explaining how you used each actor's constraints
|
| 207 |
+
- Press `Step`
|
| 208 |
+
4. Read the `score_breakdown` and `feedback` in the Raw JSON response.
|
| 209 |
+
|
| 210 |
+
Aim for reward **β₯ 0.85** for full actor acceptance. If actors reject, the episode continues and you can revise.
|
| 211 |
+
|
| 212 |
+
---
|
| 213 |
+
|
| 214 |
## Episode Flow
|
| 215 |
|
| 216 |
```
|
| 217 |
+
Reset β Client profile + complications
|
| 218 |
|
| 219 |
+
consult_actor(fitness_advisor) β volume range, equipment, banned exercises
|
| 220 |
+
consult_actor(nutrition_advisor) β macro targets, banned foods, IFCT 2017
|
| 221 |
+
consult_actor(progress_analyst) β plateau status, overload signals
|
| 222 |
|
| 223 |
+
Conflicts detected between actors (shown in observation.active_conflicts)
|
| 224 |
|
| 225 |
submit_plan(workout + nutrition + reasoning)
|
| 226 |
|
| 227 |
+
If score < 0.85: actors REJECT with specific fixes β agent revises
|
| 228 |
+
If score β₯ 0.85: all actors ACCEPT β episode ends
|
| 229 |
```
|
| 230 |
|
| 231 |
+
---
|
| 232 |
+
|
| 233 |
## Actor Pushback System
|
| 234 |
|
| 235 |
+
After the agent submits a plan, each actor **reviews** it against its own constraints:
|
| 236 |
|
| 237 |
+
- **FitnessAdvisor** checks volume range, equipment, banned exercises β suggests equipment swaps
|
| 238 |
+
- **NutritionAdvisor** checks calorie/protein targets, banned foods β suggests IFCT 2017 alternatives
|
| 239 |
+
- **ProgressAnalyst** checks plateau adaptation β requires volume/calorie changes
|
| 240 |
|
| 241 |
If any actor rejects, the episode continues and the agent must revise. This transforms the environment from a passive grader into an **active negotiation arena**.
|
| 242 |
|
| 243 |
+
---
|
| 244 |
+
|
| 245 |
## Domain Knowledge
|
| 246 |
|
| 247 |
- **Nutrition**: Grounded in IFCT 2017 (Indian Food Composition Tables, NIN Hyderabad) + USDA FoodData. 30+ foods with verified macros per 100g.
|
| 248 |
+
- **Plateau Detection**: 7-day rolling mean + OLS linear regression. Classifies trend as `plateau` / `on_track` / `overshooting` / `reversing`.
|
| 249 |
+
- **Progressive Overload**: Double-progression rules β add weight when all sets hit top of rep range, deload on heavy misses.
|
| 250 |
- **Injury Safety**: Contraindicated exercise lists per injury type with safe alternatives.
|
| 251 |
|
| 252 |
+
---
|
| 253 |
+
|
| 254 |
## Running Locally
|
| 255 |
|
| 256 |
```bash
|
| 257 |
+
# Pick a task and start the server
|
| 258 |
+
FITCOACH_TASK=week1_plan uvicorn server.app:app --host 0.0.0.0 --port 8000
|
| 259 |
+
FITCOACH_TASK=plateau_adaptation uvicorn server.app:app --host 0.0.0.0 --port 8000
|
| 260 |
+
FITCOACH_TASK=conflict_resolution uvicorn server.app:app --host 0.0.0.0 --port 8000
|
| 261 |
+
FITCOACH_TASK=curriculum uvicorn server.app:app --host 0.0.0.0 --port 8000
|
| 262 |
```
|
| 263 |
|
| 264 |
+
Then in a separate process, run the orchestrator:
|
| 265 |
+
|
| 266 |
+
```bash
|
| 267 |
+
export API_BASE_URL="https://api.groq.com/openai/v1"
|
| 268 |
+
export API_KEY="gsk_..."
|
| 269 |
+
export MODEL_NAME="llama-3.3-70b-versatile"
|
| 270 |
+
export FITCOACH_TASK="week1_plan"
|
| 271 |
+
python inference.py
|
| 272 |
+
```
|
| 273 |
+
|
| 274 |
+
---
|
| 275 |
+
|
| 276 |
## Project Structure
|
| 277 |
|
| 278 |
```
|
| 279 |
FitCoach/
|
| 280 |
+
βββ models.py # Action/Observation Pydantic models
|
| 281 |
+
βββ client.py # WebSocket client (FitcoachEnv)
|
| 282 |
+
βββ inference.py # Multi-actor orchestrator agent
|
| 283 |
+
βββ test_pushback.py # End-to-end pushback + injury injection test
|
| 284 |
+
βββ openenv.yaml # OpenEnv manifest (4 tasks)
|
| 285 |
+
βββ pyproject.toml
|
| 286 |
+
βββ server/
|
| 287 |
+
β βββ FitCoach_environment.py # Core environment + 8-dimension grader
|
| 288 |
+
β βββ app.py # FastAPI application
|
| 289 |
+
β βββ Dockerfile # Container build
|
| 290 |
+
βββ utils/
|
| 291 |
+
βββ actors.py # 3 deterministic specialist actors
|
| 292 |
+
βββ pushback.py # Actor review + rejection engine
|
| 293 |
+
βββ nutrition.py # IFCT 2017 nutrition database
|
| 294 |
+
βββ plateau.py # Statistical plateau detection
|
| 295 |
+
βββ overload.py # Progressive overload verification
|
| 296 |
+
βββ curriculum.py # Adaptive curriculum manager (Theme 4)
|
| 297 |
```
|
| 298 |
|
| 299 |
+
---
|
| 300 |
+
|
| 301 |
+
## Common Pitfalls
|
| 302 |
+
|
| 303 |
+
- **Forgetting to JSON-encode plans**: `workout_plan` and `nutrition_plan` must be **strings**, not dicts. Use `json.dumps(...)`.
|
| 304 |
+
- **Empty `actor_target` on consult**: server will reject with `"Unknown actor ''"`. Always set it when `action_type="consult_actor"`.
|
| 305 |
+
- **Submitting before consulting**: you can technically do it, but `actor_coordination` will score near 0 because no actor data was used.
|
| 306 |
+
- **Submitting an identical plan twice**: rejected with `"Identical plan submitted twice. Revise based on actor feedback."`
|
| 307 |
+
- **Ignoring `active_conflicts`**: conflicts left unresolved tank the `actor_coordination` score even if other dimensions look fine.
|