Skip to content

Repository files navigation

TestoAI

CI

Nutrient-aware food recommendation system built on USDA nutrient data. It learns food embeddings with a small autoencoder and ranks foods by similarity to a testosterone-supportive nutrient profile (protein, zinc, magnesium, selenium, B-vitamins) — not a claim that any individual food is medically proven to raise testosterone.

What it does

Given an activity level and (optionally) a food group, TestoAI returns a ranked list of foods that best match a nutrient profile built from seed foods known to be dense in the relevant micronutrients (e.g. oysters, egg yolk, beef liver). Ranking is rule-augmented: results are also shaped by activity-aware fat/calorie thresholds, food-group preferences, and filters that drop ultra-processed or near-duplicate items.

How it works

USDA nutrient data (Kaggle, or bundled sample fixture)
      ↓
preprocessing (column selection + MinMax scaling)
      ↓
autoencoder (13 → 64 → 16 → 64 → 13)
      ↓
food embeddings (16-dim, from the encoder)
      ↓
canonical recommender (cosine similarity to a seed-food prototype + rules)
      ↓
CLI / interactive demo

train.py builds the embeddings and saves them along with the encoder weights and scaler to data/ and model/. src/testoai/recommend.py loads those artifacts at inference time, scores every food by cosine similarity to the seed prototype, applies activity/food-group adjustments, and returns the top picks. demo.py and the testoai CLI both call this same function.

Quickstart

git clone <repo>
cd TestoAI
python -m pip install -e .
python train.py
python demo.py

train.py first tries to download the full USDA National Nutrient Database via kagglehub (requires a Kaggle account/API token). If that's unavailable, it automatically falls back to the tracked sample fixture at fixtures/sample_nutrients.csv so training always succeeds — just with less food variety.

CLI usage

testoai --activity high --k 5
testoai --food-groups "Beef Products,Poultry Products" --activity medium
  • --activity: low, medium/moderate, or high (default moderate)
  • --food-groups: comma-separated FoodGroup names to restrict results to (default: all groups)
  • --k: cap the number of recommendations returned (default: full curated set)

--food-groups only affects which of these groups the recommender scores from — passing a FoodGroup outside this list returns no results:

Beef Products, Dairy and Egg Products, Fruits and Fruit Juices, Lamb, Veal, and Game Products, Finfish and Shellfish Products, Nut and Seed Products, Pork Products, Poultry Products

Project structure

TestoAI/
├─ src/testoai/
│  ├─ recommend.py        # canonical ranking/scoring engine
│  └─ cli.py               # argument parsing, calls recommend()
├─ train.py                # builds embeddings, saves artifacts to data/ and model/
├─ demo.py                 # interactive CLI demo
├─ fixtures/
│  └─ sample_nutrients.csv # tracked fallback dataset used when Kaggle is unavailable
├─ tests/                  # pytest suite
├─ .github/workflows/ci.yml
├─ pyproject.toml
└─ README.md

data/ and model/ are generated by train.py and are gitignored.

Testing / CI

  • pytest covers the recommender (recommend()/load_embeddings()) and the CLI, using synthetic/fixture-derived artifacts — no Kaggle account or network access required.
  • GitHub Actions (.github/workflows/ci.yml) runs ruff check and pytest on every push and pull request to main.

Tech stack

Python, PyTorch (autoencoder), scikit-learn (scaling, cosine similarity), pandas/pyarrow (data + parquet artifacts), pytest, ruff.

Evaluation

evaluation/evaluate.py asks one question: does the learned autoencoder embedding provide anything useful compared with simpler nutrient-based baselines? There's no labeled ground truth for "correct" food recommendations, so this is a descriptive comparison of ranking behavior and nutrient composition, not an accuracy benchmark.

python evaluation/evaluate.py

Methods compared

  1. Macro cosine baseline — cosine similarity to the mean normalized Protein_g/Fat_g/Carb_g vector of the seed foods, using the fitted MinMaxScaler.
  2. Raw normalized nutrient cosine — same approach, but using all 13 normalized nutrient columns from model/meta.json (no autoencoder).
  3. Autoencoder embedding cosine — same approach, using the learned 16-dim emb_* embeddings.
  4. Final rule-augmented TestoAI recommender — the real recommend() used by the app/CLI, including activity thresholds, food-group weighting, and curation rules.

Methods 1-3 share the exact same seed foods (SEED_FOODS), candidate set, cosine-similarity method, and TOP_N=10; only the representation differs, so any difference between them is attributable to the representation itself. Method 4 is a system-level comparison, not a pure representation test — it intentionally adds rules on top of the embedding similarity.

Results

Run against the full USDA dataset (6,894 rows):

Method Avg protein (g) Avg sugar (g) Avg fiber (g) Avg calories Food groups
Macro baseline 21.9 1.7 0.9 253.6 8
Raw nutrient baseline 17.0 0.0 0.0 172.7 4
Autoencoder embedding 19.7 0.0 0.0 146.3 4
Final TestoAI 21.7 0.0 0.0 179.6 1

The key comparison is raw nutrient baseline vs. autoencoder embedding: full-candidate-ranking (Spearman-equivalent) correlation between the two is 0.87, but their top-10 lists overlap by only 2/10 (20%). See evaluation/results.csv for the full numbers, including macro-vs-embedding (0.85) and macro-vs-raw (0.95) correlations.

Interpretation

The raw nutrient and autoencoder rankings had a rank correlation of 0.87, indicating that the learned representation preserves much of the overall similarity structure already present in normalized nutrient space. Their top-10 recommendations overlapped by only 20%, however, showing that the embedding still meaningfully reorders which foods end up as the closest matches to the seed prototype. Without labeled ground truth, this evaluation can't establish whether that reordering is better, worse, or just different — only that it's a distinct ranking, not a restatement of the raw-nutrient one. The final recommender's top-10 was drawn entirely from Beef Products, which shows that in practice its output is influenced substantially by the explicit activity, food-group, and curation rules layered on top of similarity, not by the embedding alone.

Limitations

  • There is no labeled ground truth for "correct" recommendations — these metrics describe ranking behavior and nutrient composition, not recommendation accuracy or medical effectiveness.
  • Results depend on the chosen seed foods (SEED_FOODS) and nutrient features, and may look different with a different seed set.
  • The final recommender (method 4) is not a pure representation comparison, since it includes explicit activity/food-group rules on top of embedding similarity.
  • Results generated from the bundled sample fixture (rather than the full USDA/Kaggle dataset) should not be interpreted as evidence of full-dataset model quality; evaluate.py prints the row count and warns when this may be the case.
  • Recommendations are heuristic/ranking-based, not medical advice.

License

MIT (see LICENSE).

About

Autoencoder-based nutrient embeddings + cosine similarity to recommend macro/micro-aligned foods; optional CLI.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages