Tomertg commited on
Commit
55b5c0f
·
verified ·
1 Parent(s): f430353

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -147
app.py CHANGED
@@ -7,251 +7,204 @@ import random
7
  model = joblib.load('fitness_model.joblib')
8
 
9
  # ==========================================
10
- # CONFIG DICTIONARIES (THE BRAIN)
11
  # ==========================================
12
 
13
- # 1. GOAL CONFIGURATION
14
- # Defines the structure (slots), sets, reps, and specific instructions per goal.
15
  GOAL_CONFIG = {
16
- "Strength": {
17
- "sets": 5, "reps": "3-5", "rest": "3-5 min",
18
- "intensity": "85-90% 1RM",
19
- "structure_modifier": "Focus on Compound Lifts",
20
- "finisher": "Core Static Hold"
21
- },
22
- "Muscle Gain": {
23
- "sets": 3, "reps": "8-12", "rest": "60-90 sec",
24
- "intensity": "70-80% 1RM",
25
- "structure_modifier": "Mix of Compound and Isolation",
26
- "finisher": "Pump Work (High Reps)"
27
- },
28
- "Weight Loss": {
29
- "sets": 3, "reps": "15-20", "rest": "30-45 sec",
30
- "intensity": "60% 1RM",
31
- "structure_modifier": "Circuit Style (Minimal Rest)",
32
- "finisher": "High Intensity Interval (HIIT)"
33
- },
34
- "Endurance": {
35
- "sets": 2, "reps": "20+", "rest": "30 sec",
36
- "intensity": "50% 1RM",
37
- "structure_modifier": "High Volume",
38
- "finisher": "Steady State Cardio"
39
- },
40
- "General Health": {
41
- "sets": 3, "reps": "12-15", "rest": "60 sec",
42
- "intensity": "Moderate",
43
- "structure_modifier": "Balanced Full Body",
44
- "finisher": "Mobility Flow"
45
- }
46
  }
47
 
48
- # 2. AGE CONFIGURATION
49
- # Adjusts warmup and safety parameters based on age groups.
50
- AGE_CONFIG = {
51
- "Young (18-35)": {"warmup": "5 min", "rest_mod": 0, "type": "Standard"},
52
- "Middle (36-55)": {"warmup": "8 min", "rest_mod": 15, "type": "Joint Prep Focus"},
53
- "Senior (56+)": {"warmup": "12 min", "rest_mod": 30, "type": "Low Impact & Stability"}
54
- }
55
-
56
- # 3. LEVEL CONFIGURATION
57
- # Defines which difficulty tier (0-2) a user can access.
58
  LEVEL_CONFIG = {
59
- "Beginner": {"tier": 0, "complexity": "Low (Machines/Stable)"},
60
- "Intermediate": {"tier": 1, "complexity": "Medium (Free Weights)"},
61
- "Advanced": {"tier": 2, "complexity": "High (Complex/Explosive)"}
62
  }
63
 
