Case Study - A menu scanner that picks what to order, entirely on device

An iOS app that reads a restaurant menu from one photo, checks it against what you logged in Apple Health today and ranks the dishes. The on-device model reads; Swift does the math.

Client
Prandial
Year
Service
iOS Development, On-device AI
Prandial results: three ranked picks from a bistro menu, each with its reason

Overview

What to order, from one photo

Prandial is an iOS app that tells you what to order at a restaurant. It reads what you've already logged in Apple Health today, reads the menu from a single photo, and ranks the dishes against what's left of your day.

All of it runs on the iPhone. There's no account and no networking code, and Health access is read-only. The on-device model does no arithmetic: it structures the menu, sorts each dish into a coarse band and writes a short reason for each pick. Swift computes every number and the ranking.

  • 100% on device
  • Health, read-only
  • Calorie bands, never exact numbers
  • The model reads, Swift ranks
  • Allergens set aside

How it works

The model reads. Swift decides.

A menu photo goes through five steps, all on the phone. The on-device model handles language. The numbers on screen and the order of the picks come from plain Swift code with tests behind it.
Vision

Read the photo

Vision's document recognition reads the menu, preferring tables and lists, and falls back to plain text recognition. The text is split into chunks small enough for the model's context window.

Foundation Models

Structure the dishes

The model turns each chunk into dishes with a name, description, section and price, plus a calorie band and a macro lean. Its answers map straight into strict enums. If the model is unavailable or refuses, a price-line parser takes over.

Swift

Set allergens aside

The model's conflict tags are combined with a word-boundary keyword match, so “ham” never matches “champagne”. Flagged dishes go to a “check with the restaurant” group and are never recommended. Detection is advisory, and the app says to confirm ingredients.

Swift

Rank in Swift

Swift subtracts what Health says you've eaten from your targets and splits the rest across the meals left today. Every remaining dish gets a score, and the top three come back. Changing the meal context re-runs only this step.

Foundation Models

Explain the pick

A second pass streams a sentence or two on why each pick fits. The prompt already holds the numbers Swift computed and tells the model not to invent any. If the pass fails, Swift's own fit summary stays on screen.

The app

From a menu photo to three picks

The recording is a live scan on the iOS 27 simulator: a menu photo from the library, read, analyzed by the on-device model and ranked. The waits for the photo picker and the model are cut short; the rest plays as it ran.

The still screens come from the app's debug screenshot mode, which runs a fixed bistro menu through the real ranking engine with the explanations written in advance.

Screen recording: choosing a menu photo from the library, the Read, Analyze and Rank progress card, then the ranked picks with their reasons streaming in

Live scan · photo to picks

Results with Seared Salmon, Chopped Salad and Roast Vegetable Plate ranked, each with a calorie band, a macro lean and a one-line reason

Results · three picks

Today screen showing 860 kcal left to spend at lunch, with the protein, carbs and fat that remain

Today · what's left

Bottom of the results: the other dishes, then Chicken Satay Skewers set aside for a possible peanut conflict, with a note to confirm ingredients with the restaurant

Check with the restaurant

Settings showing Privacy at 100% on-device, Apple Intelligence ready, and a note that Prandial only reads from Health

Settings · on device

First intro card: an illustrated menu inside scan corners, titled Point it at the menu

Intro

Onboarding step asking to connect Health, explaining that Prandial reads what you logged today and never writes to Health

Setup · Health, read-only

History with two past lunch scans and their top picks

History

Stack & proof

Nothing leaves the phone

There's no server, so there's nothing to send. Health is read and never written, and the numbers on screen come from tested Swift code.
Calorie bands
3

Under 400, 400 to 700, or over 700 kcal. A dish never gets an exact figure.

Allergens
9

On the avoid list, plus free text. Detection is advisory: confirm with the restaurant.

Tests
83

Swift Testing functions, including guards that keep exact dish calories out of the UI

Network requests
0

The app has no networking code at all

Technologies

  • Swift
  • SwiftUI
  • SwiftData
  • HealthKit
  • Vision
  • Foundation Models
  • Swift Testing

SwiftUI and SwiftData for the app and its scan history; HealthKit with read-only access to calories, protein, carbs and fat; Vision for the menu text; Apple's Foundation Models framework for structuring dishes and writing the explanations. Without Apple Intelligence the app still works, with the dish list, keyword filters and a note on why AI picks are off.

More case studies

English lessons from the game on your screen

Looté is an iOS app for Brazilian gamers learning English. It reads a game screen, explains each line in the context of the scene, and turns what you save into spaced-repetition flashcards.

Read more

Your music taste gives you away.

Quem Botou Essa? turns the call’s playlist into a file of suspeitos. A realtime music party game on the web and in a native SwiftUI client, connected to the same room.

Read more

Tell us about your project

Where we are

  • São Paulo
    São Paulo, SP
    Brazil