WeightPredict / app.py
Anupam007's picture
Update app.py
17407a4 verified
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)