64
- # 4. EXERCISE DATABASE (Categorized)
65
- # Level 0 = Easy/Safe, Level 1 = Medium, Level 2 = Hard
66
  EXERCISE_DB = {
67
  "Chest": [
68
- {"name": "Machine Chest Press", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.6},
69
- {"name": "Push-ups (Knees)", "equip": ["Bodyweight"], "bad": ["Wrist"], "level": 0, "ratio": 0},
70
- {"name": "Push-ups (Regular)", "equip": ["Bodyweight"], "bad": ["Wrist"], "level": 1, "ratio": 0},
71
- {"name": "Dumbbell Bench Press", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.35},
72
  {"name": "Barbell Bench Press", "equip": ["Barbell", "Gym"], "bad": ["Shoulder"], "level": 1, "ratio": 0.9},
 
73
  {"name": "Incline Dumbbell Press", "equip": ["Dumbbells", "Gym"], "bad": ["Shoulder"], "level": 1, "ratio": 0.3},
 
 
 
 
74
  {"name": "Weighted Dips", "equip": ["Gym"], "bad": ["Shoulder"], "level": 2, "ratio": 0},
75
- {"name": "Cable Flys", "equip": ["Gym"], "bad": [], "level": 1, "ratio": 0.2},
76
  ],
77
  "Back": [
 
78
  {"name": "Lat Pulldown", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.6},
79
  {"name": "Seated Cable Row", "equip": ["Gym"], "bad": ["Back"], "level": 0, "ratio": 0.6},
80
- {"name": "Chest Supported Row", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.5},
81
  {"name": "Single Arm Dumbbell Row", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.3},
82
  {"name": "Pull-ups", "equip": ["Bodyweight", "Gym"], "bad": ["Shoulder"], "level": 1, "ratio": 0},
83
- {"name": "Deadlift", "equip": ["Barbell", "Gym"], "bad": ["Back"], "level": 2, "ratio": 1.4},
84
- {"name": "Barbell Row", "equip": ["Barbell", "Gym"], "bad": ["Back"], "level": 1, "ratio": 0.8},
85
  {"name": "Inverted Row", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0},
86
  ],
87
  "Legs": [
88
- {"name": "Bodyweight Squats", "equip": ["Bodyweight"], "bad": ["Knee"], "level": 0, "ratio": 0},
89
- {"name": "Goblet Squat", "equip": ["Dumbbells", "Gym"], "bad": ["Knee"], "level": 0, "ratio": 0.4},
90
  {"name": "Leg Press", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 1.8},
91
- {"name": "Lunge Walk", "equip": ["Bodyweight", "Dumbbells"], "bad": ["Knee"], "level": 1, "ratio": 0},
92
- {"name": "Bulgarian Split Squat", "equip": ["Dumbbells", "Bodyweight"], "bad": ["Knee"], "level": 2, "ratio": 0.2},
93
- {"name": "Barbell Back Squat", "equip": ["Barbell", "Gym"], "bad": ["Back", "Knee"], "level": 2, "ratio": 1.2},
94
- {"name": "Romanian Deadlift", "equip": ["Barbell", "Dumbbells"], "bad": ["Back"], "level": 1, "ratio": 0.9},
95
- {"name": "Leg Curls", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.4},
 
96
  {"name": "Glute Bridges", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0},
97
  ],
98
  "Shoulders": [
 
99
  {"name": "Seated Dumbbell Press", "equip": ["Dumbbells", "Gym"], "bad": ["Shoulder"], "level": 0, "ratio": 0.25},
100
- {"name": "Lateral Raises", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.1},
101
  {"name": "Face Pulls", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.2},
102
- {"name": "Overhead Barbell Press", "equip": ["Barbell", "Gym"], "bad": ["Shoulder", "Back"], "level": 2, "ratio": 0.5},
103
- {"name": "Pike Pushups", "equip": ["Bodyweight"], "bad": ["Shoulder"], "level": 1, "ratio": 0},
104
  ],
105
  "Arms": [
106
- {"name": "Dumbbell Curls", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.15},
107
- {"name": "Tricep Pushdowns", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.3},
108
  {"name": "Barbell Curls", "equip": ["Barbell", "Gym"], "bad": ["Wrist"], "level": 0, "ratio": 0.25},
 
 
109
  {"name": "Skullcrushers", "equip": ["Barbell", "Dumbbells"], "bad": ["Elbow"], "level": 1, "ratio": 0.2},
110
- {"name": "Bench Dips", "equip": ["Bodyweight"], "bad": ["Shoulder"], "level": 0, "ratio": 0},
111
  ],
112
  "Core": [
113
  {"name": "Plank", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0},
114
- {"name": "Dead Bug", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0},
115
- {"name": "Hanging Leg Raises", "equip": ["Gym"], "bad": ["Shoulder"], "level": 2, "ratio": 0},
116
  {"name": "Cable Woodchoppers", "equip": ["Gym"], "bad": ["Back"], "level": 1, "ratio": 0.3},
 
 
117
  ],
118
  "Cardio": [
119
- {"name": "Walking", "equip": ["Bodyweight", "Gym"], "bad": [], "level": 0, "ratio": 0},
120
  {"name": "Elliptical", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0},
121
  {"name": "Burpees", "equip": ["Bodyweight"], "bad": ["Back", "Knee"], "level": 2, "ratio": 0},
122
- {"name": "Sprints", "equip": ["Bodyweight"], "bad": ["Knee"], "level": 1, "ratio": 0},
123
  ]
124
  }
