coffeine16 commited on
Commit
ede87aa
Β·
verified Β·
1 Parent(s): e64b30c

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +202 -64
README.md CHANGED
@@ -10,12 +10,15 @@ tags:
10
  - openenv
11
  ---
12
 
13
- # FitCoach -- Multi-Actor Fitness Orchestrator RL Environment
14
- Youtube-Video link : https://www.youtube.com/watch?v=2GxX_Ie5_7o
 
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 -- Halluminate sub-theme) | Professional Tasks (Theme 3.1) | Self-Improvement (Theme 4 -- Snorkel AI sub-theme)
 
 
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** -- random clients each episode, difficulty escalates with performance
29
 
30
  The actors are **deterministic rule engines**, not LLMs. The LLM being trained is the orchestrator that manages them.
31
 
32
- ## Reward Dimensions (8 total, scored 0-1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  | Dimension | What It Measures |
35
  |---|---|
36
  | `equipment_compliance` | Exercises match available equipment only |
37
- | `macro_accuracy` | Macros within +/-15% of IFCT 2017 formula targets |
38
- | `volume_appropriateness` | Weekly sets in correct range for fitness level x goal |
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: -0.3 for any hard constraint violation (injury-banned exercise or dietary violation).
 
 
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->medium->hard with performance. |
 
 
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.active_conflicts)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
- import json
85
  result = env.step(FitcoachAction(
86
  action_type="submit_plan",
87
- workout_plan=json.dumps({
88
- "days": [{"name": "Day 1", "focus": "upper", "exercises": [
89
- {"name": "Dumbbell Bench Press", "sets": 3, "reps": "8-12",
90
- "rest_seconds": 90, "weight_kg": 15}
91
- ]}],
92
- "weekly_volume_sets": 14,
93
- }),
94
- nutrition_plan=json.dumps({
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 -> Client profile + complications
111
 
112
- consult_actor(fitness_advisor) -> volume range, equipment, banned exercises
113
- consult_actor(nutrition_advisor) -> macro targets, banned foods, IFCT 2017
114
- consult_actor(progress_analyst) -> plateau status, overload signals
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 -> agent revises
121
- If score >= 0.85: all actors ACCEPT -> episode ends
122
  ```
123
 
 
 
124
  ## Actor Pushback System
125
 
126
- After the agent submits a plan, each actor **reviews** it against their own constraints:
127
 
128
- - **FitnessAdvisor** checks volume range, equipment, banned exercises -> suggests equipment swaps
129
- - **NutritionAdvisor** checks calorie/protein targets, banned foods -> suggests IFCT 2017 alternatives
130
- - **ProgressAnalyst** checks plateau adaptation -> requires volume/calorie changes
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 -- add weight when all sets hit top of rep range, deload on heavy misses.
139
  - **Injury Safety**: Contraindicated exercise lists per injury type with safe alternatives.
140
 
 
 
141
  ## Running Locally
142
 
143
  ```bash
144
- FITCOACH_TASK=week1_plan uvicorn server.app:app --host 0.0.0.0 --port 8000
145
- FITCOACH_TASK=curriculum uvicorn server.app:app --host 0.0.0.0 --port 8000
 
 
 
146
  ```
147
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  ## Project Structure
149
 
150
  ```
151
  FitCoach/
152
- models.py # Action/Observation Pydantic models
153
- client.py # WebSocket client (FitcoachEnv)
154
- inference.py # Multi-actor orchestrator agent
155
- baseline_weak.py # Untrained baseline for comparison
156
- openenv.yaml # OpenEnv manifest (4 tasks)
157
- server/
158
- FitCoach_environment.py # Core environment + 8-dimension grader
159
- app.py # FastAPI application
160
- Dockerfile # Container build
161
- utils/
162
- actors.py # 3 deterministic specialist actors
163
- pushback.py # Actor review + rejection engine
164
- nutrition.py # IFCT 2017 nutrition database
165
- plateau.py # Statistical plateau detection
166
- overload.py # Progressive overload verification
167
- curriculum.py # Adaptive curriculum manager (Theme 4)
 
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.