CityLink
Hackathon · Hackathon discoveryPick a city. Start exploring.
A selected city connects recommendations, map markers and the conversation, with my front-end contribution called out.
Interactive explanation · not the live service
Loading interactive explanation…
Explore the architectureSystem diagrams, design decisions and detailed flows
System overview
- REACT FRONT ENDCity search pageGoogle Map, autocompleteStep 1, autocompleteGoogle Maps PlatformMaps JS + Places
- City search pageStep 2, recommendationsFlask AI servicerecommendations, chatbotfixed-format promptOpenAI APIgpt-4o-mini
- City search pagecity + listsREACT FRONT ENDCity chat pageroom, lists, chatbotStep 3, ws ?placeIdWebSocket serverNode, Express, wspush / rangeRedischat history per city
Other connections
- City chat pagetoFlask AI servicechatbot
View the diagram as text
Parts
- City search page (Google Map, autocomplete): Client / UI
- City chat page (room, lists, chatbot): Client / UI
- Google Maps Platform (Maps JS + Places): External service
- Flask AI service (recommendations, chatbot): Owned service
- WebSocket server (Node, Express, ws): Owned service
- OpenAI API (gpt-4o-mini): External service
- Redis (chat history per city): Data store / broker
Connections
- Step 1: City search page → Google Maps Platform: autocomplete
- Step 2: City search page → Flask AI service: recommendations
- Flask AI service → OpenAI API: fixed-format prompt
- City search page → City chat page: city + lists
- Step 3: City chat page → WebSocket server: ws ?placeId
- WebSocket server → Redis: push / range
- City chat page → Flask AI service: chatbot
From picking a city to joining its chat room
Pick a city
Places autocomplete is limited to cities, and clicking the map runs a nearby search for localities within 50 km and offers them as suggestions.
Get AI recommendations
The page asks the Flask service for recommendations; it requests exactly five places and five restaurants from gpt-4o-mini in a fixed format and parses the reply into two lists.
Open the city page
The app navigates to the chat page with the Google Place ID, city name and lists, and each item gets a Google Maps link.
Join the room
The page opens a WebSocket for that Place ID. The server adds the socket to the room, broadcasts the online count and sends saved history from Redis.
Chat and refine
Messages are pushed to the room's Redis list, trimmed to the most recent ones, and broadcast to the room. The chatbot can regenerate one of the lists or give a short answer.
The project & my contribution
- Problem
- Planning a city visit means looking up places, restaurants and other travelers' tips in separate apps.
- Solution
- A map app: pick a city to get AI picks for places and restaurants, and chat live with others viewing the same city.
- Result
- Built at a 2025 UVA hackathon, with every recommendation linking straight to Google Maps.
My part
- Fixed city-suggestion clicks so they call the recommendation API
- Added a dark Google Maps style, custom map markers and click-outside closing for the suggestion list
- My teammate built the Flask recommendation service and the WebSocket chat server
How it's built
- React front end with Google Maps and Places search
- A Flask service asks gpt-4o-mini for five places and five restaurants in a strict format
- Node.js WebSocket chat rooms keyed by Google Place ID, with history in Redis
Highlights
- The chatbot regenerates only the list you ask about and keeps the other
- Every recommendation links straight to Google Maps