55 "sedentary" : 1.2 ,
66 "light" : 1.375 ,
77 "moderate" : 1.55 ,
8- "active" : 1.725
8+ "active" : 1.725 ,
9+ "very_active" : 1.9
910}
1011
1112def calculate_bmr (weight , height , age , gender ):
@@ -15,28 +16,89 @@ def calculate_bmr(weight, height, age, gender):
1516 return 10 * weight + 6.25 * height - 5 * age - 161
1617
1718
18- def calculate_goal ( profile , target_weight , weekly_goal_kg , target_calories = None ):
19+ def calculate_adjusted_calories ( bmr , activity_level , goal_type , weekly_rate ):
1920 """
20- Calculate goal with macros based on target calories.
21+ Calculate TDEE with adjustment based on goal type and weekly rate.
22+
23+ Args:
24+ bmr: Basal Metabolic Rate
25+ activity_level: User's activity level string
26+ goal_type: "lose", "gain", or "maintain"
27+ weekly_rate: Weekly weight change rate (kg/week)
28+
29+ Returns:
30+ Adjusted daily calorie target (int)
31+ """
32+ # Energy equivalent: 1 kg ≈ 7700 kcal
33+ base_tdee = bmr * ACTIVITY_FACTORS .get (activity_level , 1.2 )
34+
35+ if goal_type == "maintain" :
36+ return int (round (base_tdee ))
37+
38+ # Daily calorie adjustment: (weeklyRate * 7700) / 7
39+ daily_adjustment = (weekly_rate * 7700 ) / 7
40+
41+ if goal_type == "lose" :
42+ adjusted = base_tdee - daily_adjustment
43+ elif goal_type == "gain" :
44+ adjusted = base_tdee + daily_adjustment
45+ else :
46+ adjusted = base_tdee
47+
48+ # Ensure minimum of 1000 kcal/day to prevent dangerously low intake
49+ return max (1000 , int (round (adjusted )))
50+
51+
52+ def calculate_estimated_date (current_weight , target_weight , weekly_rate ):
53+ """
54+ Calculate estimated date to reach target weight.
55+
56+ Args:
57+ current_weight: Current weight in kg
58+ target_weight: Target weight in kg
59+ weekly_rate: Weekly weight change rate (kg/week)
60+
61+ Returns:
62+ Estimated completion date
63+ """
64+ if weekly_rate == 0 :
65+ return None
66+
67+ weight_difference = abs (current_weight - target_weight )
68+ weeks_required = math .ceil (weight_difference / weekly_rate )
69+ days_required = weeks_required * 7
70+
71+ return date .today () + timedelta (days = days_required )
72+
73+
74+ def calculate_goal (profile , target_weight , weekly_goal_kg , target_calories = None , goal_type = "lose" ):
75+ """
76+ Calculate goal with macros based on target calories and goal type.
2177
2278 Args:
2379 profile: User profile with health metrics
2480 target_weight: Target weight in kg
25- weekly_goal_kg: Weekly weight loss goal in kg
81+ weekly_goal_kg: Weekly weight loss/gain goal in kg
2682 target_calories: User's target daily calories (if None, calculated from profile)
83+ goal_type: "lose", "gain", or "maintain"
2784 """
2885
29- # If no target_calories provided, calculate from profile
86+ # Calculate BMR once
87+ bmr = calculate_bmr (
88+ profile .weight_kg ,
89+ profile .height_cm ,
90+ profile .age ,
91+ profile .gender
92+ )
93+
94+ # If no target_calories provided, calculate from profile with adjustment
3095 if target_calories is None :
31- bmr = calculate_bmr (
32- profile . weight_kg ,
33- profile .height_cm ,
34- profile . age ,
35- profile . gender
96+ daily_calories = calculate_adjusted_calories (
97+ bmr ,
98+ profile .activity_level ,
99+ goal_type ,
100+ weekly_goal_kg
36101 )
37- tdee = bmr * ACTIVITY_FACTORS .get (profile .activity_level , 1.2 )
38- deficit = 500 if weekly_goal_kg == 0.5 else 1000
39- daily_calories = int (tdee - deficit )
40102 else :
41103 # Use provided target_calories as source of truth
42104 daily_calories = target_calories
@@ -47,10 +109,10 @@ def calculate_goal(profile, target_weight, weekly_goal_kg, target_calories=None)
47109 carbs_g = int (daily_calories * 0.40 / 4 )
48110 fat_g = int (daily_calories * 0.30 / 9 )
49111
50- weeks = abs ( profile . weight_kg - target_weight ) / weekly_goal_kg
51- days = math . ceil ( weeks * 7 )
52-
53- target_date = date .today () + timedelta ( days = days )
112+ # Calculate estimated date
113+ target_date = calculate_estimated_date ( profile . weight_kg , target_weight , weekly_goal_kg )
114+ if target_date is None :
115+ target_date = date .today ()
54116
55117 return {
56118 "daily_calories" : daily_calories ,
0 commit comments