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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +229 -170
app.py CHANGED
@@ -6,196 +6,252 @@ import random
6
  # 1. Load Model
7
  model = joblib.load('fitness_model.joblib')
8
 
9
- # --- 2. THE INTELLIGENT EXERCISE DATABASE ---
10
- # base_ratio: How much of bodyweight a standard male can lift in this exercise.
11
- # min_level: 0=Beginner, 1=Intermediate, 2=Advanced
12
-
13
- DB = [
14
- # --- CHEST ---
15
- {"name": "Barbell Bench Press", "muscle": "Chest", "type": "Compound", "equip": ["Barbell", "Gym"], "bad_for": ["Shoulder"], "min_level": 1, "base_ratio": 0.8},
16
- {"name": "Dumbbell Chest Press", "muscle": "Chest", "type": "Compound", "equip": ["Dumbbells", "Gym"], "bad_for": [], "min_level": 0, "base_ratio": 0.35}, # Per hand
17
- {"name": "Machine Chest Press", "muscle": "Chest", "type": "Isolation", "equip": ["Gym"], "bad_for": [], "min_level": 0, "base_ratio": 0.6},
18
- {"name": "Incline Dumbbell Press", "muscle": "Chest", "type": "Compound", "equip": ["Dumbbells", "Gym"], "bad_for": ["Shoulder"], "min_level": 1, "base_ratio": 0.3},
19
- {"name": "Cable Crossovers", "muscle": "Chest", "type": "Isolation", "equip": ["Gym"], "bad_for": [], "min_level": 1, "base_ratio": 0.15},
20
- {"name": "Push-ups", "muscle": "Chest", "type": "Compound", "equip": ["Bodyweight"], "bad_for": ["Wrist"], "min_level": 0, "base_ratio": 0},
21
- {"name": "Weighted Dips", "muscle": "Chest", "type": "Compound", "equip": ["Gym", "Bodyweight"], "bad_for": ["Shoulder"], "min_level": 2, "base_ratio": 0},
22
-
23
- # --- BACK ---
24
- {"name": "Deadlift", "muscle": "Back", "type": "Compound", "equip": ["Barbell", "Gym"], "bad_for": ["Back"], "min_level": 2, "base_ratio": 1.2},
25
- {"name": "Lat Pulldown", "muscle": "Back", "type": "Compound", "equip": ["Gym"], "bad_for": [], "min_level": 0, "base_ratio": 0.6},
26
- {"name": "Seated Cable Row", "muscle": "Back", "type": "Isolation", "equip": ["Gym"], "bad_for": ["Back"], "min_level": 0, "base_ratio": 0.6},
27
- {"name": "Barbell Bent Over Row", "muscle": "Back", "type": "Compound", "equip": ["Barbell", "Gym"], "bad_for": ["Back"], "min_level": 2, "base_ratio": 0.7},
28
- {"name": "Single Arm Dumbbell Row", "muscle": "Back", "type": "Isolation", "equip": ["Dumbbells", "Gym"], "bad_for": [], "min_level": 0, "base_ratio": 0.3},
29
- {"name": "Pull-ups", "muscle": "Back", "type": "Compound", "equip": ["Bodyweight", "Gym"], "bad_for": ["Shoulder"], "min_level": 1, "base_ratio": 0},
30
-
31
- # --- LEGS ---
32
- {"name": "Barbell Squat", "muscle": "Legs", "type": "Compound", "equip": ["Barbell", "Gym"], "bad_for": ["Knee", "Back"], "min_level": 2, "base_ratio": 1.0},
33
- {"name": "Leg Press", "muscle": "Legs", "type": "Compound", "equip": ["Gym"], "bad_for": [], "min_level": 0, "base_ratio": 1.5},
34
- {"name": "Goblet Squat", "muscle": "Legs", "type": "Compound", "equip": ["Dumbbells", "Gym"], "bad_for": ["Knee"], "min_level": 0, "base_ratio": 0.3},
35
- {"name": "Walking Lunges", "muscle": "Legs", "type": "Compound", "equip": ["Dumbbells", "Bodyweight"], "bad_for": ["Knee"], "min_level": 1, "base_ratio": 0.15},
36
- {"name": "Leg Extensions", "muscle": "Legs", "type": "Isolation", "equip": ["Gym"], "bad_for": ["Knee"], "min_level": 0, "base_ratio": 0.4},
37
- {"name": "Romanian Deadlift", "muscle": "Legs", "type": "Compound", "equip": ["Barbell", "Dumbbells"], "bad_for": ["Back"], "min_level": 1, "base_ratio": 0.8},
38
- {"name": "Lying Leg Curl", "muscle": "Legs", "type": "Isolation", "equip": ["Gym"], "bad_for": [], "min_level": 0, "base_ratio": 0.3},
39
-
40
- # --- SHOULDERS ---
41
- {"name": "Overhead Barbell Press", "muscle": "Shoulders", "type": "Compound", "equip": ["Barbell", "Gym"], "bad_for": ["Shoulder", "Back"], "min_level": 2, "base_ratio": 0.5},
42
- {"name": "Seated Dumbbell Press", "muscle": "Shoulders", "type": "Compound", "equip": ["Dumbbells", "Gym"], "bad_for": ["Shoulder"], "min_level": 0, "base_ratio": 0.2},
43
- {"name": "Lateral Raises", "muscle": "Shoulders", "type": "Isolation", "equip": ["Dumbbells", "Gym"], "bad_for": [], "min_level": 0, "base_ratio": 0.05}, # Light!
44
- {"name": "Face Pulls", "muscle": "Shoulders", "type": "Isolation", "equip": ["Gym"], "bad_for": [], "min_level": 0, "base_ratio": 0.2},
45
-
46
- # --- ARMS ---
47
- {"name": "Barbell Curl", "muscle": "Arms", "type": "Isolation", "equip": ["Barbell", "Gym"], "bad_for": ["Wrist"], "min_level": 0, "base_ratio": 0.3},
48
- {"name": "Dumbbell Hammer Curl", "muscle": "Arms", "type": "Isolation", "equip": ["Dumbbells", "Gym"], "bad_for": [], "min_level": 0, "base_ratio": 0.15},
49
- {"name": "Tricep Rope Pushdown", "muscle": "Arms", "type": "Isolation", "equip": ["Gym"], "bad_for": [], "min_level": 0, "base_ratio": 0.3},
50
- {"name": "Skullcrushers", "muscle": "Arms", "type": "Isolation", "equip": ["Barbell", "Gym"], "bad_for": ["Elbow"], "min_level": 1, "base_ratio": 0.25},
51
-
52
- # --- CORE ---
53
- {"name": "Plank", "muscle": "Core", "type": "Static", "equip": ["Bodyweight"], "bad_for": [], "min_level": 0, "base_ratio": 0},
54
- {"name": "Cable Woodchoppers", "muscle": "Core", "type": "Isolation", "equip": ["Gym"], "bad_for": ["Back"], "min_level": 1, "base_ratio": 0.3},
55
- {"name": "Hanging Leg Raises", "muscle": "Core", "type": "Isolation", "equip": ["Gym"], "bad_for": ["Shoulder"], "min_level": 2, "base_ratio": 0}
56
- ]
57
-
58
- # --- 3. THE CALCULATOR ENGINE ---
59
-
60
- def calculate_weight(base_ratio, user_weight, gender, experience):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  if base_ratio == 0: return "Bodyweight"
62
 
