WeightPredict / app.py
Anupam007's picture
Update app.py
17407a4 verified
Raw
History Blame Contribute Delete
20.2 kB
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)