Full-Stack · AI · Mobile
Menuto icon

Menuto

A full-stack AI dish recommendation app — solo-built end to end. Tell it your restaurants and taste preferences, it tells you what to order. Fully functional, deployed to TestFlight.

View on GitHub ↗TestFlight ↗
Year
2024
Role
Solo — Product · Design · Full-Stack
Context
Personal Project · End-to-End Ownership
Tools
React Native · Expo · FastAPI · OpenAI GPT-4o · Supabase · PostgreSQL · Google Places API · Tesseract OCR

The Idea

Restaurant reviews tell you where to eat. Nothing tells you what to order — especially at a place you've never been. I wanted an app that knows your taste profile, browses the actual menu, and surfaces the right dishes for you specifically. So I built it, entirely solo: product vision, design, React Native frontend, FastAPI backend, database schema, LLM integration, and deployment.

I'm always indecisive about what to order at restaurants. So I solved my own problem.

2
Codebases: FastAPI backend + React Native app
3
Tabs: My Restaurants, Choose Dish, Profile
60–80%
LLM cost reduction via model + prompt optimization
0
Team members — fully solo

The App

Add Restaurants screen
Add restaurants
Restaurant menu
Browse menu
Choose Dish preferences
Set preferences

User Flow

Add up to 3 restaurants from Google Places (location-aware) → browse each restaurant's full menu, filtered by course (All / Starter / Main / Dessert), and save favorite dishes → open Choose Dish, confirm the restaurant and menu, then indicate preferences — how hungry you are, how much you want popular vs. personalized picks, and what you're craving (light, fresh, carb-heavy, protein-heavy, spicy, creamy, crispy, comforting) → AI loads your recommendations.

Craving selector
Craving chips
My Restaurants
Saved restaurants
Profile
Taste profile

The AI Pipeline

Menu Parsing

The FastAPI backend accepts a menu image, URL, or raw text. Images go through Tesseract OCR; all inputs are structured by GPT-4o (vision) or GPT-4o-mini (text) into a typed JSON array: dish name, description, price, course category, ingredients, and dietary tags. The same `/upload-menu` endpoint handles all three input types via content-type detection. Low-confidence parses surface a user-correction flow rather than silently passing bad data downstream.

Cost Optimization

Initially used GPT-4 across all calls. After the first working build, I profiled the cost per request and systematically reduced it: switched text-based parsing to GPT-4o-mini, added max_tokens caps (300–1,500 depending on call type), and reduced the recommendation set from 8 to 5. Total cost reduction: 60–80% with no perceptible quality loss.

Engineering Decisions

Technical Highlights

  • Mixed navigationstate-machine for top-level transitions (sign-in → onboarding → main app), React Navigation tabs only for the inner My Restaurants / Choose Dish / Profile views.
  • Zustand state managementtyped slices for user preferences, current menu session, and recommendation state; no prop-drilling across screens.
  • Location-aware restaurant searchdebounced Google Places autocomplete (300ms) with GPS; graceful degradation to city-level if permission denied.
  • Supabase/PostgreSQL schemauser preference vectors, dish favorites per restaurant, and restaurant menu cache; structured so ratings and preferences update asynchronously.
  • Dual AI modelsGPT-4o vision for photo menus (richer context needed), GPT-4o-mini for text/URL parsing (cost-efficient, output quality equivalent).
DishcoveryFlock