63
  load = user_weight * base_ratio
64
 
65
- # Adjust for Gender
66
  if gender == "Female": load *= 0.6
 
 
67
 
68
- # Adjust for Experience
69
- if experience == "Beginner": load *= 0.7
70
- elif experience == "Advanced": load *= 1.3
71
-
72
- # Round to nearest 2.5kg (standard plate size)
73
- load = round(load / 2.5) * 2.5
74
-
75
  return f"{int(load)} kg"
76
 
77
- def get_exercises(target_muscle, target_type, user_equip, user_injury, user_level_score):
78
-
79
- # Define Equipment Lists
80
  my_gear = []
81
- if user_equip == "Gym Membership": my_gear = ["Gym", "Barbell", "Dumbbells", "Bodyweight"]
82
- elif user_equip == "Full Home Gym (Rack+Barbell)": my_gear = ["Barbell", "Dumbbells", "Bodyweight"]
83
- elif user_equip == "Home Dumbbells": my_gear = ["Dumbbells", "Bodyweight"]
84
  else: my_gear = ["Bodyweight"]
85
 
86
- candidates = []
 
 
87
 
88
- for ex in DB:
89
- # 1. Muscle Match
90
- if ex["muscle"] != target_muscle: continue
91
-
92
- # 2. Type Match (Compound vs Isolation) - Optional but good for structure
93
- if target_type and ex["type"] != target_type: continue
 
