132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
"""
|
||
Utility functions for calories calculation
|
||
"""
|
||
from datetime import date
|
||
from enum import Enum
|
||
from typing import Dict, Any
|
||
|
||
|
||
class ActivityLevel(str, Enum):
|
||
"""Activity level for BMR calculations"""
|
||
SEDENTARY = "sedentary" # Little or no exercise
|
||
LIGHTLY_ACTIVE = "lightly_active" # Light exercise/sports 1-3 days/week
|
||
MODERATELY_ACTIVE = "moderately_active" # Moderate exercise/sports 3-5 days/week
|
||
VERY_ACTIVE = "very_active" # Hard exercise/sports 6-7 days/week
|
||
EXTRA_ACTIVE = "extra_active" # Very hard exercise, physical job or training twice a day
|
||
|
||
|
||
class WeightGoal(str, Enum):
|
||
"""Weight goals for calorie adjustments"""
|
||
LOSE_FAST = "lose_fast" # Lose 1kg per week
|
||
LOSE = "lose" # Lose 0.5kg per week
|
||
MAINTAIN = "maintain" # Maintain current weight
|
||
GAIN = "gain" # Gain 0.5kg per week
|
||
GAIN_FAST = "gain_fast" # Gain 1kg per week
|
||
|
||
|
||
def calculate_age(birth_date: date) -> int:
|
||
"""
|
||
Calculate age from birth date
|
||
"""
|
||
today = date.today()
|
||
age = today.year - birth_date.year
|
||
|
||
# Check if birthday has occurred this year
|
||
if today.month < birth_date.month or (today.month == birth_date.month and today.day < birth_date.day):
|
||
age -= 1
|
||
|
||
return age
|
||
|
||
|
||
def calculate_bmr(
|
||
weight_kg: float,
|
||
height_cm: float,
|
||
age: int,
|
||
gender: str
|
||
) -> float:
|
||
"""
|
||
Calculate Basal Metabolic Rate (BMR) using the Mifflin-St Jeor Equation
|
||
|
||
For men: BMR = (10 × weight in kg) + (6.25 × height in cm) - (5 × age in years) + 5
|
||
For women: BMR = (10 × weight in kg) + (6.25 × height in cm) - (5 × age in years) - 161
|
||
"""
|
||
if gender.lower() in ("male", "m"):
|
||
return (10 * weight_kg) + (6.25 * height_cm) - (5 * age) + 5
|
||
else: # female
|
||
return (10 * weight_kg) + (6.25 * height_cm) - (5 * age) - 161
|
||
|
||
|
||
def calculate_tdee(bmr: float, activity_level: ActivityLevel) -> float:
|
||
"""
|
||
Calculate Total Daily Energy Expenditure (TDEE) based on BMR and activity level
|
||
"""
|
||
activity_multipliers = {
|
||
ActivityLevel.SEDENTARY: 1.2,
|
||
ActivityLevel.LIGHTLY_ACTIVE: 1.375,
|
||
ActivityLevel.MODERATELY_ACTIVE: 1.55,
|
||
ActivityLevel.VERY_ACTIVE: 1.725,
|
||
ActivityLevel.EXTRA_ACTIVE: 1.9,
|
||
}
|
||
|
||
return bmr * activity_multipliers[activity_level]
|
||
|
||
|
||
def adjust_calories_for_goal(tdee: float, goal: WeightGoal) -> float:
|
||
"""
|
||
Adjust TDEE based on weight goal
|
||
|
||
1kg of fat is approximately 7700 calories
|
||
To lose/gain 1kg per week: 7700 / 7 = 1100 calories per day
|
||
To lose/gain 0.5kg per week: 7700 / 14 = 550 calories per day
|
||
"""
|
||
goal_adjustments = {
|
||
WeightGoal.LOSE_FAST: -1100,
|
||
WeightGoal.LOSE: -550,
|
||
WeightGoal.MAINTAIN: 0,
|
||
WeightGoal.GAIN: 550,
|
||
WeightGoal.GAIN_FAST: 1100,
|
||
}
|
||
|
||
return tdee + goal_adjustments[goal]
|
||
|
||
|
||
def calculate_recommended_calories(
|
||
weight_kg: float,
|
||
height_cm: float,
|
||
birth_date: date,
|
||
gender: str,
|
||
activity_level: ActivityLevel,
|
||
goal: WeightGoal
|
||
) -> Dict[str, Any]:
|
||
"""
|
||
Calculate recommended daily calories based on personal data and goals
|
||
"""
|
||
age = calculate_age(birth_date)
|
||
bmr = calculate_bmr(weight_kg, height_cm, age, gender)
|
||
tdee = calculate_tdee(bmr, activity_level)
|
||
adjusted_calories = adjust_calories_for_goal(tdee, goal)
|
||
|
||
# Calculate macronutrient recommendations based on a balanced diet
|
||
# Protein: 30%, Carbs: 40%, Fat: 30%
|
||
calories_from_protein = adjusted_calories * 0.3
|
||
calories_from_carbs = adjusted_calories * 0.4
|
||
calories_from_fat = adjusted_calories * 0.3
|
||
|
||
# Convert calories to grams
|
||
# Protein: 4 calories per gram
|
||
# Carbs: 4 calories per gram
|
||
# Fat: 9 calories per gram
|
||
protein_g = calories_from_protein / 4
|
||
carbs_g = calories_from_carbs / 4
|
||
fat_g = calories_from_fat / 9
|
||
|
||
return {
|
||
"bmr": round(bmr),
|
||
"tdee": round(tdee),
|
||
"recommended_calories": round(adjusted_calories),
|
||
"macronutrients": {
|
||
"protein_g": round(protein_g),
|
||
"carbs_g": round(carbs_g),
|
||
"fat_g": round(fat_g),
|
||
}
|
||
} |