-
Each person adds an address and a few things they love. One click fills a New York demo group.
-
Qloo resolves each taste, finds what the group shares, and shows which popular venues were left out and why.
-
Every venue shows each person's rank out of 30 and the taste that drove it, from Qloo explainability.
-
The MeetSpot agent calls its Qloo group-taste tool and explains the pick person by person.
-
The fair midpoint, the venues, and green cells where everyone's Qloo taste heatmap overlaps.
-
How MeetSpot uses Qloo: search, heatmap, insights per person with explainability, and compare.
Inspiration
MeetSpot is my open-source project for "where should we meet?". It already found a fair location: the midpoint between everyone's addresses, checked against real commute times. But the venue it picked was the same for any group, because it knew nothing about the people.
Group decisions have a familiar failure mode. Two friends love a place, the third would hate it, and the average still says "great choice". I wanted the venue to be fair the same way the location is fair: judged by the person who is worst off.
What it does
Each person adds a few things they love: artists, movies, shows, brands, books. For example "Taylor Swift, Barbie", "Metallica, John Wick", "Bad Bunny, Trader Joe's". MeetSpot then:
- Resolves every taste to a Qloo entity and shows each person what their taste was recognized as.
- Finds a fair center between the addresses and checks real commute times (Google Routes). Among the centers that pass, it prefers the area the whole group likes, using one Qloo taste heatmap per person and the cell-wise minimum.
- Gets 30 candidate restaurants, cafes or bars around that center from Qloo.
- Has Qloo score the same 30 venues once for each person, converts each score to a percentile, and ranks venues by the lowest percentile in the group (maximin).
- Shows the result: a fit bar per person per venue with the reason from Qloo's explainability ("Person 1 via Barbie"), the venues that were left out and who would have been unhappy there, and what the group has in common.
A real run with the demo group in New York: Hard Rock Cafe scores well on average but is left out because Person 3 ranks it only #17, and TAO Uptown because Person 2 ranks it #16. The shared tags Qloo found were Blues, Folk, Emotional, Country and Melodic.
The agent. MeetSpot has a ReAct agent (MeetSpotAgent, on DeepSeek) with tools for geocoding, center calculation, place search and recommendation. I added a group_taste_rank tool that wraps the whole Qloo pipeline. On the results page, Ask the agent runs it on the same group: you see each tool call it made, then its answer, which explains the pick person by person using only what the tools returned.
How I built it
- Backend: Python, FastAPI, aiohttp. The Qloo client is
app/tool/qloo_client.py; percentile and maximin ranking and the heatmap minimum are pure functions with unit tests. - Qloo endpoints used:
/search(resolve tastes),/v2/insightsfor places near the center withfilter.price_level.maxmapped from the budget field,/v2/insightswithfilter.results.entitiesandsignal.interests.entities(score the same candidates per person),feature.explainability(the "via Barbie" reasons),filter.type=urn:heatmap(per-person taste heatmaps), and/v2/analysis/compare(common ground). - Agent: the existing MeetSpotAgent plus the new
group_taste_ranktool and an English mode. The tool is only registered on the international (Google Maps) path, so the Chinese path is unchanged. - Frontend: per-person taste inputs, a one-click New York demo group, and the taste card, fit bars and agent card on the generated results page.
- Deploy: Docker on Render. 115 tests run in GitHub Actions on every push.
Challenges I ran into
- Making scores comparable across people. Qloo affinity values for different people are on different scales, so averaging raw scores would let one enthusiastic profile decide for everyone. Scoring a fixed candidate set per person and converting to percentiles fixed that.
- Rate limits. Scoring per person fans out requests, and the API returns 429 under concurrency. I added retry with backoff, and if any taste lookup still fails the app falls back to the normal search instead of ranking on partial data.
- The agent never finishing in English. The loop's stop condition was written for Chinese output, so English answers ran to the 15-step limit. I found it while testing the agent card and fixed it.
- Keeping the existing product intact. Requests without tastes, and the Chinese path, behave exactly as before; tests check both.
Accomplishments that I'm proud of
- The ranking can explain why a venue is not recommended, and name the person it would have failed.
- Every reason on the page comes from Qloo's explainability data, not from a language model guessing.
- It runs in the live product, not in a separate demo.
What I learned
Group fairness is a different question from group preference. Once the scores per person are comparable, the maximin rule is simple to compute, and it changes the answer in exactly the cases where averages hide someone.
What's next
- Let each person weight their tastes, or say "anything but X".
- Use Qloo's audience and demographic signals for groups who do not want to list favorites.
- Bring taste fairness to the Chinese (Amap) path once a matching place data source is available.
How the project changed during the hackathon
MeetSpot existed before the hackathon (location fairness only). Everything Qloo-related was built after 2026-09-30: the Qloo client, per-person maximin ranking, the taste heatmap, the group_taste_rank agent tool and English agent mode, the taste inputs and demo group, the results page taste card, and the Ask the agent card. The README section "Group Taste Fairness with Qloo" lists it, and the git history shows it (PR #92).
Try it
Open the finder link below, click Try a demo group in New York, then Find Fair Midpoint. Taste searches do not count against the free daily limit during judging. The app runs on a free Render instance, so the first request after it has been idle can take about a minute to wake up.
Built With
- aiohttp
- css3
- deepseek
- docker
- fastapi
- github-actions
- google-maps
- google-places
- google-routes
- html5
- javascript
- python
- qloo
- render

Log in or sign up for Devpost to join the conversation.