Fitness Nutrition

Планировщик тренировок в зале и трекер питания. Поиск 690+ упражнений по группе мышц, оборудованию или категории через wger. База данных макронутриентов и калорий для 380 000+ продуктов через USDA FoodData Central. Расчёт BMI, TDEE, одноповторного максимума, разбивки макросов и процента жира — чистый Python, без pip-зависимостей. Подходит всем: набор массы, сушка или просто стремление питаться лучше.

Метаданные навыка

ИсточникОпциональный — hermes skills install official/health/fitness-nutrition
Путьoptional-skills/health/fitness-nutrition
Версия1.0.0
ЛицензияMIT
Платформыlinux, macos, windows
Тегиhealth, fitness, nutrition, gym, workout, diet, exercise

Справочник: полный SKILL.md

инфо

Ниже приведено полное определение навыка, которое Hermes Agent загружает при активации. Именно этот текст агент видит как инструкцию во время работы навыка.

Fitness & Nutrition

Навык опытного фитнес-тренера и спортивного нутрициолога. Два источника данных плюс офлайн-калькуляторы — всё, что нужно посетителю зала, в одном месте.

Источники данных (бесплатно, без pip-зависимостей):

  • wger (https://wger.de/api/v2/) — открытая база упражнений: 690+ позиций с мышцами, оборудованием и изображениями. Публичные эндпоинты не требуют авторизации.
  • USDA FoodData Central (https://api.nal.usda.gov/fdc/v1/) — государственная база данных США по питанию: 380 000+ продуктов. DEMO_KEY работает сразу; бесплатная регистрация даёт более высокий лимит запросов.

Офлайн-калькуляторы (чистый stdlib Python):

  • BMI, TDEE (Mifflin-St Jeor), одноповторный максимум (Epley/Brzycki/Lombardi), разбивка макросов, процент жира (метод ВМС США)

Когда использовать

Активируй этот навык, когда пользователь спрашивает о:

  • упражнениях, тренировках, программах в зале, группах мышц, сплитах;
  • макронутриентах, калориях, содержании белка в продуктах, планировании питания, подсчёте калорий;
  • составе тела: BMI, процент жира, TDEE, калорийный профицит/дефицит;
  • оценке одноповторного максимума, тренировочных процентах, прогрессивной перегрузке;
  • соотношении макросов на сушке, массонаборе или поддержании.

Процедура

Поиск упражнений (wger API)

Все публичные эндпоинты wger возвращают JSON и не требуют авторизации. К запросам упражнений всегда добавляй format=json и language=2 (английский).

Шаг 1 — Определи, что нужно пользователю:

  • По мышце → /api/v2/exercise/?muscles={id}&language=2&status=2&format=json
  • По категории → /api/v2/exercise/?category={id}&language=2&status=2&format=json
  • По оборудованию → /api/v2/exercise/?equipment={id}&language=2&status=2&format=json
  • По названию → /api/v2/exercise/search/?term={query}&language=english&format=json
  • Полные данные → /api/v2/exerciseinfo/{exercise_id}/?format=json

Шаг 2 — Справочник ID (чтобы не делать лишних запросов):

Категории упражнений:

IDCategory
8Arms
9Legs
10Abs
11Chest
12Back
13Shoulders
14Calves
15Cardio

Мышцы:

IDMuscleIDMuscle
1Biceps brachii2Anterior deltoid
3Serratus anterior4Pectoralis major
5Obliquus externus6Gastrocnemius
7Rectus abdominis8Gluteus maximus
9Trapezius10Quadriceps femoris
11Biceps femoris12Latissimus dorsi
13Brachialis14Triceps brachii
15Soleus

Оборудование:

IDEquipment
1Barbell
3Dumbbell
4Gym mat
5Swiss Ball
6Pull-up bar
7none (bodyweight)
8Bench
9Incline bench
10Kettlebell

Шаг 3 — Получи и покажи результаты:

# Search exercises by name
QUERY="$1"
ENCODED=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$QUERY")
curl -s "https://wger.de/api/v2/exercise/search/?term=${ENCODED}&language=english&format=json" \
  | python3 -c "
import json,sys
data=json.load(sys.stdin)
for s in data.get('suggestions',[])[:10]:
    d=s.get('data',{})
    print(f\"  ID {d.get('id','?'):>4} | {d.get('name','N/A'):<35} | Category: {d.get('category','N/A')}\")
"
# Get full details for a specific exercise
EXERCISE_ID="$1"
curl -s "https://wger.de/api/v2/exerciseinfo/${EXERCISE_ID}/?format=json" \
  | python3 -c "
import json,sys,html,re
data=json.load(sys.stdin)
trans=[t for t in data.get('translations',[]) if t.get('language')==2]
t=trans[0] if trans else data.get('translations',[{}])[0]
desc=re.sub('<[^>]+>','',html.unescape(t.get('description','N/A')))
print(f\"Exercise  : {t.get('name','N/A')}\")
print(f\"Category  : {data.get('category',{}).get('name','N/A')}\")
print(f\"Primary   : {', '.join(m.get('name_en','') for m in data.get('muscles',[])) or 'N/A'}\")
print(f\"Secondary : {', '.join(m.get('name_en','') for m in data.get('muscles_secondary',[])) or 'none'}\")
print(f\"Equipment : {', '.join(e.get('name','') for e in data.get('equipment',[])) or 'bodyweight'}\")
print(f\"How to    : {desc[:500]}\")
imgs=data.get('images',[])
if imgs: print(f\"Image     : {imgs[0].get('image','')}\")
"
# List exercises filtering by muscle, category, or equipment
# Combine filters as needed: ?muscles=4&equipment=1&language=2&status=2
FILTER="$1"  # e.g. "muscles=4" or "category=11" or "equipment=3"
curl -s "https://wger.de/api/v2/exercise/?${FILTER}&language=2&status=2&limit=20&format=json" \
  | python3 -c "
import json,sys
data=json.load(sys.stdin)
print(f'Found {data.get(\"count\",0)} exercises.')
for ex in data.get('results',[]):
    print(f\"  ID {ex['id']:>4} | muscles: {ex.get('muscles',[])} | equipment: {ex.get('equipment',[])}\")
"

Поиск по питанию (USDA FoodData Central)

Использует переменную окружения USDA_API_KEY, если задана; иначе откатывается на DEMO_KEY. DEMO_KEY — 30 запросов/час. Ключ после бесплатной регистрации — 1 000 запросов/час.

# Search foods by name
FOOD="$1"
API_KEY="${USDA_API_KEY:-DEMO_KEY}"
ENCODED=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$FOOD")
curl -s "https://api.nal.usda.gov/fdc/v1/foods/search?api_key=${API_KEY}&query=${ENCODED}&pageSize=5&dataType=Foundation,SR%20Legacy" \
  | python3 -c "
import json,sys
data=json.load(sys.stdin)
foods=data.get('foods',[])
if not foods: print('No foods found.'); sys.exit()
for f in foods:
    n={x['nutrientName']:x.get('value','?') for x in f.get('foodNutrients',[])}
    cal=n.get('Energy','?'); prot=n.get('Protein','?')
    fat=n.get('Total lipid (fat)','?'); carb=n.get('Carbohydrate, by difference','?')
    print(f\"{f.get('description','N/A')}\")
    print(f\"  Per 100g: {cal} kcal | {prot}g protein | {fat}g fat | {carb}g carbs\")
    print(f\"  FDC ID: {f.get('fdcId','N/A')}\")
    print()
"
# Detailed nutrient profile by FDC ID
FDC_ID="$1"
API_KEY="${USDA_API_KEY:-DEMO_KEY}"
curl -s "https://api.nal.usda.gov/fdc/v1/food/${FDC_ID}?api_key=${API_KEY}" \
  | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f\"Food: {d.get('description','N/A')}\")
print(f\"{'Nutrient':<40} {'Amount':>8} {'Unit'}\")
print('-'*56)
for x in sorted(d.get('foodNutrients',[]),key=lambda x:x.get('nutrient',{}).get('rank',9999)):
    nut=x.get('nutrient',{}); amt=x.get('amount',0)
    if amt and float(amt)>0:
        print(f\"  {nut.get('name',''):<38} {amt:>8} {nut.get('unitName','')}\")
"

Офлайн-калькуляторы

Для пакетных расчётов используй вспомогательные скрипты из scripts/, для разовых — запускай инлайн:

  • python3 scripts/body_calc.py bmi <weight_kg> <height_cm>
  • python3 scripts/body_calc.py tdee <weight_kg> <height_cm> <age> <M|F> <activity 1-5>
  • python3 scripts/body_calc.py 1rm <weight> <reps>
  • python3 scripts/body_calc.py macros <tdee_kcal> <cut|maintain|bulk>
  • python3 scripts/body_calc.py bodyfat <M|F> <neck_cm> <waist_cm> [hip_cm] <height_cm>

Научное обоснование каждой формулы — в references/FORMULAS.md.


Подводные камни

  • Эндпоинт упражнений wger по умолчанию возвращает все языки — всегда добавляй language=2 для английского.
  • wger включает непроверенные пользовательские записи — добавляй status=2, чтобы получать только одобренные упражнения.
  • DEMO_KEY USDA ограничен 30 запросами/час — между пакетными запросами добавляй sleep 2 или получи бесплатный ключ.
  • Данные USDA приводятся на 100 г — напоминай пользователям пересчитывать под реальный размер порции.
  • BMI не различает мышцы и жир — высокий BMI у мускулистых людей не обязательно означает нарушение здоровья.
  • Формулы расчёта жира дают оценку с погрешностью ±3–5% — для точных данных рекомендуй DEXA-сканирование.
  • Формулы 1RM теряют точность выше 10 повторений — для лучших оценок используй подходы по 3–5 повторений.
  • В эндпоинте exercise/search wger параметр называется term, а не query.

Проверка

После поиска упражнений: убедись, что результаты содержат названия упражнений, группы мышц и оборудование. После поиска по питанию: убедись, что возвращаются макросы на 100 г — ккал, белки, жиры, углеводы. После расчётов: проверь здравый смысл результатов (например, TDEE для большинства взрослых должен быть в диапазоне 1500–3500 ккал).


Быстрый справочник

ЗадачаИсточникЭндпоинт
Поиск упражнений по названиюwgerGET /api/v2/exercise/search/?term=&language=english
Детали упражненияwgerGET /api/v2/exerciseinfo/{id}/
Фильтр по мышцеwgerGET /api/v2/exercise/?muscles={id}&language=2&status=2
Фильтр по оборудованиюwgerGET /api/v2/exercise/?equipment={id}&language=2&status=2
Список категорийwgerGET /api/v2/exercisecategory/
Список мышцwgerGET /api/v2/muscle/
Поиск продуктовUSDAGET /fdc/v1/foods/search?query=&dataType=Foundation,SR Legacy
Детали продуктаUSDAGET /fdc/v1/food/{fdcId}
BMI / TDEE / 1RM / макросыофлайнpython3 scripts/body_calc.py
ESC