nniehaus commited on
Commit
4ab4a0c
·
verified ·
1 Parent(s): 0dbbd99

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -129
app.py CHANGED
@@ -5,114 +5,58 @@ from geopy.geocoders import Nominatim
5
  import os
6
  import folium
7
  from streamlit_folium import folium_static
8
- from jsonschema import validate, ValidationError
9
  from fake_useragent import UserAgent
10
 
11
  # Configure environment
12
  DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_KEY")
13
  API_ENDPOINT = "https://api.deepseek.com/v1/chat/completions"
14
 
15
- # JSON Schema for API response validation
16
- RESPONSE_SCHEMA = {
17
- "type": "object",
18
- "required": ["choices"],
19
- "properties": {
20
- "choices": {
21
- "type": "array",
22
- "minItems": 1,
23
- "items": {
24
- "type": "object",
25
- "required": ["message"],
26
- "properties": {
27
- "message": {
28
- "type": "object",
29
- "required": ["content"],
30
- "properties": {
31
- "content": {"type": "string"}
32
- }
33
- }
34
- }
35
- }
36
- }
37
- }
38
- }
39
 
40
  def get_scraping_headers():
41
- """Generate random browser headers"""
42
  ua = UserAgent()
43
  return {
44
  'User-Agent': ua.chrome,
45
  'Accept-Language': 'en-US,en;q=0.9',
46
- 'Referer': 'https://www.google.com/',
47
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
48
- 'DNT': '1'
49
  }
50
 
51
  @st.cache_data
52
  def scrape_location_data(query):
53
- """Scrape location data with advanced anti-bot measures"""
54
  session = requests.Session()
55
- results = []
56
-
57
  try:
58
- # First request to get through potential bot checks
59
- search_url = f"https://www.niche.com/places-to-live/search/{query}"
60
  response = session.get(
61
- search_url,
62
  headers=get_scraping_headers(),
63
- timeout=15,
64
- allow_redirects=True
65
  )
66
-
67
- # Detect bot protection
68
- if any(keyword in response.text.lower() for keyword in ['captcha', 'security check']):
69
- st.warning("""
70
- **Manual Verification Required:**
71
- 1. Visit [Niche.com](https://www.niche.com) directly
72
- 2. Complete any security checks
73
- 3. Return here and try again
74
- """)
75
- return []
76
-
77
- soup = BeautifulSoup(response.text, 'html.parser')
78
-
79
- # Resilient CSS selector patterns
80
- listings = soup.select('div[class*="search-results__list__item"]')
81
-
82
- for item in listings[:3]:
83
- result = {
84
- 'name': item.select_one('h2').get_text(strip=True) if item.select_one('h2') else 'N/A',
85
- 'details': item.select_one('div[class*="tagline"]').get_text(strip=True) if item.select_one('div[class*="tagline"]') else '',
86
- 'score': item.select_one('div[class*="grade"]').get_text(strip=True) if item.select_one('div[class*="grade"]")') else ''
87
- }
88
- results.append(result)
89
-
90
- return results
91
-
92
- except Exception as e:
93
- st.error(f"Data retrieval issue: {str(e)}")
94
  return []
95
 
96
- def generate_recommendations(preferences):
97
- """Generate recommendations with robust error handling"""
98
- if not DEEPSEEK_API_KEY:
99
- st.error("Missing API key configuration")
100
- return None
101
-
102
  headers = {
103
  "Authorization": f"Bearer {DEEPSEEK_API_KEY}",
104
  "Content-Type": "application/json"
105
  }
106
 
107
- prompt = f"""
108
- Analyze these neighborhood preferences: {preferences}
 
 
 
 
 
109
  Create a detailed report with:
110
- - Top 3 matches
111
- - 1 hidden gem
112
- - Amenity analysis
113
- - Safety insights
114
- - Price comparisons
115
- Format with markdown sections
116
  """
117
 
118
  try:
@@ -120,75 +64,82 @@ def generate_recommendations(preferences):
120
  API_ENDPOINT,
