95 lines
2.6 KiB
Python
95 lines
2.6 KiB
Python
from typing import Any
|
|
|
|
ACTIVITY_MULTIPLIERS = {
|
|
"sedentary": 1.2,
|
|
"light": 1.375,
|
|
"moderate": 1.55,
|
|
"active": 1.725,
|
|
"very_active": 1.9,
|
|
}
|
|
|
|
GOAL_CALORIE_ADJUST = {
|
|
"lose": -500,
|
|
"maintain": 0,
|
|
"gain": 300,
|
|
}
|
|
|
|
|
|
def bmr_mifflin(*, sex: str, weight_kg: float, height_cm: float, age: int) -> float:
|
|
base = 10 * weight_kg + 6.25 * height_cm - 5 * age
|
|
if sex.lower() in ("m", "male", "м", "мужской"):
|
|
return base + 5
|
|
return base - 161
|
|
|
|
|
|
def tdee(
|
|
*,
|
|
sex: str,
|
|
weight_kg: float,
|
|
height_cm: float,
|
|
age: int,
|
|
activity_level: str = "moderate",
|
|
) -> float:
|
|
bmr = bmr_mifflin(sex=sex, weight_kg=weight_kg, height_cm=height_cm, age=age)
|
|
mult = ACTIVITY_MULTIPLIERS.get(activity_level, 1.55)
|
|
return bmr * mult
|
|
|
|
|
|
def bmi(weight_kg: float, height_cm: float) -> float:
|
|
if height_cm <= 0:
|
|
return 0.0
|
|
h = height_cm / 100
|
|
return weight_kg / (h * h)
|
|
|
|
|
|
def water_target_l(weight_kg: float) -> float:
|
|
return round(weight_kg * 0.033, 1)
|
|
|
|
|
|
def macro_targets(
|
|
calorie_target: float,
|
|
weight_kg: float,
|
|
goal: str = "maintain",
|
|
) -> dict[str, float]:
|
|
protein_g = round(weight_kg * (2.0 if goal == "gain" else 1.8), 0)
|
|
fat_g = round((calorie_target * 0.25) / 9, 0)
|
|
protein_cal = protein_g * 4
|
|
fat_cal = fat_g * 9
|
|
carbs_g = max(0, round((calorie_target - protein_cal - fat_cal) / 4, 0))
|
|
return {"protein_g": protein_g, "fat_g": fat_g, "carbs_g": carbs_g}
|
|
|
|
|
|
def one_rep_max(weight_kg: float, reps: int) -> float:
|
|
if reps <= 0:
|
|
return weight_kg
|
|
if reps == 1:
|
|
return weight_kg
|
|
return round(weight_kg * (1 + reps / 30), 1)
|
|
|
|
|
|
def compute_targets(profile: dict[str, Any]) -> dict[str, Any]:
|
|
weight = float(profile.get("weight_kg") or 70)
|
|
height = float(profile.get("height_cm") or 170)
|
|
age = int(profile.get("age") or 30)
|
|
sex = str(profile.get("sex") or "male")
|
|
activity = str(profile.get("activity_level") or "moderate")
|
|
goal = str(profile.get("goal") or "maintain")
|
|
|
|
tdee_val = tdee(
|
|
sex=sex, weight_kg=weight, height_cm=height, age=age, activity_level=activity
|
|
)
|
|
calorie_target = round(tdee_val + GOAL_CALORIE_ADJUST.get(goal, 0), 0)
|
|
macros = macro_targets(calorie_target, weight, goal)
|
|
water = water_target_l(weight)
|
|
|
|
return {
|
|
"bmr": round(bmr_mifflin(sex=sex, weight_kg=weight, height_cm=height, age=age), 0),
|
|
"tdee": round(tdee_val, 0),
|
|
"bmi": round(bmi(weight, height), 1),
|
|
"calorie_target": calorie_target,
|
|
"protein_g": macros["protein_g"],
|
|
"fat_g": macros["fat_g"],
|
|
"carbs_g": macros["carbs_g"],
|
|
"water_l": water,
|
|
}
|