| import streamlit as st |
| import requests |
| from bs4 import BeautifulSoup |
| from geopy.geocoders import Nominatim |
| from urllib.parse import urljoin, urlparse |
| import re |
| import os |
| import pandas as pd |
| import folium |
| from streamlit_folium import folium_static |
|
|
| |
| DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_KEY") |
| API_ENDPOINT = "https://api.deepseek.com/v1/chat/completions" |
|
|
| |
| @st.cache_data |
| def scrape_location_data(query): |
| """Scrape location data from public sources""" |
| sources = { |
| "Niche": f"https://www.niche.com/places-to-live/search/{query}", |
| "AreaVibes": f"https://www.areavibes.com/search/?query={query}", |
| } |
| |
| results = [] |
| for source, url in sources.items(): |
| try: |
| response = requests.get(url, timeout=15) |
| soup = BeautifulSoup(response.text, 'html.parser') |
| |
| if source == "Niche": |
| listings = soup.find_all('div', class_='search-results__list__item') |
| for item in listings[:3]: |
| results.append({ |
| 'name': item.find('h2').text.strip(), |
| 'details': item.find('div', class_='search-result-tagline').text.strip(), |
| 'score': item.find('div', class_='search-result-grade').text.strip() |
| }) |
| |
| except Exception as e: |
| continue |
| |
| return results |
|
|
| def generate_recommendations(preferences): |
| """Generate neighborhood recommendations using Deepseek API""" |
| headers = { |
| "Authorization": f"Bearer {DEEPSEEK_API_KEY}", |
| "Content-Type": "application/json" |
| } |
| |
| prompt = f""" |
| Create a neighborhood recommendation report based on these preferences: |
| {preferences} |
| |
| Include these sections: |
| 1. Top 5 Neighborhood Matches |
| 2. Hidden Gem Recommendation |
| 3. Key Amenities Analysis |
| 4. Commute Times Overview |
| 5. Safety & Community Insights |
| |
| Format with markdown headers and bullet points. Keep sections concise. |
| """ |
| |
| try: |
| response = requests.post( |
| API_ENDPOINT, |
| json={ |
| "model": "deepseek-chat", |
| "messages": [{"role": "user", "content": prompt}], |
| "temperature": 0.7, |
| "max_tokens": 1500 |
| }, |
| headers=headers, |
| timeout=30 |
| ) |
| return response.json()["choices"][0]["message"]["content"] |
| except Exception as e: |
| st.error(f"API Error: {str(e)}") |
| return None |
|
|
| |
| st.set_page_config(layout="wide", page_icon="🏡") |
| st.title("Neighborhood Matchmaker") |
|
|
| with st.sidebar: |
| st.header("Search Preferences") |
| city = st.text_input("City/Region", "New York, NY") |
| budget = st.slider("Monthly Housing Budget ($)", 1000, 10000, 3000) |
| commute = st.selectbox("Max Commute Time", ["15 mins", "30 mins", "45 mins", "1 hour"]) |
| amenities = st.multiselect("Must-Have Amenities", [ |
| "Good Schools", "Parks", "Public Transport", |
| "Nightlife", "Shopping", "Healthcare" |
| ]) |
| lifestyle = st.selectbox("Lifestyle Preference", [ |
| "Family-Friendly", "Urban Professional", "Retirement", |
| "Student", "Remote Worker", "Outdoor Enthusiast" |
| ]) |
|
|
| if st.button("Find My Neighborhood"): |
| with st.spinner("Analyzing locations..."): |
| |
| preferences = { |
| "city": city, |
| "budget": f"${budget}/mo", |
| "max_commute": commute, |
| "amenities": amenities, |
| "lifestyle": lifestyle |
| } |
| |
| |
| location_data = scrape_location_data(city) |
| |
| |
| report = generate_recommendations(preferences) |
| |
| |
| if report: |
| st.subheader("Your Personalized Neighborhood Report") |
| st.markdown(report) |
| |
| |
| try: |
| geolocator = Nominatim(user_agent="neighborhood_finder") |
| location = geolocator.geocode(city) |
| m = folium.Map(location=[location.latitude, location.longitude], zoom_start=12) |
| folium_static(m, width=1200, height=500) |
| except Exception as e: |
| st.warning("Couldn't generate map visualization") |
|
|
| st.markdown("---") |
| st.caption("Note: Recommendations generated by AI. Verify with local experts.") |