Skip to content
RK
02 · Mobile / AI · 2026

A working Android shopping app with conversational search, occasion-aware styling and photorealistic virtual try-on — every AI feature optional, sitting on top of a deterministic engine that runs on the phone.

Academic Project Team of 5 Public repo

Catalogue

35 products, 2 departments

Offline

Fully usable, no API key

Shown at

Emergex, August 2026

Overview

Online clothing shops are very good at “show me black dresses under $100” and very poor at “what should I wear to dinner at a Michelin-starred restaurant?” The first is a database query. The second is a judgement — and it is the reason people still shop in physical stores, where a member of staff can look at them and answer it.

FitCheck is a working Android shopping app that attempts the second question. It has three AI features: a search that reads a plain-English request and then asks a language model which of the results genuinely suit the occasion; a Smart Closet that styles what a customer already owns against an occasion and the weather they describe; and a virtual try-on that renders a photorealistic studio photograph of the customer wearing a garment.

The finding I care about is not that the models work. It is that they can be made optional. Every AI feature sits on top of a deterministic engine that runs on the phone, so the app is fully usable with no network, no API key and no running cost. The model improves the answer; it is never required to produce one.

Underneath sits an ordinary retail spine — 35 products across two departments, per-variant stock, filtering and sorting, favourites, a bag, a validated delivery address and a placed order. The AI features are only interesting attached to something real.

What I built

  • Conversational search — “Outfit for Calgary in December” resolves into a season and a warmth requirement. Because the catalogue contains nothing rated for that cold, the app says so plainly and recommends layering a coat it does not sell.
  • Smart Closet — turns a customer's order history into a wardrobe and styles it against an occasion and weather described in their own words.
  • Photorealistic try-on — takes a full-body photograph and returns a studio photograph of that person wearing the garment: same face, same build, correct colour, seamless backdrop, commercial colour grading.
  • A deterministic layer between the interface and the network — a query parser, a product ranker, a rule-based stylist and a size calculator. Every AI feature calls into that layer first and reaches the network only if a proxy is configured.
  • One error type for every model failure — no key, no network, a timeout, a rate limit — with every caller catching it and falling through to the engine on the device.
  • A rebuilt product data pipeline that reads colour off the product photograph: chroma-keying the background, eroding the edge halo, grouping shades of one fabric together, and naming the result by hue rather than RGB distance.

Decisions worth explaining

The engine narrows; the model chooses among what it narrowed to

I could have handed the model the whole catalogue and asked it to pick. Instead the ranker produces a shortlist and the model chooses within it, with its answer intersected against that shortlist before anything renders. A stylist that recommends a garment the shop does not stock is worse than no stylist — this makes that structurally impossible rather than merely unlikely. Tested by feeding it invented product identifiers, none of which reach the screen.

Body measurements are never transmitted

Size recommendation could have been a model call. It is arithmetic against a size chart, computed on the device, and the measurements are excluded from every request — specifically because the provider's free tier states that submitted content may be used to improve their products. A customer's waist measurement is not mine to contribute to a training set.

Secrets live server-side because an APK can be unzipped

The app never holds a key. A pair of serverless functions adds them. When a token was once pasted into the wrong configuration field and echoed into the UI, I added shape validation and redaction so no string with the provider's token prefix can reach a log or a screen.

Prompts are code with unusually bad error messages

Two early versions of the try-on prompt issued instructions — “replace their outfit”, then “remove every garment”. The first was satisfied by compositing a dress over the joggers already in the photo. The second was taken literally enough to remove the subject's legs. The working version contains no destructive verbs at all: it describes the photograph that should exist, including an explicit statement that the subject's limbs are present and correctly proportioned.

Filters exclude; judgements rank

A search for “dresses” returned handbags for some time, because matching the women's department scored +30 while missing the category scored −25 and the remainder cleared the relevance threshold. Department, category, colour, size, budget and sale are literal properties a shopper can point at, so they now exclude. Occasion, warmth, formality and free text are judgements, so they only rank. When a combination has no stock the app concedes one constraint at a time and names the one it gave up.

Testing across the whole catalogue, not one product

The domain logic is written as pure functions, separate from the React components, so the real source can be compiled and executed directly against the real catalogue. Generating the try-on prompt for all 35 items is what exposed a naive singularisation producing “dresse”, the word “Occasion” being treated as a garment, “suitable” being read as “suit”, and sunglasses being described as opaque fabric. A single-product test finds none of these.

What it does not do

  • Payment processing is deliberately out of scope — handling card data brings PCI-DSS obligations that are not a reasonable undertaking here, so checkout validates and records a real order and stops before taking payment.
  • Orders live on the device, so they do not follow a customer to a second phone.
  • The try-on renders one garment rather than a complete outfit, and image models are not deterministic: the same request twice gives two different photographs.
  • Generative image models are trained on datasets that over-represent some body types and skin tones. The prompt instructs the model that the subject's build, skin tone, age and ethnicity are unchanged, but whether that instruction holds equally well across all customers is not something five people testing on themselves can establish.
Behind the curtains

Decoding logic && the lyrics

Rishabh's GitHub
@rishabh7431

Initializing connection to GitHub daemon..._

Contributions
Repositories
Stars earned
Followers
Latest push