125
 
126
  # ==========================================
127
- # LOGIC ENGINE
128
  # ==========================================
129
 
130
- def get_age_group(age):
131
- if age <= 35: return "Young (18-35)"
132
- if age <= 55: return "Middle (36-55)"
133
- return "Senior (56+)"
134
-
135
- def calculate_weight(base_ratio, user_weight, gender, level_tier):
136
  if base_ratio == 0: return "Bodyweight"
137
 
138
  load = user_weight * base_ratio
139
 
140
- # Adjustments
141
- if gender == "Female": load *= 0.6
142
- if level_tier == 0: load *= 0.6 # Beginner
143
- if level_tier == 2: load *= 1.3 # Advanced
144
-
145
- # Rounding
146
- load = 2.5 * round(load / 2.5)
147
- return f"{int(load)} kg"
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
  def get_exercises(muscle, equipment, injury, level_tier, count=1):
150
- # 1. Define Equipment List
151
  my_gear = []
152
  if equipment == "Gym Membership": my_gear = ["Gym", "Barbell", "Dumbbells", "Bodyweight"]
153
  elif equipment == "Full Home Gym (Rack+Barbell)": my_gear = ["Barbell", "Dumbbells", "Bodyweight"]
154
  elif equipment == "Home Dumbbells": my_gear = ["Dumbbells", "Bodyweight"]
155
  else: my_gear = ["Bodyweight"]
156
 
157
- # 2. Filter Pool
158
  pool = EXERCISE_DB.get(muscle, [])
159
  valid = []
160
 
161
  for ex in pool:
162
- # Equip check
163
  if not any(g in my_gear for g in ex["equip"]): continue
164
- # Injury check
165
  if injury in ex["bad"]: continue
166
- # Level check (User Tier must be >= Exercise Level)
167
  if level_tier < ex["level"]: continue
168
 
169
  valid.append(ex)
170
 
171
- # 3. Shuffle for Variety
172
  random.shuffle(valid)
173
 
174
- # 4. Return
175
- if not valid:
176
- return [{"name": f"Standard {muscle} Move", "ratio": 0}]
177
  return valid[:count]
178
 
179
  def generate_routine(plan_name, age, gender, weight, goal, equipment, injury, experience):
180
 
181
- # --- STEP 1: RESOLVE CONFIGS ---
182
  goal_settings = GOAL_CONFIG[goal]
183
- level_settings = LEVEL_CONFIG[experience]
184
- age_group = get_age_group(age)
185
- age_settings = AGE_CONFIG[age_group]
186
 
187
- # --- STEP 2: BUILD STRUCTURE BASED ON PLAN ---
188
- # This determines WHICH muscles we hit
189
  slots = []
190
-
191
  if "Upper" in plan_name or "Push" in plan_name:
192
- slots = ["Chest", "Back", "Shoulders", "Chest", "Back", "Arms"]
193
- routine_name = "Upper Body Focus"
194
  elif "Lower" in plan_name or "Legs" in plan_name:
195
- slots = ["Legs", "Legs", "Legs", "Core", "Core", "Cardio"]
196
- routine_name = "Lower Body Focus"
197
- else: # Full Body
198
- slots = ["Legs", "Chest", "Back", "Shoulders", "Legs", "Core"]
199
- routine_name = "Full Body Mix"
200
 
201
- # --- STEP 3: GENERATE TEXT ---
202
- text = f"WORKOUT PLAN: {routine_name}\n"
203
  text += f"User: {age}y | {gender} | {weight}kg | {experience}\n"
204
- text += f"Config: {goal} ({goal_settings['intensity']}) | Equip: {equipment}\n"
205
- text += "="*45 + "\n\n"
206
 
207
- # Warmup
208
- text += f"WARM-UP ({age_settings['warmup']}):\n"
209
- text += f"Type: {age_settings['type']}\n"
210
- if injury == "Knee": text += "- Avoid high impact jumping.\n"
211
- text += "- 3 mins Light Cardio\n- Dynamic Stretching\n\n"
212
 
