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 (чтобы не делать лишних запросов):
Категории упражнений:
| ID | Category |
|---|---|
| 8 | Arms |
| 9 | Legs |
| 10 | Abs |
| 11 | Chest |
| 12 | Back |
| 13 | Shoulders |
| 14 | Calves |
| 15 | Cardio |
Мышцы:
| ID | Muscle | ID | Muscle |
|---|---|---|---|
| 1 | Biceps brachii | 2 | Anterior deltoid |
| 3 | Serratus anterior | 4 | Pectoralis major |
| 5 | Obliquus externus | 6 | Gastrocnemius |
| 7 | Rectus abdominis | 8 | Gluteus maximus |
| 9 | Trapezius | 10 | Quadriceps femoris |
| 11 | Biceps femoris | 12 | Latissimus dorsi |
| 13 | Brachialis | 14 | Triceps brachii |
| 15 | Soleus |
Оборудование:
| ID | Equipment |
|---|---|
| 1 | Barbell |
| 3 | Dumbbell |
| 4 | Gym mat |
| 5 | Swiss Ball |
| 6 | Pull-up bar |
| 7 | none (bodyweight) |
| 8 | Bench |
| 9 | Incline bench |
| 10 | Kettlebell |
Шаг 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_KEYUSDA ограничен 30 запросами/час — между пакетными запросами добавляйsleep 2или получи бесплатный ключ.- Данные USDA приводятся на 100 г — напоминай пользователям пересчитывать под реальный размер порции.
- BMI не различает мышцы и жир — высокий BMI у мускулистых людей не обязательно означает нарушение здоровья.
- Формулы расчёта жира дают оценку с погрешностью ±3–5% — для точных данных рекомендуй DEXA-сканирование.
- Формулы 1RM теряют точность выше 10 повторений — для лучших оценок используй подходы по 3–5 повторений.
- В эндпоинте
exercise/searchwger параметр называетсяterm, а неquery.
Проверка
После поиска упражнений: убедись, что результаты содержат названия упражнений, группы мышц и оборудование. После поиска по питанию: убедись, что возвращаются макросы на 100 г — ккал, белки, жиры, углеводы. После расчётов: проверь здравый смысл результатов (например, TDEE для большинства взрослых должен быть в диапазоне 1500–3500 ккал).
Быстрый справочник
| Задача | Источник | Эндпоинт |
|---|---|---|
| Поиск упражнений по названию | wger | GET /api/v2/exercise/search/?term=&language=english |
| Детали упражнения | wger | GET /api/v2/exerciseinfo/{id}/ |
| Фильтр по мышце | wger | GET /api/v2/exercise/?muscles={id}&language=2&status=2 |
| Фильтр по оборудованию | wger | GET /api/v2/exercise/?equipment={id}&language=2&status=2 |
| Список категорий | wger | GET /api/v2/exercisecategory/ |
| Список мышц | wger | GET /api/v2/muscle/ |
| Поиск продуктов | USDA | GET /fdc/v1/foods/search?query=&dataType=Foundation,SR Legacy |
| Детали продукта | USDA | GET /fdc/v1/food/{fdcId} |
| BMI / TDEE / 1RM / макросы | офлайн | python3 scripts/body_calc.py |