-
-
Bolobao: where should we eat?
-
Swipe through restaurant profiles: right to save, left to skip.
-
Add a place: search any of 34,383 Hong Kong restaurants and watch the profile get written live.
-
Written live in about a minute, or no profile when the sources aren’t enough to trust.
-
Saved places stay on your phone, ordered by recency.
Inspiration
When I'm back in Hong Kong, I want an honest local's guide to eating out, the good and the bad: what to order, what to skip, and whether the queue is worth it. Those answers are out there, in reviews, blogs and forum posts, but mostly in Chinese, and there are far too many to read before deciding to visit a place. Bolobao reads them for you and turns each place into a short profile to swipe on, so you can decide whether to go in a few seconds.
What it does
Bolobao is a deck of restaurant profiles you swipe. Each one is styled like the handwritten order slip a waiter fills in at a traditional Hong Kong diner (cha chaan teng), with a photo of the restaurant's storefront, the inside, or a dish.
A profile answers up to five "prompts", picked from 23: the best dish, what to order first, what to skip, whether the queue is worth it, what the room is like, whether it's cash only, and so on. It only answers what people actually wrote about that place, so every profile is different, and anything the sources don't cover is left out. When the sources agree on a price range, it shows a price level from \$ to \$$$$.
Swipe right to save, left to skip, or use the corresponding buttons. Saved places stay on your phone in a list, with their original profile and the option to open it in Maps.
Add a place works for any of 34,383 dining places in Hong Kong. Pick one without a profile and Bolobao writes it live: Tavily searches for sources, Nemotron Ultra writes the profile, Nemotron Super fact-checks and rates it, and Nemotron Super VL picks the photo. It takes about a minute, and you watch each step happen in real time.
How we built it
Data and search (Tavily Search)
Foursquare OS Places is clipped to Hong Kong's official district boundaries with DuckDB. All 34,383 dining places are searchable in the app. To fill the deck, I ran the pipeline on one district, Sham Shui Po — after removing bars, chains and closed places, that left 1,956. Each place gets one Tavily search — set to basic, using its name and its area in Chinese. Most results are Traditional Chinese reviews, blogs and forum posts.
Writing (Nemotron 3 Ultra)
The writer first decides whether the sources are about this shop at this address, not another branch, a namesake or a shop that has closed. Only then does it answer up to five prompts: one short line each, citing its source. It may only say what the source says: a dish in a list isn't a "signature" and no dish is guessed from the shop's name. Output is a strict JSON schema.
Fact-checking and rating (Nemotron 3 Super)
Two separate calls, made three times each. The check compares every answer against its source, drops anything unsupported and catches closures. The rating sees only the checked profile, not the sources, and judges whether it would change where you eat or what you order. Only usable profiles reach the app, ordered by score.
Photos (Nemotron 3.5 Super VL)
The vision model receives candidate images returned by Tavily's search, checks whether the storefront's sign matches the shop, rejects ads, menus, blurry shots, and picks the best storefront picture when available. It otherwise picks a picture of the inside, a dish, or none if no photo meets its criteria.
App and backend (Nebius AI Cloud)
A Python pipeline saves every stage to AWS S3, so reruns skip finished work. PostgreSQL and an OpenAPI spec-first Go API return data for the SwiftUI iOS app on TestFlight. "Add a place" streams each step live over SSE from a small FastAPI service. Everything runs in Docker Compose on a Nebius AI Cloud VM.
Challenges we ran into
- Generic answers. The first run's profiles were often vague, things like "good food" or "wide variety of sushi" that don't help you decide. I told the writer to keep the concrete detail (the dish, the price, the time) and had the judge reject profiles with nothing specific to act on. 334 of 1,141 matched places were dropped that way. Some lines still read flat, because a profile can only be as specific as what people wrote.
- Which shop is this? Hong Kong has many restaurants with the same name, and 14% of the places in Sham Shui Po have no address at all. Early profiles mixed up branches, merged two different shops into one, or described places that had closed. Most of the prompt work went into identity rules: a different address means a different place, a shop with no address only counts if the sources describe one restaurant, and closed means no profile.
- Trusting the judge. I wanted to use an LLM judge to compare prompt versions, but first I had to know whether it judged like I would. I hand-labelled 50 random places, and it agreed with me 94% of the time on whether a profile is usable. Running it twice on the same profiles showed the per-line checks wobble on borderline sources, so each check became a three-way vote.
- One judge call wasn't enough. When checking and rating happened in a single call, the source check leaked into the rating, and good profiles were marked unusable for details the sources didn't cover. Splitting it into two calls fixed that.
- Picking photos. Choosing from Tavily's text descriptions of images matched my own picks only 3 out of 10 times, so I switched to a vision model that looks at the images.
Accomplishments that we're proud of
- 1,956 places in Sham Shui Po became 1,141 matched and 747 profiles in the deck.
- The judge removed 737 unsupported claims and 73 closed restaurants before they reached the app.
- Across 7 prompt versions, measured with paired comparisons and confidence intervals, wrong-restaurant or closed matches fell from 9 to 4, and unsupported answers from 29% to 18%, with no loss in usable profiles.
- Add a place writes a checked profile for any restaurant in Hong Kong in about a minute, for around $0.05.
- The whole pipeline, including every experiment, cost about $86 in tokens and 2,089 Tavily credits.
What we learned
- Build the judge first, and check it against your own labels before trusting it.
- The ceiling is retrieval: a profile can only be as good as what the search found.
- What you measure is what you get. My metrics rewarded shorter answers, and some lines got shorter but harder to read. Readability needs its own measure.
What's next for Bolobao
- Marking a profile as visited, with a personal ranking of places you've visited via a pairwise comparison.
- An editor pass so the lines read more naturally.
- Better closure detection, then more districts.
- Sorting by distance, so you can see what's good near you.
Built With
- amazon-web-services
- docker
- duckdb
- fastapi
- foursquare
- go
- ios
- nebius-ai-cloud
- nebius-token-factory
- nemotron
- postgresql
- python
- swiftui
- tavily
Log in or sign up for Devpost to join the conversation.