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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +187 -149
app.py CHANGED
@@ -3,195 +3,233 @@ import joblib
3
  import pandas as pd
4
  import random
5
 
6
- # 1. Load Model
7
  model = joblib.load('fitness_model.joblib')
8
 
9
- # 2. Smart Logic Generator
10
- def generate_dynamic_workout(plan_category, age, gender, weight, height, goal, equipment, injury, experience):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- # --- A. Setup Variables based on Profile ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- # 1. Calculate suggested starting weights (Estimates)
15
- strength_base = weight * 0.4 if gender == "Male" else weight * 0.25
16
- if experience == "Beginner": strength_base *= 0.6
17
- if experience == "Advanced": strength_base *= 1.4
18
 
19
- suggested_weight_db = f"{int(strength_base * 0.3)}kg" # Dumbbells
20
- suggested_weight_bb = f"{int(strength_base * 0.8)}kg" # Barbell
 
 
 
 
 
 
 
21
 
22
- if equipment == "Bodyweight Only":
23
- weight_text = "Bodyweight"
24
- elif equipment == "Home Dumbbells":
25
- weight_text = f"Dumbbells (~{suggested_weight_db})"
 
 
 
26
  else:
27
- weight_text = f"Moderate Weight (~{suggested_weight_bb} Barbell / {suggested_weight_db} DBs)"
28
 
29
- # 2. Adjust Volume (Sets/Reps) based on Goal
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  if goal == "Muscle Gain":
31
- protocol = "4 sets x 8-12 reps"
32
- rest = "90 sec rest"
33
- focus = "Hypertrophy (Focus on the squeeze)"
34
  elif goal == "Strength":
35
- protocol = "5 sets x 5 reps"
36
- rest = "3 min rest"
37
- focus = "Max Force (Lift heavy safely)"
38
  elif goal == "Weight Loss":
39
- protocol = "3 sets x 15-20 reps"
40
- rest = "30-45 sec rest"
41
- focus = "High Heart Rate (Keep moving)"
42
- else: # General Health / Endurance
43
- protocol = "3 sets x 12 reps"
44
- rest = "60 sec rest"
45
- focus = "Consistency & Form"
46
-
47
- # 3. Adjust for Age
48
- warmup_duration = "5 mins"
49
- if age > 50:
50
- warmup_duration = "10-12 mins (Joint mobilization focus)"
51
- rest += " + 30 sec extra for recovery"
52
-
53
- # --- B. Build the Routine Components ---
54
-
55
- # 1. Warmup
56
- warmup = f"""
57
- ⏱️ DURATION: {warmup_duration}
58
- 1. Joint Rotations (Neck, Shoulders, Hips, Ankles)
59
- 2. 3 min Light Cardio ({'Jumping Jacks' if injury != 'Knee' else 'March in place'})
60
- 3. Dynamic Stretch: {'Arm Circles' if 'Upper' in plan_category else 'Leg Swings'}
61
- """
62
 
63
- # 2. Main Exercises Selection (Logic Tree)
64
- exercises = []
 
 
 
 
65
 
66
- # -- IF INJURED (Safety Priority) --
67
- if injury == "Knee":
68
- exercises = [
69
- f"1. Glute Bridges (Floor): {protocol} (Safe for knees)",
70
- f"2. Seated Overhead Press: {protocol} ({weight_text})",
71
- f"3. Lat Pulldowns or Pull-ups: {protocol}",
72
- f"4. Plank Hold: 3 sets x 45 sec"
73
- ]
74
- elif injury == "Back":
75
- exercises = [
76
- f"1. Wall Sits: 3 sets x 45 sec (Spine neutral)",
77
- f"2. Supported Single-Arm Row: {protocol} ({weight_text})",
78
- f"3. Seated Chest Press/Pushups (Incline): {protocol}",
79
- f"4. Bird-Dog: 3 sets x 12 reps (Stability)"
80
- ]
81
- elif injury == "Shoulder":
82
- exercises = [
83
- f"1. Leg Press or Goblet Squat (Hands low): {protocol}",
84
- f"2. Lunges: {protocol} (Bodyweight)",
85
- f"3. Bicep Curls: {protocol} ({weight_text})",
86
- f"4. Tricep Pushdowns (Elbows tucked): {protocol}"
87
- ]
88
-
89
- # -- IF HEALTHY (Goal & Equipment Priority) --
90
- else:
91
- # Leg Exercise
92
- if equipment == "Bodyweight Only": leg_ex = "Air Squats"
93
- elif equipment == "Home Dumbbells": leg_ex = "Dumbbell Goblet Squats"
94
- else: leg_ex = "Barbell Back Squats"
95
-
96
- # Push Exercise
97
- if equipment == "Bodyweight Only": push_ex = "Push-ups"
98
- elif equipment == "Home Dumbbells": push_ex = "Dumbbell Bench Press"
99
- else: push_ex = "Barbell Bench Press"
100
-
101
- # Pull Exercise
102
- if equipment == "Bodyweight Only": pull_ex = "Inverted Rows (using table)"
103
- elif equipment == "Home Dumbbells": pull_ex = "Dumbbell Rows"
104
- else: pull_ex = "Barbell Bent Over Row"
105
-
106
- exercises = [
107
- f"1. {leg_ex}: {protocol} using {weight_text}",
108
- f"2. {push_ex}: {protocol}",
109
- f"3. {pull_ex}: {protocol}",
110
- f"4. {'Shoulder Press' if goal != 'Weight Loss' else 'Burpees'}: {protocol}"
111
- ]
112
-
113
- # 3. Finisher (Core/Cardio)
114
- if goal in ["Weight Loss", "Athletic Performance", "Endurance"]:
115
- finisher = """
116
- 🔥 CARDIO FINISHER:
117
- - 30 sec High Knees / Mountain Climbers
118
- - 30 sec Rest
119
- - Repeat 5 times
120
- """
121
- else: # Muscle/Strength/Health
122
- finisher = """
123
- 🧱 CORE & STABILITY FINISHER:
124
- - Plank: 3 sets x failure
125
- - Russian Twists: 3 sets x 20 reps
126
- """
127
-
128
- # 4. Cooldown
129
- cooldown = """
130
- 🧘 COOLDOWN (Don't skip!):
131
- 1. Hamstring Stretch (30 sec per leg)
132
- 2. Chest Opener (Doorway stretch)
133
- 3. Child's Pose (Relieve back tension)
134
- """
135
 
