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)