121
  json={
122
  "model": "deepseek-chat",
123
- "messages": [{"role": "user", "content": prompt}],
124
  "temperature": 0.7,
125
  "max_tokens": 1500
126
  },
127
  headers=headers,
128
  timeout=30
129
  )
130
-
131
- if response.status_code != 200:
132
- error_msg = response.json().get('error', {}).get('message', 'Unknown API error')
133
- st.error(f"API Error {response.status_code}: {error_msg}")
134
- return None
135
-
136
- response_data = response.json()
137
- validate(instance=response_data, schema=RESPONSE_SCHEMA)
138
-
139
- return response_data["choices"][0]["message"]["content"]
140
-
141
- except ValidationError as ve:
142
- st.error(f"Invalid API response: {str(ve)}")
143
- return None
144
- except Exception as e:
145
- st.error(f"Connection Error: {str(e)}")
146
  return None
147
 
148
  # Streamlit UI
149
  st.set_page_config(layout="wide", page_icon="🏡")
150
- st.title("Neighborhood Matchmaker Pro")
 
 
 
 
 
 
 
 
151
 
152
  with st.sidebar:
153
- st.header("Search Preferences")
 
 
 
 
 
 
 
 
154
  city = st.text_input("City/Region", "New York, NY")
155
- budget = st.slider("Monthly Budget ($)", 1000, 10000, 3000)
156
- commute = st.selectbox("Max Commute", ["15 mins", "30 mins", "45 mins"])
157
- lifestyle = st.selectbox("Lifestyle", ["Family", "Urban", "Remote"])
 
 
 
 
 
158
 
159
- if st.button("Find Neighborhoods"):
160
- with st.spinner("Analyzing locations..."):
 
161
  preferences = {
162
- "city": city,
163
- "budget": budget,
164
- "commute": commute,
165
- "lifestyle": lifestyle
166
  }
167
 
168
- location_data = scrape_location_data(city)
169
-
170
- if not location_data:
171
- st.info("Using alternative data sources...")
172
- # Implement fallback scraping here
173
-
174
- report = generate_recommendations(preferences)
175
 
176
  if report:
177
- st.subheader("Custom Neighborhood Report")
178
  st.markdown(report)
179
 
180
- try:
181
- geolocator = Nominatim(user_agent="geo_app_v2")
182
- location = geolocator.geocode(city)
183
- if location:
184
- m = folium.Map(
185
- location=[location.latitude, location.longitude],
186
- zoom_start=12,
187
- tiles="CartoDB positron"
188
- )
189
- folium_static(m, width=1000, height=500)
190
- except Exception as e:
191
- st.warning(f"Map error: {str(e)}")
 
 
192
 
193
- st.markdown("---")
194
- st.caption("Note: Results may vary based on data availability")
 
 
 
 
 
5
  import os
6
  import folium
7
  from streamlit_folium import folium_static
 
8
  from fake_useragent import UserAgent
9
 
10
  # Configure environment
11
  DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_KEY")
12
  API_ENDPOINT = "https://api.deepseek.com/v1/chat/completions"
13
 
14
+ # Customizable branding
15
+ PROMOTION_LINK = "www.myeverydayai.com"
16
+ BRANDING_TEXT = "Powered by [Everyday AI Solutions](https://www.myeverydayai.com)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  def get_scraping_headers():
 
19
  ua = UserAgent()
20
  return {
21
  'User-Agent': ua.chrome,
22
  'Accept-Language': 'en-US,en;q=0.9',
23
+ 'Referer': 'https://www.google.com/'
 
 
24
  }
25
 
26
  @st.cache_data
27
  def scrape_location_data(query):
 
28
  session = requests.Session()
 
 
29
  try:
 
 
30
  response = session.get(
31
+ f"https://www.niche.com/places-to-live/search/{query}",
32
  headers=get_scraping_headers(),
33
+ timeout=15
 
34
  )
35
+ # Add scraping logic here
36
+ return ["Sample Neighborhood 1", "Sample Neighborhood 2"]
37
+ except Exception:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  return []
39
 
