Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import pandas as pd | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| import os | |
| import datetime | |
| import json | |
| from sklearn.linear_model import LinearRegression | |
| from sklearn.preprocessing import StandardScaler | |
| import joblib | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| # Initialize data directory and files | |
| os.makedirs('data', exist_ok=True) | |
| DATA_FILE = 'data/weight_journal.csv' | |
| GOAL_FILE = 'data/goal.json' | |
| MODEL_FILE = 'data/weight_prediction_model.pkl' | |
| SCALER_FILE = 'data/weight_prediction_scaler.pkl' | |
| ACHIEVEMENTS_FILE = 'data/achievements.json' | |
| # Load or initialize dataframe | |
| if os.path.exists(DATA_FILE): | |
| df = pd.read_csv(DATA_FILE) | |
| df['date'] = pd.to_datetime(df['date']) | |
| else: | |
| df = pd.DataFrame(columns=['date', 'weight', 'calories_consumed', 'calories_burned', | |
| 'water_intake', 'sleep_hours', 'stress_level', 'mood', | |
| 'exercise_minutes', 'notes']) | |
| df.to_csv(DATA_FILE, index=False) | |
| # Load or initialize goals | |
| if os.path.exists(GOAL_FILE): | |
| with open(GOAL_FILE, 'r') as f: | |
| goal = json.load(f) | |
| else: | |
| goal = {'target_weight': None, 'target_date': None} | |
| # Load or initialize achievements | |
| if os.path.exists(ACHIEVEMENTS_FILE): | |
| with open(ACHIEVEMENTS_FILE, 'r') as f: | |
| achievements = json.load(f) | |
| else: | |
| achievements = [] | |
| # Load Indian food dataset with robust column handling | |
| try: | |
| from datasets import load_dataset | |
| ds = load_dataset("Anupam007/nutarian-Indianfood") | |
| food_df = pd.DataFrame(ds['train']) | |
| print(f"Successfully loaded Indian food dataset with {len(food_df)} items") | |
| print("Columns in dataset:", food_df.columns.tolist()) | |
| # Rename potential column names to 'name' for consistency | |
| if 'name' not in food_df.columns: | |
| if 'food_name' in food_df.columns: | |
| food_df = food_df.rename(columns={'food_name': 'name'}) | |
| elif 'item' in food_df.columns: | |
| food_df = food_df.rename(columns={'item': 'name'}) | |
| else: | |
| raise ValueError("No suitable 'name' column found in dataset") | |
| # Ensure 'calories' column exists | |
| if 'calories' not in food_df.columns and 'calorie_count' in food_df.columns: | |
| food_df = food_df.rename(columns={'calorie_count': 'calories'}) | |
| elif 'calories' not in food_df.columns: | |
| raise ValueError("No 'calories' column found in dataset") | |
| except Exception as e: | |
| print(f"Failed to load dataset or process columns: {e}. Using fallback data.") | |
| food_df = pd.DataFrame({ | |
| 'name': ['Rice', 'Dal', 'Roti', 'Chicken Curry'], | |
| 'calories': [130, 150, 80, 200] | |
| }) | |
| # Core Functions | |
| def add_entry(date, weight, calories_consumed, calories_burned, water_intake, sleep_hours, | |
| stress_level, mood, exercise_minutes, notes): | |
| global df | |
| if not date or not weight: | |
| return "❌ Date and weight are required fields." | |
| try: | |
| entry_date = pd.to_datetime(date) | |
| if entry_date in df['date'].values: | |
| return f"❌ An entry for {date} already exists." | |
| new_entry = { | |
| 'date': entry_date, | |
| 'weight': float(weight), | |
| 'calories_consumed': float(calories_consumed or 0), | |
| 'calories_burned': float(calories_burned or 0), | |
| 'water_intake': float(water_intake or 0), | |
| 'sleep_hours': float(sleep_hours or 0), | |
| 'stress_level': int(stress_level or 5), | |
| 'mood': mood or 'Neutral', | |
| 'exercise_minutes': float(exercise_minutes or 0), | |
| 'notes': notes or '' | |
| } | |
| df = pd.concat([df, pd.DataFrame([new_entry])], ignore_index=True) | |
| df = df.sort_values('date', ascending=False) | |
| df.to_csv(DATA_FILE, index=False) | |
| update_achievements() | |
| return f"✅ Entry for {date} added successfully!" | |
| except Exception as e: | |
| return f"❌ Error: {str(e)}" | |
| def view_entries(num_entries=10): | |
| if len(df) == 0: | |
| return pd.DataFrame(columns=df.columns) | |
| display_df = df.sort_values('date', ascending=False).head(int(num_entries)).copy() | |
| display_df['date'] = display_df['date'].dt.strftime('%Y-%m-%d') | |
| return display_df | |
| def update_entry(date, weight, calories_consumed, calories_burned, water_intake, sleep_hours, | |
| stress_level, mood, exercise_minutes, notes): | |
| global df | |
| if not date: | |
| return "❌ Date is required." | |
| try: | |
| entry_date = pd.to_datetime(date) | |
| if entry_date not in df['date'].values: | |
| return f"❌ No entry found for {date}." | |
| idx = df[df['date'] == entry_date].index[0] | |
| if weight is not None: df.at[idx, 'weight'] = float(weight) | |
| if calories_consumed is not None: df.at[idx, 'calories_consumed'] = float(calories_consumed) | |
| if calories_burned is not None: df.at[idx, 'calories_burned'] = float(calories_burned) | |
| if water_intake is not None: df.at[idx, 'water_intake'] = float(water_intake) | |
| if sleep_hours is not None: df.at[idx, 'sleep_hours'] = float(sleep_hours) | |
| if stress_level is not None: df.at[idx, 'stress_level'] = int(stress_level) | |
| if mood: df.at[idx, 'mood'] = mood | |
| if exercise_minutes is not None: df.at[idx, 'exercise_minutes'] = float(exercise_minutes) | |
| if notes is not None: df.at[idx, 'notes'] = notes | |
| df.to_csv(DATA_FILE, index=False) | |
| update_achievements() | |
| return f"✅ Entry for {date} updated successfully!" | |
| except Exception as e: | |
| return f"❌ Error: {str(e)}" | |
| def delete_entry(date): | |
| global df | |
| if not date: | |
| return "❌ Date is required." | |
| try: | |
| entry_date = pd.to_datetime(date) | |
| if entry_date not in df['date'].values: | |
| return f"❌ No entry found for {date}." | |
| df = df[df['date'] != entry_date] | |
| df.to_csv(DATA_FILE, index=False) | |
| update_achievements() | |
| return f"✅ Entry for {date} deleted successfully!" | |
| except Exception as e: | |
| return f"❌ Error: {str(e)}" | |
| def load_entry_by_date(date): | |
| if not date: | |
| return [None] * 9 + ["❌ Date is required."] | |
| try: | |
| entry_date = pd.to_datetime(date) | |
| if entry_date not in df['date'].values: | |
| return [None] * 9 + [f"❌ No entry found for {date}."] | |
| entry = df[df['date'] == entry_date].iloc[0] | |
| return [entry[col] for col in ['weight', 'calories_consumed', 'calories_burned', 'water_intake', | |
| 'sleep_hours', 'stress_level', 'mood', 'exercise_minutes', 'notes']] + \ | |
| [f"✅ Entry for {date} loaded successfully!"] | |
| except Exception as e: | |
| return [None] * 9 + [f"❌ Error: {str(e)}"] | |
| # Visualization Functions | |
| def create_dashboard(): | |
| if len(df) < 3: | |
| return "❌ Not enough data.", None | |
| fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 5)) | |
| df.sort_values('date').plot(x='date', y='weight', ax=ax1, title="Weight Trend", marker='o', color='blue') | |
| df.sort_values('date').plot(x='date', y=['calories_consumed', 'calories_burned'], ax=ax2, title="Calories", kind='bar') | |
| df.sort_values('date').plot(x='date', y='water_intake', ax=ax3, title="Water Intake", marker='s', color='green') | |
| for ax in [ax1, ax2, ax3]: | |
| ax.grid(True, alpha=0.3) | |
| ax.tick_params(axis='x', rotation=45) | |
| plt.tight_layout() | |
| return "✅ Dashboard ready!", fig | |
| def create_weight_plot(): | |
| if len(df) < 3: | |
| return "❌ Not enough data.", None | |
| plot_df = df.sort_values('date') | |
| plt.figure(figsize=(10, 6)) | |
| plt.plot(plot_df['date'], plot_df['weight'], marker='o', linestyle='-', color='blue', label='Weight') | |
| if goal['target_weight']: | |
| plt.axhline(y=goal['target_weight'], color='green', linestyle='--', label='Goal') | |
| plt.title('Weight Over Time') | |
| plt.xlabel('Date') | |
| plt.ylabel('Weight') | |
| plt.legend() | |
| plt.grid(True, alpha=0.3) | |
| plt.xticks(rotation=45) | |
| temp_file = "temp_weight_plot.png" | |
| plt.tight_layout() | |
| plt.savefig(temp_file) | |
| plt.close() | |
| return "✅ Plot generated!", temp_file | |
| # Goal Setting | |
| def set_goal(target_weight, target_date): | |
| global goal | |
| if not target_weight or not target_date: | |
| return "❌ Target weight and date are required." | |
| try: | |
| goal = {'target_weight': float(target_weight), 'target_date': pd.to_datetime(target_date).strftime('%Y-%m-%d')} | |
| with open(GOAL_FILE, 'w') as f: | |
| json.dump(goal, f) | |
| return "✅ Goal set successfully!" | |
| except Exception as e: | |
| return f"❌ Error: {str(e)}" | |
| def view_goal(): | |
| if not goal['target_weight']: | |
| return "No goal set yet." | |
| return f"Target Weight: {goal['target_weight']} | Target Date: {goal['target_date']}\n" + \ | |
| f"Progress: {((df['weight'].iloc[-1] - goal['target_weight']) / (df['weight'].iloc[0] - goal['target_weight']) * 100):.1f}%" | |
| # Achievements | |
| def update_achievements(): | |
| global achievements | |
| new_achievements = [] | |
| if len(df) >= 1 and "First Entry 🏅" not in achievements: | |
| new_achievements.append("First Entry 🏅") | |
| if len(df) >= 7 and df['date'].diff().mean().days <= 1 and "Consistency Star 🌟" not in achievements: | |
| new_achievements.append("Consistency Star 🌟") | |
| if len(df) >= 7 and df['water_intake'].tail(7).mean() >= 8 and "Water Warrior 💧" not in achievements: | |
| new_achievements.append("Water Warrior 💧") | |
| achievements.extend(new_achievements) | |
| with open(ACHIEVEMENTS_FILE, 'w') as f: | |
| json.dump(achievements, f) | |
| return "\n".join(achievements) or "No achievements yet—keep going!" | |
| # Prediction | |
| def predict_weight_trajectory(days=30, calorie_adjustment=0, exercise_adjustment=0): | |
| if len(df) < 7 or not os.path.exists(MODEL_FILE): | |
| return "❌ Not enough data or model not trained.", None, "" | |
| model = joblib.load(MODEL_FILE) | |
| scaler = joblib.load(SCALER_FILE) | |
| last_entry = df.sort_values('date', ascending=False).iloc[0] | |
| last_week = df.sort_values('date', ascending=False).head(7) | |
| avg_calories_consumed = last_week['calories_consumed'].mean() + calorie_adjustment | |
| avg_calories_burned = last_week['calories_burned'].mean() + calorie_adjustment | |
| avg_exercise = last_week['exercise_minutes'].mean() + exercise_adjustment | |
| predict_data = pd.DataFrame({ | |
| 'date': [last_entry['date'] + datetime.timedelta(days=i) for i in range(1, days+1)], | |
| 'calories_consumed': [avg_calories_consumed] * days, | |
| 'calories_burned': [avg_calories_burned] * days, | |
| 'water_intake': [last_week['water_intake'].mean()] * days, | |
| 'sleep_hours': [last_week['sleep_hours'].mean()] * days, | |
| 'stress_level': [last_week['stress_level'].mean()] * days, | |
| 'exercise_minutes': [avg_exercise] * days | |
| }) | |
| X_pred = predict_data[['calories_consumed', 'calories_burned', 'water_intake', 'sleep_hours', 'stress_level', 'exercise_minutes']] | |
| X_pred_scaled = scaler.transform(X_pred) | |
| predict_data['weight'] = model.predict(X_pred_scaled) | |
| plt.figure(figsize=(10, 6)) | |
| plt.plot(df['date'], df['weight'], 'o-', color='blue', label='Historical') | |
| plt.plot(predict_data['date'], predict_data['weight'], 'o--', color='red', label='Predicted') | |
| if goal['target_weight']: | |
| plt.axhline(y=goal['target_weight'], color='green', linestyle='--', label='Goal') | |
| plt.title('Weight Trajectory Prediction') | |
| plt.xlabel('Date') | |
| plt.ylabel('Weight') | |
| plt.grid(True, alpha=0.3) | |
| plt.xticks(rotation=45) | |
| plt.legend() | |
| start_weight = df['weight'].iloc[-1] | |
| end_weight = predict_data['weight'].iloc[-1] | |
| report = f"Starting weight: {start_weight:.1f}\nPredicted weight after {days} days: {end_weight:.1f}\n" + \ | |
| f"Change: {end_weight - start_weight:.1f}" | |
| recommendations = "Keep tracking consistently!" if end_weight < start_weight else "Consider reducing calories." | |
| return report, plt, recommendations | |
| def train_prediction_model(): | |
| if len(df) < 7: | |
| return "❌ Not enough data." | |
| model_df = df.sort_values('date') | |
| features = ['calories_consumed', 'calories_burned', 'water_intake', 'sleep_hours', 'stress_level', 'exercise_minutes'] | |
| X = model_df[features].fillna(model_df[features].median()) | |
| y = model_df['weight'] | |
| scaler = StandardScaler() | |
| X_scaled = scaler.fit_transform(X) | |
| model = LinearRegression() | |
| model.fit(X_scaled, y) | |
| joblib.dump(model, MODEL_FILE) | |
| joblib.dump(scaler, SCALER_FILE) | |
| return "✅ Model trained!" | |
| # Food Log | |
| def log_food(food_name, quantity): | |
| if food_name not in food_df['name'].values: | |
| return "❌ Food not found." | |
| calories = food_df[food_df['name'] == food_name]['calories'].iloc[0] * quantity | |
| return f"✅ Logged {quantity} of {food_name} ({calories} calories). Add to your entry!" | |
| # Gradio Interface | |
| with gr.Blocks(title="FitJourney", theme=gr.themes.Soft(primary_hue="blue")) as iface: | |
| gr.Markdown("# 🏋️♀️ FitJourney - Your Weight Loss Companion") | |
| with gr.Tab("Dashboard"): | |
| dashboard_button = gr.Button("Show Dashboard", variant="primary") | |
| dashboard_text = gr.Markdown() | |
| dashboard_plot = gr.Plot() | |
| dashboard_button.click(create_dashboard, outputs=[dashboard_text, dashboard_plot]) | |
| with gr.Tab("Add Entry"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| date_input = gr.Textbox(label="Date (YYYY-MM-DD)") | |
| weight_input = gr.Number(label="Weight (lbs)") | |
| calories_consumed_input = gr.Number(label="Calories Consumed") | |
| calories_burned_input = gr.Number(label="Calories Burned") | |
| water_intake_input = gr.Number(label="Water Intake (cups)") | |
| sleep_hours_input = gr.Number(label="Sleep Hours") | |
| stress_level_input = gr.Slider(1, 10, step=1, label="Stress Level") | |
| mood_input = gr.Dropdown(['Great', 'Good', 'Neutral', 'Poor'], label="Mood") | |
| exercise_minutes_input = gr.Number(label="Exercise Minutes") | |
| notes_input = gr.Textbox(label="Notes") | |
| add_button = gr.Button("Add Entry", variant="primary") | |
| add_output = gr.Markdown() | |
| add_button.click(add_entry, inputs=[date_input, weight_input, calories_consumed_input, calories_burned_input, | |
| water_intake_input, sleep_hours_input, stress_level_input, mood_input, | |
| exercise_minutes_input, notes_input], outputs=add_output) | |
| with gr.Tab("View Entries"): | |
| num_entries_view = gr.Slider(5, 30, step=5, value=10, label="Entries to View") | |
| view_button = gr.Button("View", variant="secondary") | |
| view_output = gr.DataFrame() | |
| view_button.click(view_entries, inputs=num_entries_view, outputs=view_output) | |
| with gr.Tab("Update Entry"): | |
| date_update_input = gr.Textbox(label="Date (YYYY-MM-DD)") | |
| with gr.Row(): | |
| with gr.Column(): | |
| weight_update_input = gr.Number(label="Weight (lbs)") | |
| calories_consumed_update_input = gr.Number(label="Calories Consumed") | |
| calories_burned_update_input = gr.Number(label="Calories Burned") | |
| water_intake_update_input = gr.Number(label="Water Intake (cups)") | |
| sleep_hours_update_input = gr.Number(label="Sleep Hours") | |
| stress_level_update_input = gr.Slider(1, 10, step=1, label="Stress Level") | |
| mood_update_input = gr.Dropdown(['Great', 'Good', 'Neutral', 'Poor'], label="Mood") | |
| exercise_minutes_update_input = gr.Number(label="Exercise Minutes") | |
| notes_update_input = gr.Textbox(label="Notes") | |
| update_button = gr.Button("Update", variant="primary") | |
| update_output = gr.Markdown() | |
| update_button.click(update_entry, inputs=[date_update_input, weight_update_input, calories_consumed_update_input, | |
| calories_burned_update_input, water_intake_update_input, sleep_hours_update_input, | |
| stress_level_update_input, mood_update_input, exercise_minutes_update_input, | |
| notes_update_input], outputs=update_output) | |
| with gr.Tab("Goals"): | |
| target_weight_input = gr.Number(label="Target Weight (lbs)") | |
| target_date_input = gr.Textbox(label="Target Date (YYYY-MM-DD)") | |
| goal_button = gr.Button("Set Goal", variant="primary") | |
| goal_output = gr.Markdown() | |
| goal_view_button = gr.Button("View Goal Progress", variant="secondary") | |
| goal_view_output = gr.Markdown() | |
| goal_button.click(set_goal, inputs=[target_weight_input, target_date_input], outputs=goal_output) | |
| goal_view_button.click(view_goal, outputs=goal_view_output) | |
| with gr.Tab("Achievements"): | |
| achievements_output = gr.Markdown(value=update_achievements()) | |
| gr.Button("Refresh Achievements").click(update_achievements, outputs=achievements_output) | |
| with gr.Tab("Analytics"): | |
| weight_plot_button = gr.Button("Weight Over Time", variant="secondary") | |
| weight_plot_output_text = gr.Markdown() | |
| weight_plot_output = gr.Image() | |
| weight_plot_button.click(create_weight_plot, outputs=[weight_plot_output_text, weight_plot_output]) | |
| with gr.Tab("Prediction"): | |
| days_input = gr.Slider(7, 90, step=7, value=30, label="Days to Predict") | |
| calorie_adjustment_input = gr.Number(label="Calorie Adjustment") | |
| exercise_adjustment_input = gr.Number(label="Exercise Adjustment") | |
| predict_button = gr.Button("Predict", variant="primary") | |
| prediction_output_text = gr.Markdown() | |
| prediction_plot_output = gr.Plot() | |
| recommendation_output = gr.Markdown() | |
| predict_button.click(predict_weight_trajectory, inputs=[days_input, calorie_adjustment_input, exercise_adjustment_input], | |
| outputs=[prediction_output_text, prediction_plot_output, recommendation_output]) | |
| with gr.Tab("Train Model"): | |
| train_button = gr.Button("Train Model", variant="primary") | |
| train_output = gr.Markdown() | |
| train_button.click(train_prediction_model, outputs=train_output) | |
| with gr.Tab("Food Log"): | |
| food_name_input = gr.Dropdown(choices=food_df['name'].tolist(), label="Food Item") | |
| quantity_input = gr.Number(label="Quantity", minimum=1, value=1) | |
| food_log_button = gr.Button("Log Food", variant="secondary") | |
| food_log_output = gr.Markdown() | |
| food_log_button.click(log_food, inputs=[food_name_input, quantity_input], outputs=food_log_output) | |
| with gr.Tab("Sample Data"): | |
| def load_sample_data(): | |
| global df | |
| start_date = datetime.datetime.now() - datetime.timedelta(days=30) | |
| sample_data = [{'date': start_date + datetime.timedelta(days=i), | |
| 'weight': 180 - (0.1 * i) + np.random.normal(0, 0.3), | |
| 'calories_consumed': np.random.randint(1800, 2300), | |
| 'calories_burned': np.random.randint(2000, 2500), | |
| 'water_intake': np.random.randint(5, 10), | |
| 'sleep_hours': round(np.random.normal(7, 0.5), 1), | |
| 'stress_level': np.random.randint(3, 8), | |
| 'mood': np.random.choice(['Great', 'Good', 'Neutral', 'Poor']), | |
| 'exercise_minutes': np.random.randint(20, 60), | |
| 'notes': ''} for i in range(30)] | |
| df = pd.concat([df, pd.DataFrame(sample_data)], ignore_index=True) | |
| df['date'] = pd.to_datetime(df['date']) | |
| df = df.sort_values('date', ascending=False) | |
| df.to_csv(DATA_FILE, index=False) | |
| update_achievements() | |
| return "✅ Sample data loaded!" | |
| sample_button = gr.Button("Load Sample Data", variant="secondary") | |
| sample_output = gr.Markdown() | |
| sample_button.click(load_sample_data, outputs=sample_output) | |
| iface.launch(debug=False) |