-
Notifications
You must be signed in to change notification settings - Fork 39
docs(showcase): CityPulse - AI-powered Geospatial Search with Sonar API #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+65
−2
Merged
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,272 @@ | ||
--- | ||
title: CityPulse - AI-Powered Geospatial Discovery Search | ||
description: Real-time local discovery search using Perplexity AI for personalized location insights and recommendations | ||
sidebar_position: 1 | ||
keywords: [perplexity, geospatial, location, real-time, maps, local-discovery, sonar, fasthtml] | ||
--- | ||
|
||
# CityPulse - AI-Powered Geospatial Discovery | ||
|
||
 | ||
|
||
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. | ||
|
||
## Demo Video | ||
|
||
[](https://youtu.be/Y0UIhh3diJg) | ||
|
||
## Features | ||
|
||
- **Real-time location discovery** using Perplexity's Sonar models for current information | ||
- **Interactive map interface** with custom markers and auto-zoom functionality | ||
- **AI-powered search suggestions** with natural language query processing | ||
- **Structured data extraction** with JSON schema validation and citation tracking | ||
- **Personalized insights** using Sonar Reasoning for location recommendations | ||
- **Geographic context awareness** for coordinate-based search queries | ||
|
||
## Prerequisites | ||
|
||
- Python 3.11+ | ||
- Perplexity API key | ||
- Google Maps API key | ||
- Basic knowledge of FastHTML framework | ||
|
||
## Installation | ||
|
||
1. **Clone and setup environment** | ||
```bash | ||
git clone <repository-url> | ||
cd citypulse | ||
python3 -m venv venv | ||
source venv/bin/activate | ||
pip install -r requirements.txt | ||
``` | ||
|
||
2. **Configure API keys** | ||
```env | ||
# .env file | ||
PERPLEXITY_API_KEY=your_perplexity_api_key_here | ||
GOOGLE_MAPS_API_KEY=your_google_maps_api_key_here | ||
``` | ||
|
||
3. **Run the application** | ||
```bash | ||
python3 main.py | ||
``` | ||
|
||
## Usage | ||
|
||
### Basic Local Discovery | ||
```python | ||
# Get nearby events, restaurants, and alerts | ||
api.geo_structured_output_with_citations( | ||
prompt=f"Find current events, restaurants, and local alerts near coordinates {lat}, {lng}", | ||
schema=LOCAL_INFO_SCHEMA | ||
) | ||
``` | ||
|
||
 | ||
|
||
### AI-Powered Search Suggestions | ||
```python | ||
# Generate contextual search suggestions | ||
api.get_search_suggestions( | ||
query="coffee", | ||
location="San Francisco, CA" | ||
) | ||
``` | ||
|
||
 | ||
|
||
### Personalized Location Insights | ||
```python | ||
# Get AI reasoning for specific locations | ||
api.get_location_insights( | ||
location_name="Blue Bottle Coffee", | ||
location_type="restaurant", | ||
description="Specialty coffee roaster", | ||
address="315 Linden St, Oakland, CA" | ||
) | ||
``` | ||
|
||
 | ||
|
||
## Code Explanation | ||
|
||
### Perplexity API Integration | ||
```python | ||
class PerplexityAPI: | ||
def __init__(self, api_key: Optional[str] = None): | ||
"""Initialize the Perplexity API client.""" | ||
self.api_key = api_key or os.environ.get("PERPLEXITY_API_KEY") | ||
if not self.api_key: | ||
raise ValueError("API key is required. Set PERPLEXITY_API_KEY environment variable or pass it directly.") | ||
self.base_url = "https://api.perplexity.ai/chat/completions" | ||
self.headers = {"Authorization": f"Bearer {self.api_key}"} | ||
|
||
def geo_structured_output_with_citations(self, | ||
prompt: str, | ||
schema: Dict[str, Any], | ||
model: str = "sonar") -> Dict: | ||
"""Get a structured JSON response with detailed citations.""" | ||
payload = { | ||
"model": model, | ||
"messages": [ | ||
{"role": "system", "content": | ||
""" | ||
You are an expert on current events and a real-time local discovery app for city exploration. | ||
|
||
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: | ||
|
||
1. Live local events (concerts, meetups, pop-ups happening now) | ||
2. Contextual business info (what's open, busy, or recommended nearby) | ||
3. Real-time alerts (weather, traffic, safety updates) | ||
4. Smart recommendations based on location and time | ||
|
||
Find current information near coordinates: | ||
|
||
1. EVENTS: Live events happening today/this week (concerts, festivals, sports, etc.) | ||
2. RESTAURANTS: Popular local restaurants and cafes currently open | ||
3. ALERTS: Any weather, traffic, or safety alerts for the area | ||
|
||
For each item: | ||
- Generate a unique ID (like "event_001", "restaurant_001", "alert_001") | ||
- Include specific addresses and approximate coordinates if possible | ||
- Include official website URLs when available | ||
- Provide citation information ONLY if it's from a different source than the official website | ||
- For every category, try to include at least 5 items | ||
|
||
Return as JSON with events, restaurants, and alerts arrays. | ||
|
||
IMPORTANT: For each item, include: | ||
- id: unique identifier | ||
- website: official website URL if available (leave empty if not available) | ||
- citation: object with url, title, and description ONLY if different from official website (leave empty if not available or same as website) | ||
""" | ||
}, | ||
{"role": "user", "content": prompt} | ||
], | ||
"response_format": { | ||
"type": "json_schema", | ||
"json_schema": {"schema": schema} | ||
}, | ||
"return_citations": True, | ||
"return_images": False | ||
} | ||
|
||
response = requests.post(self.base_url, headers=self.headers, json=payload).json() | ||
|
||
# Return both content and citations | ||
result = { | ||
"content": response["choices"][0]["message"]["content"], | ||
"citations": response.get("citations", []) | ||
} | ||
|
||
return result | ||
``` | ||
|
||
### JSON Schema for Structured Output | ||
```python | ||
LOCAL_INFO_SCHEMA = { | ||
"type": "object", | ||
"properties": { | ||
"events": { | ||
"type": "array", | ||
"items": { | ||
"type": "object", | ||
"properties": { | ||
"id": {"type": "string"}, | ||
"name": {"type": "string"}, | ||
"type": {"type": "string"}, | ||
"address": {"type": "string"}, | ||
"date": {"type": "string"}, | ||
"time": {"type": "string"}, | ||
"description": {"type": "string"}, | ||
"latitude": {"type": "number"}, | ||
"longitude": {"type": "number"}, | ||
"website": {"type": "string"}, | ||
"citation": { | ||
"type": "object", | ||
"properties": { | ||
"url": {"type": "string"}, | ||
"title": {"type": "string"}, | ||
"description": {"type": "string"} | ||
} | ||
} | ||
}, | ||
"required": ["id", "name", "type", "description"] | ||
} | ||
}, | ||
"restaurants": { | ||
"type": "array", | ||
"items": { | ||
"type": "object", | ||
"properties": { | ||
"id": {"type": "string"}, | ||
"name": {"type": "string"}, | ||
"address": {"type": "string"}, | ||
"cuisine": {"type": "string"}, | ||
"description": {"type": "string"}, | ||
"date": {"type": "string"}, | ||
"time": {"type": "string"}, | ||
"latitude": {"type": "number"}, | ||
"longitude": {"type": "number"}, | ||
"website": {"type": "string"}, | ||
"citation": { | ||
"type": "object", | ||
"properties": { | ||
"url": {"type": "string"}, | ||
"title": {"type": "string"}, | ||
"description": {"type": "string"} | ||
} | ||
} | ||
}, | ||
"required": ["id", "name", "description"] | ||
} | ||
}, | ||
"alerts": { | ||
"type": "array", | ||
"items": { | ||
"type": "object", | ||
"properties": { | ||
"id": {"type": "string"}, | ||
"title": {"type": "string"}, | ||
"description": {"type": "string"}, | ||
"severity": {"type": "string"}, | ||
"date": {"type": "string"}, | ||
"time": {"type": "string"}, | ||
"latitude": {"type": "number"}, | ||
"longitude": {"type": "number"}, | ||
"website": {"type": "string"}, | ||
"citation": { | ||
"type": "object", | ||
"properties": { | ||
"url": {"type": "string"}, | ||
"title": {"type": "string"}, | ||
"description": {"type": "string"} | ||
} | ||
} | ||
}, | ||
"required": ["id", "title", "description"] | ||
} | ||
} | ||
}, | ||
"required": ["events", "restaurants", "alerts"] | ||
} | ||
``` | ||
|
||
## Links | ||
|
||
- [GitHub Repository](https://github.com/anevsky/CityPulse) | ||
- [Live Demo](https://citypulse-ppx.uc.r.appspot.com/) | ||
- [Video Demo](https://youtu.be/Y0UIhh3diJg) | ||
- [Perplexity API Documentation](https://docs.perplexity.ai) | ||
- **[Built with ❤️ by Alex Nevsky](https://alexnevsky.com)** | ||
|
||
## Limitations | ||
|
||
- **API Rate Limits**: Perplexity API has usage limits depending on your plan | ||
- **Real-time Data Accuracy**: Information freshness depends on available sources | ||
- **Geographic Coverage**: Results quality varies by location and data availability | ||
- **Citation Reliability**: Always verify critical information from provided sources | ||
- **Mobile Performance**: Large datasets may impact performance on slower devices |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.