Inspiration

Three days before a job interview, your skin is stressed, you don't know what to wear, and you have no idea what the weather's going to do to either plan. Every beauty and styling app treats those as three separate problems: a skin app, a wardrobe app, a weather app, and makes you do the synthesis yourself.

We built Last Look on a simple bet: skin, outfit, and timing aren't three decisions. They're one decision, made under a deadline, and an agent system is the right shape to make it, not a static quiz that spits out a generic result.

What it does

Give Last Look a clear picture showing your face and your shoulders, an occasion (interview, first date, wedding guest), how many days you have, and — optionally — your city. It comes back with:

  • A day-by-day skincare plan, grounded in real YouCam Skin AI diagnostic scores from your actual photo, honest about what's fixable in the time you have and what isn't.

  • A color season and palette, derived from undertone/depth sampled directly from your photo's pixels, not guessed by an LLM.

  • Color-verified outfit picks, rendered on your real photo via YouCam Apparel VTO, and only shown if the rendered color actually matches your palette; the system checks its own output before you ever see it.

  • Live weather for your event day, factored into the skin routine and styling reasoning when it genuinely changes the advice (heat → oil control, cold → richer moisturizer, rain → lighter fabrics).

  • A real shopping link per outfit, built from the verified color and garment type, so a recommendation is something you can act on before your deadline, not just something to look at.

How we built it

Last Look is a FastAPI backend running a LangGraph multi-agent pipeline, with a Next.js/Tailwind frontend that streams the agents' progress live instead of showing a spinner.

Six specialized agents, not one model doing everything: Diagnostic, Weather, Timeline, Stylist, Verifier, and Presenter, each with a single job and a typed state object passed between them.

The graph itself does real work:

  • Diagnostic and Weather agents run as a genuine parallel branch, independent nodes that fan out from the graph's entry point and fan back in at a join, not a fixed linear sequence.

  • Diagnostic calls YouCam's Skin AI on a server-side face crop (built from a real detected face region, not a blind guess), and grounds the color palette in pixel-sampled undertone/depth, since Skin AI itself returns no tone data at all. Diagnostic reads all 14 individual concern scores YouCam returns (acne, redness, pore, wrinkle, dark circles, and more) not a single number. so the routine responds to what's actually wrong, not a generic average.

  • Stylist ranks a garment catalog against that palette using retrieval-grounded color theory, the LLM explains a fixed color-season reference, it doesn't invent one.

  • Verifier is the closed loop: it calls YouCam Apparel VTO to render each candidate, then inspects the actual rendered pixels, cropping to the likely garment region, excluding skin-tone and background clusters, and cross-validating the result against the original reference photo, before accepting or rejecting an outfit and trying the next candidate.

  • Presenter writes the final summary, weaving in weather only when it matters.

DeepSeek powers the reasoning steps; Open-Meteo powers real weather grounding by city.

Challenges we ran into

Almost every real bug came from the same root cause: YouCam's actual API response shapes don't match what a first read of the docs suggests, and the only way to find the real shape was to trigger a live call and read what came back. Skin Analysis returns a presigned ZIP URL, not inline scores. Apparel VTO's output is nested under results.url, not a top-level field. dst_actions and garment_category are required fields with no obvious default. We rebuilt the client twice against real responses instead of documentation guesses.

The hardest problem wasn't API shape, though, it was color. A rendered outfit's "dominant color" kept reading as the studio background or the wearer's skin tone instead of the garment, especially for thin straps or wide necklines. We fixed it in layers: cropping to the likely garment region, explicitly excluding skin-tone and background-like clusters, and finally cross-validating the rendered composite against the original reference photo, two independent images agreeing is real evidence, one sample alone wasn't reliable enough. Even after fixing detection, naming a color for the shop-link query had its own bug: matching raw RGB distance against a small fixed swatch list put a visibly green, desaturated fabric closer to "gray" than any green swatch. The fix was switching to HSV hue-based classification, hue is far more stable than RGB under real-world lighting than a nearest-swatch distance check.

We also hit a genuine physical conflict: Skin Analysis needs a face filling most of the frame; Apparel VTO needs shoulders and chest visible. One photo can't satisfy both if you crop it the same way twice, so we derive two different crops server-side from the single photo the user takes.

Accomplishments that we're proud of

  • A real conditional loop in the agent graph, the Verifier doesn't just render once, it rejects and retries based on evidence.

  • A genuine parallel branch (Weather + Diagnostic) with a proper join, not a disguised sequential pipeline.

  • Cross-validated color detection using two independent photos instead of trusting a single heuristic pass.

  • A bounded retry budget (max 4 verification attempts, 2 accepted outfits) the Verifier loop is real and conditional, but capped, so a bad palette/catalog combination can't loop forever or silently burn through API credits.

  • Streaming the agent pipeline's real progress to the user live, instead of hiding it behind a loading spinner.

  • Grounding every color decision, palette, and verification in either real pixel data or a fixed color-theory reference, never an LLM's unaided guess.

What we learned

The biggest lesson was epistemic: never trust an assumed API field name over a live response. Every "mystery bug" in this build was really a wrong assumption about response shape, and the fix was always the same print the real payload, read it, adjust.

The second lesson was about honesty in AI systems: a plausible-sounding LLM guess (an invented undertone, a confident color name) is more dangerous than an obvious failure, because it's wrong in a way that looks right. Grounding decisions in retrievable data or measured pixels, even with heuristic limits, beats an ungrounded guess every time.

What's next for Last Look

  • A bigger, more diverse garment catalog. Right now the catalog is intentionally small and sourced from a handful of stock photoshoots — that's the single biggest lever on result quality and variety. More candidates per occasion/gender means the Stylist and Verifier agents have real options to choose between instead of a thin set, and fewer cases where the best available match is a compromise.

  • Live selfie capture, done right. We shipped and then pulled a live-camera flow with real-time face-position guidance during this build; it's coming back with a more robust version that reuses the actual detected face region for cropping instead of a heuristic guess.

  • Deeper shopping integration. Today's "Shop this look" is a real, working search link built from verified color + garment type. Next is a real shopping/product API, live pricing, availability, and a direct product match instead of a search results page.

  • True garment segmentation. Our color detection is a strong heuristic (region crop + skin/background exclusion + cross-validation), not pixel-perfect segmentation. A real segmentation model closes that last gap.

  • Shoes VTO for a genuinely head-to-toe recommendation.

  • Colorblind-safe palette mode, since accessibility shouldn't be an afterthought in a color-driven product.

Built With

  • fastapi
  • httpx
  • javascript
  • langchain
  • langgraph
  • next.js
  • open-meteo
  • python
  • react
  • skin+ai-apparel-vto
  • tailwind-css
  • youcam-api
Share this project:

Updates