mtoft20 commited on
Commit
67ff9f3
·
verified ·
1 Parent(s): 883b00b

Delete app_deploy.py

Browse files
Files changed (1) hide show
  1. app_deploy.py +0 -448
app_deploy.py DELETED
@@ -1,448 +0,0 @@
1
- import streamlit as st
2
- import requests
3
- import pandas as pd
4
- from together import Together
5
- import os
6
-
7
- # =============================================================================
8
- # CONFIGURATION - Using Secrets Management
9
- # =============================================================================
10
- NOCODB_URL = "https://app.nocodb.com" # Base URL
11
-
12
- # Get sensitive data from Streamlit secrets or environment variables
13
- def get_api_credentials():
14
- """Get API credentials from secrets or environment"""
15
- try:
16
- # Try Streamlit secrets first (for Hugging Face Spaces)
17
- api_token = st.secrets.get("NOCODB_API_TOKEN", os.environ.get("NOCODB_API_TOKEN", ""))
18
- together_key = st.secrets.get("TOGETHER_API_KEY", os.environ.get("TOGETHER_API_KEY", ""))
19
- endpoint_path = st.secrets.get("NOCODB_ENDPOINT_PATH", os.environ.get("NOCODB_ENDPOINT_PATH", ""))
20
-
21
- return api_token, together_key, endpoint_path
22
- except:
23
- # Fallback to environment variables
24
- api_token = os.environ.get("NOCODB_API_TOKEN", "")
25
- together_key = os.environ.get("TOGETHER_API_KEY", "")
26
- endpoint_path = os.environ.get("NOCODB_ENDPOINT_PATH", "")
27
-
28
- return api_token, together_key, endpoint_path
29
-
30
- # Initialize Together AI client
31
- @st.cache_resource
32
- def get_ai_client():
33
- """Initialize Together AI client"""
34
- _, together_key, _ = get_api_credentials()
35
- if not together_key:
36
- st.error("Together AI API key not found. Please configure it in the secrets.")
37
- return None
38
- return Together(api_key=together_key)
39
-
40
- # =============================================================================
41
- # HELPER FUNCTIONS
42
- # =============================================================================
43
- def safe_int(value, default=0):
44
- """Safely convert value to integer"""
45
- try:
46
- return int(float(value)) if value else default
47
- except (ValueError, TypeError):
48
- return default
49
-
50
- def safe_float(value, default=0.0):
51
- """Safely convert value to float"""
52
- try:
53
- return float(value) if value else default
54
- except (ValueError, TypeError):
55
- return default
56
-
57
- @st.cache_data(ttl=300) # Cache for 5 minutes
58
- def get_properties():
59
- """Fetch properties from NocoDB"""
60
- api_token, _, endpoint_path = get_api_credentials()
61
-
62
- if not api_token or not endpoint_path:
63
- st.error("NocoDB credentials not configured. Please set up your secrets.")
64
- return []
65
-
66
- headers = {"xc-token": api_token}
67
-
68
- try:
69
- response = requests.get(
70
- f"{NOCODB_URL}{endpoint_path}?limit=1000", # Get more records
71
- headers=headers
72
- )
73
-
74
- if response.status_code == 200:
75
- data = response.json()
76
- return data.get('list', [])
77
- else:
78
- st.error(f"Failed to fetch data: {response.status_code}")
79
- return []
80
-
81
- except Exception as e:
82
- st.error(f"Error connecting to database: {e}")
83
- return []
84
-
85
- def filter_properties(properties, filters):
86
- """Apply filters to properties list"""
87
- filtered = []
88
-
89
- for prop in properties:
90
- # Price filter
91
- price = safe_int(prop.get('cash_price'))
92
- if price > filters['max_price']:
93
- continue
94
-
95
- # Rooms filter
96
- rooms = safe_int(prop.get('rooms'))
97
- if rooms < filters['min_rooms']:
98
- continue
99
-
100
- # Energy rating filter
101
- if filters['energy_ratings'] and prop.get('energy_rating') not in filters['energy_ratings']:
102
- continue
103
-
104
- # City filter
105
- if filters['cities'] and prop.get('city') not in filters['cities']:
106
- continue
107
-
108
- filtered.append(prop)
109
-
110
- return filtered
111
-
112
- def create_property_context(properties):
113
- """Create context string about current properties for AI"""
114
- if not properties:
115
- return "No properties match the current filters."
116
-
117
- total = len(properties)
118
- prices = [safe_int(p.get('cash_price')) for p in properties if safe_int(p.get('cash_price')) > 0]
119
-
120
- if prices:
121
- avg_price = sum(prices) / len(prices)
122
- min_price = min(prices)
123
- max_price = max(prices)
124
-
125
- context = f"""Currently showing {total} Danish villas.
126
- Price range: {min_price:,} - {max_price:,} DKK.
127
- Average price: {avg_price:,.0f} DKK. """
128
- else:
129
- context = f"Currently showing {total} Danish villas. "
130
-
131
- # Add some location info
132
- cities = list(set([p.get('city', 'Unknown') for p in properties[:10]]))
133
- if cities:
134
- context += f"Cities include: {', '.join(cities[:5])}. "
135
-
136
- return context
137
-
138
- def get_ai_response(client, question, context, model_name):
139
- """Get response from Together AI"""
140
- try:
141
- # Create a comprehensive prompt
142
- prompt = f"""You are a helpful Danish real estate assistant. Based on the current property data, please answer the user's question accurately and helpfully.
143
-
144
- Current Property Data Context:
145
- {context}
146
-
147
- User Question: {question}
148
-
149
- Please provide a helpful, accurate response based on the data provided. Keep your answer concise but informative."""
150
-
151
- response = client.chat.completions.create(
152
- model=model_name,
153
- messages=[
154
- {"role": "system", "content": "You are a helpful Danish real estate assistant with expertise in property analysis and market insights."},
155
- {"role": "user", "content": prompt}
156
- ],
157
- max_tokens=300,
158
- temperature=0.7,
159
- )
160
-
161
- return response.choices[0].message.content
162
-
163
- except Exception as e:
164
- raise Exception(f"Together AI Error: {str(e)}")
165
-
166
- def test_together_models():
167
- """Test different Together AI models"""
168
- # Include both Gemma and other reliable serverless models
169
- models_to_test = [
170
- # Gemma models (Google's lightweight models)
171
- "google/gemma-2b-it",
172
- "google/gemma-2-27b-it",
173
- # Other reliable models
174
- "mistralai/Mistral-7B-Instruct-v0.1",
175
- "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
176
- "mistralai/Mixtral-8x7B-Instruct-v0.1"
177
- ]
178
-
179
- results = {}
180
- client = get_ai_client()
181
-
182
- if not client:
183
- return {"error": "Could not initialize AI client"}
184
-
185
- for model_name in models_to_test:
186
- try:
187
- test_response = client.chat.completions.create(
188
- model=model_name,
189
- messages=[
190
- {"role": "system", "content": "You are a helpful assistant."},
191
- {"role": "user", "content": "Hello, can you help me analyze real estate data?"}
192
- ],
193
- max_tokens=50,
194
- temperature=0.7,
195
- )
196
-
197
- results[model_name] = {
198
- "status": "✅ Success",
199
- "response": test_response.choices[0].message.content[:100]
200
- }
201
-
202
- except Exception as e:
203
- results[model_name] = {"status": "❌ Error", "response": str(e)[:100]}
204
-
205
- return results
206
-
207
- # =============================================================================
208
- # MAIN APP
209
- # =============================================================================
210
- def main():
211
- # Page config
212
- st.set_page_config(
213
- page_title="Danish Villa Assistant",
214
- page_icon="🏡",
215
- layout="wide"
216
- )
217
-
218
- # Header
219
- st.title("🏡 Danish Villa Assistant")
220
- st.write("Explore Danish villas with AI-powered insights using Together AI!")
221
-
222
- # Check API credentials
223
- api_token, together_key, endpoint_path = get_api_credentials()
224
-
225
- if not together_key:
226
- st.error("⚠️ Together AI API key not configured!")
227
- st.info("Please set your TOGETHER_API_KEY in the Hugging Face Spaces secrets.")
228
- st.stop()
229
-
230
- if not api_token or not endpoint_path:
231
- st.error("⚠️ NocoDB credentials not configured!")
232
- st.info("Please set NOCODB_API_TOKEN and NOCODB_ENDPOINT_PATH in the Hugging Face Spaces secrets.")
233
- st.stop()
234
-
235
- # Add model testing section
236
- with st.expander("🧪 Test Together AI Models (for debugging)"):
237
- if st.button("Test Different Models"):
238
- with st.spinner("Testing models..."):
239
- test_results = test_together_models()
240
- for model, result in test_results.items():
241
- st.write(f"**{model}:** {result['status']}")
242
- if result['status'] == "✅ Success":
243
- st.success(f"Response preview: {result['response']}")
244
- else:
245
- st.error(f"Error: {result['response']}")
246
-
247
- # Initialize AI client
248
- try:
249
- client = get_ai_client()
250
- if not client:
251
- st.stop()
252
- except Exception as e:
253
- st.error(f"Failed to initialize Together AI client: {e}")
254
- st.stop()
255
-
256
- # Sidebar filters
257
- st.sidebar.header("🔍 Filter Properties")
258
-
259
- # Get all properties first to populate filter options
260
- with st.spinner("Loading properties..."):
261
- all_properties = get_properties()
262
-
263
- if not all_properties:
264
- st.error("Could not load properties. Please check your NocoDB connection.")
265
- st.stop()
266
-
267
- # Extract unique values for filters
268
- all_cities = sorted(list(set([p.get('city', 'Unknown') for p in all_properties if p.get('city')])))
269
- all_energy_ratings = sorted(list(set([p.get('energy_rating') for p in all_properties if p.get('energy_rating')])))
270
-
271
- # Sidebar filter controls
272
- max_price = st.sidebar.slider(
273
- "Maximum Price (DKK)",
274
- min_value=0,
275
- max_value=20000000,
276
- value=10000000,
277
- step=500000,
278
- format="%d"
279
- )
280
-
281
- min_rooms = st.sidebar.slider(
282
- "Minimum Rooms",
283
- min_value=1,
284
- max_value=15,
285
- value=3
286
- )
287
-
288
- selected_cities = st.sidebar.multiselect(
289
- "Cities",
290
- options=all_cities,
291
- default=[]
292
- )
293
-
294
- selected_energy_ratings = st.sidebar.multiselect(
295
- "Energy Ratings",
296
- options=all_energy_ratings,
297
- default=[]
298
- )
299
-
300
- # Create filter dictionary
301
- filters = {
302
- 'max_price': max_price,
303
- 'min_rooms': min_rooms,
304
- 'cities': selected_cities,
305
- 'energy_ratings': selected_energy_ratings
306
- }
307
-
308
- # Apply filters
309
- filtered_properties = filter_properties(all_properties, filters)
310
-
311
- # Main content area
312
- col1, col2 = st.columns([2, 1])
313
-
314
- with col1:
315
- # Property listings
316
- st.subheader(f"📋 Found {len(filtered_properties)} Properties")
317
-
318
- if filtered_properties:
319
- # Show first 10 properties
320
- for i, prop in enumerate(filtered_properties[:10]):
321
- with st.expander(
322
- f"{prop.get('address', 'N/A')} - {safe_int(prop.get('cash_price')):,} DKK"
323
- ):
324
- # Property details in columns
325
- detail_col1, detail_col2, detail_col3 = st.columns(3)
326
-
327
- with detail_col1:
328
- st.write(f"**🏙️ City:** {prop.get('city', 'N/A')}")
329
- st.write(f"**🚪 Rooms:** {prop.get('rooms', 'N/A')}")
330
- st.write(f"**📐 Living Area:** {prop.get('living_area', 'N/A')} m²")
331
-
332
- with detail_col2:
333
- st.write(f"**⚡ Energy Rating:** {prop.get('energy_rating', 'N/A')}")
334
- st.write(f"**📅 Year Built:** {prop.get('year_built', 'N/A')}")
335
- st.write(f"**🏛️ Municipality:** {prop.get('municipal', 'N/A')}")
336
-
337
- with detail_col3:
338
- price_per_sqm = safe_int(prop.get('square_meter_price'))
339
- st.write(f"**💰 Price/m²:** {price_per_sqm:,} DKK" if price_per_sqm else "**💰 Price/m²:** N/A")
340
-
341
- plot_area = safe_int(prop.get('area'))
342
- st.write(f"**🌿 Plot Area:** {plot_area:,} m²" if plot_area else "**🌿 Plot Area:** N/A")
343
-
344
- st.write(f"**🏠 Type:** {prop.get('legal_type', 'N/A')}")
345
-
346
- if len(filtered_properties) > 10:
347
- st.info(f"Showing first 10 of {len(filtered_properties)} properties. Adjust filters to narrow results.")
348
- else:
349
- st.info("No properties match your current filters. Try adjusting the criteria.")
350
-
351
- with col2:
352
- # AI Chat Section
353
- st.subheader("🤖 Ask AI Assistant")
354
- st.write("Ask questions about the Danish villa market!")
355
-
356
- # Model selection for Together AI
357
- model_choice = st.selectbox(
358
- "Select AI Model:",
359
- [
360
- # Gemma models (Google's efficient models)
361
- "google/gemma-2b-it",
362
- "google/gemma-2-27b-it",
363
- # Other reliable models
364
- "mistralai/Mistral-7B-Instruct-v0.1",
365
- "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
366
- "mistralai/Mixtral-8x7B-Instruct-v0.1"
367
- ],
368
- help="Gemma models are Google's efficient, lightweight models."
369
- )
370
-
371
- # Example questions
372
- with st.expander("💡 Example Questions"):
373
- st.write("• What's the average price range?")
374
- st.write("• Tell me about energy ratings in the data")
375
- st.write("• Which areas have the most expensive properties?")
376
- st.write("• How many properties are available in each city?")
377
- st.write("• What's the price per square meter trend?")
378
-
379
- user_question = st.text_area(
380
- "Your Question:",
381
- placeholder="Ask about prices, locations, energy ratings, market trends...",
382
- height=100
383
- )
384
-
385
- if st.button("🔍 Ask AI", type="primary"):
386
- if user_question:
387
- with st.spinner("AI is analyzing the data..."):
388
- # Create context from current filtered data
389
- context = create_property_context(filtered_properties)
390
-
391
- try:
392
- # Get AI response
393
- ai_response = get_ai_response(client, user_question, context, model_choice)
394
-
395
- st.success("**AI Assistant Response:**")
396
- st.write(ai_response)
397
-
398
- # Show debug info
399
- with st.expander("Debug Info"):
400
- st.write(f"Model used: {model_choice}")
401
- st.write(f"Properties analyzed: {len(filtered_properties)}")
402
- st.write(f"Context: {context[:150]}...")
403
-
404
- except Exception as e:
405
- st.error(f"AI Error: {str(e)}")
406
-
407
- # Fallback response with data analysis
408
- st.info("**Fallback Analysis:**")
409
- if filtered_properties:
410
- avg_price = sum(safe_int(p.get('cash_price')) for p in filtered_properties) / len(filtered_properties)
411
- st.write(f"• Found {len(filtered_properties)} properties")
412
- st.write(f"• Average price: {avg_price:,.0f} DKK")
413
-
414
- cities = list(set(p.get('city') for p in filtered_properties if p.get('city')))
415
- if cities:
416
- st.write(f"• Cities: {', '.join(cities[:3])}")
417
-
418
- energy_ratings = list(set(p.get('energy_rating') for p in filtered_properties if p.get('energy_rating')))
419
- if energy_ratings:
420
- st.write(f"• Energy ratings: {', '.join(energy_ratings[:3])}")
421
- else:
422
- st.warning("Please enter a question first!")
423
-
424
- # Footer stats
425
- st.markdown("---")
426
- if all_properties:
427
- total_props = len(all_properties)
428
- filtered_props = len(filtered_properties)
429
-
430
- stat_col1, stat_col2, stat_col3, stat_col4 = st.columns(4)
431
-
432
- with stat_col1:
433
- st.metric("Total Properties", total_props)
434
-
435
- with stat_col2:
436
- st.metric("Filtered Results", filtered_props)
437
-
438
- with stat_col3:
439
- if filtered_properties:
440
- avg_price = sum(safe_int(p.get('cash_price')) for p in filtered_properties) / len(filtered_properties)
441
- st.metric("Avg Price", f"{avg_price:,.0f} DKK")
442
-
443
- with stat_col4:
444
- unique_cities = len(set(p.get('city') for p in filtered_properties if p.get('city')))
445
- st.metric("Cities", unique_cities)
446
-
447
- if __name__ == "__main__":
448
- main()