Skip to content

Commit 69c7ae1

Browse files
authored
Create citypulse-ai-search.mdx
1 parent 181019c commit 69c7ae1

File tree

1 file changed

+272
-0
lines changed

1 file changed

+272
-0
lines changed

docs/showcase/citypulse-ai-search.mdx

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
---
2+
title: CityPulse - AI-Powered Geospatial Discovery Search
3+
description: Real-time local discovery search using Perplexity AI for personalized location insights and recommendations
4+
sidebar_position: 1
5+
keywords: [perplexity, geospatial, location, real-time, maps, local-discovery, sonar, fasthtml]
6+
---
7+
8+
# CityPulse - AI-Powered Geospatial Discovery
9+
10+
![CityPulse Main Interface](https://raw.githubusercontent.com/anevsky/CityPulse/main/assets/CityPulse-GeoSearch-App-1.jpg)
11+
12+
CityPulse is an intelligent location-based discovery app that helps users explore what's happening around them right now. Built with Perplexity AI's Sonar models, it provides personalized, real-time insights about local events, restaurants, alerts, and activities with geographic context and citation tracking.
13+
14+
## Demo Video
15+
16+
[![CityPulse Demo Video](https://cdn.loom.com/sessions/thumbnails/6507fa27571442e680edf787b0f0690d-2fa2c36169822631-full-play.gif)](https://youtu.be/Y0UIhh3diJg)
17+
18+
## Features
19+
20+
- **Real-time location discovery** using Perplexity's Sonar models for current information
21+
- **Interactive map interface** with custom markers and auto-zoom functionality
22+
- **AI-powered search suggestions** with natural language query processing
23+
- **Structured data extraction** with JSON schema validation and citation tracking
24+
- **Personalized insights** using Sonar Reasoning for location recommendations
25+
- **Geographic context awareness** for coordinate-based search queries
26+
27+
## Prerequisites
28+
29+
- Python 3.11+
30+
- Perplexity API key
31+
- Google Maps API key
32+
- Basic knowledge of FastHTML framework
33+
34+
## Installation
35+
36+
1. **Clone and setup environment**
37+
```bash
38+
git clone <repository-url>
39+
cd citypulse
40+
python3 -m venv venv
41+
source venv/bin/activate
42+
pip install -r requirements.txt
43+
```
44+
45+
2. **Configure API keys**
46+
```env
47+
# .env file
48+
PERPLEXITY_API_KEY=your_perplexity_api_key_here
49+
GOOGLE_MAPS_API_KEY=your_google_maps_api_key_here
50+
```
51+
52+
3. **Run the application**
53+
```bash
54+
python3 main.py
55+
```
56+
57+
## Usage
58+
59+
### Basic Local Discovery
60+
```python
61+
# Get nearby events, restaurants, and alerts
62+
api.geo_structured_output_with_citations(
63+
prompt=f"Find current events, restaurants, and local alerts near coordinates {lat}, {lng}",
64+
schema=LOCAL_INFO_SCHEMA
65+
)
66+
```
67+
68+
![Search Interface](https://raw.githubusercontent.com/anevsky/CityPulse/main/assets/CityPulse-GeoSearch-App-4.jpg)
69+
70+
### AI-Powered Search Suggestions
71+
```python
72+
# Generate contextual search suggestions
73+
api.get_search_suggestions(
74+
query="coffee",
75+
location="San Francisco, CA"
76+
)
77+
```
78+
79+
![Location Details Modal](https://raw.githubusercontent.com/anevsky/CityPulse/main/assets/CityPulse-GeoSearch-App-2.jpg)
80+
81+
### Personalized Location Insights
82+
```python
83+
# Get AI reasoning for specific locations
84+
api.get_location_insights(
85+
location_name="Blue Bottle Coffee",
86+
location_type="restaurant",
87+
description="Specialty coffee roaster",
88+
address="315 Linden St, Oakland, CA"
89+
)
90+
```
91+
92+
![AI-Powered Insights](https://raw.githubusercontent.com/anevsky/CityPulse/main/assets/CityPulse-GeoSearch-App-3.jpg)
93+
94+
## Code Explanation
95+
96+
### Perplexity API Integration
97+
```python
98+
class PerplexityAPI:
99+
def __init__(self, api_key: Optional[str] = None):
100+
"""Initialize the Perplexity API client."""
101+
self.api_key = api_key or os.environ.get("PERPLEXITY_API_KEY")
102+
if not self.api_key:
103+
raise ValueError("API key is required. Set PERPLEXITY_API_KEY environment variable or pass it directly.")
104+
self.base_url = "https://api.perplexity.ai/chat/completions"
105+
self.headers = {"Authorization": f"Bearer {self.api_key}"}
106+
107+
def geo_structured_output_with_citations(self,
108+
prompt: str,
109+
schema: Dict[str, Any],
110+
model: str = "sonar") -> Dict:
111+
"""Get a structured JSON response with detailed citations."""
112+
payload = {
113+
"model": model,
114+
"messages": [
115+
{"role": "system", "content":
116+
"""
117+
You are an expert on current events and a real-time local discovery app for city exploration.
118+
119+
We're building an app that helps people discover what's happening right around them, whether they're tourists or locals. The key features would be:
120+
121+
1. Live local events (concerts, meetups, pop-ups happening now)
122+
2. Contextual business info (what's open, busy, or recommended nearby)
123+
3. Real-time alerts (weather, traffic, safety updates)
124+
4. Smart recommendations based on location and time
125+
126+
Find current information near coordinates:
127+
128+
1. EVENTS: Live events happening today/this week (concerts, festivals, sports, etc.)
129+
2. RESTAURANTS: Popular local restaurants and cafes currently open
130+
3. ALERTS: Any weather, traffic, or safety alerts for the area
131+
132+
For each item:
133+
- Generate a unique ID (like "event_001", "restaurant_001", "alert_001")
134+
- Include specific addresses and approximate coordinates if possible
135+
- Include official website URLs when available
136+
- Provide citation information ONLY if it's from a different source than the official website
137+
- For every category, try to include at least 5 items
138+
139+
Return as JSON with events, restaurants, and alerts arrays.
140+
141+
IMPORTANT: For each item, include:
142+
- id: unique identifier
143+
- website: official website URL if available (leave empty if not available)
144+
- citation: object with url, title, and description ONLY if different from official website (leave empty if not available or same as website)
145+
"""
146+
},
147+
{"role": "user", "content": prompt}
148+
],
149+
"response_format": {
150+
"type": "json_schema",
151+
"json_schema": {"schema": schema}
152+
},
153+
"return_citations": True,
154+
"return_images": False
155+
}
156+
157+
response = requests.post(self.base_url, headers=self.headers, json=payload).json()
158+
159+
# Return both content and citations
160+
result = {
161+
"content": response["choices"][0]["message"]["content"],
162+
"citations": response.get("citations", [])
163+
}
164+
165+
return result
166+
```
167+
168+
### JSON Schema for Structured Output
169+
```python
170+
LOCAL_INFO_SCHEMA = {
171+
"type": "object",
172+
"properties": {
173+
"events": {
174+
"type": "array",
175+
"items": {
176+
"type": "object",
177+
"properties": {
178+
"id": {"type": "string"},
179+
"name": {"type": "string"},
180+
"type": {"type": "string"},
181+
"address": {"type": "string"},
182+
"date": {"type": "string"},
183+
"time": {"type": "string"},
184+
"description": {"type": "string"},
185+
"latitude": {"type": "number"},
186+
"longitude": {"type": "number"},
187+
"website": {"type": "string"},
188+
"citation": {
189+
"type": "object",
190+
"properties": {
191+
"url": {"type": "string"},
192+
"title": {"type": "string"},
193+
"description": {"type": "string"}
194+
}
195+
}
196+
},
197+
"required": ["id", "name", "type", "description"]
198+
}
199+
},
200+
"restaurants": {
201+
"type": "array",
202+
"items": {
203+
"type": "object",
204+
"properties": {
205+
"id": {"type": "string"},
206+
"name": {"type": "string"},
207+
"address": {"type": "string"},
208+
"cuisine": {"type": "string"},
209+
"description": {"type": "string"},
210+
"date": {"type": "string"},
211+
"time": {"type": "string"},
212+
"latitude": {"type": "number"},
213+
"longitude": {"type": "number"},
214+
"website": {"type": "string"},
215+
"citation": {
216+
"type": "object",
217+
"properties": {
218+
"url": {"type": "string"},
219+
"title": {"type": "string"},
220+
"description": {"type": "string"}
221+
}
222+
}
223+
},
224+
"required": ["id", "name", "description"]
225+
}
226+
},
227+
"alerts": {
228+
"type": "array",
229+
"items": {
230+
"type": "object",
231+
"properties": {
232+
"id": {"type": "string"},
233+
"title": {"type": "string"},
234+
"description": {"type": "string"},
235+
"severity": {"type": "string"},
236+
"date": {"type": "string"},
237+
"time": {"type": "string"},
238+
"latitude": {"type": "number"},
239+
"longitude": {"type": "number"},
240+
"website": {"type": "string"},
241+
"citation": {
242+
"type": "object",
243+
"properties": {
244+
"url": {"type": "string"},
245+
"title": {"type": "string"},
246+
"description": {"type": "string"}
247+
}
248+
}
249+
},
250+
"required": ["id", "title", "description"]
251+
}
252+
}
253+
},
254+
"required": ["events", "restaurants", "alerts"]
255+
}
256+
```
257+
258+
## Links
259+
260+
- [GitHub Repository](https://github.com/anevsky/CityPulse)
261+
- [Live Demo](https://citypulse-ppx.uc.r.appspot.com/)
262+
- [Video Demo](https://youtu.be/Y0UIhh3diJg)
263+
- [Perplexity API Documentation](https://docs.perplexity.ai)
264+
- **[Built with ❤️ by Alex Nevsky](https://alexnevsky.com)**
265+
266+
## Limitations
267+
268+
- **API Rate Limits**: Perplexity API has usage limits depending on your plan
269+
- **Real-time Data Accuracy**: Information freshness depends on available sources
270+
- **Geographic Coverage**: Results quality varies by location and data availability
271+
- **Citation Reliability**: Always verify critical information from provided sources
272+
- **Mobile Performance**: Large datasets may impact performance on slower devices

0 commit comments

Comments
 (0)