🍽️ BiteTime

Personalized dining recommendations for SJSU students β€” powered by Bob AI.

🌐 Live site: sjsufood.sagg.in  Β·  Built for the IBM AI Challenge @ SpartHill Hacks 2026: AI for Sustainable Impact


Inspiration

Every day, SJSU students walk into The Dining Commons without knowing what to eat. The currently offered menu is a flat list of food with no personal context. We wanted to solve the daily "what should I eat?" friction for our students by building something that learns their taste. Sending them a notification of food they might be interested in on the menu. This way they have a source to know whether they want to spend a meal swipe before actually getting into the cafeteria.


What it does

BiteTime is a personalized dining recommendation web app for SJSU students:

Feature Description
πŸ“… Live daily menu Browse breakfast, lunch, and dinner for any date, pulled live from the Dine On Campus API by SpartanEat
πŸ‘ Rate dishes Thumbs up / down on any menu item, saved to your Google-authenticated account
✨ AI recommendations Unrated dishes you're likely to enjoy are flagged "You might like this" and floated to the top
πŸ“§ Daily email digest Each morning you receive a personalized shortlist of top picks before you even leave for campus

How we built it

Stack

  • Backend: Django 6.1 Β· Python 3.12 Β· SQLite
  • Frontend: Server-rendered Django templates Β· Tailwind CSS
  • AI: Bob Ai Β· Claude Β· Codex
  • ML: fastembed Β· sentence-transformers/all-MiniLM-L6-v2
  • Auth: Google OAuth 2.0 (server-side token verification)
  • Email: Django email backend Β· scheduled send_recommendations management command
  • Deployment: Gunicorn Β· sjsufood.sagg.in

Architecture

Dine On Campus API
      β”‚
      β–Ό
lib/menu_scraper.py   ←── seed_menu management command (runs per meal period)
      β”‚
      β–Ό
 MenuEntry / Food  (Django ORM)
      β”‚
      β”œβ”€β”€β–Ά  menu view  ──▢  lib/food_recommender.py  ──▢  "You might like this" badges
      β”‚         β–²
      β”‚    UserRating  (thumbs up / down per user)
      β”‚
      └──▢  send_recommendations  ──▢  daily email digest

Recommendation engine

lib/food_recommender.py embeds food names as vectors using all-MiniLM-L6-v2 and computes cosine similarity between a candidate dish and everything a user has liked or disliked:

  1. Exact match short-circuits the model instantly.
  2. Best-like similarity must exceed a threshold (0.55).
  3. Like–dislike margin must be positive enough (0.05) to avoid recommending something that's actually closer to a disliked dish.

This means "Chicken Teriyaki Bowl" gets recommended to someone who liked "Orange Chicken" β€” purely from dish-name semantics, no ingredient lists required.


Challenges we ran into

  • No public API docs β€” The Dine On Campus site is a JavaScript SPA. We reverse-engineered its JSON endpoints, including a multi-step flow (fetch period IDs β†’ fetch menu) and browser-like headers to avoid being rate-limited.
  • Embedding model cold start β€” fastembed downloads the model on first use. A failed download or inference timeout must never hide already-saved user votes, so the recommendation step is wrapped in a silent fallback.
  • Idempotent email delivery β€” Preventing duplicate emails required a RecommendationDelivery model with a UniqueConstraint on (gmail, recommendation_date) and careful get_or_create + sent_at gating.
  • Threshold tuning β€” Finding the right cosine similarity threshold and like-vs-dislike margin to surface genuinely relevant dishes without over-recommending took several iterations.

Accomplishments that we're proud of

  • πŸ€– A working AI recommendation pipeline driven entirely by food name embeddings β€” no nutrition data, no ingredient lists β€” that still produces intuitive results.
  • πŸ”„ A robust, idempotent menu scraper that handles API quirks and can be safely re-run for any date and meal period.
  • 🎨 A clean, accessible UI with date navigation, meal period tabs, and per-item vote toggles β€” server-rendered, zero JavaScript frameworks.
  • πŸ“¬ A proactive daily email pipeline with deduplication, error logging, and a full audit trail of every recommendation sent.

What we learned

  • Semantic text embeddings are a surprisingly powerful signal for food similarity β€” treating dish names as natural language and measuring their proximity in embedding space works well enough to drive real recommendations.
  • Reverse-engineering a JS-heavy SPA's internal API (session cookies, multi-step period IDs, CORS headers) takes patience but produces a far more stable integration than HTML scraping.
  • Building idempotent pipelines (menu seeding, email delivery) from the start saves a lot of pain when things need to be recovered or replayed.

What's next for BiteTime

  • [ ] Nutrition-aware filtering β€” incorporate dietary tags (vegetarian, vegan, allergens) to let users set hard preferences
  • [ ] Community ratings β€” surface crowd upvote counts so students can see what's popular today
  • [ ] Push / SMS notifications β€” replace email with same-morning phone nudges
  • [ ] Multi-hall support β€” the architecture is location-agnostic; adding other SJSU locations only requires a new location ID
  • [ ] Collaborative filtering β€” blend the content-based (embedding) approach with user–user similarity to surface hidden gems
  • [ ] Mobile-first redesign β€” optimise the UI for the phone-in-hand use case students actually have standing in line

Built with ❀️ by Sparkhill β€” IBM Group 29 Β· SpartHill Hacks 2026

Built With

Share this project:

Updates

Submission history