213
- # Main Block
214
  text += f"MAIN WORKOUT:\n"
215
- text += f"Sets: {goal_settings['sets']} | Reps: {goal_settings['reps']}\n"
216
- text += f"Rest: {goal_settings['rest']}\n\n"
217
 
218
  used_names = []
219
 
220
  for i, muscle in enumerate(slots):
221
- # Fetch 1 exercise, exclude used ones if possible
222
- candidates = get_exercises(muscle, equipment, injury, level_settings['tier'], count=5)
223
 
 
224
  selected = candidates[0]
225
- # Try to find one not used yet
226
  for cand in candidates:
227
  if cand['name'] not in used_names:
228
  selected = cand
229
  break
230
-
231
  used_names.append(selected['name'])
232
 
233
- # Calc Weight
234
- load = calculate_weight(selected['ratio'], weight, gender, level_settings['tier'])
235
 
236
  text += f"{i+1}. {selected['name']} ({muscle})\n"
237
- text += f" Load: {load}\n\n"
238
 
239
- # Finisher
240
  text += f"FINISHER:\n"
241
- text += f"Style: {goal_settings['finisher']}\n"
242
-
243
  if goal in ["Weight Loss", "Endurance"]:
244
- cardio = get_exercises("Cardio", equipment, injury, level_settings['tier'])[0]
245
- text += f"Activity: {cardio['name']} - 5 mins burnout"
246
  else:
247
- core = get_exercises("Core", equipment, injury, level_settings['tier'])[0]
248
- text += f"Activity: {core['name']} - 3 sets to failure"
249
 
250
  return text
251
 
252
  # 6. WRAPPER
253
  def predict_wrapper(age, gender, weight, height, goal, equipment, injury, experience):
