forever-sheikh commited on
Commit
6e2e86b
·
verified ·
1 Parent(s): 89ecf2c

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -218
app.py DELETED
@@ -1,218 +0,0 @@
1
- import gradio as gr
2
- import googlemaps
3
- import osmnx as ox
4
- import geopandas as gpd
5
- import pandas as pd
6
- import requests
7
- import zipfile
8
- import os
9
- import glob
10
- import shutil
11
- from shapely.geometry import Point, Polygon
12
-
13
- # ==========================================
14
- # AUTHENTICATION
15
- # ==========================================
16
- try:
17
- API_KEY = os.environ.get("GOOGLE_API_KEY")
18
- except:
19
- API_KEY = None
20
-
21
- # ==========================================
22
- # HELPER FUNCTIONS
23
- # ==========================================
24
- def load_geodata_to_polygon(file_obj):
25
- extract_path = "temp_extract"
26
- if os.path.exists(extract_path):
27
- shutil.rmtree(extract_path)
28
- os.makedirs(extract_path)
29
-
30
- target_kml = None
31
- try:
32
- # Check extension
33
- if file_obj.name.lower().endswith('.kmz'):
34
- with zipfile.ZipFile(file_obj.name, 'r') as zip_ref:
35
- zip_ref.extractall(extract_path)
36
- kml_files = glob.glob(extract_path + "/**/*.kml", recursive=True)
37
- if kml_files:
38
- target_kml = kml_files[0]
39
- elif file_obj.name.lower().endswith('.kml'):
40
- target_kml = file_obj.name
41
-
42
- if target_kml:
43
- return gpd.read_file(target_kml).union_all()
44
- except Exception as e:
45
- print(f"Error: {e}")
46
- return None
47
- return None
48
-
49
- def get_roof_area(lat, lng, api_key):
50
- base_url = "https://solar.googleapis.com/v1/buildingInsights:findClosest"
51
- params = {
52
- "location.latitude": lat,
53
- "location.longitude": lng,
54
- "requiredQuality": "HIGH",
55
- "key": api_key
56
- }
57
- try:
58
- resp = requests.get(base_url, params=params)
59
- data = resp.json()
60
- if 'error' in data: return None
61
- return data.get('solarPotential', {}).get('wholeRoofStats', {}).get('areaMeters2', None)
62
- except:
63
- return None
64
-
65
- def get_osm_physics(lat, lng):
66
- try:
67
- tags = {'building': True}
68
- gdf = ox.features.features_from_point((lat, lng), tags, dist=60)
69
- if not gdf.empty:
70
- gdf_proj = gdf.to_crs(epsg=3857)
71
- gdf_proj['area_m2'] = gdf_proj.geometry.area
72
- best = gdf_proj.sort_values(by='area_m2', ascending=False).iloc[0]
73
-
74
- floors = None
75
- if 'building:levels' in best and pd.notna(best['building:levels']):
76
- try: floors = int(float(str(best['building:levels']).split(';')[0]))
77
- except: pass
78
-
79
- height = None
80
- if 'height' in best and pd.notna(best['height']):
81
- try: height = float(str(best['height']).replace('m','').strip())
82
- except: pass
83
- return height, floors
84
- except:
85
- pass
86
- return None, None
87
-
88
- # DATA CONSTANTS
89
- BRAND_FLOORS = {
90
- "Macy's": 2, "JCPenney": 2, "Nordstrom": 2, "Sears": 2, "IKEA": 2,
91
- "Target": 1, "Walmart": 1, "Costco": 1, "Home Depot": 1, "Lowe's": 1,
92
- "Barnes & Noble": 1, "Dick's Sporting Goods": 1, "Kohl's": 1
93
- }
94
-
95
- BRAND_AVG_AREA = {
96
- "IKEA": 28000, "Walmart": 15000, "Costco": 14000, "Sam's Club": 13000,
97
- "Meijer": 18000, "Target": 12000, "Home Depot": 10000, "Lowe's": 10000,
98
- "Kroger": 6000, "Safeway": 5000, "Whole Foods": 4000, "Macy's": 16000,
99
- "JCPenney": 10000, "Sears": 12000, "Kohl's": 8000, "Dick's Sporting Goods": 4500,
100
- "T.J. Maxx": 2800, "Marshalls": 2800, "Ross Dress for Less": 2800,
101
- "Old Navy": 1400, "Barnes & Noble": 2500, "Best Buy": 3500, "Staples": 2000,
102
- "Office Depot": 2000, "PetSmart": 1800, "Petco": 1400, "Trader Joe's": 1200,
103
- "Aldi": 1500, "Lidl": 1500, "Ace Hardware": 800, "DSW Designer Shoe Warehouse": 2000
104
- }
105
-
106
- # THE FULL LIST (Exactly as you requested)
107
- SEARCH_LIST = [
108
- "Walmart", "Target", "Kmart", "Sears", "Kohl's", "Macy's", "JCPenney",
109
- "T.J. Maxx", "Marshalls", "HomeGoods", "HomeSense", "Ross Dress for Less", "Burlington",
110
- "Dick's Sporting Goods", "Albertsons", "Safeway", "Home Depot", "Lowe's",
111
- "Best Buy", "IKEA", "Bob's Discount Furniture", "Raymour & Flanigan",
112
- "Barnes & Noble", "Office Depot", "OfficeMax", "Staples",
113
- "PetSmart", "Petco", "Kroger", "Meijer", "Costco", "BJ's Wholesale Club",
114
- "Sam's Club", "Whole Foods", "ShopRite", "Stop & Shop", "Trader Joe's",
115
- "Lidl", "Aldi", "DSW Designer Shoe Warehouse", "Old Navy", "Ace Hardware"
116
- ]
117
-
118
- # ==========================================
119
- # MAIN LOGIC
120
- # ==========================================
121
- def process_data(file_obj, progress=gr.Progress()):
122
- if not API_KEY:
123
- raise gr.Error("API Key not found! Please set GOOGLE_API_KEY in Settings > Secrets.")
124
-
125
- if file_obj is None:
126
- raise gr.Error("Please upload a file.")
127
-
128
- progress(0, desc="Loading Polygon...")
129
- polygon = load_geodata_to_polygon(file_obj)
130
-
131
- if not polygon:
132
- raise gr.Error("Failed to read KML/KMZ file.")
133
-
134
- gmaps = googlemaps.Client(key=API_KEY)
135
- results = []
136
- seen_ids = set()
137
-
138
- total = len(SEARCH_LIST)
139
-
140
- for i, brand in enumerate(SEARCH_LIST):
141
- progress((i / total), desc=f"Scanning for {brand}...")
142
-
143
- try:
144
- places = gmaps.places_nearby(
145
- location=(polygon.centroid.y, polygon.centroid.x),
146
- radius=50000,
147
- keyword=brand
148
- )
149
-
150
- for p in places.get('results', []):
151
- pid = p.get('place_id')
152
- if pid in seen_ids: continue
153
-
154
- name = p.get('name')
155
- if any(x in name for x in ["ATM", "Redbox", "Kiosk", "Coinme", "Gas", "Fuel"]): continue
156
-
157
- lat = p['geometry']['location']['lat']
158
- lng = p['geometry']['location']['lng']
159
-
160
- if not polygon.contains(Point(lng, lat)): continue
161
- seen_ids.add(pid)
162
-
163
- # GET DATA
164
- roof_area = get_roof_area(lat, lng, API_KEY)
165
- height, floors = get_osm_physics(lat, lng)
166
-
167
- # APPLY LOGIC
168
- source_note = "SolarAPI"
169
- if roof_area is None:
170
- roof_area = BRAND_AVG_AREA.get(brand, 2500.0)
171
- source_note = "Brand_Avg (Missing)"
172
- else:
173
- if roof_area > 30000 and brand not in ["IKEA", "Costco", "Meijer", "Sam's Club", "Walmart"]:
174
- roof_area = BRAND_AVG_AREA.get(brand, 2500.0)
175
- source_note = "Brand_Avg (Mall detected)"
176
- elif roof_area < 500 and brand not in ["Ace Hardware", "Trader Joe's", "GameStop"]:
177
- roof_area = BRAND_AVG_AREA.get(brand, 2500.0)
178
- source_note = "Brand_Avg (Too Small detected)"
179
-
180
- if floors is None: floors = BRAND_FLOORS.get(brand, 1)
181
- if height is None: height = floors * 6.0
182
-
183
- results.append({
184
- 'Name': name, 'Brand': brand, 'Latitude': lat, 'Longitude': lng,
185
- 'Height_m': round(height, 2), 'Num_Floors': int(floors),
186
- 'Area_sqm': round(roof_area, 2), 'Data_Source': source_note
187
- })
188
- except:
189
- pass
190
-
191
- if not results:
192
- return "No stores found.", None
193
-
194
- # Export
195
- df = pd.DataFrame(results)
196
- bad_keywords = ['Mobile', 'Salon', 'Floral', 'Bakery', 'Pharmacy', 'Optical', 'Geek Squad', 'Photo']
197
- df = df[~df['Name'].str.contains('|'.join(bad_keywords), case=False, na=False)]
198
-
199
- output_path = "Building_Inventory.csv"
200
- df.to_csv(output_path, index=False)
201
-
202
- return f"Success! Found {len(df)} stores.", output_path
203
-
204
- # ==========================================
205
- # GRADIO INTERFACE
206
- # ==========================================
207
- iface = gr.Interface(
208
- fn=process_data,
209
- inputs=gr.File(label="Upload Polygon (.kmz or .kml)"),
210
- outputs=[
211
- gr.Textbox(label="Status"),
212
- gr.File(label="Download CSV")
213
- ],
214
- title="🏙️ Commercial Building Inventory Generator",
215
- description="Upload a KMZ file to scan for Big Box stores, calculate roof area, estimate height, and count floors."
216
- )
217
-
218
- iface.launch()