69 lines
1.7 KiB
Python
69 lines
1.7 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
DEFAULT_MET = 5.0
|
|
|
|
MET_BY_KEYWORD: list[tuple[str, float]] = [
|
|
("триатлон", 10.0),
|
|
("марафон", 9.8),
|
|
("бег", 9.8),
|
|
("running", 9.8),
|
|
("run", 9.0),
|
|
("плаван", 8.0),
|
|
("swim", 8.0),
|
|
("велосипед", 7.5),
|
|
("cycling", 7.5),
|
|
("вел", 7.5),
|
|
("hiit", 8.0),
|
|
("кроссфит", 8.0),
|
|
("силов", 6.0),
|
|
("strength", 6.0),
|
|
("зал", 5.5),
|
|
("gym", 5.5),
|
|
("йога", 3.0),
|
|
("yoga", 3.0),
|
|
("ходьб", 3.5),
|
|
("walk", 3.5),
|
|
("прогул", 3.5),
|
|
]
|
|
|
|
|
|
def infer_met(workout: dict[str, Any]) -> float | None:
|
|
explicit = workout.get("met")
|
|
if explicit is not None:
|
|
return float(explicit)
|
|
|
|
activity_type = str(workout.get("activity_type") or "").lower()
|
|
title = str(workout.get("title") or "").lower()
|
|
notes = str(workout.get("notes") or "").lower()
|
|
haystack = f"{activity_type} {title} {notes}"
|
|
|
|
for keyword, met in MET_BY_KEYWORD:
|
|
if keyword in haystack:
|
|
return met
|
|
return None
|
|
|
|
|
|
def estimate_workout_active_kcal(workout: dict[str, Any], *, weight_kg: float) -> float:
|
|
active = workout.get("active_calories")
|
|
if active is not None:
|
|
return round(float(active), 1)
|
|
|
|
duration = workout.get("duration_min")
|
|
if not duration:
|
|
return 0.0
|
|
|
|
met = infer_met(workout)
|
|
if met is None:
|
|
return 0.0
|
|
|
|
hours = float(duration) / 60.0
|
|
return round(met * weight_kg * hours, 1)
|
|
|
|
|
|
def workouts_kcal_total(workouts: list[dict[str, Any]], *, weight_kg: float) -> float:
|
|
if not workouts:
|
|
return 0.0
|
|
return round(sum(estimate_workout_active_kcal(w, weight_kg=weight_kg) for w in workouts), 1)
|