Tomertg commited on
Commit
a78d19b
·
verified ·
1 Parent(s): 92cf4ac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +221 -190
app.py CHANGED
@@ -3,219 +3,250 @@ import joblib
3
  import pandas as pd
4
  import random
5
 
6
- # 1. Load Model (The "Brain" trained on Synthetic Data)
7
  model = joblib.load('fitness_model.joblib')
8
 
9
- # --- 2. MASSIVE EXERCISE LIBRARY ---
10
- # Format: "Name": (Target, [Bad For], Min_Age, Max_BMI, Equipment_Needed)
11
- # BMI > 30 means obese, Age > 60 means senior.
12
-
13
- exercise_db = {
14
- "Legs": [
15
- ("Barbell Squat", ["Quads"], ["Back", "Knee"], 0, 30, "Rack"),
16
- ("Leg Press", ["Quads"], [], 0, 40, "Machine"),
17
- ("Goblet Squat", ["Quads"], ["Knee"], 0, 35, "Dumbbells"),
18
- ("Bodyweight Squat", ["Quads"], [], 0, 50, "Bodyweight"),
19
- ("Box Squat", ["Quads"], [], 50, 40, "Bodyweight"), # Good for seniors
20
- ("Romanian Deadlift", ["Hamstrings"], ["Back"], 0, 30, "Barbell"),
21
- ("Dumbbell RDL", ["Hamstrings"], ["Back"], 0, 35, "Dumbbells"),
22
- ("Lying Leg Curl", ["Hamstrings"], [], 0, 45, "Machine"),
23
- ("Glute Bridge", ["Glutes"], [], 0, 50, "Bodyweight"), # Safe for everyone
24
- ("Walking Lunges", ["Glutes"], ["Knee", "Ankle"], 0, 30, "Bodyweight"),
25
- ("Bulgarian Split Squat", ["Quads"], ["Knee", "Ankle"], 0, 28, "Dumbbells") # Hard!
26
- ],
27
- "Push": [
28
- ("Barbell Bench Press", ["Chest"], ["Shoulder"], 0, 35, "Rack"),
29
- ("Dumbbell Floor Press", ["Chest"], [], 0, 40, "Dumbbells"), # Shoulder safe
30
- ("Push-ups", ["Chest"], ["Shoulder"], 0, 32, "Bodyweight"),
31
- ("Knee Push-ups", ["Chest"], [], 0, 50, "Bodyweight"),
32
- ("Overhead Press (Barbell)", ["Shoulders"], ["Shoulder", "Back"], 0, 30, "Barbell"),
33
- ("Seated Dumbbell Press", ["Shoulders"], [], 0, 40, "Dumbbells"),
34
- ("Lateral Raises", ["Shoulders"], [], 0, 45, "Dumbbells"),
35
- ("Tricep Dips", ["Triceps"], ["Shoulder"], 0, 28, "Bodyweight"),
36
- ("Tricep Cable Pushdown", ["Triceps"], [], 0, 45, "Machine")
37
- ],
38
- "Pull": [
39
- ("Pull-ups", ["Back"], ["Shoulder"], 0, 28, "Bodyweight"), # Hard for heavy users
40
- ("Lat Pulldowns", ["Back"], [], 0, 50, "Machine"),
41
- ("Barbell Row", ["Back"], ["Back"], 0, 30, "Barbell"),
42
- ("Chest Supported Row", ["Back"], [], 0, 45, "Machine"), # Back safe
43
- ("Single Arm Dumbbell Row", ["Back"], [], 0, 40, "Dumbbells"),
44
- ("Face Pulls", ["Rear Delts"], [], 0, 50, "Machine"),
45
- ("Bicep Curls", ["Biceps"], [], 0, 50, "Dumbbells")
46
- ],
47
- "Core": [
48
- ("Plank", ["Abs"], [], 0, 40, "Bodyweight"),
49
- ("Hanging Leg Raises", ["Abs"], ["Shoulder"], 0, 28, "Barbell"),
50
- ("Dead Bug", ["Abs"], [], 0, 50, "Bodyweight"), # Back safe
51
- ("Russian Twists", ["Abs"], ["Back"], 0, 35, "Bodyweight"),
52
- ("Bird-Dog", ["Abs"], [], 0, 60, "Bodyweight")
53
- ],
54
- "Cardio": [
55
- ("Sprints", ["Cardio"], ["Knee", "Back", "Ankle"], 0, 28, "Bodyweight"),
56
- ("Treadmill Jog", ["Cardio"], ["Knee", "Ankle"], 0, 32, "Machine"),
57
- ("Elliptical", ["Cardio"], [], 0, 50, "Machine"), # Low impact
58
- ("Stationary Bike", ["Cardio"], [], 0, 60, "Machine"), # Very safe
59
- ("Swimming", ["Cardio"], [], 0, 60, "Pool"),
60
- ("Battle Ropes", ["Cardio"], ["Shoulder"], 0, 40, "Gym"),
61
- ("Burpees", ["Cardio"], ["Back", "Knee", "Shoulder"], 0, 28, "Bodyweight")
62
- ]
63
- }
64
-
65
- # --- 3. SMART LOGIC FUNCTIONS ---
66
-
67
- def calculate_bmi(weight, height_cm):
68
- height_m = height_cm / 100
69
- return weight / (height_m ** 2)
70
-
71
- def filter_exercises(category, injury, age, bmi, equipment):
72
- """
73
- Selects valid exercises based on constraints.
74
- Returns a random selection to ensure variety every time.
75
- """
76
- valid = []
77
 
