import streamlit as st import json from datetime import datetime from typing import Dict, Any, List import pandas as pd import hashlib import os from service import generate_ai_response, create_user_profile_prompt, create_workout_type_prompt, create_nutrition_type_prompt, create_conversation_chat_prompt # from database import create_user, get_user_data, save_user_data # Configure page st.set_page_config( page_title="AI Fitness Coach", page_icon="💪", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS for better styling st.markdown(""" """, unsafe_allow_html=True) # Initialize session state def init_session_state(): if 'session_alias' not in st.session_state: st.session_state.session_alias = "" if 'user_profile' not in st.session_state: st.session_state.user_profile = {} if 'chat_history' not in st.session_state: st.session_state.chat_history = [] if 'workout_plan' not in st.session_state: st.session_state.workout_plan = None if 'nutrition_plan' not in st.session_state: st.session_state.nutrition_plan = None if 'profile_submitted' not in st.session_state: st.session_state.profile_submitted = False if 'current_session_id' not in st.session_state: st.session_state.current_session_id = None def call_backend_service(request_type: str, user_profile: Dict[str, Any], additional_message: str = "") -> Dict[str, Any]: """Call the backend LangChain service using generateResponse method""" try: # Generate session_id based on user profile (you can modify this logic) import hashlib profile_hash = hashlib.md5(str(user_profile.get('timestamp', 'default')).encode()).hexdigest()[:8] session_id = f"user_{profile_hash}" # Format the user prompt based on request type profile_prompt = create_user_profile_prompt(user_profile) if request_type == 'workout': user_prompt = create_workout_type_prompt(profile_prompt) elif request_type == 'nutrition': user_prompt = create_nutrition_type_prompt(profile_prompt) elif request_type == 'chat': user_prompt = create_conversation_chat_prompt(profile_prompt, additional_message) else: user_prompt = additional_message response = generate_ai_response(user_prompt, session_id) if response: return { 'response': str(response), 'session_id': session_id } else: return {'error': f'Backend error: Unable to generate response'} except Exception as e: return {'error': f'Unexpected error: {str(e)}'} def collect_user_profile(): """Collect user profile information""" st.markdown('
👤 User Profile Information
', unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: age = st.number_input("Age", min_value=13, max_value=100, value=25) weight = st.number_input("Weight (kg)", min_value=30.0, max_value=300.0, value=70.0, step=0.1) height = st.number_input("Height (cm)", min_value=100.0, max_value=250.0, value=170.0, step=0.1) gender = st.selectbox("Gender", ["Male", "Female", "Other", "Prefer not to say"]) with col2: workout_preference = st.multiselect( "Workout Preferences", ["Cardio", "Strength Training", "Yoga", "Pilates", "HIIT", "CrossFit", "Swimming", "Running", "Cycling", "Dancing"], default=["Cardio", "Strength Training"] ) workout_time = st.selectbox( "Preferred Workout Duration", ["15-30 minutes", "30-45 minutes", "45-60 minutes", "60-90 minutes", "90+ minutes"] ) fitness_level = st.selectbox( "Current Fitness Level", ["Beginner", "Intermediate", "Advanced"] ) fitness_goal = st.selectbox( "Primary Fitness Goal", ["Weight Loss", "Muscle Gain", "Endurance", "Strength", "Flexibility", "General Health"] ) st.markdown('
📅 Weekly Schedule
', unsafe_allow_html=True) days_of_week = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] schedule = {} cols = st.columns(7) for i, day in enumerate(days_of_week): with cols[i]: available = st.checkbox(f"{day[:3]}", key=f"day_{i}") if available: time_slot = st.selectbox( "Time", ["Morning (6-10 AM)", "Afternoon (12-4 PM)", "Evening (5-8 PM)", "Night (8-10 PM)"], key=f"time_{i}" ) schedule[day] = time_slot else: schedule[day] = "Not Available" st.markdown('
🍽️ Dietary Preferences & Health
', unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: food_preferences = st.multiselect( "Dietary Preferences", ["Vegetarian", "Vegan", "Pescatarian", "Keto", "Paleo", "Mediterranean", "Low-carb", "High-protein", "Gluten-free", "No restrictions"], default=["No restrictions"] ) allergies = st.text_area("Food Allergies/Intolerances", placeholder="e.g., nuts, dairy, shellfish") with col2: health_issues = st.text_area( "Health Issues/Medical Conditions", placeholder="e.g., diabetes, hypertension, joint problems, injuries" ) medications = st.text_area("Current Medications", placeholder="List any medications that might affect exercise or diet") # Water intake and sleep col1, col2 = st.columns(2) with col1: water_intake = st.slider("Daily Water Intake (glasses)", 1, 15, 8) with col2: sleep_hours = st.slider("Average Sleep Hours", 4, 12, 7) user_profile = { 'age': age, 'weight': weight, 'height': height, 'gender': gender, 'workout_preference': workout_preference, 'workout_time': workout_time, 'fitness_level': fitness_level, 'fitness_goal': fitness_goal, 'schedule': schedule, 'food_preferences': food_preferences, 'allergies': allergies, 'health_issues': health_issues, 'medications': medications, 'water_intake': water_intake, 'sleep_hours': sleep_hours, 'timestamp': datetime.now().isoformat() } return user_profile def display_profile_summary(): """Display user profile summary""" if st.session_state.user_profile: profile = st.session_state.user_profile st.markdown('
📋 Profile Summary
', unsafe_allow_html=True) # Calculate BMI height_m = profile['height'] / 100 bmi = profile['weight'] / (height_m ** 2) col1, col2, col3, col4 = st.columns(4) with col1: st.metric("Age", f"{profile['age']} years") st.metric("Weight", f"{profile['weight']} kg") with col2: st.metric("Height", f"{profile['height']} cm") st.metric("BMI", f"{bmi:.1f}") with col3: st.metric("Fitness Level", profile['fitness_level']) st.metric("Primary Goal", profile['fitness_goal']) with col4: available_days = len([day for day, time in profile['schedule'].items() if time != "Not Available"]) st.metric("Available Days", f"{available_days}/7") st.metric("Water Intake", f"{profile['water_intake']} glasses/day") def generate_plans(): """Generate workout and nutrition plans""" if not st.session_state.user_profile: st.error("Please complete your profile first!") return col1, col2 = st.columns(2) with col1: if st.button("🏋️ Generate Workout Plan", type="primary", use_container_width=True): with st.spinner("Creating your personalized workout plan..."): response = call_backend_service('workout', st.session_state.user_profile) if 'error' in response: st.error(f"Error generating workout plan: {response['error']}") else: st.session_state.workout_plan = response st.session_state.current_session_id = response.get('session_id') # Add to chat history st.session_state.chat_history.append({ 'type': 'workout_request', 'user_profile': st.session_state.user_profile, 'response': response, 'session_id': response.get('session_id'), 'timestamp': datetime.now().isoformat() }) st.success("✅ Workout plan generated successfully!") st.rerun() with col2: if st.button("🥗 Generate Nutrition Plan", type="primary", use_container_width=True): with st.spinner("Creating your personalized nutrition plan..."): response = call_backend_service('nutrition', st.session_state.user_profile) if 'error' in response: st.error(f"Error generating nutrition plan: {response['error']}") else: st.session_state.nutrition_plan = response st.session_state.current_session_id = response.get('session_id') # Add to chat history st.session_state.chat_history.append({ 'type': 'nutrition_request', 'user_profile': st.session_state.user_profile, 'response': response, 'session_id': response.get('session_id'), 'timestamp': datetime.now().isoformat() }) st.success("✅ Nutrition plan generated successfully!") st.rerun() def display_workout_plan(): """Display the generated workout plan""" if st.session_state.workout_plan: st.markdown('
🏋️ Your Workout Plan
', unsafe_allow_html=True) # Display the response content workout_data = st.session_state.workout_plan if isinstance(workout_data, dict) and 'response' in workout_data: st.markdown(workout_data['response']) elif isinstance(workout_data, dict) and 'content' in workout_data: st.markdown(workout_data['content']) else: st.markdown(str(workout_data)) # Download option col1, col2 = st.columns([1, 4]) with col1: download_content = workout_data.get('response', workout_data.get('content', str(workout_data))) st.download_button( "📥 Download Plan", data=download_content, file_name=f"workout_plan_{datetime.now().strftime('%Y%m%d')}.txt", mime="text/plain" ) def display_nutrition_plan(): """Display the generated nutrition plan""" if st.session_state.nutrition_plan: st.markdown('
🥗 Your Nutrition Plan
', unsafe_allow_html=True) # Display the response content nutrition_data = st.session_state.nutrition_plan if isinstance(nutrition_data, dict) and 'response' in nutrition_data: st.markdown(nutrition_data['response']) elif isinstance(nutrition_data, dict) and 'content' in nutrition_data: st.markdown(nutrition_data['content']) else: st.markdown(str(nutrition_data)) # Download option col1, col2 = st.columns([1, 4]) with col1: download_content = nutrition_data.get('response', nutrition_data.get('content', str(nutrition_data))) st.download_button( "📥 Download Plan", data=download_content, file_name=f"nutrition_plan_{datetime.now().strftime('%Y%m%d')}.txt", mime="text/plain" ) def chat_interface(): """Chat interface for follow-up questions""" st.markdown('
💬 Chat with Your AI Coach
', unsafe_allow_html=True) # Display chat history for i, message in enumerate(st.session_state.chat_history): if message['type'] in ['user_message', 'assistant_message']: with st.chat_message(message['type'].replace('_message', '')): st.write(message['content']) # Chat input if prompt := st.chat_input("Ask questions about your workout or nutrition plan..."): # Add user message to chat st.session_state.chat_history.append({ 'type': 'user_message', 'content': prompt, 'timestamp': datetime.now().isoformat() }) with st.chat_message("user"): st.write(prompt) # Get response from backend with st.chat_message("assistant"): with st.spinner("Thinking..."): response = call_backend_service('chat', st.session_state.user_profile, prompt) if 'error' in response: assistant_response = f"I apologize, but I encountered an error: {response['error']}. Please try again." else: assistant_response = response.get('response', 'I apologize, but I couldn\'t process your request.') st.write(assistant_response) # Add assistant response to chat history st.session_state.chat_history.append({ 'type': 'assistant_message', 'content': assistant_response, 'session_id': response.get('session_id'), 'timestamp': datetime.now().isoformat() }) def sidebar_navigation(): """Sidebar navigation and settings""" with st.sidebar: st.markdown("### 🏃‍♀️ AI Fitness Coach") st.markdown("---") # Navigation page = st.radio( "Navigation", ["👤 Profile Setup", "📊 Dashboard", "💬 Chat Coach"] ) # Quick stats if profile exists if st.session_state.user_profile and st.session_state.user_profile.get('height') and st.session_state.user_profile.get('weight'): st.markdown("### 📈 Quick Stats") profile = st.session_state.user_profile # BMI calculation height_m = profile['height'] / 100 bmi = profile['weight'] / (height_m ** 2) if bmi < 18.5: bmi_status = "Underweight" bmi_color = "blue" elif bmi < 25: bmi_status = "Normal" bmi_color = "green" elif bmi < 30: bmi_status = "Overweight" bmi_color = "orange" else: bmi_status = "Obese" bmi_color = "red" st.markdown(f"**BMI:** {bmi:.1f} ({bmi_status})", unsafe_allow_html=True) st.markdown(f"**Goal:** {profile.get('fitness_goal', 'Not set')}") st.markdown(f"**Level:** {profile.get('fitness_level', 'Not set')}") if 'schedule' in profile: available_days = len([day for day, time in profile['schedule'].items() if time != "Not Available"]) st.markdown(f"**Available Days:** {available_days}/7") # Show current session ID if available if st.session_state.current_session_id: st.markdown(f"**Session:** {st.session_state.current_session_id}") st.markdown("---") st.markdown( "
" "Created by Sayon" "
", unsafe_allow_html=True ) return page def main(): """Main application function""" init_session_state() # Header st.markdown('
🏋️ AI Fitness Coach
', unsafe_allow_html=True) st.markdown("*Your personalized fitness and nutrition companion powered by AI*") st.markdown("---") # Sidebar navigation current_page = sidebar_navigation() if current_page == "👤 Profile Setup": user_profile = collect_user_profile() st.markdown("---") if st.button("💾 Save Profile & Continue", type="primary", use_container_width=True): st.session_state.user_profile = user_profile st.session_state.profile_submitted = True # Save to JSON file st.success("✅ Profile saved successfully!") st.balloons() st.rerun() elif current_page == "📊 Dashboard": if not st.session_state.user_profile: st.warning("⚠️ Please complete your profile setup first!") if st.button("Go to Profile Setup"): st.rerun() else: display_profile_summary() st.markdown("---") generate_plans() col1, col2 = st.columns(2) with col1: display_workout_plan() with col2: display_nutrition_plan() elif current_page == "💬 Chat Coach": if not st.session_state.user_profile: st.warning("⚠️ Please complete your profile setup first!") else: chat_interface() if __name__ == "__main__": main()