Most apps that try to recommend a meal start by interrogating you. How hungry are you, 1 to 10? Who are you eating with? How are you feeling today? I built one for myself, and the first decision I made was to throw all of that out. The only input it asks for is a tap on a button that says "shake."
Eight passive feature groups
Every time you tap shake, the app assembles a feature snapshot from eight groups and writes it as JSON onto the lottery result:
- Time: weekday, hour, weekend flag, season.
- Lunar calendar: Chinese lunar date, current solar term (清明, 立春, 谷雨, ...), holiday flag, workday flag.
- Geo: city, climate zone, location type (home / office / commute).
- Weather and air: temperature, humidity, AQI, PM2.5, wind. Pulled from Open-Meteo, optionally enriched with a WAQI key.
- Hours since last meal: computed automatically. The
eaten_attimestamp is grabbed from whichever moment you accept a suggestion — there is no separate "I ate" button. - Seven-day rhythm: how many meals at what times in the last week.
- Last three cuisines: a sliding window over what's already in the log.
- Same-dish counter: how many times this exact recipe appeared in the last week.
None of these need me to type anything. They all come from clocks, sensors, and history.
A model ladder, not a model
The recommendation engine is a stepladder of strategies, each with its own gate before the next one unlocks:
uniform— pure random over the seed recipe pool, used until any feedback exists.weighted— rating × time decay, kicks in once a few accepts/rejects are logged.thompson— per-recipe Beta posterior, takes over once there's enough variance per recipe.lgbm_v1— LightGBM binary classifier (accept vs reject) trained on the feature snapshots above.
LightGBM retraining runs nightly at 03:30 via a systemd timer. It splits 8:2 stratified, uses early stopping, and refuses to retrain if the feature schema hash has drifted since the last successful train. If the new model's AUC drops below 0.65, the previous version stays in production. A minimum of 200 feedback rows is required before LightGBM is allowed to take over from Thompson at all.
After dinner I take a photo of what I actually ate and send it to the app. Qwen-VL-Max identifies the dish and fills the meal log for me, so I never have to type a dish name either. The whole loop happens in the background — the app is doing math, I'm just eating.
Comments (0)
Be the first to leave a thought.