78
- # Map user equipment choice to database keys
79
- equip_map = []
80
- if equipment == "Bodyweight Only": equip_map = ["Bodyweight"]
81
- elif equipment == "Home Dumbbells": equip_map = ["Bodyweight", "Dumbbells"]
82
- elif equipment == "Gym Membership": equip_map = ["Bodyweight", "Dumbbells", "Barbell", "Machine", "Rack", "Gym"]
83
- else: equip_map = ["Bodyweight", "Dumbbells", "Barbell", "Rack"] # Full Home Gym
84
-
85
- for name, targets, bad_for, min_age_limit, max_bmi_limit, req_equip in exercise_db[category]:
86
- # 1. Injury Filter
87
- if injury in bad_for: continue
88
- # 2. Age Filter (e.g., Box squats for seniors)
89
- if age > 60 and min_age_limit > 0 and age < min_age_limit: continue
90
- # 3. BMI Filter (No burpees for obese users)
91
- if bmi > max_bmi_limit: continue
92
- # 4. Equipment Filter
93
- if req_equip not in equip_map: continue
94
-
95
- valid.append(name)
96
 
97
- # If list is empty (strict constraints), give a generic fallback
98
- if not valid: return [f"Standard {category} Movement (Low Impact)"]
 
 
 
 
 
99
 
100
- # Return 2-3 random exercises for variety
101
- count = 3 if len(valid) >= 3 else len(valid)
102
- return random.sample(valid, count)
103
-
104
- def generate_finisher(goal, injury, equipment):
105
- """
106
- Generates a specialized finisher: Foam Rolling, Stretching, or Burnout.
107
- """
108
- options = []
109
 
110
- # Option A: Foam Rolling (Recovery)
111
- if injury == "Knee":
112
- options.append("🌀 FOAM ROLL: Quads & IT Band (2 mins each leg)")
113
- elif injury == "Back":
114
- options.append("🌀 FOAM ROLL: Glutes & Hamstrings (Avoid lower back directly!)")
115
- elif injury == "Shoulder":
116
- options.append("🌀 LACROSSE BALL: Roll Pecs & Upper Traps")
117
- else:
118
- options.append("🌀 FOAM ROLL: Full body flush (Calves, Quads, Upper Back)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
- # Option B: Burnout (Metabolic) - Only if healthy
121
- if goal in ["Weight Loss", "Athletic Performance"] and injury == "None":
122
- if equipment == "Bodyweight Only":
123
- options.append("🔥 BURNOUT: 50 Air Squats for time!")
124
- else:
125
- options.append("🔥 BURNOUT: 'Farmer Carry' max distance walking")
126
 
127
- # Option C: Static Stretch (Flexibility)
128
- if goal == "General Health" or injury != "None":
129
- options.append("🧘 STRETCH: Deep Pigeon Pose (3 min hold total)")
130
- options.append("🧘 STRETCH: Doorway Chest Stretch + Hang from bar")
131
 
132
- return random.choice(options)
 
 
 
 
133
 
134
- # --- 4. MAIN GENERATOR ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
 
136
- def create_full_plan(plan_name, age, gender, weight, height, goal, equipment, injury, experience):
137
-
138
- # A. Calculate Stats
139
- bmi = calculate_bmi(weight, height)
140
- bmi_status = "Normal"
141
- if bmi > 25: bmi_status = "Overweight"
142
- if bmi > 30: bmi_status = "Obese (Low Impact Priority)"
143
-
144
- # B. Define Protocol (Sets/Reps) based on Goal & Age
145
- warmup_time = "5-7 mins"
146
- if age > 50: warmup_time = "10-12 mins (Joint Focus)"
147
-
148
- main_scheme = "3 sets x 12 reps"
149
  rest = "60s"
150
 
151
- if goal == "Muscle Gain":
152
- main_scheme = "4 sets x 8-10 reps (Slow Eccentric)"
 
 
 
 
 
 
 
153
  rest = "90s"
154
- elif goal == "Strength":
155
- main_scheme = "5 sets x 5 reps (Heavy)"
156
- rest = "3 mins"
157
  elif goal == "Weight Loss":
158
- main_scheme = "3 sets x 15-20 reps (Circuit Style)"
 
159
  rest = "30s"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
- # C. Select Exercises
162
- legs = filter_exercises("Legs", injury, age, bmi, equipment)
163
- push = filter_exercises("Push", injury, age, bmi, equipment)
164
- pull = filter_exercises("Pull", injury, age, bmi, equipment)
165
- core = filter_exercises("Core", injury, age, bmi, equipment)
166
- cardio = filter_exercises("Cardio", injury, age, bmi, equipment)
167
-
168
- finisher = generate_finisher(goal, injury, equipment)
169
-
170
- # D. Construct the Text
171
- plan = f"📋 YOUR AI CUSTOM PLAN: {plan_name}\n"
172
- plan += f"👤 Profile: {age}y | BMI: {bmi:.1f} ({bmi_status}) | Goal: {goal}\n"
173
- plan += "---------------------------------------------------\n\n"
174
-
175
- plan += f"🌡️ WARM-UP ({warmup_time}):\n"
176
- plan += "1. Joint Rotations (Neck, Shoulders, Wrists, Ankles)\n"
177
- if injury != "Knee": plan += "2. Light Jumping Jacks or Skipping (2 mins)\n"
178
- else: plan += "2. March in Place (High Knees) (2 mins)\n"
179
- plan += "3. Dynamic Stretch: Arm Swings & Leg Swings\n\n"
180
-
181
- plan += f"💪 MAIN WORKOUT (Protocol: {main_scheme} | Rest: {rest}):\n"
182
- plan += f"1. LEG FOCUS: {legs[0]}\n"
183
- plan += f"2. PUSH FOCUS: {push[0]}\n"
184
- plan += f"3. PULL FOCUS: {pull[0]}\n"
185
- if len(legs) > 1: plan += f"4. SECONDARY LEGS: {legs[1]}\n"
186
- if len(push) > 1: plan += f"5. SECONDARY UPPER: {push[1]}\n"
187
-
188
- plan += "\n🛡️ CORE & STABILITY:\n"
189
- plan += f"1. {core[0]}: 3 sets\n"
190
- if len(core) > 1: plan += f"2. {core[1]}: 3 sets\n"
191
-
192
- plan += f"\n🏁 THE FINISHER (One Click Bonus):\n{finisher}\n"
193
-
194
- return plan
195
-
196
- # 5. GRADIO WRAPPER
197
- def predict_wrapper(age, gender, weight, height, goal, equipment, injury, experience):
198
- # 1. AI Logic (The CSV Model)
199
- input_df = pd.DataFrame({
200
  'Age': [age], 'Gender': [gender], 'Weight_kg': [weight],
201
  'Height_cm': [height], 'Goal': [goal], 'Equipment': [equipment],
202
  'Injury': [injury], 'Experience': [experience]
203
  })
204
- plan_category = model.predict(input_df)[0]
205
 
206
- # 2. Rule Logic (The Python Generator)
207
- detailed_plan = create_full_plan(plan_category, age, gender, weight, height, goal, equipment, injury, experience)
208
 
209
- # 3. Strategy Note
210
- note = f"🧠 AI Logic: Model detected '{plan_category}'. We adjusted volume for {goal} and removed dangerous exercises for {injury}."
211
 
212
- return detailed_plan, note
213
 
214
- # 6. UI LAUNCH
215
  iface = gr.Interface(
216
- fn=predict_wrapper,
217
  inputs=[
218
- gr.Slider(18, 80, value=25, label="Age"),
219
  gr.Radio(["Male", "Female"], label="Gender", value="Male"),
220
  gr.Number(label="Weight (kg)", value=75),
221
  gr.Number(label="Height (cm)", value=175),
@@ -225,11 +256,11 @@ iface = gr.Interface(
225
  gr.Radio(['Beginner', 'Intermediate', 'Advanced'], label="Experience", value="Intermediate")
226
  ],
227
  outputs=[
228
- gr.Textbox(label="Your Ultimate Plan", lines=25),
229
- gr.Textbox(label="Behind the Scenes")
230
  ],
231
- title="SmartFit AI Ultimate ",
232
- description="One-Click Personalized Workout Generator. Adapts to BMI, Injuries, and Equipment instantly.",
233
  theme="soft"
234
  )
235
 
 
3
  import pandas as pd
4
  import random
5
 
6
+ # 1. Load the AI Model
7
  model = joblib.load('fitness_model.joblib')
8
 
9
+ # --- 2. THE EXTENDED EXERCISE DATABASE ---
10
+ # Format: Name, Equipment, Type, Main Muscle, Bad For (Injury), Min Level (0=All, 1=Int, 2=Adv)
11
+
12
+ EXERCISE_DB = [
13
+ # LEGS - QUAD DOMINANT
14
+ {"name": "Barbell Back Squat", "equip": ["Barbell", "Gym"], "type": "Compound", "muscle": "Quads", "bad_for": ["Back", "Knee"], "level": 2},
15
+ {"name": "Goblet Squat", "equip": ["Dumbbells", "Gym"], "type": "Compound", "muscle": "Quads", "bad_for": ["Knee"], "level": 0},
16
+ {"name": "Leg Press Machine", "equip": ["Gym"], "type": "Compound", "muscle": "Quads", "bad_for": [], "level": 0},
17
+ {"name": "Bulgarian Split Squat", "equip": ["Dumbbells", "Bodyweight"], "type": "Compound", "muscle": "Quads", "bad_for": ["Knee"], "level": 2},
18
+ {"name": "Step-Ups", "equip": ["Bodyweight", "Dumbbells"], "type": "Isolation", "muscle": "Quads", "bad_for": ["Knee"], "level": 0},
19
+ {"name": "Leg Extensions", "equip": ["Gym"], "type": "Isolation", "muscle": "Quads", "bad_for": ["Knee"], "level": 0},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
+ # LEGS - GLUTE/HAMSTRING DOMINANT
22
+ {"name": "Romanian Deadlift", "equip": ["Barbell", "Dumbbells"], "type": "Compound", "muscle": "Hamstrings", "bad_for": ["Back"], "level": 1},
23
+ {"name": "Glute Bridges", "equip": ["Bodyweight"], "type": "Isolation", "muscle": "Glutes", "bad_for": [], "level": 0},
24
+ {"name": "Hip Thrusts", "equip": ["Barbell", "Dumbbells", "Gym"], "type": "Compound", "muscle": "Glutes", "bad_for": ["Back"], "level": 1},
25
+ {"name": "Lying Leg Curl", "equip": ["Gym"], "type": "Isolation", "muscle": "Hamstrings", "bad_for": [], "level": 0},
26
+ {"name": "Walking Lunges", "equip": ["Bodyweight", "Dumbbells"], "type": "Compound", "muscle": "Glutes", "bad_for": ["Knee"], "level": 1},
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ # PUSH - CHEST
29
+ {"name": "Barbell Bench Press", "equip": ["Barbell", "Gym"], "type": "Compound", "muscle": "Chest", "bad_for": ["Shoulder"], "level": 1},
30
+ {"name": "Dumbbell Chest Press", "equip": ["Dumbbells", "Gym"], "type": "Compound", "muscle": "Chest", "bad_for": [], "level": 0},
31
+ {"name": "Push-ups", "equip": ["Bodyweight"], "type": "Compound", "muscle": "Chest", "bad_for": ["Shoulder", "Wrist"], "level": 0},
32
+ {"name": "Incline Dumbbell Press", "equip": ["Dumbbells", "Gym"], "type": "Compound", "muscle": "Chest", "bad_for": ["Shoulder"], "level": 1},
33
+ {"name": "Cable Flys", "equip": ["Gym"], "type": "Isolation", "muscle": "Chest", "bad_for": [], "level": 1},
34
+ {"name": "Machine Chest Press", "equip": ["Gym"], "type": "Compound", "muscle": "Chest", "bad_for": [], "level": 0},
35
 
36
+ # PUSH - SHOULDERS
37
+ {"name": "Overhead Barbell Press", "equip": ["Barbell", "Gym"], "type": "Compound", "muscle": "Shoulders", "bad_for": ["Shoulder", "Back"], "level": 2},
38
+ {"name": "Seated Dumbbell Press", "equip": ["Dumbbells", "Gym"], "type": "Compound", "muscle": "Shoulders", "bad_for": ["Shoulder"], "level": 0},
39
+ {"name": "Lateral Raises", "equip": ["Dumbbells", "Gym"], "type": "Isolation", "muscle": "Shoulders", "bad_for": [], "level": 0},
40
+ {"name": "Front Raises", "equip": ["Dumbbells", "Gym"], "type": "Isolation", "muscle": "Shoulders", "bad_for": [], "level": 0},
41
+ {"name": "Face Pulls", "equip": ["Gym"], "type": "Isolation", "muscle": "Rear Delts", "bad_for": [], "level": 0},
 
 
 
42
 
43
+ # PUSH - TRICEPS
44
+ {"name": "Tricep Dips", "equip": ["Bodyweight", "Gym"], "type": "Compound", "muscle": "Triceps", "bad_for": ["Shoulder"], "level": 1},
45
+ {"name": "Skullcrushers", "equip": ["Barbell", "Dumbbells"], "type": "Isolation", "muscle": "Triceps", "bad_for": ["Elbow"], "level": 1},
46
+ {"name": "Cable Tricep Pushdown", "equip": ["Gym"], "type": "Isolation", "muscle": "Triceps", "bad_for": [], "level": 0},
47
+ {"name": "Diamond Push-ups", "equip": ["Bodyweight"], "type": "Compound", "muscle": "Triceps", "bad_for": ["Wrist"], "level": 2},
48
+
49
+ # PULL - BACK
50
+ {"name": "Pull-ups", "equip": ["Bodyweight", "Gym"], "type": "Compound", "muscle": "Back", "bad_for": ["Shoulder"], "level": 2},
51
+ {"name": "Lat Pulldown Machine", "equip": ["Gym"], "type": "Compound", "muscle": "Back", "bad_for": [], "level": 0},
52
+ {"name": "Barbell Bent Over Row", "equip": ["Barbell", "Gym"], "type": "Compound", "muscle": "Back", "bad_for": ["Back"], "level": 2},
53
+ {"name": "One Arm Dumbbell Row", "equip": ["Dumbbells", "Gym"], "type": "Compound", "muscle": "Back", "bad_for": [], "level": 0},
54
+ {"name": "Seated Cable Row", "equip": ["Gym"], "type": "Compound", "muscle": "Back", "bad_for": ["Back"], "level": 1},
55
+ {"name": "Inverted Row", "equip": ["Bodyweight"], "type": "Compound", "muscle": "Back", "bad_for": [], "level": 0},
56
+
57
+ # PULL - BICEPS
58
+ {"name": "Barbell Curl", "equip": ["Barbell", "Gym"], "type": "Isolation", "muscle": "Biceps", "bad_for": ["Wrist"], "level": 0},
59
+ {"name": "Hammer Curls", "equip": ["Dumbbells", "Gym"], "type": "Isolation", "muscle": "Biceps", "bad_for": [], "level": 0},
60
+ {"name": "Incline Dumbbell Curl", "equip": ["Dumbbells", "Gym"], "type": "Isolation", "muscle": "Biceps", "bad_for": [], "level": 0},
61
+ {"name": "Chin-ups", "equip": ["Bodyweight", "Gym"], "type": "Compound", "muscle": "Biceps", "bad_for": ["Shoulder"], "level": 2},
62
+
63
+ # CORE
64
+ {"name": "Plank", "equip": ["Bodyweight"], "type": "Isolation", "muscle": "Core", "bad_for": [], "level": 0},
65
+ {"name": "Hanging Leg Raises", "equip": ["Gym", "Barbell"], "type": "Isolation", "muscle": "Core", "bad_for": ["Shoulder"], "level": 2},
66
+ {"name": "Russian Twists", "equip": ["Bodyweight", "Dumbbells"], "type": "Isolation", "muscle": "Core", "bad_for": ["Back"], "level": 0},
67
+ {"name": "Ab Wheel Rollout", "equip": ["Gym", "Dumbbells"], "type": "Isolation", "muscle": "Core", "bad_for": ["Back"], "level": 2},
68
+ {"name": "Dead Bug", "equip": ["Bodyweight"], "type": "Isolation", "muscle": "Core", "bad_for": [], "level": 0},
69
+
70
+ # CARDIO
71
+ {"name": "Treadmill Run", "equip": ["Gym"], "type": "Cardio", "muscle": "Cardio", "bad_for": ["Knee"], "level": 0},
72
+ {"name": "Burpees", "equip": ["Bodyweight"], "type": "Cardio", "muscle": "Cardio", "bad_for": ["Knee", "Back"], "level": 2},
73
+ {"name": "Stationary Bike", "equip": ["Gym"], "type": "Cardio", "muscle": "Cardio", "bad_for": [], "level": 0},
74
+ {"name": "Jumping Jacks", "equip": ["Bodyweight"], "type": "Cardio", "muscle": "Cardio", "bad_for": ["Knee", "Ankle"], "level": 0},
75
+ {"name": "Mountain Climbers", "equip": ["Bodyweight"], "type": "Cardio", "muscle": "Cardio", "bad_for": ["Shoulder"], "level": 1}
76
+ ]
77
 
78
+ # --- 3. LOGIC FUNCTIONS ---
 
 
 
 
 
79
 
80
+ def get_level_score(experience):
81
+ if experience == "Beginner": return 0
82
+ if experience == "Intermediate": return 1
83
+ return 2
84
 
85
+ def get_available_equipment(user_equip):
86
+ if user_equip == "Gym Membership": return ["Gym", "Barbell", "Dumbbells", "Bodyweight"]
87
+ if user_equip == "Full Home Gym (Rack+Barbell)": return ["Barbell", "Dumbbells", "Bodyweight"]
88
+ if user_equip == "Home Dumbbells": return ["Dumbbells", "Bodyweight"]
89
+ return ["Bodyweight"]
90
 
91
+ def filter_exercises(target_muscle, equipment_list, injury, user_level_score, exercise_type=None):
92
+ valid = []
93
+ for ex in EXERCISE_DB:
94
+ # Muscle Match
95
+ if ex["muscle"] != target_muscle: continue
96
+
97
+ # Equipment Match
98
+ has_equip = any(eq in equipment_list for eq in ex["equip"])
99
+ if not has_equip: continue
100
+
101
+ # Injury Match
102
+ if injury in ex["bad_for"]: continue
103
+
104
+ # Level Match (Don't give advanced moves to beginners)
105
+ if ex["level"] > user_level_score: continue
106
+
107
+ # Type Match (Compound vs Isolation) - Optional
108
+ if exercise_type and ex["type"] != exercise_type: continue
109
+
110
+ valid.append(ex["name"])
111
+
112
+ return valid
113
 
114
+ def generate_parameters(goal, experience, age):
115
+ # Calculates Sets/Reps/Rest based on exact inputs
116
+ sets = 3
117
+ reps = "10-12"
 
 
 
 
 
 
 
 
 
118
  rest = "60s"
119
 
120
+ if goal == "Strength":
121
+ sets = 5
122
+ reps = "3-5"
123
+ rest = "3 min"
124
+ if experience == "Beginner": sets = 3; reps = "5-8" # Safe start
125
+
126
+ elif goal == "Muscle Gain":
127
+ sets = 4
128
+ reps = "8-12"
129
  rest = "90s"
130
+
 
 
131
  elif goal == "Weight Loss":
132
+ sets = 3
133
+ reps = "15-20"
134
  rest = "30s"
135
+
136
+ elif goal == "Endurance":
137
+ sets = 2
138
+ reps = "20+"
139
+ rest = "15s"
140
+
141
+ # Age Adjustment
142
+ if age >= 50:
143
+ rest = f"{rest} (+30s)"
144
+ if goal == "Strength": sets -= 1 # Reduce volume for seniors
145
+
146
+ return f"{sets} Sets | {reps} Reps | {rest} Rest"
147
+
148
+ def select_exercise(muscle, equip, injury, level, type_pref, fallback_name):
149
+ # Tries to find specific type (Compound), falls back to any valid
150
+ options = filter_exercises(muscle, equip, injury, level, type_pref)
151
+ if not options:
152
+ options = filter_exercises(muscle, equip, injury, level) # Try any type
153
+
154
+ if not options:
155
+ return f"Standard {muscle} Exercise (Safe Mode)"
156
+
157
+ return random.choice(options)
158
+
159
+ # --- 4. MAIN WORKOUT BUILDER ---
160
+
161
+ def generate_workout(plan_name, age, weight, goal, equipment, injury, experience):
162
+ # A. Setup
163
+ level_score = get_level_score(experience)
164
+ equip_list = get_available_equipment(equipment)
165
+ params = generate_parameters(goal, experience, age)
166
+
167
+ # B. Define Routine Skeleton based on Body Part Split
168
+ # Logic: AI Predicted "Upper Body" -> We give Chest+Back+Shoulders
169
+
170
+ skeleton = [] # List of (Muscle, Type) tuples
171
+
172
+ if "Upper" in plan_name or "Push" in plan_name:
173
+ skeleton = [
174
+ ("Chest", "Compound"), ("Back", "Compound"),
175
+ ("Shoulders", "Compound"), ("Chest", "Isolation"),
176
+ ("Back", "Isolation"), ("Triceps", "Isolation"), ("Biceps", "Isolation")
177
+ ]
178
+ title = "UPPER BODY POWER"
179
+
180
+ elif "Lower" in plan_name or "Legs" in plan_name:
181
+ skeleton = [
182
+ ("Quads", "Compound"), ("Hamstrings", "Compound"),
183
+ ("Glutes", "Compound"), ("Quads", "Isolation"),
184
+ ("Hamstrings", "Isolation"), ("Core", "Isolation")
185
+ ]
186
+ title = "LOWER BODY & CORE"
187
+
188
+ else: # Full Body / Generic
189
+ skeleton = [
190
+ ("Quads", "Compound"), ("Chest", "Compound"),
191
+ ("Back", "Compound"), ("Hamstrings", "Isolation"),
192
+ ("Shoulders", "Isolation"), ("Core", "Isolation")
193
+ ]
194
+ title = "FULL BODY CONDITIONING"
195
+
196
+ # C. Build Text
197
+ text = f"WORKOUT PLAN: {title}\n"
198
+ text += f"Profile: {int(age)} years old | Level: {experience} | Goal: {goal}\n"
199
+ text += f"Config: {equipment} | Injury Avoidance: {injury}\n"
200
+ text += "-" * 50 + "\n\n"
201
+
202
+ text += f"PROTOCOL: {params}\n\n"
203
+
204
+ text += "WARM-UP (5-7 mins):\n"
205
+ if injury == "Knee":
206
+ text += "1. Arm Circles & Torso Rotation\n2. Glute Bridges\n3. Cat-Cow Stretch\n\n"
207
+ else:
208
+ text += "1. Jumping Jacks (2 mins)\n2. Bodyweight Squats\n3. Arm Swings\n\n"
209
+
210
+ text += "MAIN EXERCISES:\n"
211
+
212
+ for i, (muscle, ex_type) in enumerate(skeleton):
213
+ ex_name = select_exercise(muscle, equip_list, injury, level_score, ex_type, "Generic Move")
214
+ text += f"{i+1}. {ex_name} ({muscle} - {ex_type})\n"
215
+
216
+ text += "\nFINISHER (Burnout):\n"
217
+ if goal in ["Weight Loss", "Cardio"]:
218
+ cardio_opts = filter_exercises("Cardio", equip_list, injury, level_score)
219
+ finisher = random.choice(cardio_opts) if cardio_opts else "March in Place"
220
+ text += f"--> {finisher}: 3 Rounds x 45 Seconds (Max Effort)"
221
+ else:
222
+ core_opts = filter_exercises("Core", equip_list, injury, level_score)
223
+ finisher = random.choice(core_opts) if core_opts else "Plank"
224
+ text += f"--> {finisher}: 3 Sets x Failure"
225
+
226
+ return text
227
 
228
+ # 5. GRADIO INTERFACE
229
+ def predict(age, gender, weight, height, goal, equipment, injury, experience):
230
+ # AI Prediction
231
+ input_data = pd.DataFrame({
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  'Age': [age], 'Gender': [gender], 'Weight_kg': [weight],
233
  'Height_cm': [height], 'Goal': [goal], 'Equipment': [equipment],
234
  'Injury': [injury], 'Experience': [experience]
235
  })
236
+ plan_name = model.predict(input_data)[0]
237
 
238
+ # Python Generation
239
+ final_routine = generate_workout(plan_name, age, weight, goal, equipment, injury, experience)
240
 
241
+ logic_note = f"System detected '{plan_name}'. Parameters adjusted for {experience} level."
 
242
 
243
+ return final_routine, logic_note
244
 
245
+ # Launch
246
  iface = gr.Interface(
247
+ fn=predict,
248
  inputs=[
249
+ gr.Slider(18, 80, step=1, value=25, label="Age"), # Step=1 forces integers
250
  gr.Radio(["Male", "Female"], label="Gender", value="Male"),
251
  gr.Number(label="Weight (kg)", value=75),
252
  gr.Number(label="Height (cm)", value=175),
 
256
  gr.Radio(['Beginner', 'Intermediate', 'Advanced'], label="Experience", value="Intermediate")
257
  ],
258
  outputs=[
259
+ gr.Textbox(label="Generated Workout", lines=18),
260
+ gr.Textbox(label="Logic Trace")
261
  ],
262
+ title="SmartFit AI - Pro Edition",
263
+ description="Generates strict, equipment-specific workouts based on AI analysis.",
264
  theme="soft"
265
  )
266