40
+ def generate_recommendations(preferences, custom_factors):
 
 
 
 
 
41
  headers = {
42
  "Authorization": f"Bearer {DEEPSEEK_API_KEY}",
43
  "Content-Type": "application/json"
44
  }
45
 
46
+ base_prompt = f"""
47
+ Analyze these neighborhood preferences:
48
+ {preferences}
49
+
50
+ Additional Custom Factors:
51
+ {custom_factors}
52
+
53
  Create a detailed report with:
54
+ - Top 3 neighborhood matches
55
+ - Unique benefits for each
56
+ - Comparison of custom factors
57
+ - Final recommendation
58
+
59
+ End with: "Want your own AI tool? Visit {PROMOTION_LINK}"
60
  """
61
 
62
  try:
 
64
  API_ENDPOINT,
65
  json={
66
  "model": "deepseek-chat",
67
+ "messages": [{"role": "user", "content": base_prompt}],
68
  "temperature": 0.7,
69
  "max_tokens": 1500
70
  },
71
  headers=headers,
72
  timeout=30
73
  )
74
+ return response.json()["choices"][0]["message"]["content"]
75
+ except Exception:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  return None
77
 
78
  # Streamlit UI
79
  st.set_page_config(layout="wide", page_icon="🏡")
80
+
81
+ # Branding Header
82
+ st.markdown(f"""
83
+ <div style="background:#f0f2f6;padding:10px;border-radius:5px;margin-bottom:20px">
84
+ <h3 style="color:#1e88e5;text-align:center;">{BRANDING_TEXT}</h3>
85
+ </div>
86
+ """, unsafe_allow_html=True)
87
+
88
+ st.title("🏡 Smart Neighborhood Finder")
89
 
90
  with st.sidebar:
91
+ st.header("Realtor Instructions")
92
+ st.markdown(f"""
93
+ Add this tool to your website for free!
94
+ [Get your customized version](https://{PROMOTION_LINK})
95
+ """)
96
+ st.markdown("---")
97
+ st.header("Client Preferences")
98
+
99
+ # Core inputs
100
  city = st.text_input("City/Region", "New York, NY")
101
+ budget = st.slider("Price Range ($)", 1000, 5000, (2000, 4000))
102
+ home_type = st.selectbox("Home Type", ["House", "Apartment", "Condominium"])
103
+
104
+ # Custom factors
105
+ custom_factors = st.text_area(
106
+ "Add Your Special Requirements",
107
+ placeholder="e.g., Near dog parks, Vegan restaurants, Yoga studios"
108
+ )
109
 
110
+ # Generate report
111
+ if st.button("Find My Perfect Neighborhood"):
112
+ with st.spinner("Creating your custom report..."):
113
  preferences = {
114
+ "City": city,
115
+ "Budget": f"${budget[0]} - ${budget[1]}",
116
+ "Home Type": home_type
 
117
  }
118
 
119
+ report = generate_recommendations(preferences, custom_factors)
 
 
 
 
 
 
120
 
121
  if report:
122
+ st.subheader("Your Personalized Neighborhood Report")
123
  st.markdown(report)
124
 
125
+ # Promotional footer
126
+ st.markdown(f"""
127
+ ---
128
+ <div style="text-align:center;margin-top:40px">
129
+ <h4>Want this AI tool on your website?</h4>
130
+ <a href="https://{PROMOTION_LINK}">
131
+ <button style="background:#1e88e5;color:white;padding:10px 20px;border:none;border-radius:5px">
132
+ Get Your Free Version
133
+ </button>
134
+ </a>
135
+ </div>
136
+ """, unsafe_allow_html=True)
137
+ else:
138
+ st.error("Error generating report. Please try again.")
139
 
140
+ # Always show branding footer
141
+ st.markdown(f"""
142
+ <div style="text-align:center;margin-top:50px;padding:20px;background:#f8f9fa">
143
+ {BRANDING_TEXT} - Provide AI-powered tools to your clients
144
+ </div>
145
+ """, unsafe_allow_html=True)