AI-система персоналізації фітнес-програм
Особистий тренер коштує дорого. AI-тренер доступний 24/7 і враховує прогрес, відновлення, цілі та обмеження. Додатки типу Freeletics, Whoop, Peloton використовують ML для адаптації тренувальних планів у реальному часі на основі біометричних даних.
Адаптивний тренувальний план
import numpy as np
import pandas as pd
from dataclasses import dataclass
from typing import Optional
from anthropic import Anthropic
import json
@dataclass
class AthleteProfile:
user_id: str
age: int
sex: str
weight_kg: float
height_cm: float
fitness_level: str # beginner, intermediate, advanced
primary_goal: str # weight_loss, muscle_gain, endurance, general_fitness
available_days_per_week: int
equipment: list # ['dumbbells', 'barbell', 'pull_up_bar']
injuries: list # ['lower_back', 'knee']
vo2max: Optional[float] = None
class FitnessPlanGenerator:
"""Генерація та адаптація тренувальних планів"""
def __init__(self):
self.llm = Anthropic()
def calculate_training_zones(self, profile: AthleteProfile) -> dict:
"""Пульсові зони для кардіо тренувань"""
# Формула Танака (точніша за 220-вік)
max_hr = 208 - 0.7 * profile.age
return {
'max_hr': int(max_hr),
'zone1_recovery': (int(max_hr * 0.50), int(max_hr * 0.60)),
'zone2_aerobic': (int(max_hr * 0.60), int(max_hr * 0.70)),
'zone3_tempo': (int(max_hr * 0.70), int(max_hr * 0.80)),
'zone4_threshold': (int(max_hr * 0.80), int(max_hr * 0.90)),
'zone5_vo2max': (int(max_hr * 0.90), int(max_hr * 1.00)),
}
def generate_weekly_plan(self, profile: AthleteProfile,
recent_performance: list[dict]) -> list[dict]:
"""Тижневий тренувальний план"""
training_zones = self.calculate_training_zones(profile)
# Періодизація: 3 тижні зростаючого навантаження + 1 тиждень відновлення
# Визначаємо поточний тиждень періодизації з історії
week_in_cycle = self._get_week_in_cycle(recent_performance)
load_modifier = [0.85, 1.0, 1.15, 0.70][week_in_cycle % 4]
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=700,
messages=[{
"role": "user",
"content": f"""Create a personalized weekly training plan.
Profile:
- Fitness level: {profile.fitness_level}
- Goal: {profile.primary_goal}
- Available days: {profile.available_days_per_week}
- Equipment: {profile.equipment}
- Injuries to avoid: {profile.injuries}
- Age: {profile.age}, Weight: {profile.weight_kg}kg
Current training intensity: {load_modifier:.0%} of base load
Training zones: Zone 2 aerobic = {training_zones['zone2_aerobic']} bpm
Recent performance (last 5 sessions):
{json.dumps(recent_performance[-5:], ensure_ascii=False)[:400]}
Create {profile.available_days_per_week} training sessions. Return JSON array:
[{{
"day": "Monday",
"session_type": "strength|cardio|hiit|recovery",
"duration_min": 45,
"exercises": [{{"name": "...", "sets": 3, "reps": "8-10", "rest_sec": 90}}],
"cardio_zone": "zone2",
"notes": "..."
}}]"""
}]
)
try:
return json.loads(response.content[0].text)
except Exception:
return []
def _get_week_in_cycle(self, performance: list[dict]) -> int:
if not performance:
return 0
return len(set(p.get('week_number', 0) for p in performance)) % 4
class RecoveryMonitor:
"""Моніторинг відновлення з біометрії"""
def compute_readiness_score(self, biometrics: dict) -> dict:
"""
Скор готовності до тренування (0-100).
Дані: HRV, RHR, sleep_score, previous_day_load.
"""
score = 100.0
factors = []
# HRV (Heart Rate Variability) — головний індикатор
hrv = biometrics.get('hrv_ms')
hrv_baseline = biometrics.get('hrv_baseline_ms', 50)
if hrv and hrv_baseline:
hrv_ratio = hrv / hrv_baseline
if hrv_ratio < 0.85:
score -= 25
factors.append(f'HRV знижен ({hrv:.0f}ms vs {hrv_baseline:.0f}ms baseline)')
elif hrv_ratio > 1.15:
score += 5 # Хороше відновлення
# Частота серцевих скорочень у спокої
rhr = biometrics.get('resting_hr_bpm')
rhr_baseline = biometrics.get('rhr_baseline_bpm', 60)
if rhr and rhr_baseline:
if rhr > rhr_baseline + 5:
score -= 15
factors.append(f'RHR підвищен ({rhr} vs {rhr_baseline} baseline)')
# Сон
sleep_score = biometrics.get('sleep_score', 80) # 0-100
if sleep_score < 60:
score -= 20
factors.append(f'Поганий сон (скор: {sleep_score})')
elif sleep_score < 75:
score -= 10
# Навантаження попередного дня
previous_load = biometrics.get('yesterday_training_load', 0) # AU (Arbitrary Units)
high_load_threshold = biometrics.get('weekly_avg_load', 300) * 0.4
if previous_load > high_load_threshold:
score -= 10
factors.append('Високе навантаження вчора')
score = float(np.clip(score, 0, 100))
if score > 75:
recommendation = 'Відмінний день для інтенсивного тренування'
intensity_modifier = 1.0
elif score > 55:
recommendation = 'Помірне тренування — знизьте інтенсивність на 15%'
intensity_modifier = 0.85
elif score > 35:
recommendation = 'Тільки легке відновлювальне заняття або відпочинок'
intensity_modifier = 0.60
else:
recommendation = 'Активний відпочинок або вихідний'
intensity_modifier = 0.0
return {
'readiness_score': round(score),
'recommendation': recommendation,
'intensity_modifier': intensity_modifier,
'limiting_factors': factors
}
class ProgressTracker:
"""Відстеження прогресу та корегування плану"""
def analyze_progress(self, training_logs: pd.DataFrame,
profile: AthleteProfile,
weeks: int = 8) -> dict:
"""Аналіз прогресу за період"""
recent = training_logs[
training_logs['date'] >= pd.Timestamp.now() - pd.Timedelta(weeks=weeks)
]
if recent.empty:
return {}
return {
'sessions_completed': len(recent),
'sessions_planned': weeks * profile.available_days_per_week,
'adherence_rate': len(recent) / (weeks * profile.available_days_per_week),
# Прогрес за основними вправами
'strength_progress': self._compute_strength_progress(recent),
'endurance_progress': self._compute_endurance_progress(recent),
'avg_session_duration_min': recent.get('duration_minutes', pd.Series([45])).mean(),
'total_volume_kg': recent.get('total_volume_kg', pd.Series([0])).sum(),
}
def _compute_strength_progress(self, logs: pd.DataFrame) -> dict:
"""Зміна максимальних ваг у основних вправах"""
if 'exercise_name' not in logs.columns:
return {}
key_exercises = ['squat', 'bench_press', 'deadlift', 'overhead_press']
progress = {}
for exercise in key_exercises:
exercise_logs = logs[logs['exercise_name'] == exercise]
if len(exercise_logs) < 2:
continue
first_max = exercise_logs.nsmallest(3, 'date')['max_weight_kg'].mean()
last_max = exercise_logs.nlargest(3, 'date')['max_weight_kg'].mean()
progress[exercise] = round((last_max - first_max) / max(first_max, 1) * 100, 1)
return progress
def _compute_endurance_progress(self, logs: pd.DataFrame) -> dict:
if 'pace_min_per_km' not in logs.columns:
return {}
cardio = logs[logs['session_type'] == 'cardio']
if cardio.empty:
return {}
early = cardio.head(3)['pace_min_per_km'].mean()
recent = cardio.tail(3)['pace_min_per_km'].mean()
improvement = (early - recent) / early * 100 # Зниження темпу = покращення
return {'pace_improvement_pct': round(improvement, 1)}
Персоналізовані фітнес-плани з адаптацією на основі біометрії підвищують adherence rate з 35-45% до 65-75% за даними Whoop та Oura. Ключова метрика: не кількість тренувань, а відповідність навантаження рівню відновлення — це знижує ризик травм на 30-40%.