254
- # AI Prediction
255
  input_df = pd.DataFrame({
256
  'Age': [age], 'Gender': [gender], 'Weight_kg': [weight],
257
  'Height_cm': [height], 'Goal': [goal], 'Equipment': [equipment],
@@ -259,13 +212,9 @@ def predict_wrapper(age, gender, weight, height, goal, equipment, injury, experi
259
  })
260
  plan_name = model.predict(input_df)[0]
261
 
262
- # Logic Generation
263
  routine = generate_routine(plan_name, age, gender, weight, goal, equipment, injury, experience)
264
 
265
- info = f"AI Strategy: {plan_name}\n"
266
- info += f"Adjusted for {experience} level and {goal} goal."
267
-
268
- return routine, info
269
 
270
  # 7. LAUNCH
271
  iface = gr.Interface(
@@ -281,11 +230,11 @@ iface = gr.Interface(
281
  gr.Dropdown(list(LEVEL_CONFIG.keys()), label="Experience", value="Intermediate")
282
  ],
283
  outputs=[
284
- gr.Textbox(label="Result", lines=22),
285
- gr.Textbox(label="System Note")
286
  ],
287
- title="SmartFit AI - Matrix Edition",
288
- description="Fully modular workout engine controlled by strict Logic Dictionaries.",
289
  theme="soft"
290
  )
291
 
 
7
  model = joblib.load('fitness_model.joblib')
8
 
9
  # ==========================================
10
+ # CONFIG DICTIONARIES
11
  # ==========================================
12
 
 
 
13
  GOAL_CONFIG = {
14
+ "Strength": {"sets": 5, "reps": "3-5", "rest": "3 min", "intensity": "Heavy"},
15
+ "Muscle Gain": {"sets": 3, "reps": "8-12", "rest": "90 sec", "intensity": "Moderate"},
16
+ "Weight Loss": {"sets": 4, "reps": "15-20", "rest": "45 sec", "intensity": "High Tempo"},
17
+ "Endurance": {"sets": 2, "reps": "20-25", "rest": "30 sec", "intensity": "Light"},
18
+ "General Health": {"sets": 3, "reps": "12-15", "rest": "60 sec", "intensity": "Moderate"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  }
20
 
 
 
 
 
 
 
 
 
 
 
21
  LEVEL_CONFIG = {
22
+ "Beginner": {"tier": 0},
23
+ "Intermediate": {"tier": 1},
24
+ "Advanced": {"tier": 2}
25
  }
26
 
27
+ # EXERCISE DATABASE with Base Strength Ratios
28
+ # Ratio 1.0 means an intermediate male can lift 100% of his bodyweight in this exercise.
29
  EXERCISE_DB = {
30
  "Chest": [
 
 
 
 
31
  {"name": "Barbell Bench Press", "equip": ["Barbell", "Gym"], "bad": ["Shoulder"], "level": 1, "ratio": 0.9},
32
+ {"name": "Dumbbell Chest Press", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.35},
33
  {"name": "Incline Dumbbell Press", "equip": ["Dumbbells", "Gym"], "bad": ["Shoulder"], "level": 1, "ratio": 0.3},
34
+ {"name": "Machine Chest Press", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.6},
35
+ {"name": "Push-ups", "equip": ["Bodyweight"], "bad": ["Wrist"], "level": 0, "ratio": 0},
36
+ {"name": "Cable Flys", "equip": ["Gym"], "bad": [], "level": 1, "ratio": 0.15},
37
+ {"name": "Dumbbell Flys", "equip": ["Dumbbells"], "bad": ["Shoulder"], "level": 0, "ratio": 0.12},
38
  {"name": "Weighted Dips", "equip": ["Gym"], "bad": ["Shoulder"], "level": 2, "ratio": 0},
 
39
  ],
40
  "Back": [
41
+ {"name": "Deadlift", "equip": ["Barbell", "Gym"], "bad": ["Back"], "level": 2, "ratio": 1.4},
42
  {"name": "Lat Pulldown", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.6},
43
  {"name": "Seated Cable Row", "equip": ["Gym"], "bad": ["Back"], "level": 0, "ratio": 0.6},
44
+ {"name": "Barbell Bent Over Row", "equip": ["Barbell", "Gym"], "bad": ["Back"], "level": 1, "ratio": 0.7},
45
  {"name": "Single Arm Dumbbell Row", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.3},
46
  {"name": "Pull-ups", "equip": ["Bodyweight", "Gym"], "bad": ["Shoulder"], "level": 1, "ratio": 0},
47
+ {"name": "Chest Supported Row", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.5},
 
48
  {"name": "Inverted Row", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0},
49
  ],
50
  "Legs": [
51
+ {"name": "Barbell Squat", "equip": ["Barbell", "Gym"], "bad": ["Back", "Knee"], "level": 2, "ratio": 1.1},
 
52
  {"name": "Leg Press", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 1.8},
53
+ {"name": "Goblet Squat", "equip": ["Dumbbells", "Gym"], "bad": ["Knee"], "level": 0, "ratio": 0.4},
54
+ {"name": "Walking Lunges", "equip": ["Dumbbells", "Bodyweight"], "bad": ["Knee"], "level": 1, "ratio": 0.15},
55
+ {"name": "Romanian Deadlift", "equip": ["Barbell", "Dumbbells"], "bad": ["Back"], "level": 1, "ratio": 0.8},
56
+ {"name": "Lying Leg Curl", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.35},
57
+ {"name": "Leg Extensions", "equip": ["Gym"], "bad": ["Knee"], "level": 0, "ratio": 0.35},
58
+ {"name": "Bulgarian Split Squat", "equip": ["Dumbbells"], "bad": ["Knee"], "level": 2, "ratio": 0.2},
59
  {"name": "Glute Bridges", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0},
60
  ],
61
  "Shoulders": [
62
+ {"name": "Overhead Barbell Press", "equip": ["Barbell", "Gym"], "bad": ["Shoulder", "Back"], "level": 2, "ratio": 0.5},
63
  {"name": "Seated Dumbbell Press", "equip": ["Dumbbells", "Gym"], "bad": ["Shoulder"], "level": 0, "ratio": 0.25},
64
+ {"name": "Lateral Raises", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.08},
65
  {"name": "Face Pulls", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.2},
66
+ {"name": "Front Raises", "equip": ["Dumbbells"], "bad": [], "level": 0, "ratio": 0.08},
 
67
  ],
68
  "Arms": [
 
 
69
  {"name": "Barbell Curls", "equip": ["Barbell", "Gym"], "bad": ["Wrist"], "level": 0, "ratio": 0.25},
70
+ {"name": "Dumbbell Hammer Curls", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.12},
71
+ {"name": "Tricep Rope Pushdown", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.25},
72
  {"name": "Skullcrushers", "equip": ["Barbell", "Dumbbells"], "bad": ["Elbow"], "level": 1, "ratio": 0.2},
73
+ {"name": "Dips", "equip": ["Bodyweight"], "bad": ["Shoulder"], "level": 1, "ratio": 0},
74
  ],
75
  "Core": [
76
  {"name": "Plank", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0},
 
 
77
  {"name": "Cable Woodchoppers", "equip": ["Gym"], "bad": ["Back"], "level": 1, "ratio": 0.3},
78
+ {"name": "Russian Twists", "equip": ["Bodyweight"], "bad": ["Back"], "level": 0, "ratio": 0},
79
+ {"name": "Hanging Leg Raises", "equip": ["Gym"], "bad": ["Shoulder"], "level": 2, "ratio": 0},
80
  ],
81
  "Cardio": [
82
+ {"name": "Treadmill Run", "equip": ["Gym"], "bad": ["Knee"], "level": 0, "ratio": 0},
83
  {"name": "Elliptical", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0},
84
  {"name": "Burpees", "equip": ["Bodyweight"], "bad": ["Back", "Knee"], "level": 2, "ratio": 0},
85
+ {"name": "Jump Rope", "equip": ["Bodyweight"], "bad": ["Knee", "Ankle"], "level": 1, "ratio": 0},
86
  ]
87
  }
88
 
89
  # ==========================================
90
+ # LOGIC ENGINE (CALCULATOR)
91
  # ==========================================
92
 
93
+ def calculate_weight(base_ratio, user_weight, gender, level_tier, muscle_group):
94
+ """
95
+ Calculates precise weight based on Gender Physiology.
96
+ """
 
 
97
  if base_ratio == 0: return "Bodyweight"
98
 
99
  load = user_weight * base_ratio
100
 
101
+ # 1. Gender Adjustment (The Science)
102
+ if gender == "Female":
103
+ # Women are relatively stronger in lower body than upper body
104
+ if muscle_group in ["Legs", "Core"]:
105
+ load *= 0.75 # Stronger legs
106
+ else:
107
+ load *= 0.55 # Weaker upper body push/pull relative to men
108
+
109
+ # 2. Level Adjustment
110
+ if level_tier == 0: load *= 0.6 # Beginner
111
+ if level_tier == 2: load *= 1.3 # Advanced
112
+
113
+ # 3. Smart Rounding
114
+ # Round to nearest 2.5kg (plate size) or 1kg (dumbbell size)
115
+ if load < 10:
116
+ final_load = round(load)
117
+ else:
118
+ final_load = 2.5 * round(load / 2.5)
119
+
120
+ return f"{int(final_load)} kg"
121
 
122
  def get_exercises(muscle, equipment, injury, level_tier, count=1):
123
+ # Filter available gear
124
  my_gear = []
125
  if equipment == "Gym Membership": my_gear = ["Gym", "Barbell", "Dumbbells", "Bodyweight"]
126
  elif equipment == "Full Home Gym (Rack+Barbell)": my_gear = ["Barbell", "Dumbbells", "Bodyweight"]
127
  elif equipment == "Home Dumbbells": my_gear = ["Dumbbells", "Bodyweight"]
128
  else: my_gear = ["Bodyweight"]
129
 
 
130
  pool = EXERCISE_DB.get(muscle, [])
131
  valid = []
132
 
133
  for ex in pool:
134
+ # Filter Logic
135
  if not any(g in my_gear for g in ex["equip"]): continue
 
136
  if injury in ex["bad"]: continue
 
137
  if level_tier < ex["level"]: continue
138
 
139
  valid.append(ex)
140
 
141
+ # SHUFFLE to ensure variety every time
142
  random.shuffle(valid)
143
 
144
+ if not valid: return [{"name": f"Standard {muscle} Move", "ratio": 0}]
 
 
145
  return valid[:count]
146
 
147
  def generate_routine(plan_name, age, gender, weight, goal, equipment, injury, experience):
148
 
149
+ # Configs
150
  goal_settings = GOAL_CONFIG[goal]
151
+ level_tier = LEVEL_CONFIG[experience]["tier"]
 
 
152
 
153
+ # Structure based on Plan Category
 
154
  slots = []
 
155
  if "Upper" in plan_name or "Push" in plan_name:
156
+ slots = ["Chest", "Back", "Shoulders", "Arms", "Core"]
157
+ title = "Upper Body Focus"
158
  elif "Lower" in plan_name or "Legs" in plan_name:
159
+ slots = ["Legs", "Legs", "Legs", "Core", "Cardio"]
160
+ title = "Lower Body Focus"
161
+ else:
162
+ slots = ["Legs", "Chest", "Back", "Shoulders", "Core"]
163
+ title = "Full Body Mix"
164
 
165
+ # Build Text
166
+ text = f"WORKOUT PLAN: {title}\n"
167
  text += f"User: {age}y | {gender} | {weight}kg | {experience}\n"
168
+ text += f"Goal: {goal} | Equip: {equipment}\n"
169
+ text += "="*40 + "\n\n"
170
 
171
+ text += f"WARM-UP (5-8 mins):\n"
172
+ if injury == "Knee": text += "- Arm Circles & Torso Twists\n- Glute Bridges\n\n"
173
+ else: text += "- Jumping Jacks\n- Dynamic Stretching\n\n"
 
 
174
 
 
175
  text += f"MAIN WORKOUT:\n"
176
+ text += f"Sets: {goal_settings['sets']} | Reps: {goal_settings['reps']} | Rest: {goal_settings['rest']}\n\n"
 
177
 
178
  used_names = []
179
 
180
  for i, muscle in enumerate(slots):
181
+ # Fetch exercise
182
+ candidates = get_exercises(muscle, equipment, injury, level_tier, count=3)
183
 
184
+ # Pick unique
185
  selected = candidates[0]
 
186
  for cand in candidates:
187
  if cand['name'] not in used_names:
188
  selected = cand
189
  break
 
190
  used_names.append(selected['name'])
191
 
192
+ # Calculate Load
193
+ load = calculate_weight(selected['ratio'], weight, gender, level_tier, muscle)
194
 
195
  text += f"{i+1}. {selected['name']} ({muscle})\n"
196
+ text += f" Rec. Load: {load}\n\n"
197
 
 
198
  text += f"FINISHER:\n"
 
 
199
  if goal in ["Weight Loss", "Endurance"]:
200
+ text += "HIIT: 30s Work / 30s Rest (5 Rounds)"
 
201
  else:
202
+ text += "Core Stability: 3 Sets to Failure"
 
203
 
204
  return text
205
 
206
  # 6. WRAPPER
207
  def predict_wrapper(age, gender, weight, height, goal, equipment, injury, experience):
 
208
  input_df = pd.DataFrame({
209
  'Age': [age], 'Gender': [gender], 'Weight_kg': [weight],
210
  'Height_cm': [height], 'Goal': [goal], 'Equipment': [equipment],
 
212
  })
213
  plan_name = model.predict(input_df)[0]
214
 
 
215
  routine = generate_routine(plan_name, age, gender, weight, goal, equipment, injury, experience)
216
 
217
+ return routine, f"AI Strategy: {plan_name}"
 
 
 
218
 
219
  # 7. LAUNCH
220
  iface = gr.Interface(
 
230
  gr.Dropdown(list(LEVEL_CONFIG.keys()), label="Experience", value="Intermediate")
231
  ],
232
  outputs=[
233
+ gr.Textbox(label="Generated Workout", lines=20),
234
+ gr.Textbox(label="AI Note")
235
  ],
236
+ title="SmartFit AI - Biological Engine",
237
+ description="Advanced generator with gender-specific strength standards.",
238
  theme="soft"
239
  )
240