94
 
95
- # 3. Equipment Match
96
- has_gear = False
97
- for gear in ex["equip"]:
98
- if gear in my_gear:
99
- has_gear = True
100
- break
101
- if not has_gear: continue
102
-
103
- # 4. Injury Check
104
- if user_injury in ex["bad_for"]: continue
105
-
106
- # 5. Level Check (Strict)
107
- # Beginner (0) cannot do Advanced (2)
108
- if user_level_score < ex["min_level"]: continue
109
-
110
- candidates.append(ex)
111
-
112
- return candidates
113
-
114
- # --- 4. ROUTINE GENERATOR ---
115
 
116
  def generate_routine(plan_name, age, gender, weight, goal, equipment, injury, experience):
117
 
118
- # A. Parse Level
119
- level_score = 0
120
- if experience == "Intermediate": level_score = 1
121
- if experience == "Advanced": level_score = 2
 
122
 
123
- # B. Define Structure based on AI Plan
124
- # We create slots: (Muscle, Type)
125
  slots = []
126
 
127
  if "Upper" in plan_name or "Push" in plan_name:
128
- slots = [
129
- ("Chest", "Compound"), ("Back", "Compound"),
130
- ("Shoulders", "Compound"), ("Chest", "Isolation"),
131
- ("Back", "Isolation"), ("Arms", "Isolation")
132
- ]
133
  elif "Lower" in plan_name or "Legs" in plan_name:
134
- slots = [
135
- ("Legs", "Compound"), ("Legs", "Compound"), # Two big lifts
136
- ("Legs", "Isolation"), ("Legs", "Isolation"),
137
- ("Core", "Isolation")
138
- ]
139
  else: # Full Body
140
- slots = [
141
- ("Legs", "Compound"), ("Chest", "Compound"),
142
- ("Back", "Compound"), ("Shoulders", "Compound"),
143
- ("Arms", "Isolation"), ("Core", "Static")
144
- ]
145
-
146
- # C. Build Output
147
- text = f"CUSTOM WORKOUT PLAN\n"
148
- text += f"Config: {gender}, {weight}kg, {experience}, {equipment}\n"
149
- text += f"Focus: {goal} | Avoid: {injury}\n"
150
- text += "="*40 + "\n\n"
151
-
152
- # Sets/Reps Logic
153
- sets = "3"
154
- reps = "10"
155
- rest = "60s"
156
- if goal == "Strength": sets="5"; reps="5"; rest="3 min"
157
- if goal == "Muscle Gain": sets="4"; reps="8-12"; rest="90s"
158
- if goal == "Weight Loss": sets="3"; reps="15+"; rest="30s"
159
-
160
- text += f"GLOBAL PROTOCOL: {sets} Sets | {reps} Reps | {rest} Rest\n\n"
161
- text += "EXERCISES:\n"
162
-
163
- used_names = [] # To prevent duplicates
164
-
165
- for i, (muscle, ex_type) in enumerate(slots):
166
- # 1. Get Options
167
- options = get_exercises(muscle, ex_type, equipment, injury, level_score)
168
 
