mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
Cherry-picked from PR #9177 by @haileymarshall. Adds a fitness and nutrition skill for gym-goers and health-conscious users: - Exercise search via wger API (690+ exercises, free, no auth) - Nutrition lookup via USDA FoodData Central (380K+ foods, DEMO_KEY fallback) - Offline body composition calculators (BMI, TDEE, 1RM, macros, body fat %) - Pure stdlib Python, no pip dependencies Changes from original PR: - Moved from skills/ to optional-skills/health/ (correct location) - Fixed BMR formula in FORMULAS.md (removed confusing -5+10, now just +5) - Fixed author attribution to match PR submitter - Marked USDA_API_KEY as optional (DEMO_KEY works without signup) Also adds optional env var support to the skill readiness checker: - New 'optional: true' field in required_environment_variables entries - Optional vars are preserved in metadata but don't block skill readiness - Optional vars skip the CLI capture prompt flow - Skills with only optional missing vars show as 'available' not 'setup_needed'
86 lines
No EOL
2.6 KiB
Python
86 lines
No EOL
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
nutrition_search.py — Search USDA FoodData Central for nutrition info.
|
|
|
|
Usage:
|
|
python3 nutrition_search.py "chicken breast"
|
|
python3 nutrition_search.py "rice" "eggs" "broccoli"
|
|
echo -e "oats\\nbanana\\nwhey protein" | python3 nutrition_search.py -
|
|
|
|
Reads USDA_API_KEY from environment, falls back to DEMO_KEY.
|
|
No external dependencies.
|
|
"""
|
|
import sys
|
|
import os
|
|
import json
|
|
import time
|
|
import urllib.request
|
|
import urllib.parse
|
|
import urllib.error
|
|
|
|
API_KEY = os.environ.get("USDA_API_KEY", "DEMO_KEY")
|
|
BASE = "https://api.nal.usda.gov/fdc/v1"
|
|
|
|
|
|
def search(query, max_results=3):
|
|
encoded = urllib.parse.quote(query)
|
|
url = (
|
|
f"{BASE}/foods/search?api_key={API_KEY}"
|
|
f"&query={encoded}&pageSize={max_results}"
|
|
f"&dataType=Foundation,SR%20Legacy"
|
|
)
|
|
try:
|
|
req = urllib.request.Request(url, headers={"Accept": "application/json"})
|
|
with urllib.request.urlopen(req, timeout=15) as r:
|
|
return json.loads(r.read())
|
|
except Exception as e:
|
|
print(f" API error: {e}", file=sys.stderr)
|
|
return None
|
|
|
|
|
|
def display(food):
|
|
nutrients = {n["nutrientName"]: n.get("value", "?") for n in food.get("foodNutrients", [])}
|
|
cal = nutrients.get("Energy", "?")
|
|
prot = nutrients.get("Protein", "?")
|
|
fat = nutrients.get("Total lipid (fat)", "?")
|
|
carb = nutrients.get("Carbohydrate, by difference", "?")
|
|
fib = nutrients.get("Fiber, total dietary", "?")
|
|
sug = nutrients.get("Sugars, total including NLEA", "?")
|
|
|
|
print(f" {food.get('description', 'N/A')}")
|
|
print(f" Calories : {cal} kcal")
|
|
print(f" Protein : {prot}g")
|
|
print(f" Fat : {fat}g")
|
|
print(f" Carbs : {carb}g (fiber: {fib}g, sugar: {sug}g)")
|
|
print(f" FDC ID : {food.get('fdcId', 'N/A')}")
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print(__doc__)
|
|
sys.exit(1)
|
|
|
|
if sys.argv[1] == "-":
|
|
queries = [line.strip() for line in sys.stdin if line.strip()]
|
|
else:
|
|
queries = sys.argv[1:]
|
|
|
|
for query in queries:
|
|
print(f"\n--- {query.upper()} (per 100g) ---")
|
|
data = search(query, max_results=2)
|
|
if not data or not data.get("foods"):
|
|
print(" No results found.")
|
|
else:
|
|
for food in data["foods"]:
|
|
display(food)
|
|
print()
|
|
if len(queries) > 1:
|
|
time.sleep(1) # respect rate limits
|
|
|
|
if API_KEY == "DEMO_KEY":
|
|
print("\nTip: using DEMO_KEY (30 req/hr). Set USDA_API_KEY for 1000 req/hr.")
|
|
print("Free signup: https://fdc.nal.usda.gov/api-key-signup/")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |