Spaces:
Running
Running
| import gradio as gr | |
| import joblib | |
| import pandas as pd | |
| import random | |
| # 1. Load Model | |
| model = joblib.load('fitness_model.joblib') | |
| # ========================================== | |
| # CONFIG DICTIONARIES | |
| # ========================================== | |
| GOAL_CONFIG = { | |
| "Strength": {"sets": 5, "reps": "3-5", "rest": "3 min", "intensity": "Heavy"}, | |
| "Muscle Gain": {"sets": 3, "reps": "8-12", "rest": "90 sec", "intensity": "Moderate"}, | |
| "Weight Loss": {"sets": 4, "reps": "15-20", "rest": "45 sec", "intensity": "High Tempo"}, | |
| "Endurance": {"sets": 2, "reps": "20-25", "rest": "30 sec", "intensity": "Light"}, | |
| "General Health": {"sets": 3, "reps": "12-15", "rest": "60 sec", "intensity": "Moderate"} | |
| } | |
| LEVEL_CONFIG = { | |
| "Beginner": {"tier": 0}, | |
| "Intermediate": {"tier": 1}, | |
| "Advanced": {"tier": 2} | |
| } | |
| EXERCISE_DB = { | |
| "Chest": [ | |
| {"name": "Barbell Bench Press", "equip": ["Barbell", "Gym"], "bad": ["Shoulder"], "level": 1, "ratio": 0.9}, | |
| {"name": "Dumbbell Chest Press", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.35}, | |
| {"name": "Incline Dumbbell Press", "equip": ["Dumbbells", "Gym"], "bad": ["Shoulder"], "level": 1, "ratio": 0.3}, | |
| {"name": "Machine Chest Press", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.6}, | |
| {"name": "Push-ups", "equip": ["Bodyweight"], "bad": ["Wrist"], "level": 0, "ratio": 0}, | |
| {"name": "Cable Flys", "equip": ["Gym"], "bad": [], "level": 1, "ratio": 0.15}, | |
| {"name": "Dumbbell Flys", "equip": ["Dumbbells"], "bad": ["Shoulder"], "level": 0, "ratio": 0.12}, | |
| {"name": "Weighted Dips", "equip": ["Gym"], "bad": ["Shoulder"], "level": 2, "ratio": 0}, | |
| ], | |
| "Back": [ | |
| {"name": "Deadlift", "equip": ["Barbell", "Gym"], "bad": ["Back"], "level": 2, "ratio": 1.4}, | |
| {"name": "Lat Pulldown", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.6}, | |
| {"name": "Seated Cable Row", "equip": ["Gym"], "bad": ["Back"], "level": 0, "ratio": 0.6}, | |
| {"name": "Barbell Bent Over Row", "equip": ["Barbell", "Gym"], "bad": ["Back"], "level": 1, "ratio": 0.7}, | |
| {"name": "Single Arm Dumbbell Row", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.3}, | |
| {"name": "Pull-ups", "equip": ["Bodyweight", "Gym"], "bad": ["Shoulder"], "level": 1, "ratio": 0}, | |
| {"name": "Chest Supported Row", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.5}, | |
| {"name": "Inverted Row", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0}, | |
| ], | |
| "Legs": [ | |
| {"name": "Barbell Squat", "equip": ["Barbell", "Gym"], "bad": ["Back", "Knee"], "level": 2, "ratio": 1.1}, | |
| {"name": "Leg Press", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 1.8}, | |
| {"name": "Goblet Squat", "equip": ["Dumbbells", "Gym"], "bad": ["Knee"], "level": 0, "ratio": 0.4}, | |
| {"name": "Walking Lunges", "equip": ["Dumbbells", "Bodyweight"], "bad": ["Knee"], "level": 1, "ratio": 0.15}, | |
| {"name": "Romanian Deadlift", "equip": ["Barbell", "Dumbbells"], "bad": ["Back"], "level": 1, "ratio": 0.8}, | |
| {"name": "Lying Leg Curl", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.35}, | |
| {"name": "Leg Extensions", "equip": ["Gym"], "bad": ["Knee"], "level": 0, "ratio": 0.35}, | |
| {"name": "Bulgarian Split Squat", "equip": ["Dumbbells"], "bad": ["Knee"], "level": 2, "ratio": 0.2}, | |
| {"name": "Glute Bridges", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0}, | |
| ], | |
| "Shoulders": [ | |
| {"name": "Overhead Barbell Press", "equip": ["Barbell", "Gym"], "bad": ["Shoulder", "Back"], "level": 2, "ratio": 0.5}, | |
| {"name": "Seated Dumbbell Press", "equip": ["Dumbbells", "Gym"], "bad": ["Shoulder"], "level": 0, "ratio": 0.25}, | |
| {"name": "Lateral Raises", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.08}, | |
| {"name": "Face Pulls", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.2}, | |
| {"name": "Front Raises", "equip": ["Dumbbells"], "bad": [], "level": 0, "ratio": 0.08}, | |
| ], | |
| "Arms": [ | |
| {"name": "Barbell Curls", "equip": ["Barbell", "Gym"], "bad": ["Wrist"], "level": 0, "ratio": 0.25}, | |
| {"name": "Dumbbell Hammer Curls", "equip": ["Dumbbells", "Gym"], "bad": [], "level": 0, "ratio": 0.12}, | |
| {"name": "Tricep Rope Pushdown", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0.25}, | |
| {"name": "Skullcrushers", "equip": ["Barbell", "Dumbbells"], "bad": ["Elbow"], "level": 1, "ratio": 0.2}, | |
| {"name": "Dips", "equip": ["Bodyweight"], "bad": ["Shoulder"], "level": 1, "ratio": 0}, | |
| ], | |
| "Core": [ | |
| {"name": "Plank", "equip": ["Bodyweight"], "bad": [], "level": 0, "ratio": 0}, | |
| {"name": "Cable Woodchoppers", "equip": ["Gym"], "bad": ["Back"], "level": 1, "ratio": 0.3}, | |
| {"name": "Russian Twists", "equip": ["Bodyweight"], "bad": ["Back"], "level": 0, "ratio": 0}, | |
| {"name": "Hanging Leg Raises", "equip": ["Gym"], "bad": ["Shoulder"], "level": 2, "ratio": 0}, | |
| ], | |
| "Cardio": [ | |
| {"name": "Treadmill Run", "equip": ["Gym"], "bad": ["Knee"], "level": 0, "ratio": 0}, | |
| {"name": "Elliptical", "equip": ["Gym"], "bad": [], "level": 0, "ratio": 0}, | |
| {"name": "Burpees", "equip": ["Bodyweight"], "bad": ["Back", "Knee"], "level": 2, "ratio": 0}, | |
| {"name": "Jump Rope", "equip": ["Bodyweight"], "bad": ["Knee", "Ankle"], "level": 1, "ratio": 0}, | |
| ] | |
| } | |
| # ========================================== | |
| # LOGIC ENGINE (CALCULATOR) | |
| # ========================================== | |
| def calculate_weight(base_ratio, user_weight, gender, level_tier, muscle_group): | |
| if base_ratio == 0: return "Bodyweight" | |
| load = user_weight * base_ratio | |
| # Gender Logic | |
| if gender == "Female": | |
| if muscle_group in ["Legs", "Core"]: | |
| load *= 0.75 | |
| else: | |
| load *= 0.55 | |
| # Level Logic | |
| if level_tier == 0: load *= 0.6 | |
| if level_tier == 2: load *= 1.3 | |
| # Rounding | |
| if load < 10: | |
| final_load = round(load) | |
| else: | |
| final_load = 2.5 * round(load / 2.5) | |
| return f"{int(final_load)} kg" | |
| def get_exercises(muscle, equipment, injury, level_tier, count=1): | |
| my_gear = [] | |
| if equipment == "Gym Membership": my_gear = ["Gym", "Barbell", "Dumbbells", "Bodyweight"] | |
| elif equipment == "Full Home Gym (Rack+Barbell)": my_gear = ["Barbell", "Dumbbells", "Bodyweight"] | |
| elif equipment == "Home Dumbbells": my_gear = ["Dumbbells", "Bodyweight"] | |
| else: my_gear = ["Bodyweight"] | |
| pool = EXERCISE_DB.get(muscle, []) | |
| valid = [] | |
| for ex in pool: | |
| if not any(g in my_gear for g in ex["equip"]): continue | |
| if injury in ex["bad"]: continue | |
| if level_tier < ex["level"]: continue | |
| valid.append(ex) | |
| random.shuffle(valid) | |
| if not valid: return [{"name": f"Standard {muscle} Move", "ratio": 0}] | |
| return valid[:count] | |
| def generate_routine(plan_name, age, gender, weight, goal, equipment, injury, experience): | |
| goal_settings = GOAL_CONFIG[goal] | |
| level_tier = LEVEL_CONFIG[experience]["tier"] | |
| slots = [] | |
| if "Upper" in plan_name or "Push" in plan_name: | |
| slots = ["Chest", "Back", "Shoulders", "Arms", "Core"] | |
| title = "Upper Body Focus" | |
| elif "Lower" in plan_name or "Legs" in plan_name: | |
| slots = ["Legs", "Legs", "Legs", "Core", "Cardio"] | |
| title = "Lower Body Focus" | |
| else: | |
| slots = ["Legs", "Chest", "Back", "Shoulders", "Core"] | |
| title = "Full Body Mix" | |
| text = f"WORKOUT PLAN: {title}\n" | |
| text += f"User: {age}y | {gender} | {weight}kg | {experience}\n" | |
| text += f"Goal: {goal} | Equip: {equipment}\n" | |
| text += "="*40 + "\n\n" | |
| text += f"WARM-UP (5-8 mins):\n" | |
| if injury == "Knee": text += "- Arm Circles & Torso Twists\n- Glute Bridges\n\n" | |
| else: text += "- Jumping Jacks\n- Dynamic Stretching\n\n" | |
| text += f"MAIN WORKOUT:\n" | |
| text += f"Sets: {goal_settings['sets']} | Reps: {goal_settings['reps']} | Rest: {goal_settings['rest']}\n\n" | |
| used_names = [] | |
| for i, muscle in enumerate(slots): | |
| candidates = get_exercises(muscle, equipment, injury, level_tier, count=3) | |
| selected = candidates[0] | |
| for cand in candidates: | |
| if cand['name'] not in used_names: | |
| selected = cand | |
| break | |
| used_names.append(selected['name']) | |
| load = calculate_weight(selected['ratio'], weight, gender, level_tier, muscle) | |
| text += f"{i+1}. {selected['name']} ({muscle})\n" | |
| text += f" Rec. Load: {load}\n\n" | |
| text += f"FINISHER:\n" | |
| if goal in ["Weight Loss", "Endurance"]: | |
| text += "HIIT: 30s Work / 30s Rest (5 Rounds)" | |
| else: | |
| text += "Core Stability: 3 Sets to Failure" | |
| return text | |
| # 6. WRAPPER | |
| def predict_wrapper(age, gender, weight, height, goal, equipment, injury, experience): | |
| input_df = pd.DataFrame({ | |
| 'Age': [age], 'Gender': [gender], 'Weight_kg': [weight], | |
| 'Height_cm': [height], 'Goal': [goal], 'Equipment': [equipment], | |
| 'Injury': [injury], 'Experience': [experience] | |
| }) | |
| plan_name = model.predict(input_df)[0] | |
| routine = generate_routine(plan_name, age, gender, weight, goal, equipment, injury, experience) | |
| return routine, f"AI Strategy: {plan_name}" | |
| # 7. LAUNCH | |
| iface = gr.Interface( | |
| fn=predict_wrapper, | |
| inputs=[ | |
| gr.Slider(18, 80, step=1, value=25, label="Age"), | |
| gr.Radio(["Male", "Female"], label="Gender", value="Male"), | |
| gr.Number(label="Weight (kg)", value=75), | |
| gr.Number(label="Height (cm)", value=175), | |
| gr.Dropdown(list(GOAL_CONFIG.keys()), label="Goal", value="Muscle Gain"), | |
| gr.Dropdown(['Gym Membership', 'Home Dumbbells', 'Bodyweight Only', 'Full Home Gym (Rack+Barbell)'], label="Equipment", value="Gym Membership"), | |
| gr.Dropdown(['None', 'Knee', 'Back', 'Shoulder', 'Ankle'], label="Injury", value="None"), | |
| gr.Dropdown(list(LEVEL_CONFIG.keys()), label="Experience", value="Intermediate") | |
| ], | |
| outputs=[ | |
| gr.Textbox(label="Generated Workout", lines=20), | |
| gr.Textbox(label="AI Note") | |
| ], | |
| title="SmartFit AI - Biological Engine", | |
| description="Advanced generator with gender-specific strength standards.", | |
| # ====================================================== | |
| # THIS IS THE NEW PART - THE 3 QUICK STARTERS | |
| # ====================================================== | |
| examples=[ | |
| # Example 1: The Bodybuilder (Young Male, Gym, No Injury) | |
| [24, "Male", 80, 180, "Muscle Gain", "Gym Membership", "None", "Advanced"], | |
| # Example 2: The Rehab/Home User (Female, Knee Injury, Home) | |
| [35, "Female", 65, 165, "Weight Loss", "Home Dumbbells", "Knee", "Beginner"], | |
| # Example 3: The Senior Health (Older Male, Bodyweight, Back safe) | |
| [60, "Male", 85, 175, "General Health", "Bodyweight Only", "Back", "Beginner"] | |
| ], | |
| theme="soft" | |
| ) | |
| iface.launch() |