136
- # --- C. Assemble Final Text ---
137
- full_text = f"""
138
- 📋 PERSONALIZED PLAN: {plan_category}
139
- ----------------------------------------------------
140
- 👤 PROFILE: {age}y/o {gender} | Goal: {goal} | Exp: {experience}
141
- ⚖️ REC. WEIGHTS: {weight_text}
142
- 🎯 FOCUS: {focus}
143
- ----------------------------------------------------
144
 
145
- 🔥 WARM-UP:
146
- {warmup}
 
 
 
147
 
148
- 💪 MAIN WORKOUT (Rest: {rest}):
149
- {chr(10).join(exercises)}
 
 
 
 
150
 
151
- {finisher}
 
 
152
 
153
- {cooldown}
154
- """
155
 
156
- return full_text
157
 
158
- # 3. Prediction Wrapper
159
- def predict_plan(age, gender, weight, height, goal, equipment, injury, experience):
160
- # Predict Category
161
- input_data = pd.DataFrame({
162
  'Age': [age], 'Gender': [gender], 'Weight_kg': [weight],
163
  'Height_cm': [height], 'Goal': [goal], 'Equipment': [equipment],
164
  'Injury': [injury], 'Experience': [experience]
165
  })
166
- plan_name = model.predict(input_data)[0]
167
 
168
- # Generate Unique Text
169
- routine = generate_dynamic_workout(plan_name, age, gender, weight, height, goal, equipment, injury, experience)
170
 
171
- # Generate Tip
172
- tip = f"AI Insight: We selected '{plan_name}' based on your safety needs, but customized the intensity for {goal}."
173
 
174
- return routine, tip
175
 
176
- # 4. Interface
177
  iface = gr.Interface(
178
- fn=predict_plan,
179
  inputs=[
180
  gr.Slider(18, 80, value=25, label="Age"),
181
  gr.Radio(["Male", "Female"], label="Gender", value="Male"),
182
  gr.Number(label="Weight (kg)", value=75),
183
  gr.Number(label="Height (cm)", value=175),
184
- gr.Dropdown(['Weight Loss', 'Muscle Gain', 'Endurance', 'General Health', 'Strength'], label="Goal", value="Muscle Gain"),
185
  gr.Dropdown(['Gym Membership', 'Home Dumbbells', 'Bodyweight Only', 'Full Home Gym (Rack+Barbell)'], label="Equipment", value="Gym Membership"),
186
  gr.Dropdown(['None', 'Knee', 'Back', 'Shoulder', 'Ankle'], label="Injury", value="None"),
187
  gr.Radio(['Beginner', 'Intermediate', 'Advanced'], label="Experience", value="Intermediate")
188
  ],
189
  outputs=[
190
- gr.Textbox(label="Your Custom Routine", lines=22),
191
- gr.Textbox(label="AI Coach Note")
192
  ],
193
- title="SmartFit AI Ultimate 🚀",
194
- description="A fully dynamic workout generator that calculates weights, sets, and exercises based on your exact profile.",
195
  theme="soft"
196
  )
197
 
 
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),
222
+ gr.Dropdown(['Weight Loss', 'Muscle Gain', 'Endurance', 'General Health', 'Strength'], label="Goal", value="General Health"),
223
  gr.Dropdown(['Gym Membership', 'Home Dumbbells', 'Bodyweight Only', 'Full Home Gym (Rack+Barbell)'], label="Equipment", value="Gym Membership"),
224
  gr.Dropdown(['None', 'Knee', 'Back', 'Shoulder', 'Ankle'], label="Injury", value="None"),
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