AI-система персоналізації фітнес-програм

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1566 послуг
AI-система персоналізації фітнес-програм
Середній
~2-4 тижні
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1285
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1122
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    859

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%.