Spaces:
Build error
Build error
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| from io import BytesIO | |
| from reportlab.lib.pagesizes import letter | |
| from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, ListFlowable, ListItem | |
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle | |
| from datetime import date | |
| from openai import OpenAI | |
| import os | |
| from datetime import datetime, timedelta | |
| from dotenv import load_dotenv | |
| from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, ListFlowable, ListItem | |
| # Load environment variables | |
| load_dotenv() | |
| # Set up OpenAI client | |
| client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) | |
| # Constants | |
| MEAL_FREQUENCY = ["Breakfast", "Morning Snack", "Lunch", "Afternoon Snack", "Dinner", "Evening Snack"] | |
| FOOD_GROUPS = ["Fruits", "Vegetables", "Grains", "Proteins", "Dairy"] | |
| EXERCISE = ["Cardio", "Strength", "Flexibility", "Balance"] | |
| LIFESTYLE = ["Sleep", "Stress", "Work-Life Balance", "Social Connections"] | |
| MEDICAL_HISTORY = ["Chronic Conditions", "Family History", "Medications", "Allergies"] | |
| # Helper functions | |
| def get_gpt_analysis(prompt, data): | |
| try: | |
| response = client.chat.completions.create( | |
| model="gpt-3.5-turbo", | |
| messages=[ | |
| {"role": "system", "content": "You are a senior nutritionist and health advisor. Provide concise, personalized advice in bullet points."}, | |
| {"role": "user", "content": f"{prompt}\n\nUser Data: {data}"} | |
| ], | |
| temperature=0.2, | |
| max_tokens=1024 | |
| ) | |
| return response.choices[0].message.content | |
| except Exception as e: | |
| print(f"Error in GPT API call: {e}") | |
| return "I apologize, but I encountered an error while processing your request." | |
| # Update the create_chart function | |
| def create_chart(data, labels, title, chart_type='bar'): | |
| fig, ax = plt.subplots(figsize=(8, 6)) | |
| if chart_type == 'bar': | |
| ax.bar(labels, data) | |
| elif chart_type == 'pie': | |
| # Filter out zero values to avoid plotting empty slices | |
| non_zero = [(label, value) for label, value in zip(labels, data) if value > 0] | |
| if non_zero: | |
| labels, data = zip(*non_zero) | |
| ax.pie(data, labels=labels, autopct='%1.1f%%', startangle=90) | |
| ax.axis('equal') | |
| else: | |
| ax.text(0.5, 0.5, "No data to display", ha='center', va='center') | |
| ax.set_title(title) | |
| plt.close(fig) | |
| buf = BytesIO() | |
| fig.savefig(buf, format='png') | |
| buf.seek(0) | |
| return buf | |
| # Add this new function to generate a personalized weekly plan | |
| def generate_personalized_weekly_plan(user_data): | |
| prefs = user_data['detailed_preferences'] | |
| plan = {} | |
| for i in range(7): | |
| day = (datetime.now() + timedelta(days=i)).strftime("%A") | |
| plan[day] = { | |
| "Meals": [], | |
| "Exercise": [], | |
| "Lifestyle": [] | |
| } | |
| # Generate meal suggestions based on preferences and nutrition data | |
| if "Vegetarian" in prefs['meal_preferences']: | |
| plan[day]["Meals"].append(f"Breakfast: Vegetarian omelette with spinach and mushrooms") | |
| elif "Vegan" in prefs['meal_preferences']: | |
| plan[day]["Meals"].append(f"Breakfast: Vegan smoothie bowl with berries and nuts") | |
| else: | |
| plan[day]["Meals"].append(f"Breakfast: Whole grain toast with avocado and eggs") | |
| plan[day]["Meals"].append(f"Lunch: Mixed green salad with {', '.join(prefs['meal_preferences'][:2])} protein") | |
| plan[day]["Meals"].append(f"Dinner: Grilled {prefs['meal_preferences'][0] if prefs['meal_preferences'] else 'chicken'} with roasted vegetables") | |
| # Generate exercise suggestions based on preferences and schedule | |
| if prefs['exercise_time'] == "Morning": | |
| plan[day]["Exercise"].append(f"Morning: 30-minute {prefs['exercise_preferences'][0] if prefs['exercise_preferences'] else 'walk'}") | |
| elif prefs['exercise_time'] == "Evening": | |
| plan[day]["Exercise"].append(f"Evening: 45-minute {prefs['exercise_preferences'][0] if prefs['exercise_preferences'] else 'jog'}") | |
| else: | |
| plan[day]["Exercise"].append(f"Afternoon: 1-hour {prefs['exercise_preferences'][0] if prefs['exercise_preferences'] else 'gym session'}") | |
| # Add lifestyle recommendations | |
| plan[day]["Lifestyle"].append(f"Practice {prefs['stress_relief'][0] if prefs['stress_relief'] else 'meditation'} for 15 minutes") | |
| plan[day]["Lifestyle"].append(f"Get {user_data.get('sleep_hours', 8)} hours of sleep, from {prefs['sleep_time'].strftime('%I:%M %p')} to {prefs['wake_time'].strftime('%I:%M %p')}") | |
| return plan | |
| def generate_pdf_report(user_data, analysis): | |
| buffer = BytesIO() | |
| doc = SimpleDocTemplate(buffer, pagesize=letter, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=18) | |
| styles = getSampleStyleSheet() | |
| if 'Bullet' not in styles: | |
| styles.add(ParagraphStyle(name='Bullet', parent=styles['BodyText'], bulletIndent=20, leftIndent=35)) | |
| story = [] | |
| # Cover Page | |
| story.append(Paragraph(f"{user_data['name']}'s Health and Wellness Report", styles['Title'])) | |
| story.append(Paragraph(f"Date: {date.today().strftime('%Y-%m-%d')}", styles['Normal'])) | |
| story.append(Spacer(1, 12)) | |
| # Personal Information | |
| story.append(Paragraph("Personal Information", styles['Heading1'])) | |
| for key, value in user_data.items(): | |
| if key not in ['nutrition', 'exercise', 'lifestyle', 'medical_history', 'detailed_preferences']: | |
| story.append(Paragraph(f"{key.capitalize()}: {value}", styles['Normal'])) | |
| # Nutrition Analysis | |
| story.append(Paragraph("Nutrition Analysis", styles['Heading1'])) | |
| nutrition_data = [user_data['nutrition'].get(group, 0) for group in FOOD_GROUPS] | |
| nutrition_chart = create_chart(nutrition_data, FOOD_GROUPS, "Food Group Intake") | |
| story.append(Image(nutrition_chart, width=400, height=300)) | |
| bullet_points = [Paragraph(point.strip(), styles['Bullet']) for point in analysis['nutrition'].split('\n') if point.strip()] | |
| story.append(ListFlowable(bullet_points, bulletType='bullet', start='')) | |
| # Exercise Analysis | |
| story.append(Paragraph("Exercise Analysis", styles['Heading1'])) | |
| exercise_data = [user_data['exercise'].get(exercise, 0) for exercise in EXERCISE] | |
| exercise_chart = create_chart(exercise_data, EXERCISE, "Exercise Habits") | |
| story.append(Image(exercise_chart, width=400, height=300)) | |
| bullet_points = [Paragraph(point.strip(), styles['Bullet']) for point in analysis['exercise'].split('\n') if point.strip()] | |
| story.append(ListFlowable(bullet_points, bulletType='bullet', start='')) | |
| # Lifestyle Analysis | |
| story.append(Paragraph("Lifestyle Analysis", styles['Heading1'])) | |
| lifestyle_data = [user_data['lifestyle'].get(factor, 0) for factor in LIFESTYLE] | |
| lifestyle_chart = create_chart(lifestyle_data, LIFESTYLE, "Lifestyle Factors", chart_type='pie') | |
| story.append(Image(lifestyle_chart, width=400, height=300)) | |
| bullet_points = [Paragraph(point.strip(), styles['Bullet']) for point in analysis['lifestyle'].split('\n') if point.strip()] | |
| story.append(ListFlowable(bullet_points, bulletType='bullet', start='')) | |
| # Personalized Recommendations | |
| story.append(Paragraph("Personalized Recommendations", styles['Heading1'])) | |
| bullet_points = [Paragraph(point.strip(), styles['Bullet']) for point in analysis['recommendations'].split('\n') if point.strip()] | |
| story.append(ListFlowable(bullet_points, bulletType='bullet', start='')) | |
| # Weekly Plan | |
| story.append(Paragraph("Your Personalized Weekly Plan", styles['Heading1'])) | |
| # Generate a personalized weekly plan | |
| weekly_plan = generate_personalized_weekly_plan(user_data) | |
| # Add the weekly plan to the PDF | |
| for day, plan in weekly_plan.items(): | |
| story.append(Paragraph(day, styles['Heading2'])) | |
| for category, items in plan.items(): | |
| story.append(Paragraph(category, styles['Heading3'])) | |
| bullet_points = [Paragraph(item, styles['Bullet']) for item in items] | |
| story.append(ListFlowable(bullet_points, bulletType='bullet', start='')) | |
| doc.build(story) | |
| buffer.seek(0) | |
| return buffer | |
| # Streamlit UI | |
| st.set_page_config(page_title="Health and Wellness Assessment", page_icon="🍏", layout="wide") | |
| def introduction_page(): | |
| st.header("Welcome to Your Health and Wellness Journey") | |
| st.markdown(""" | |
| This comprehensive assessment will help you understand your current health status and provide personalized recommendations for improvement. | |
| Please answer all questions honestly for the most accurate results. Your data is confidential and will only be used to generate your personalized report. | |
| Let's begin your journey to better health! | |
| """) | |
| def personal_info_page(): | |
| st.header("Personal Information") | |
| st.session_state.user_data['name'] = st.text_input("Name", st.session_state.user_data.get('name', '')) | |
| st.session_state.user_data['age'] = st.number_input("Age", min_value=18, max_value=100, value=st.session_state.user_data.get('age', 30)) | |
| st.session_state.user_data['gender'] = st.selectbox("Gender", ["Male", "Female", "Other"], index=["Male", "Female", "Other"].index(st.session_state.user_data.get('gender', 'Male'))) | |
| st.session_state.user_data['height'] = st.number_input("Height (cm)", min_value=100, max_value=250, value=st.session_state.user_data.get('height', 170)) | |
| st.session_state.user_data['weight'] = st.number_input("Weight (kg)", min_value=30, max_value=200, value=st.session_state.user_data.get('weight', 70)) | |
| def nutrition_page(): | |
| st.header("Nutrition Assessment") | |
| if 'nutrition' not in st.session_state.user_data: | |
| st.session_state.user_data['nutrition'] = {} | |
| st.subheader("How often do you include the following food groups in your meals?") | |
| for group in FOOD_GROUPS: | |
| st.session_state.user_data['nutrition'][group] = st.select_slider( | |
| f"{group}", | |
| options=["Never", "Rarely", "Sometimes", "Often", "Always"], | |
| value=st.session_state.user_data['nutrition'].get(group, "Sometimes") | |
| ) | |
| st.subheader("Meal Frequency") | |
| for meal in MEAL_FREQUENCY: | |
| st.session_state.user_data['nutrition'][f"{meal}_frequency"] = st.select_slider( | |
| f"How often do you have {meal}?", | |
| options=["Never", "1-2 times/week", "3-4 times/week", "5-6 times/week", "Daily"], | |
| value=st.session_state.user_data['nutrition'].get(f"{meal}_frequency", "Daily") | |
| ) | |
| st.session_state.user_data['water_intake'] = st.number_input( | |
| "How many glasses of water do you drink per day?", | |
| min_value=0, | |
| max_value=20, | |
| value=st.session_state.user_data.get('water_intake', 8) | |
| ) | |
| def exercise_page(): | |
| st.header("Exercise Habits") | |
| if 'exercise' not in st.session_state.user_data: | |
| st.session_state.user_data['exercise'] = {} | |
| st.subheader("How often do you engage in the following types of exercise?") | |
| for exercise_type in EXERCISE: | |
| st.session_state.user_data['exercise'][exercise_type] = st.select_slider( | |
| f"{exercise_type}", | |
| options=["Never", "1-2 times/month", "1-2 times/week", "3-4 times/week", "5+ times/week"], | |
| value=st.session_state.user_data['exercise'].get(exercise_type, "1-2 times/week") | |
| ) | |
| st.session_state.user_data['exercise_duration'] = st.number_input( | |
| "On average, how long are your exercise sessions? (minutes)", | |
| min_value=0, | |
| max_value=180, | |
| value=st.session_state.user_data.get('exercise_duration', 30) | |
| ) | |
| # Add this function to convert lifestyle ratings to numeric values | |
| def lifestyle_to_numeric(rating): | |
| conversion = { | |
| "Poor": 1, | |
| "Fair": 2, | |
| "Good": 3, | |
| "Very Good": 4, | |
| "Excellent": 5, | |
| "Very Low": 1, | |
| "Low": 2, | |
| "Moderate": 3, | |
| "High": 4, | |
| "Very High": 5 | |
| } | |
| return conversion.get(rating, 3) # Default to 3 if rating not found | |
| # Update the lifestyle_page function | |
| def lifestyle_page(): | |
| st.header("Lifestyle Factors") | |
| if 'lifestyle' not in st.session_state.user_data: | |
| st.session_state.user_data['lifestyle'] = {} | |
| st.subheader("Rate the following aspects of your lifestyle:") | |
| options = ["Poor", "Fair", "Good", "Very Good", "Excellent"] | |
| for factor in LIFESTYLE: | |
| # Get the current value, defaulting to "Good" if not set or not in options | |
| current_value = st.session_state.user_data['lifestyle'].get(factor, "Good") | |
| if current_value not in options: | |
| current_value = "Good" | |
| rating = st.select_slider( | |
| f"{factor}", | |
| options=options, | |
| value=current_value | |
| ) | |
| st.session_state.user_data['lifestyle'][factor] = lifestyle_to_numeric(rating) | |
| st.session_state.user_data['sleep_hours'] = st.number_input( | |
| "How many hours of sleep do you get on average?", | |
| min_value=4, | |
| max_value=12, | |
| value=st.session_state.user_data.get('sleep_hours', 7) | |
| ) | |
| stress_options = ["Very Low", "Low", "Moderate", "High", "Very High"] | |
| current_stress = st.session_state.user_data.get('stress_level', "Moderate") | |
| if current_stress not in stress_options: | |
| current_stress = "Moderate" | |
| stress_level = st.select_slider( | |
| "Rate your overall stress level", | |
| options=stress_options, | |
| value=current_stress | |
| ) | |
| st.session_state.user_data['stress_level'] = lifestyle_to_numeric(stress_level) | |
| def medical_history_page(): | |
| st.header("Medical History") | |
| if 'medical_history' not in st.session_state.user_data: | |
| st.session_state.user_data['medical_history'] = {} | |
| for category in MEDICAL_HISTORY: | |
| st.session_state.user_data['medical_history'][category] = st.text_area( | |
| f"{category}", | |
| value=st.session_state.user_data['medical_history'].get(category, ''), | |
| help="Enter relevant information or 'None' if not applicable" | |
| ) | |
| st.session_state.user_data['smoker'] = st.selectbox( | |
| "Do you smoke?", | |
| ["No", "Occasionally", "Regularly"], | |
| index=["No", "Occasionally", "Regularly"].index(st.session_state.user_data.get('smoker', 'No')) | |
| ) | |
| st.session_state.user_data['alcohol'] = st.selectbox( | |
| "How often do you consume alcohol?", | |
| ["Never", "Occasionally", "Weekly", "Daily"], | |
| index=["Never", "Occasionally", "Weekly", "Daily"].index(st.session_state.user_data.get('alcohol', 'Occasionally')) | |
| ) | |
| def detailed_preferences_page(): | |
| st.header("Detailed Preferences") | |
| if 'detailed_preferences' not in st.session_state.user_data: | |
| st.session_state.user_data['detailed_preferences'] = {} | |
| prefs = st.session_state.user_data['detailed_preferences'] | |
| prefs['wake_time'] = st.time_input("What time do you usually wake up?", value=prefs.get('wake_time', datetime.strptime("07:00", "%H:%M").time())) | |
| prefs['sleep_time'] = st.time_input("What time do you usually go to sleep?", value=prefs.get('sleep_time', datetime.strptime("22:00", "%H:%M").time())) | |
| prefs['meal_preferences'] = st.multiselect( | |
| "Do you have any specific meal preferences?", | |
| ["Vegetarian", "Vegan", "Low-carb", "High-protein", "Gluten-free", "Dairy-free"], | |
| default=prefs.get('meal_preferences', []) | |
| ) | |
| prefs['food_allergies'] = st.text_input("Do you have any food allergies? (Separate with commas)", value=prefs.get('food_allergies', '')) | |
| prefs['exercise_preferences'] = st.multiselect( | |
| "What types of exercise do you enjoy?", | |
| ["Walking", "Running", "Cycling", "Swimming", "Yoga", "Weight Training", "HIIT", "Dance", "Team Sports"], | |
| default=prefs.get('exercise_preferences', []) | |
| ) | |
| prefs['exercise_time'] = st.selectbox( | |
| "When do you prefer to exercise?", | |
| ["Morning", "Afternoon", "Evening"], | |
| index=["Morning", "Afternoon", "Evening"].index(prefs.get('exercise_time', "Morning")) | |
| ) | |
| prefs['work_hours'] = st.text_input("What are your typical work hours? (e.g., 9am-5pm)", value=prefs.get('work_hours', '')) | |
| prefs['stress_relief'] = st.multiselect( | |
| "What activities help you relieve stress?", | |
| ["Meditation", "Reading", "Listening to Music", "Taking a Bath", "Gardening", "Painting/Art", "Cooking"], | |
| default=prefs.get('stress_relief', []) | |
| ) | |
| def generate_report_page(): | |
| st.header("Generate Your Health and Wellness Report") | |
| if st.button("Generate Report", key="generate_report_button"): # Added unique key here | |
| if not all(key in st.session_state.user_data for key in ['name', 'age', 'gender', 'height', 'weight', 'nutrition', 'exercise', 'lifestyle', 'medical_history']): | |
| st.error("Please complete all sections before generating the report.") | |
| else: | |
| with st.spinner("Analyzing your data and generating report..."): | |
| analysis = { | |
| 'nutrition': get_gpt_analysis("Analyze the user's nutritional habits and provide 3-5 key insights or recommendations in bullet points.", st.session_state.user_data['nutrition']), | |
| 'exercise': get_gpt_analysis("Analyze the user's exercise habits and provide 3-5 key insights or recommendations in bullet points.", st.session_state.user_data['exercise']), | |
| 'lifestyle': get_gpt_analysis("Analyze the user's lifestyle factors and provide 3-5 key insights or recommendations in bullet points.", st.session_state.user_data['lifestyle']), | |
| 'recommendations': get_gpt_analysis("Provide 5 personalized health and wellness recommendations based on the user's overall profile. Present these as bullet points.", st.session_state.user_data), | |
| 'weekly_plan': get_gpt_analysis("Create a brief, bullet-point weekly plan for the user, including suggested meals, exercises, and lifestyle adjustments. Keep it concise and actionable.", st.session_state.user_data) | |
| } | |
| pdf_buffer = generate_pdf_report(st.session_state.user_data, analysis) | |
| st.success("Your Health and Wellness Report has been generated!") | |
| st.download_button( | |
| label="Download Your Report", | |
| data=pdf_buffer, | |
| file_name="health_wellness_report.pdf", | |
| mime="application/pdf" | |
| ) | |
| st.subheader("Summary of Recommendations") | |
| st.write(analysis['recommendations']) | |
| st.subheader("Your Personalized Weekly Plan") | |
| st.write(analysis['weekly_plan']) | |
| # Make sure to add unique keys to the navigation buttons in the main() function as well | |
| def main(): | |
| if 'user_data' not in st.session_state: | |
| st.session_state.user_data = {} | |
| if 'page' not in st.session_state: | |
| st.session_state.page = 0 | |
| st.title("Health and Wellness Assessment") | |
| pages = [ | |
| introduction_page, | |
| personal_info_page, | |
| nutrition_page, | |
| exercise_page, | |
| lifestyle_page, | |
| medical_history_page, | |
| detailed_preferences_page, | |
| generate_report_page | |
| ] | |
| # Convert existing lifestyle data to numeric if it's not already | |
| if 'lifestyle' in st.session_state.user_data: | |
| for factor in LIFESTYLE: | |
| if factor in st.session_state.user_data['lifestyle']: | |
| st.session_state.user_data['lifestyle'][factor] = lifestyle_to_numeric(st.session_state.user_data['lifestyle'][factor]) | |
| st.sidebar.title("Navigation") | |
| page_names = ["Introduction", "Personal Information", "Nutrition Assessment", "Exercise Habits", "Lifestyle Factors", "Medical History", "Generate Report"] | |
| for i, page_name in enumerate(page_names): | |
| if st.sidebar.button(page_name, key=f"nav_{i}"): # Added unique keys here | |
| st.session_state.page = i | |
| pages[st.session_state.page]() | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| if st.button("Previous", key="prev_button") and st.session_state.page > 0: # Added unique key | |
| st.session_state.page -= 1 | |
| st.rerun() | |
| with col2: | |
| if st.button("Next", key="next_button") and st.session_state.page < len(pages) - 1: # Added unique key | |
| st.session_state.page += 1 | |
| st.rerun() | |
| if __name__ == "__main__": | |
| main() |