celikn commited on
Commit
f94f352
·
verified ·
1 Parent(s): 1bc28b6

En yakın POI

Browse files
Files changed (1) hide show
  1. app.py +223 -1
app.py CHANGED
@@ -59,9 +59,206 @@ DEFAULT_TAGS = {
59
 
60
 
61
 
 
 
62
  # ==========================================
63
  # OSM / CBS FONKSİYONLARI
64
  # ==========================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  def get_neighborhood_gdf(city: str, district: str, neighborhood: str):
66
  """
67
  1) Önce önceden kaydedilmiş GeoJSON'dan arar (city + district + neighborhood).
@@ -1079,6 +1276,10 @@ with gr.Blocks() as demo:
1079
  )
1080
 
1081
  gen_and_run_btn = gr.Button("LLM ile Sorguyu Üret ve Çalıştır")
 
 
 
 
1082
 
1083
  # 2) Üretilen veya manuel Overpass sorgusu
1084
  overpass_box = gr.Textbox(
@@ -1089,7 +1290,28 @@ with gr.Blocks() as demo:
1089
 
1090
  run_overpass_btn = gr.Button("Sorguyu Çalıştır ve Haritayı Güncelle")
1091
 
1092
- # LLM ile üret + çalıştır
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1093
  # LLM ile üret + çalıştır (birikimli)
1094
  gen_and_run_btn.click(
1095
  fn=llm_overpass_to_map,
 
59
 
60
 
61
 
62
+
63
+
64
  # ==========================================
65
  # OSM / CBS FONKSİYONLARI
66
  # ==========================================
67
+
68
+ from shapely.geometry import Point
69
+ import math
70
+
71
+ def get_neighborhood_center(city, district, neighborhood):
72
+ """
73
+ Verilen şehir/ilçe/mahalle için poligonu alır ve merkez (centroid) koordinatını döndürür.
74
+ (lat, lon) şeklinde WGS84 (EPSG:4326) döner.
75
+ """
76
+ gdf = get_neighborhood_gdf(city, district, neighborhood)
77
+ if gdf is None or len(gdf) == 0:
78
+ return None
79
+
80
+ # Emin olmak için WGS84'e çevir
81
+ try:
82
+ gdf_ll = gdf.to_crs(epsg=4326)
83
+ except Exception:
84
+ gdf_ll = gdf # zaten 4326 ise
85
+
86
+ poly = gdf_ll.geometry.iloc[0]
87
+ c = poly.centroid
88
+ return c.y, c.x # (lat, lon)
89
+
90
+
91
+ def _build_nearest_poi_query(lat, lon, key, values, radius):
92
+ """
93
+ Overpass için: verilen key + values (örn: amenity=university, shop=supermarket)
94
+ etrafında en yakın POI'yi arayan sorguyu üretir.
95
+ """
96
+ if isinstance(values, str):
97
+ values = [values]
98
+
99
+ filters = []
100
+ for v in values:
101
+ filters.append(f' node["{key}"="{v}"](around:{radius},{lat},{lon});')
102
+ filters.append(f' way["{key}"="{v}"](around:{radius},{lat},{lon});')
103
+ filters.append(f' rel["{key}"="{v}"](around:{radius},{lat},{lon});')
104
+
105
+ filters_str = "\n".join(filters)
106
+
107
+ query = f"""
108
+ [out:json][timeout:25];
109
+ (
110
+ {filters_str}
111
+ );
112
+ out center 1;
113
+ """
114
+ return query
115
+
116
+
117
+ def _haversine_m(lat1, lon1, lat2, lon2):
118
+ """
119
+ İki nokta arasındaki yaklaşık mesafeyi (metre) hesaplar.
120
+ """
121
+ R = 6371000 # Dünya yarıçapı (m)
122
+ phi1 = math.radians(lat1)
123
+ phi2 = math.radians(lat2)
124
+ dphi = math.radians(lat2 - lat1)
125
+ dlambda = math.radians(lon2 - lon1)
126
+
127
+ a = math.sin(dphi/2)**2 + math.cos(phi1)*math.cos(phi2)*math.sin(dlambda/2)**2
128
+ c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
129
+ return R * c
130
+
131
+
132
+ def find_nearest_poi_overpass(city, district, neighborhood, key, values, radius=5000):
133
+ """
134
+ Mahalle merkezinden belirli bir yarıçap içinde (m cinsinden)
135
+ verilen OSM tag'ine göre (örn: amenity, shop) en yakın POI'yi arar.
136
+ Örnek:
137
+ key="amenity", values=["university", "college"]
138
+ key="shop", values=["supermarket", "convenience"]
139
+ Dönüş:
140
+ None -> bulunamadı
141
+ dict -> {"name", "lat", "lon", "tag_key", "tag_value", "distance_m", "distance_km"}
142
+ """
143
+ center = get_neighborhood_center(city, district, neighborhood)
144
+ if center is None:
145
+ return None
146
+
147
+ lat_c, lon_c = center
148
+
149
+ query = _build_nearest_poi_query(lat_c, lon_c, key, values, radius)
150
+
151
+ url = "https://overpass-api.de/api/interpreter"
152
+ try:
153
+ resp = requests.post(url, data={"data": query}, timeout=30)
154
+ resp.raise_for_status()
155
+ data = resp.json()
156
+ except Exception as e:
157
+ print("Overpass nearest POI isteği hatası:", e)
158
+ return None
159
+
160
+ elements = data.get("elements", [])
161
+ if not elements:
162
+ return None
163
+
164
+ # İlk element en yakın kabul ediliyor
165
+ e = elements[0]
166
+ tags = e.get("tags", {}) or {}
167
+ name = tags.get("name", "(isimsiz POI)")
168
+
169
+ # node ise lat/lon direk var; way/rel ise center altında
170
+ lat_p = e.get("lat") or (e.get("center") or {}).get("lat")
171
+ lon_p = e.get("lon") or (e.get("center") or {}).get("lon")
172
+
173
+ tag_value = None
174
+ if isinstance(values, list):
175
+ for v in values:
176
+ if tags.get(key) == v:
177
+ tag_value = v
178
+ break
179
+ if tag_value is None:
180
+ tag_value = tags.get(key)
181
+ else:
182
+ tag_value = tags.get(key)
183
+
184
+ dist_m = None
185
+ dist_km = None
186
+ if lat_p is not None and lon_p is not None:
187
+ dist_m = _haversine_m(lat_c, lon_c, lat_p, lon_p)
188
+ dist_km = dist_m / 1000.0
189
+
190
+ return {
191
+ "name": name,
192
+ "lat": lat_p,
193
+ "lon": lon_p,
194
+ "tag_key": key,
195
+ "tag_value": tag_value,
196
+ "distance_m": dist_m,
197
+ "distance_km": dist_km,
198
+ }
199
+
200
+
201
+ def answer_nearest_poi(city, district, neighborhood, key, values, human_label=None, radius=5000):
202
+ """
203
+ Kullanıcıya gösterilecek generic cevap metni.
204
+ human_label: 'üniversite', 'market', 'hastane' gibi daha okunaklı isim.
205
+ """
206
+ info = find_nearest_poi_overpass(city, district, neighborhood, key, values, radius=radius)
207
+ if info is None:
208
+ label = human_label or f"{key}={values}"
209
+ return f"{city} / {district} / {neighborhood} çevresinde belirli bir yarıçapta {label} bulunamadı."
210
+
211
+ name = info["name"]
212
+ lat = info["lat"]
213
+ lon = info["lon"]
214
+ dist_km = info["distance_km"]
215
+
216
+ label = human_label or info.get("tag_value") or f"{key}={values}"
217
+
218
+ if lat is not None and lon is not None and dist_km is not None:
219
+ return (
220
+ f"{city} / {district} / {neighborhood} mahallesi merkezine en yakın {label}: "
221
+ f"{name} (yaklaşık {dist_km:.2f} km, konum: {lat:.5f}, {lon:.5f})."
222
+ )
223
+ else:
224
+ return (
225
+ f"{city} / {district} / {neighborhood} mahallesi merkezine en yakın {label}: {name}."
226
+ )
227
+
228
+ def nearest_poi_wrapper(city, district, neighborhood, poi_type):
229
+ """
230
+ Gradio dropdown'dan seçilen poi_type'ı gerçek tag'lere çeviren yardımcı.
231
+ """
232
+ if poi_type == "Üniversite":
233
+ key = "amenity"
234
+ values = ["university", "college"]
235
+ label = "üniversite"
236
+ elif poi_type == "Market":
237
+ key = "shop"
238
+ values = ["supermarket", "convenience", "mall", "department_store"]
239
+ label = "market"
240
+ elif poi_type == "Hastane":
241
+ key = "amenity"
242
+ values = "hospital"
243
+ label = "hastane"
244
+ elif poi_type == "Eczane":
245
+ key = "amenity"
246
+ values = "pharmacy"
247
+ label = "eczane"
248
+ elif poi_type == "Park":
249
+ key = "leisure"
250
+ values = "park"
251
+ label = "park"
252
+ else:
253
+ # varsayılan: üniversite
254
+ key = "amenity"
255
+ values = ["university", "college"]
256
+ label = "üniversite"
257
+
258
+ return answer_nearest_poi(city, district, neighborhood, key, values, human_label=label)
259
+
260
+
261
+
262
  def get_neighborhood_gdf(city: str, district: str, neighborhood: str):
263
  """
264
  1) Önce önceden kaydedilmiş GeoJSON'dan arar (city + district + neighborhood).
 
