get_activity_recommendations
Generate personalized training recommendations by analyzing recent Strava activities to optimize workout planning and performance.
Instructions
Получить рекомендации по тренировкам на основе анализа последних активностей
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/server.py:449-604 (handler)The primary handler for the 'get_activity_recommendations' tool. This function fetches recent activities from Strava, analyzes training load and intensity distribution, and generates personalized training recommendations. It is registered as an MCP tool via the @mcp.tool() decorator.@mcp.tool() def get_activity_recommendations() -> Dict: """Получить рекомендации по тренировкам на основе анализа последних активностей""" try: # Get recent activities with proper error handling try: activities = get_recent_activities() except StravaApiError as e: return { "status": "error", "error": str(e), "recommendations": ["Проверьте подключение к Strava"] } if not activities: return { "status": "warning", "error": "Нет активностей за последние 30 дней", "recommendations": ["Начните записывать тренировки"] } # Analyze training load analysis = analyze_training_load(activities) recommendations = [] # Анализ разнообразия тренировок activity_types = analysis["activities_by_type"] total_activities = analysis["activities_count"] # Анализ интенсивности по зонам zones = analysis["heart_rate_zones"] total_zone_activities = sum(zones.values()) if total_zone_activities > 0: easy_percent = (zones["easy"] / total_zone_activities) * 100 medium_percent = (zones["medium"] / total_zone_activities) * 100 hard_percent = (zones["hard"] / total_zone_activities) * 100 # Проверка распределения интенсивности if easy_percent < 70: recommendations.append( f"Слишком мало легких тренировок ({easy_percent:.0f}%). " "Рекомендуется:\n" "- Добавить восстановительные тренировки\n" "- Больше базовых тренировок в низких пульсовых зонах\n" "- Использовать контроль пульса во время тренировок" ) if medium_percent > 40: recommendations.append( f"Большой процент тренировок в средней зоне ({medium_percent:.0f}%). " "Рекомендуется:\n" "- Четко разделять легкие и интенсивные тренировки\n" "- Избегать тренировок в 'серой зоне'" ) # Анализ объемов по видам спорта if "Run" in activity_types: run_volume = sum(a.get("distance", 0) for a in activities if a.get("type") == "Run") / 1000 if run_volume < 20: recommendations.append( f"Беговой объем ({run_volume:.1f} км) ниже оптимального.\n" "Рекомендации по увеличению:\n" "- Добавить 1-2 км к длинной пробежке еженедельно\n" "- Включить легкие восстановительные пробежки\n" "- Постепенно довести объем до 30-40 км в неделю" ) # Анализ общего объема weekly_distance = analysis["total_distance"] weekly_hours = analysis["total_time"] if weekly_hours < 5: recommendations.append( f"Общий объем ({weekly_hours:.1f} ч) можно увеличить.\n" "Рекомендации:\n" "- Постепенно добавлять по 30 минут в неделю\n" "- Включить кросс-тренировки для разнообразия\n" "- Следить за самочувствием при увеличении нагрузок" ) # Рекомендации по восстановлению if total_zone_activities > 5: recommendations.append( "Рекомендации по восстановлению:\n" "- Обеспечить 7-8 часов сна\n" "- Планировать легкие дни после интенсивных тренировок\n" "- Следить за питанием и гидратацией" ) # Если всё сбалансировано if not recommendations: recommendations.append( "Тренировки хорошо сбалансированы!\n" "Рекомендации по поддержанию формы:\n" "- Продолжать текущий план тренировок\n" "- Вести дневник тренировок\n" "- Регулярно анализировать прогресс" ) # Форматируем вывод для лучшей читаемости result = { "analysis": { "activities": { "total": analysis["activities_count"], "distance": f"{analysis['total_distance']:.1f} км", "time": f"{analysis['total_time']:.1f} ч", "distribution": { activity: { "count": count, "percent": f"{(count / total_activities * 100):.0f}%", } for activity, count in activity_types.items() }, }, "intensity": { "zones": { "easy": f"{easy_percent:.0f}%" if total_zone_activities > 0 else "0%", "medium": f"{medium_percent:.0f}%" if total_zone_activities > 0 else "0%", "hard": f"{hard_percent:.0f}%" if total_zone_activities > 0 else "0%", }, "status": "Сбалансировано" if 60 <= easy_percent <= 80 else "Требует корректировки", }, }, "recommendations": [ {"category": recommendation.split("\n")[0], "details": recommendation.split("\n")[1:]} for recommendation in recommendations ], "summary": { "status": "✅ Тренировки сбалансированы" if not recommendations else "⚠️ Есть рекомендации", "weekly": { "activities": total_activities, "distance": f"{weekly_distance:.1f} км", "time": f"{weekly_hours:.1f} ч", }, }, } return result except StravaApiError as e: logger.error(f"Ошибка API Strava: {e}") return { "status": "error", "error": str(e), "recommendations": ["Проверьте подключение к Strava"] } except Exception as e: logger.error(f"Непредвиденная ошибка: {e}") return { "status": "error", "error": "Внутренняя ошибка сервера", "details": str(e) }
- src/server.py:449-449 (registration)The @mcp.tool() decorator registers the get_activity_recommendations function as an MCP tool.@mcp.tool()
- src/server.py:401-447 (helper)Helper function analyze_training_load that calculates summary statistics for activities, used internally by the recommendations handler.@mcp.tool() def analyze_training_load(activities: List[Dict]) -> Dict: """Анализ тренировочной нагрузки""" if not activities: return { "error": "Нет активностей для анализа", "activities_count": 0 } summary = { "activities_count": len(activities), "total_distance": 0, "total_time": 0, "activities_by_type": {}, "heart_rate_zones": { "easy": 0, # ЧСС < 120 "medium": 0, # ЧСС 120-150 "hard": 0, # ЧСС > 150 }, } for activity in activities: activity_type = activity.get("type") # Обновляем счетчик типа активности if activity_type not in summary["activities_by_type"]: summary["activities_by_type"][activity_type] = 0 summary["activities_by_type"][activity_type] += 1 # Суммируем дистанцию и время summary["total_distance"] += activity.get("distance", 0) summary["total_time"] += activity.get("moving_time", 0) # Анализируем зоны ЧСС hr = activity.get("average_heartrate", 0) if hr: if hr < 120: summary["heart_rate_zones"]["easy"] += 1 elif hr < 150: summary["heart_rate_zones"]["medium"] += 1 else: summary["heart_rate_zones"]["hard"] += 1 # Конвертируем единицы измерения summary["total_distance"] = round(summary["total_distance"] / 1000, 2) # в километры summary["total_time"] = round(summary["total_time"] / 3600, 2) # в часы return summary