Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import pandas as pd | |
| from datetime import datetime | |
| from transformers import AutoTokenizer, AutoModelForSeq2SeqLM | |
| import torch | |
| import re | |
| import random | |
| def load_model(): | |
| tokenizer = AutoTokenizer.from_pretrained("google/flan-t5-base") | |
| model = AutoModelForSeq2SeqLM.from_pretrained("google/flan-t5-base") | |
| return tokenizer, model | |
| tokenizer, model = load_model() | |
| # Page configuration | |
| st.set_page_config( | |
| page_title="Fitness Profile & BMI Calculator", | |
| page_icon="πͺ", | |
| layout="centered" | |
| ) | |
| # Custom CSS | |
| st.markdown(""" | |
| <style> | |
| .main { | |
| padding: 2rem; | |
| } | |
| .stButton button { | |
| width: 100%; | |
| background-color: #4CAF50; | |
| color: white; | |
| font-weight: bold; | |
| } | |
| .bmi-card { | |
| padding: 20px; | |
| border-radius: 10px; | |
| background-color: #f8f9fa; | |
| border-left: 5px solid #4CAF50; | |
| margin: 10px 0; | |
| } | |
| .category-underweight { color: #3498db; font-weight: bold; } | |
| .category-normal { color: #2ecc71; font-weight: bold; } | |
| .category-overweight { color: #f39c12; font-weight: bold; } | |
| .category-obese { color: #e74c3c; font-weight: bold; } | |
| .day-card { | |
| background-color: #f0f2f6; | |
| padding: 15px; | |
| border-radius: 10px; | |
| margin: 10px 0; | |
| border-left: 5px solid #4CAF50; | |
| } | |
| .day-title { | |
| color: #4CAF50; | |
| font-weight: bold; | |
| font-size: 20px; | |
| margin-bottom: 10px; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Title | |
| st.title("πͺ Fitness Profile & BMI Calculator") | |
| st.markdown("Complete the form below to calculate your BMI and create your fitness profile.") | |
| # Initialize session state for profile data | |
| if 'profile_created' not in st.session_state: | |
| st.session_state.profile_created = False | |
| st.session_state.profile_data = {} | |
| if 'workout_plan' not in st.session_state: | |
| st.session_state.workout_plan = None | |
| # BMI Calculation Function | |
| def calculate_bmi(weight_kg, height_cm): | |
| """Calculate BMI from weight and height""" | |
| height_m = height_cm / 100 | |
| bmi = weight_kg / (height_m ** 2) | |
| return round(bmi, 2), height_m | |
| def get_bmi_category(bmi): | |
| """Classify BMI into standard health categories""" | |
| if bmi < 18.5: | |
| return "Underweight", "category-underweight" | |
| elif 18.5 <= bmi < 25: | |
| return "Normal", "category-normal" | |
| elif 25 <= bmi < 30: | |
| return "Overweight", "category-overweight" | |
| else: | |
| return "Obese", "category-obese" | |
| def get_bmi_description(category): | |
| """Get health description based on BMI category""" | |
| descriptions = { | |
| "Underweight": "Consider consulting a healthcare provider about healthy weight gain strategies.", | |
| "Normal": "Great job! Maintain your healthy lifestyle with balanced diet and regular exercise.", | |
| "Overweight": "Focus on gradual weight management through diet and increased physical activity.", | |
| "Obese": "Consult healthcare providers for personalized weight management plans." | |
| } | |
| return descriptions.get(category, "") | |
| # Form validation function | |
| def validate_inputs(name, height, weight, age): | |
| """Validate all required inputs""" | |
| errors = [] | |
| if not name or not name.strip(): | |
| errors.append("β Name is required") | |
| if height is None or height <= 0: | |
| errors.append("β Height must be greater than 0") | |
| if weight is None or weight <= 0: | |
| errors.append("β Weight must be greater than 0") | |
| if age is None or age <= 0: | |
| errors.append("β Age must be greater than 0") | |
| return errors | |
| def create_workout_prompt(user_info): | |
| """Create a detailed prompt for workout generation""" | |
| # Determine exercise types based on goal | |
| goal_exercises = { | |
| "Build Muscle": { | |
| "sets": "3-4 sets of 8-12 reps", | |
| "rest": "60-90 seconds", | |
| "focus": "hypertrophy, moderate to heavy weights", | |
| "exercises": ["bench press", "squats", "shoulder press", "rows", "deadlifts"] | |
| }, | |
| "Weight Loss": { | |
| "sets": "3 sets of 12-15 reps", | |
| "rest": "30-45 seconds", | |
| "focus": "calorie burn, high intensity, circuit training", | |
| "exercises": ["jumping jacks", "mountain climbers", "burpees", "high knees", "jump squats"] | |
| }, | |
| "Strength Gain": { | |
| "sets": "4-5 sets of 4-6 reps", | |
| "rest": "2-3 minutes", | |
| "focus": "heavy compound lifts, progressive overload", | |
| "exercises": ["deadlifts", "squats", "bench press", "overhead press", "barbell rows"] | |
| }, | |
| "Abs Building": { | |
| "sets": "3 sets to failure", | |
| "rest": "45-60 seconds", | |
| "focus": "core strength and definition", | |
| "exercises": ["crunches", "leg raises", "planks", "russian twists", "mountain climbers"] | |
| }, | |
| "Flexible": { | |
| "sets": "Hold for 30-60 seconds", | |
| "rest": "15-30 seconds", | |
| "focus": "flexibility and mobility", | |
| "exercises": ["downward dog", "cat-cow stretch", "hamstring stretch", "hip flexor stretch", "child's pose"] | |
| }, | |
| "Endurance": { | |
| "sets": "2-3 sets of 15-20 reps", | |
| "rest": "20-30 seconds", | |
| "focus": "muscular endurance, light weights high reps", | |
| "exercises": ["bodyweight squats", "pushups", "lunges", "planks", "jumping rope"] | |
| } | |
| } | |
| goal_info = goal_exercises.get(user_info['fitness_goal'], goal_exercises["Build Muscle"]) | |
| # Determine difficulty level | |
| if user_info['fitness_level'] == "Beginner": | |
| difficulty = "Start with lighter weights, focus on form, 2-3 exercises per muscle group" | |
| elif user_info['fitness_level'] == "Intermediate": | |
| difficulty = "Moderate weights, focus on progressive overload, 3-4 exercises per muscle group" | |
| else: | |
| difficulty = "Heavy weights, advanced techniques, 4-5 exercises per muscle group" | |
| # Create a very structured prompt | |
| prompt = f"""Generate a personalized 5-day workout plan for {user_info['name']}, a {user_info['age']}-year-old {user_info['gender']} who is {user_info['category'].lower()} (BMI: {user_info['bmi']}). | |
| Their fitness goal is {user_info['fitness_goal']} and they are at {user_info['fitness_level']} level. | |
| Available equipment: {user_info['equipment_list']}. | |
| The workout should follow this structure: | |
| - For {user_info['fitness_goal']}: use {goal_info['sets']} with {goal_info['rest']} rest | |
| - Focus on: {goal_info['focus']} | |
| - Difficulty level: {difficulty} | |
| Create a complete 5-day plan with specific exercises. Each day MUST include: | |
| β’ A title with the focus area | |
| β’ 3-4 warmup exercises | |
| β’ 4-5 main exercises (each with sets x reps and rest time) | |
| β’ 2-3 cooldown stretches | |
| β’ Specific notes for this person | |
| Make sure all exercises are appropriate for their BMI category ({user_info['category']}) and fitness level ({user_info['fitness_level']}). | |
| Here's the complete workout plan: | |
| """ | |
| return prompt | |
| def generate_workout_plan(user_info): | |
| """Generate a truly personalized workout plan using the model""" | |
| # Create the prompt | |
| prompt = create_workout_prompt(user_info) | |
| try: | |
| # First attempt with structured prompt | |
| inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=1024) | |
| outputs = model.generate( | |
| **inputs, | |
| max_new_tokens=1500, | |
| temperature=0.8, | |
| do_sample=True, | |
| num_return_sequences=1, | |
| top_k=50, | |
| top_p=0.95 | |
| ) | |
| result = tokenizer.decode(outputs[0], skip_special_tokens=True).strip() | |
| # If result is too short or contains template text, use backup | |
| if len(result) < 200 or "Day 1 - [Focus" in result: | |
| return generate_backup_plan(user_info) | |
| return format_workout_plan(result) | |
| except Exception as e: | |
| st.error(f"Error in generation: {e}") | |
| return generate_backup_plan(user_info) | |
| def generate_backup_plan(user_info): | |
| """Generate a workout plan without using the model""" | |
| # Exercise database | |
| exercises = { | |
| "Upper Body": { | |
| "Beginner": ["Push-ups (knees)", "Dumbbell rows", "Overhead press (light)", "Bicep curls", "Tricep extensions"], | |
| "Intermediate": ["Push-ups", "Pull-ups/rows", "Dumbbell shoulder press", "Hammer curls", "Dips"], | |
| "Advanced": ["Weighted push-ups", "Muscle-ups", "Barbell overhead press", "Chin-ups", "Diamond push-ups"] | |
| }, | |
| "Lower Body": { | |
| "Beginner": ["Bodyweight squats", "Lunges", "Glute bridges", "Calf raises", "Step-ups"], | |
| "Intermediate": ["Goblet squats", "Walking lunges", "Romanian deadlifts", "Box jumps", "Bulgarian split squats"], | |
| "Advanced": ["Barbell squats", "Pistol squats", "Deadlifts", "Jump squats", "Weighted lunges"] | |
| }, | |
| "Core": { | |
| "Beginner": ["Planks (30 sec)", "Crunches", "Bird dogs", "Dead bugs", "Russian twists (light)"], | |
| "Intermediate": ["Side planks", "Leg raises", "Bicycle crunches", "Mountain climbers", "V-ups"], | |
| "Advanced": ["Dragon flags", "Hanging leg raises", "Ab wheel rollouts", "Turkish get-ups", "L-sits"] | |
| }, | |
| "Cardio": { | |
| "Beginner": ["Jumping jacks", "High knees", "Butt kicks", "Skaters", "Mountain climbers"], | |
| "Intermediate": ["Burpees", "Jump rope", "Box jumps", "Kettlebell swings", "Battle ropes"], | |
| "Advanced": ["Plyometric push-ups", "Burpee pull-ups", "Double unders", "Sprint intervals", "Boxing combos"] | |
| }, | |
| "Flexibility": { | |
| "Beginner": ["Cat-cow stretch", "Child's pose", "Downward dog", "Standing hamstring stretch", "Quad stretch"], | |
| "Intermediate": ["Pigeon pose", "Sun salutations", "Warrior poses", "Bridge pose", "Seated forward fold"], | |
| "Advanced": ["Splits progression", "Wheel pose", "Crow pose", "King pigeon", "Headstand"] | |
| } | |
| } | |
| # Determine sets/reps based on goal | |
| goal_params = { | |
| "Build Muscle": {"sets": 3, "reps": "8-12", "rest": "60-90 sec"}, | |
| "Weight Loss": {"sets": 3, "reps": "12-15", "rest": "30-45 sec"}, | |
| "Strength Gain": {"sets": 4, "reps": "4-6", "rest": "2-3 min"}, | |
| "Abs Building": {"sets": 3, "reps": "15-20", "rest": "45-60 sec"}, | |
| "Flexible": {"sets": 2, "reps": "hold 30-60s", "rest": "15-30 sec"}, | |
| "Endurance": {"sets": 3, "reps": "15-20", "rest": "30-45 sec"} | |
| } | |
| params = goal_params.get(user_info['fitness_goal'], goal_params["Build Muscle"]) | |
| level = user_info['fitness_level'] | |
| # Weekly schedule | |
| schedule = [ | |
| ("Day 1: Upper Body Focus", ["Upper Body"]), | |
| ("Day 2: Lower Body Focus", ["Lower Body"]), | |
| ("Day 3: Cardio & Core", ["Cardio", "Core"]), | |
| ("Day 4: Full Body", ["Upper Body", "Lower Body"]), | |
| ("Day 5: Active Recovery", ["Flexibility", "Core"]) | |
| ] | |
| # Build the plan | |
| plan = f"π PERSONALIZED WORKOUT PLAN FOR {user_info['name'].upper()}\n" | |
| plan += f"Goal: {user_info['fitness_goal']} | Level: {user_info['fitness_level']} | BMI Category: {user_info['category']}\n" | |
| plan += "=" * 60 + "\n\n" | |
| for day_title, categories in schedule: | |
| plan += f"ποΈ {day_title}\n" | |
| plan += "-" * 40 + "\n\n" | |
| # Warmup | |
| plan += "πΈ WARMUP (5-10 minutes):\n" | |
| warmup_exercises = random.sample(exercises["Flexibility"]["Beginner"] + exercises["Cardio"]["Beginner"], 3) | |
| for ex in warmup_exercises: | |
| plan += f" β’ {ex} - 30 seconds\n" | |
| plan += "\n" | |
| # Main workout | |
| plan += f"πΈ MAIN WORKOUT ({params['sets']} sets, {params['reps']} reps, rest {params['rest']}):\n" | |
| main_exercises = [] | |
| for cat in categories: | |
| cat_exercises = exercises[cat][level] | |
| main_exercises.extend(random.sample(cat_exercises, min(2, len(cat_exercises)))) | |
| # Ensure we have enough exercises | |
| while len(main_exercises) < 4: | |
| main_exercises.append(random.choice(exercises["Core"]["Beginner"])) | |
| for i, ex in enumerate(main_exercises[:4], 1): | |
| plan += f" {i}. {ex} - {params['sets']} sets x {params['reps']} reps\n" | |
| plan += "\n" | |
| # Cooldown | |
| plan += "πΈ COOLDOWN & STRETCHING:\n" | |
| cooldown = random.sample(exercises["Flexibility"]["Beginner"], 3) | |
| for ex in cooldown: | |
| plan += f" β’ {ex} - hold 30 seconds\n" | |
| plan += "\n" | |
| # Notes | |
| plan += f"π NOTES: {get_workout_note(user_info, day_title)}\n" | |
| plan += "\n" + "β’" * 40 + "\n\n" | |
| return plan | |
| def get_workout_note(user_info, day_title): | |
| """Generate personalized workout notes""" | |
| notes = [] | |
| if user_info['category'] == "Underweight": | |
| notes.append("Focus on progressive overload with compound exercises to build muscle mass.") | |
| elif user_info['category'] == "Overweight": | |
| notes.append("Maintain good form and focus on consistency. Combine with cardio for best results.") | |
| elif user_info['category'] == "Obese": | |
| notes.append("Start with low-impact variations and gradually increase intensity. Stay hydrated.") | |
| if user_info['fitness_level'] == "Beginner": | |
| notes.append("Focus on form over weight. Stop if you feel pain.") | |
| elif user_info['fitness_level'] == "Intermediate": | |
| notes.append("Try to increase weight or reps each week for progressive overload.") | |
| else: | |
| notes.append("Incorporate advanced techniques like drop sets or supersets.") | |
| if "Upper" in day_title: | |
| notes.append("Keep shoulders back and core engaged throughout upper body exercises.") | |
| elif "Lower" in day_title: | |
| notes.append("Don't let your knees go past your toes during squats and lunges.") | |
| return " ".join(notes[:2]) # Return 2 notes max | |
| def format_workout_plan(plan_text): | |
| """Format the workout plan for better display""" | |
| # Remove any template markers | |
| plan_text = re.sub(r'\[.*?\]', '', plan_text) | |
| plan_text = plan_text.replace("Create a complete", "") | |
| plan_text = plan_text.replace("Here's the complete workout plan:", "") | |
| # Ensure day headers are properly formatted | |
| plan_text = re.sub(r'(Day \d+)[:\s]*', r'\n\nποΈ \1\n' + "-"*40 + "\n", plan_text) | |
| return plan_text.strip() | |
| # Main Form | |
| with st.form("fitness_form"): | |
| st.subheader("π Personal Information") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| name = st.text_input("Full Name *", placeholder="Enter your full name", key="name_input") | |
| gender = st.selectbox("Gender *", ["Male", "Female", "Other", "Prefer not to say"], key="gender_input") | |
| weight = st.number_input("Weight (kg) *", min_value=0.1, max_value=500.0, | |
| value=None, placeholder="Enter weight", step=0.1, key="weight_input") | |
| with col2: | |
| height = st.number_input("Height (cm) *", min_value=1.0, max_value=300.0, | |
| value=None, placeholder="Enter height", step=0.1, key="height_input") | |
| age = st.number_input("Age *", min_value=1, max_value=120, | |
| value=None, placeholder="Enter age", step=1, key="age_input") | |
| st.subheader("πͺ Fitness Details") | |
| col3, col4 = st.columns(2) | |
| with col3: | |
| fitness_goal = st.selectbox( | |
| "Fitness Goal *", | |
| ["Build Muscle", "Weight Loss", "Strength Gain", "Abs Building", "Flexible", "Endurance"], | |
| key="goal_input" | |
| ) | |
| fitness_level = st.radio( | |
| "Fitness Level *", | |
| ["Beginner", "Intermediate", "Advanced"], | |
| horizontal=True, | |
| key="level_input" | |
| ) | |
| with col4: | |
| equipment_options = ["Dumbbells", "Resistance Band", "Yoga Mat", "Kettlebells", | |
| "Barbell", "Treadmill", "Exercise Bike", "Pull-up Bar", | |
| "Medicine Ball", "No Equipment"] | |
| equipment = st.multiselect( | |
| "Available Equipment *", | |
| equipment_options, | |
| help="Select all equipment you have access to", | |
| key="equipment_input" | |
| ) | |
| submitted = st.form_submit_button("π Submit Profile", use_container_width=True) | |
| # Process form submission | |
| if submitted: | |
| errors = validate_inputs(name, height, weight, age) | |
| if not equipment: | |
| errors.append("β Please select at least one equipment option") | |
| if errors: | |
| for error in errors: | |
| st.error(error) | |
| else: | |
| # Calculate BMI | |
| bmi, height_m = calculate_bmi(weight, height) | |
| category, css_class = get_bmi_category(bmi) | |
| description = get_bmi_description(category) | |
| equipment_list = ", ".join(equipment) | |
| # Store profile data | |
| st.session_state.profile_created = True | |
| st.session_state.profile_data = { | |
| 'name': name, | |
| 'gender': gender, | |
| 'age': age, | |
| 'height_cm': height, | |
| 'height_m': height_m, | |
| 'weight': weight, | |
| 'bmi': bmi, | |
| 'category': category, | |
| 'css_class': css_class, | |
| 'description': description, | |
| 'fitness_goal': fitness_goal, | |
| 'fitness_level': fitness_level, | |
| 'equipment': equipment, | |
| 'equipment_list': equipment_list, | |
| 'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M") | |
| } | |
| st.success("β Profile Submitted Successfully!") | |
| # Generate workout plan | |
| with st.spinner("π€ Creating your personalized 5-day workout plan..."): | |
| workout_plan = generate_workout_plan(st.session_state.profile_data) | |
| if workout_plan: | |
| st.session_state.workout_plan = workout_plan | |
| else: | |
| st.session_state.workout_plan = generate_backup_plan(st.session_state.profile_data) | |
| st.rerun() | |
| # Display Profile Results | |
| if st.session_state.profile_created: | |
| data = st.session_state.profile_data | |
| st.markdown("---") | |
| st.subheader("π Your Fitness Profile") | |
| # BMI Result Card | |
| st.markdown(f""" | |
| <div class="bmi-card"> | |
| <h3>π BMI Result</h3> | |
| <h1 style="font-size: 48px; margin: 10px 0;">{data['bmi']}</h1> | |
| <p style="font-size: 20px;"> | |
| <span class="{data['css_class']}">{data['category']}</span> | |
| </p> | |
| <p style="color: #666;">{data['description']}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Personal Details Card | |
| with st.container(): | |
| col5, col6 = st.columns(2) | |
| with col5: | |
| st.markdown("#### π€ Personal Details") | |
| st.write(f"**Name:** {data['name']}") | |
| st.write(f"**Gender:** {data.get('gender', 'Not specified')}") | |
| st.write(f"**Age:** {data.get('age', 'Not specified')}") | |
| st.write(f"**Height:** {data['height_cm']} cm ({data['height_m']:.2f} m)") | |
| st.write(f"**Weight:** {data['weight']} kg") | |
| with col6: | |
| st.markdown("#### π― Fitness Goals") | |
| st.write(f"**Primary Goal:** {data['fitness_goal']}") | |
| st.write(f"**Experience Level:** {data['fitness_level']}") | |
| st.write(f"**Equipment:** {', '.join(data['equipment'])}") | |
| # Display Workout Plan | |
| if st.session_state.workout_plan: | |
| st.markdown("---") | |
| st.subheader("ποΈ Your Personalized 5-Day Workout Plan") | |
| st.caption("β¨ This plan is uniquely created based on your profile") | |
| # Display the workout plan | |
| plan_text = st.session_state.workout_plan | |
| # Fixed regex pattern - properly escaped | |
| days = re.split(r'(Day \d+[:\-]?|ποΈ\s*Day\s*\d+)', plan_text) | |
| if len(days) > 1: | |
| for i in range(1, len(days), 2): | |
| if i+1 < len(days): | |
| day_title = days[i].strip() | |
| day_content = days[i+1].strip() | |
| # Clean up the content | |
| day_content = re.sub(r'^[-β=_*]+', '', day_content) | |
| with st.container(): | |
| st.markdown(f""" | |
| <div class="day-card"> | |
| <div class="day-title">{day_title}</div> | |
| <div style="white-space: pre-line;">{day_content}</div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| else: | |
| # If splitting didn't work, show in a code block | |
| st.code(plan_text, language="text") | |
| # Download button | |
| st.download_button( | |
| label="π₯ Download Workout Plan", | |
| data=plan_text, | |
| file_name=f"workout_plan_{data['name']}_{datetime.now().strftime('%Y%m%d')}.txt", | |
| mime="text/plain" | |
| ) | |
| st.caption("π€ This workout plan was generated by AI based on your unique profile. Consult with a fitness professional before starting any new exercise routine.") | |
| # Option to create new profile | |
| if st.button("π Create New Profile"): | |
| st.session_state.profile_created = False | |
| st.session_state.profile_data = {} | |
| st.session_state.workout_plan = None | |
| st.rerun() | |
| # Footer | |
| st.markdown("---") | |
| st.markdown(""" | |
| <div style='text-align: center; color: gray; padding: 20px;'> | |
| <p>ποΈββοΈ Your fitness journey starts here! Complete the form to get personalized insights.</p> | |
| <p style='font-size: 12px;'>* Required fields | BMI is a screening tool, not a diagnostic measure</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Sidebar with additional information | |
| with st.sidebar: | |
| st.image("https://cdn-icons-png.flaticon.com/512/3043/3043650.png", width=100) | |
| st.title("About BMI") | |
| st.markdown(""" | |
| **Body Mass Index (BMI)** is a simple measure that uses your height and weight to estimate body fat. | |
| ### BMI Categories: | |
| - **Underweight:** < 18.5 | |
| - **Normal:** 18.5 - 24.9 | |
| - **Overweight:** 25 - 29.9 | |
| - **Obese:** β₯ 30 | |
| ### Tips for Accuracy: | |
| - Measure height without shoes | |
| - Weigh yourself in the morning | |
| - Use consistent units | |
| """) | |
| st.markdown("---") | |
| st.markdown("### π Quick Example") | |
| st.markdown(""" | |
| **Try this example:** | |
| - Name: Sarah Johnson | |
| - Age: 28 | |
| - Height: 165 cm | |
| - Weight: 58 kg | |
| - Goal: Weight Loss | |
| - Equipment: Dumbbells, Yoga Mat | |
| - Level: Intermediate | |
| BMI: 21.3 (Normal) | |
| """) |