first commit

This commit is contained in:
Jp
2026-01-30 15:03:43 +08:00
commit 656a510c73
32 changed files with 3721 additions and 0 deletions

View File

@@ -0,0 +1,258 @@
from datetime import date, timedelta
from models import db, Meal, WaterLog, WeightLog, DailySummary, UserGoal
def calculate_bmr(weight_kg, height_cm, age, gender):
"""
Calculate Basal Metabolic Rate using Mifflin-St Jeor Equation
"""
if gender.lower() == 'male':
bmr = (10 * weight_kg) + (6.25 * height_cm) - (5 * age) + 5
else: # female
bmr = (10 * weight_kg) + (6.25 * height_cm) - (5 * age) - 161
return round(bmr)
def calculate_tdee(bmr, activity_level):
"""
Calculate Total Daily Energy Expenditure
"""
multipliers = {
'sedentary': 1.2,
'light': 1.375,
'moderate': 1.55,
'active': 1.725,
'very_active': 1.9
}
multiplier = multipliers.get(activity_level, 1.55)
return round(bmr * multiplier)
def calculate_macro_targets(weight_kg, goal_type='recomp'):
"""
Calculate macro targets based on body weight and goal
"""
if goal_type == 'muscle_gain':
protein = weight_kg * 2.4 # High protein for muscle building
carbs = weight_kg * 3.5 # Higher carbs for energy
fat = weight_kg * 1.0 # Moderate fat
elif goal_type == 'weight_loss':
protein = weight_kg * 2.2 # High protein to preserve muscle
carbs = weight_kg * 2.0 # Lower carbs for deficit
fat = weight_kg * 0.8 # Lower fat
else: # recomp (body recomposition)
protein = weight_kg * 2.2 # High protein
carbs = weight_kg * 2.5 # Moderate carbs
fat = weight_kg * 0.9 # Moderate fat
return {
'protein_g': round(protein),
'carbs_g': round(carbs),
'fat_g': round(fat)
}
def calculate_daily_totals(user_id, target_date=None):
"""
Calculate total nutrition consumed for a given date
"""
if target_date is None:
target_date = date.today()
# Get all meals for the date
meals = Meal.query.filter_by(user_id=user_id, date=target_date).all()
totals = {
'calories': 0,
'protein': 0,
'carbs': 0,
'fat': 0,
'meals': []
}
for meal in meals:
meal_totals = meal.calculate_totals()
totals['calories'] += meal_totals['calories']
totals['protein'] += meal_totals['protein']
totals['carbs'] += meal_totals['carbs']
totals['fat'] += meal_totals['fat']
totals['meals'].append({
'id': meal.id,
'type': meal.meal_type,
'time': meal.time.strftime('%H:%M') if meal.time else None,
'totals': meal_totals,
'foods': [
{
'name': mf.food.name,
'quantity': mf.quantity,
'calories': mf.calories_consumed
}
for mf in meal.foods
]
})
return totals
def calculate_water_total(user_id, target_date=None):
"""
Calculate total water intake for a given date
"""
if target_date is None:
target_date = date.today()
water_logs = WaterLog.query.filter_by(user_id=user_id, date=target_date).all()
total = sum(log.amount_ml for log in water_logs)
return {
'total_ml': total,
'logs': [
{
'id': log.id,
'amount_ml': log.amount_ml,
'time': log.time.strftime('%H:%M') if log.time else None
}
for log in water_logs
]
}
def get_weight_trend(user_id, days=7):
"""
Get weight trend for the past N days
"""
end_date = date.today()
start_date = end_date - timedelta(days=days-1)
weight_logs = WeightLog.query.filter(
WeightLog.user_id == user_id,
WeightLog.date >= start_date,
WeightLog.date <= end_date
).order_by(WeightLog.date).all()
return [
{
'date': log.date.strftime('%Y-%m-%d'),
'weight_kg': log.weight_kg
}
for log in weight_logs
]
def get_calorie_trend(user_id, days=7):
"""
Get calorie intake trend for the past N days
"""
end_date = date.today()
start_date = end_date - timedelta(days=days-1)
trend = []
current_date = start_date
while current_date <= end_date:
totals = calculate_daily_totals(user_id, current_date)
trend.append({
'date': current_date.strftime('%Y-%m-%d'),
'calories': round(totals['calories']),
'protein': round(totals['protein']),
'carbs': round(totals['carbs']),
'fat': round(totals['fat'])
})
current_date += timedelta(days=1)
return trend
def update_daily_summary(user_id, target_date=None):
"""
Update or create daily summary for a user
"""
if target_date is None:
target_date = date.today()
# Calculate totals
nutrition = calculate_daily_totals(user_id, target_date)
water = calculate_water_total(user_id, target_date)
# Get weight for the day
weight_log = WeightLog.query.filter_by(user_id=user_id, date=target_date).first()
weight = weight_log.weight_kg if weight_log else None
# Get user's calorie target
from models import User
user = User.query.get(user_id)
target_calories = user.target_daily_calories if user else 2000
# Find or create summary
summary = DailySummary.query.filter_by(user_id=user_id, date=target_date).first()
if not summary:
summary = DailySummary(user_id=user_id, date=target_date)
db.session.add(summary)
# Update values
summary.total_calories = nutrition['calories']
summary.total_protein_g = nutrition['protein']
summary.total_carbs_g = nutrition['carbs']
summary.total_fat_g = nutrition['fat']
summary.total_water_ml = water['total_ml']
summary.calories_remaining = target_calories - nutrition['calories']
summary.weight_kg = weight
try:
db.session.commit()
return summary
except Exception as e:
db.session.rollback()
print(f"Error updating daily summary: {e}")
return None
def get_macro_percentages(protein_g, carbs_g, fat_g):
"""
Calculate macro distribution as percentages
"""
protein_cal = protein_g * 4
carbs_cal = carbs_g * 4
fat_cal = fat_g * 9
total_cal = protein_cal + carbs_cal + fat_cal
if total_cal == 0:
return {'protein': 0, 'carbs': 0, 'fat': 0}
return {
'protein': round((protein_cal / total_cal) * 100),
'carbs': round((carbs_cal / total_cal) * 100),
'fat': round((fat_cal / total_cal) * 100)
}
def suggest_foods_for_macros(remaining_protein, remaining_carbs, remaining_fat):
"""
Suggest Filipino foods based on remaining macros
Returns category suggestions
"""
suggestions = []
# High protein needed
if remaining_protein > 30:
suggestions.append({
'category': 'High Protein Ulam',
'examples': ['Grilled Tilapia', 'Chicken Tinola', 'Grilled Chicken']
})
# High carbs needed
if remaining_carbs > 40:
suggestions.append({
'category': 'Carbs',
'examples': ['White Rice', 'Pandesal', 'Sweet Potato']
})
# High fat needed
if remaining_fat > 20:
suggestions.append({
'category': 'Healthy Fats',
'examples': ['Sisig', 'Lechon Kawali', 'Bicol Express']
})
# Balanced meal needed
if remaining_protein > 20 and remaining_carbs > 30:
suggestions.append({
'category': 'Balanced Meals',
'examples': ['Tapsilog', 'Chicken Adobo with Rice', 'Sinigang']
})
return suggestions