About the Project
TLDR
MapRank is a smarter way to search for places on Google Maps. It ranks results by ratings you can actually trust and shows a one-sentence AI summary of what people say about each place. You can also sort, filter by "open now," save favorites, and add your own notes.
Inspiration
Star ratings on map apps can be misleading. A place with 5.0 stars from 3 reviews shows up right next to a place with 4.8 stars from 2,000 reviews. The 5.0 looks better, but the 4.8 is the one you can actually trust. And even when you find a highly rated place, you still have to scroll through dozens of reviews to understand why people like it.
I wanted to build a search that ranks places by trustworthy ratings and sums up the reviews in one sentence.
What it does
MapRank searches Google Places and re-ranks the results using a Bayesian weighted score. Ratings based on only a few reviews are pulled toward the average, while places with many reviews keep their rating. This way, a 5.0 from 3 people doesn't automatically beat a 4.8 from 2,000. A "How we rank" panel explains the score in plain language, so users know why a place is ranked where it is.
The top 3 results are shown on a podium, each with a one-sentence AI summary of its reviews.
Users can also:
- Sort by MapRank score, Google rating, or number of reviews, with the top 3 summaries updating automatically when the order changes
- See whether each place is open now and its hours for today
- Filter to places that are open now
- Load more results (up to 60)
- Get an AI summary for any other place with one click
- Open any place directly in Google Maps
- Create an account, save favorites without reloading the page, and add personal notes
How I built it
- Backend: Python and Flask, with the Google Places API for place data and Groq for AI review summaries.
- Ranking: a Bayesian average that balances each place's rating with how many reviews it has. Places with no rating always go to the bottom.
- Performance:
- Redis caches search results for 15 minutes and AI summaries for 7 days, since reviews change slowly.
- The top summaries are generated in parallel using a thread pool.
- Summaries for other places are loaded on demand.
- Saved favorites store their own copy of each place's details, so the favorites page doesn't need to call Google again.
- Reliability: Google API calls retry with exponential backoff and a timeout. If a later page fails, users still see the results that loaded.
- AI cost control: each review is trimmed before being sent to the LLM to keep token usage low.
- Security: per-IP rate limiting on search and summaries with Flask-Limiter (backed by Redis), hashed passwords, and session-based login with Flask-Login.
- Data: SQLAlchemy models for users and favorites, with a constraint that prevents the same place from being saved twice.
- Frontend: Jinja templates, JavaScript, and CSS
- Deployment: Docker, with SQLite for local development and Postgres (Neon) in production.
Challenges I ran into
- Slow searches after adding AI summaries. Summarizing every result one at a time hit the LLM's rate limit, and the SDK was silently retrying each failed call for about 12 seconds. I fixed this by running calls in parallel, caching summaries per place, only summarizing the top 3 automatically, and making failed calls fail quickly. A first search now takes about 1 second, and a repeat search about 20 ms.
- Keeping the ranking correct when loading more results. Since the score depends on the average of all results, loading a new page changes every place's score. Instead of adding new results to the bottom, I re-rank all loaded results together and cache each Google page separately with its next-page token.
Accomplishments that I'm proud of
- A ranking that is more useful than simply sorting by stars.
- Reducing search time with live AI summaries from minutes to about one second.
- A complete, working product with search, filters, pagination, accounts, favorites, and notes, plus a distinctive design that works on mobile.
What I learned
- Caching: deciding what to cache, for how long, and how to key it. For example, summaries are stored by place ID so they can be reused across different searches.
- Working with LLM APIs: handling rate limits and token budgets, and why silent retries can be worse than failing fast.
- Security basics: password hashing, sessions, rate limiting, and not trusting data sent from the browser.
- Client-server communication: using JSON and fetch, and keeping the page in sync with the database.
What's next for MapRank
- Structured AI summaries with pros, cons, and "best for"
- Giving more weight to recent reviews in the ranking
- "Near me" search with distances
Log in or sign up for Devpost to join the conversation.