1276
  )
1277
 
1278
  gen_and_run_btn = gr.Button("LLM ile Sorguyu Üret ve Çalıştır")
1279
+
1280
+
1281
+
1282
+
1283
 
1284
  # 2) Üretilen veya manuel Overpass sorgusu
1285
  overpass_box = gr.Textbox(
 
1290
 
1291
  run_overpass_btn = gr.Button("Sorguyu Çalıştır ve Haritayı Güncelle")
1292
 
1293
+ # En yakın POI (generic)
1294
+ poi_type_dropdown = gr.Dropdown(
1295
+ choices=["Üniversite", "Market", "Hastane", "Eczane", "Park"],
1296
+ value="Üniversite",
1297
+ label="En yakın neyi bulmak istiyorsun?"
1298
+ )
1299
+
1300
+ nearest_poi_btn = gr.Button("1. Mahalle için en yakın noktayı bul")
1301
+ nearest_poi_box = gr.Textbox(
1302
+ label="En Yakın POI",
1303
+ lines=2,
1304
+ )
1305
+
1306
+ nearest_poi_btn.click(
1307
+ fn=nearest_poi_wrapper,
1308
+ inputs=[city_in, district1_in, neigh1_in, poi_type_dropdown],
1309
+ outputs=[nearest_poi_box],
1310
+ )
1311
+
1312
+
1313
+
1314
+
1315
  # LLM ile üret + çalıştır (birikimli)
1316
  gen_and_run_btn.click(
1317
  fn=llm_overpass_to_map,