169
- # 2. Fallback if empty (e.g., no compound chest for bodyweight beginner)
170
- if not options:
171
- options = get_exercises(muscle, None, equipment, injury, level_score)
172
-
173
- # 3. Random Selection (Variety!)
174
- if not options:
175
- selected = {"name": f"Generic {muscle} Move", "base_ratio": 0}
176
- else:
177
- # Shuffle and pick one that hasn't been used
178
- random.shuffle(options)
179
- selected = options[0]
180
- for opt in options:
181
- if opt["name"] not in used_names:
182
- selected = opt
183
- break
184
 
185
- used_names.append(selected["name"])
186
 
187
- # 4. Calculate Weight
188
- rec_weight = calculate_weight(selected.get("base_ratio", 0), weight, gender, experience)
189
 
190
- text += f"{i+1}. {selected['name']}\n"
191
- text += f" Target Load: {rec_weight}\n"
192
- text += f" Type: {muscle} {selected.get('type', '')}\n\n"
193
 
 
 
 
 
 
 
 
 
 
 
 
194
  return text
195
 
196
- # 5. WRAPPER
197
  def predict_wrapper(age, gender, weight, height, goal, equipment, injury, experience):
198
- # AI Logic
199
  input_df = pd.DataFrame({
200
  'Age': [age], 'Gender': [gender], 'Weight_kg': [weight],
201
  'Height_cm': [height], 'Goal': [goal], 'Equipment': [equipment],
@@ -203,12 +259,15 @@ def predict_wrapper(age, gender, weight, height, goal, equipment, injury, experi
203
  })
204
  plan_name = model.predict(input_df)[0]
205
 
206
- # Generator Logic
207
  routine = generate_routine(plan_name, age, gender, weight, goal, equipment, injury, experience)
208
 
209
- return routine, f"AI Strategy: Selected '{plan_name}' based on injury profile."
 
 
 
210
 
211
- # 6. LAUNCH
212
  iface = gr.Interface(
213
  fn=predict_wrapper,
214
  inputs=[
@@ -216,18 +275,18 @@ iface = gr.Interface(
216
  gr.Radio(["Male", "Female"], label="Gender", value="Male"),
217
  gr.Number(label="Weight (kg)", value=75),
218
  gr.Number(label="Height (cm)", value=175),
219
- gr.Dropdown(['Weight Loss', 'Muscle Gain', 'Endurance', 'General Health', 'Strength'], label="Goal", value="Muscle Gain"),
220
  gr.Dropdown(['Gym Membership', 'Home Dumbbells', 'Bodyweight Only', 'Full Home Gym (Rack+Barbell)'], label="Equipment", value="Gym Membership"),
221
  gr.Dropdown(['None', 'Knee', 'Back', 'Shoulder', 'Ankle'], label="Injury", value="None"),
222
- gr.Radio(['Beginner', 'Intermediate', 'Advanced'], label="Experience", value="Intermediate")
223
  ],
224
  outputs=[
225
- gr.Textbox(label="Result", lines=20),
226
- gr.Textbox(label="Note")
227
  ],
228
- title="SmartFit AI - Calculator Edition",
229
- description="Generates strict workouts with specific weight recommendations.",
230
  theme="soft"
231
  )
232
 
233
- iface.launch()
 
6
  # 1. Load Model
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
  })
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(
272
  fn=predict_wrapper,
273
  inputs=[
 
275
  gr.Radio(["Male", "Female"], label="Gender", value="Male"),
276
  gr.Number(label="Weight (kg)", value=75),
277
  gr.Number(label="Height (cm)", value=175),
278
+ gr.Dropdown(list(GOAL_CONFIG.keys()), label="Goal", value="Muscle Gain"),
279
  gr.Dropdown(['Gym Membership', 'Home Dumbbells', 'Bodyweight Only', 'Full Home Gym (Rack+Barbell)'], label="Equipment", value="Gym Membership"),
280
  gr.Dropdown(['None', 'Knee', 'Back', 'Shoulder', 'Ankle'], label="Injury", value="None"),
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
 
292
+ iface.launch()