celikn commited on
Commit
6ddb6b0
·
1 Parent(s): 80aa80b

modified slider

Browse files
Files changed (2) hide show
  1. app.py +37 -391
  2. app_bk2.py +435 -0
app.py CHANGED
@@ -1,353 +1,45 @@
1
  import os
2
  import gradio as gr
3
- import geopandas as gpd
4
- import folium
5
-
6
- # osmnx isteğe bağlı (fallback için)
7
- try:
8
- import osmnx as ox
9
- except ImportError:
10
- ox = None
11
-
12
  from huggingface_hub import InferenceClient, login
13
 
14
- # ================
15
- # HF TOKEN & MODEL
16
- # ================
17
  HF_TOKEN = (os.environ.get("HUGGINGFACE_HUB_TOKEN", "") or "").strip()
 
18
  if HF_TOKEN:
 
19
  login(token=HF_TOKEN)
20
  else:
21
- print("UYARI: HUGGINGFACE_HUB_TOKEN bulunamadı, kamuya açık modellerle sınırlı olabilirsiniz.")
 
22
 
 
23
  client = InferenceClient(
24
  model="openai/gpt-oss-20b",
25
- token=HF_TOKEN if HF_TOKEN else None,
26
  )
27
 
28
- # =========================
29
- # ÖNCEDEN HAZIRLANMIŞ OSM VERİSİ
30
- # =========================
31
- NEIGH_PATH = "data/neighborhoods.geojson"
32
- POIS_PATH = "data/pois.geojson"
33
-
34
- if not (os.path.exists(NEIGH_PATH) and os.path.exists(POIS_PATH)):
35
- print("UYARI: data/ klasöründe neighborhoods.geojson / pois.geojson bulunamadı!")
36
- neighborhoods_gdf = None
37
- pois_gdf = None
38
- else:
39
- neighborhoods_gdf = gpd.read_file(NEIGH_PATH)
40
- pois_gdf = gpd.read_file(POIS_PATH)
41
- print(f"{len(neighborhoods_gdf)} mahalle/semt, {len(pois_gdf)} POI yüklendi.")
42
-
43
-
44
- DEFAULT_TAGS = {
45
- "amenity": ["school", "pharmacy", "hospital", "restaurant", "cafe", "bank"],
46
- "leisure": ["park", "playground"],
47
- "shop": True,
48
- }
49
-
50
-
51
- # =========================
52
- # OSM / CBS FONKSİYONLARI
53
- # =========================
54
- def get_neighborhood_gdf(city: str, neighborhood: str):
55
- if neighborhoods_gdf is not None:
56
- mask = (
57
- (neighborhoods_gdf["city"] == city)
58
- & (neighborhoods_gdf["neighborhood"] == neighborhood)
59
- )
60
- gdf_local = neighborhoods_gdf[mask]
61
- if gdf_local is not None and len(gdf_local) > 0:
62
- return gdf_local
63
-
64
- if ox is None:
65
- print("OSM fallback kullanılamıyor: osmnx yüklü değil.")
66
- return None
67
-
68
- query = f"{neighborhood}, {city}, Türkiye"
69
- print(f"OSM fallback: {query}")
70
- try:
71
- gdf_osm = ox.geocode_to_gdf(query)
72
- except Exception as e:
73
- print("Mahalle geocode hatası (OSM fallback):", e)
74
- return None
75
-
76
- if gdf_osm is None or len(gdf_osm) == 0:
77
- return None
78
-
79
- gdf_osm = gdf_osm.copy()
80
- gdf_osm["city"] = city
81
- gdf_osm["neighborhood"] = neighborhood
82
- return gdf_osm
83
-
84
-
85
- def get_pois_within(gdf, tags=None):
86
- if gdf is None:
87
- return None
88
-
89
- if tags is None:
90
- tags = DEFAULT_TAGS
91
-
92
- if pois_gdf is not None and "city" in gdf.columns and "neighborhood" in gdf.columns:
93
- row = gdf.iloc[0]
94
- city = row["city"]
95
- neighborhood = row["neighborhood"]
96
-
97
- mask = (
98
- (pois_gdf["city"] == city)
99
- & (pois_gdf["neighborhood"] == neighborhood)
100
- )
101
- pois_local = pois_gdf[mask]
102
-
103
- if pois_local is not None and len(pois_local) > 0:
104
- return pois_local
105
-
106
- if ox is None:
107
- print("OSM POI fallback kullanılamıyor: osmnx yüklü değil.")
108
- return None
109
-
110
- try:
111
- polygon = gdf.geometry.iloc[0]
112
- pois_osm = ox.features_from_polygon(polygon, tags)
113
- return pois_osm
114
- except Exception as e:
115
- print("POI hatası (OSM fallback):", e)
116
- return None
117
-
118
-
119
- def summarize_pois(gdf, pois):
120
- summary = {}
121
-
122
- try:
123
- area_m2 = gdf.to_crs(epsg=3857).geometry.iloc[0].area
124
- summary["alan_m2"] = float(area_m2)
125
- summary["alan_km2"] = float(area_m2 / 1_000_000)
126
- except Exception as e:
127
- print("Alan hesaplama hatası:", e)
128
- summary["alan_m2"] = None
129
- summary["alan_km2"] = None
130
-
131
- if pois is None or len(pois) == 0:
132
- summary["toplam_poi"] = 0
133
- return summary
134
-
135
- summary["toplam_poi"] = int(len(pois))
136
-
137
- if "amenity" in pois.columns:
138
- for k, v in pois["amenity"].value_counts().to_dict().items():
139
- summary[f"amenity_{k}"] = int(v)
140
-
141
- if "leisure" in pois.columns:
142
- for k, v in pois["leisure"].value_counts().to_dict().items():
143
- summary[f"leisure_{k}"] = int(v)
144
-
145
- if "shop" in pois.columns:
146
- for k, v in pois["shop"].value_counts().to_dict().items():
147
- summary[f"shop_{k}"] = int(v)
148
-
149
- return summary
150
-
151
-
152
- def build_stats_text(summary: dict) -> str:
153
- if not summary:
154
- return "Veri bulunamadı."
155
-
156
- alan = summary.get("alan_km2", 0) or 0.0
157
- toplam_poi = summary.get("toplam_poi", 0)
158
- okul = summary.get("amenity_school", 0)
159
- park = summary.get("leisure_park", 0)
160
- eczane = summary.get("amenity_pharmacy", 0)
161
- cafe = summary.get("amenity_cafe", 0)
162
- restoran = summary.get("amenity_restaurant", 0)
163
-
164
- lines = [
165
- f"- Tahmini alan: {alan:.2f} km²",
166
- f"- Toplam POI (ilgi noktası): {toplam_poi}",
167
- f"- Okul sayısı: {okul}",
168
- f"- Park sayısı: {park}",
169
- f"- Eczane sayısı: {eczane}",
170
- f"- Kafe sayısı: {cafe}",
171
- f"- Restoran sayısı: {restoran}",
172
- ]
173
- return "\n".join(lines)
174
-
175
-
176
- def create_map(gdf, pois):
177
- """
178
- Mahalle poligonu + POI noktalarını, veri tipine göre
179
- farklı katman ve renklerde gösteren Folium haritası.
180
- """
181
- try:
182
- polygon = gdf.geometry.iloc[0]
183
- centroid = polygon.centroid
184
-
185
- m = folium.Map(location=[centroid.y, centroid.x], zoom_start=15)
186
-
187
- # --- Mahalle poligonu (tek katman) ---
188
- folium.GeoJson(
189
- gdf.geometry.__geo_interface__,
190
- name="Mahalle"
191
- ).add_to(m)
192
-
193
- # POI yoksa direkt döndür
194
- if pois is None or len(pois) == 0:
195
- folium.LayerControl().add_to(m)
196
- return m._repr_html_()
197
-
198
- # Sadece nokta geometriler
199
- pois_points = pois[pois.geometry.type == "Point"].copy()
200
- if len(pois_points) == 0:
201
- folium.LayerControl().add_to(m)
202
- return m._repr_html_()
203
-
204
- # -------------------------
205
- # KATMAN / RENK TANIMLARI
206
- # -------------------------
207
- layer_defs = [
208
- ("Okullar", ("amenity", "school"), "blue"),
209
- ("Hastaneler", ("amenity", "hospital"), "red"),
210
- ("Eczaneler", ("amenity", "pharmacy"), "darkred"),
211
- ("Kafeler", ("amenity", "cafe"), "purple"),
212
- ("Restoranlar", ("amenity", "restaurant"), "orange"),
213
- ("Bankalar", ("amenity", "bank"), "darkblue"),
214
- ("Parklar", ("leisure", "park"), "green"),
215
- ("Oyun Alanları",("leisure", "playground"), "lightgreen"),
216
- ("Dükkanlar", ("shop", None), "cadetblue"),
217
- ]
218
-
219
- used_indexes = set()
220
-
221
- for layer_name, (col, value), color in layer_defs:
222
- if col not in pois_points.columns:
223
- continue
224
-
225
- if value is None:
226
- mask = pois_points[col].notna()
227
- else:
228
- mask = (pois_points[col] == value)
229
-
230
- layer_gdf = pois_points[mask]
231
- if layer_gdf.empty:
232
- continue
233
-
234
- fg = folium.FeatureGroup(name=layer_name, show=True)
235
-
236
- for idx, row in layer_gdf.iterrows():
237
- used_indexes.add(idx)
238
- lon, lat = row.geometry.x, row.geometry.y
239
-
240
- # name kolonunda NaN / sayı vs. olabilir → str'e çevir
241
- raw_name = row.get("name", layer_name[:-1] if layer_name.endswith("lar") else "POI")
242
- name = str(raw_name) if raw_name is not None else "POI"
243
-
244
- popup_lines = [name]
245
-
246
- # biraz daha bilgi ekleyelim – hepsini str'e çeviriyoruz
247
- if "amenity" in row and isinstance(row["amenity"], str):
248
- popup_lines.append(f"amenity: {row['amenity']}")
249
- if "leisure" in row and isinstance(row["leisure"], str):
250
- popup_lines.append(f"leisure: {row['leisure']}")
251
- if "shop" in row and isinstance(row["shop"], str):
252
- popup_lines.append(f"shop: {row['shop']}")
253
-
254
- # HER ŞEYİN string olduğundan emin ol
255
- popup_lines = [str(x) for x in popup_lines]
256
- popup_text = "<br>".join(popup_lines)
257
-
258
- folium.CircleMarker(
259
- location=[lat, lon],
260
- radius=4,
261
- color=color,
262
- fill=True,
263
- fill_opacity=0.8,
264
- popup=folium.Popup(popup_text, max_width=250),
265
- ).add_to(fg)
266
-
267
- fg.add_to(m)
268
-
269
- # Diğer POI'ler
270
- others = pois_points[~pois_points.index.isin(used_indexes)]
271
- if not others.empty:
272
- fg_other = folium.FeatureGroup(name="Diğer POI'ler", show=False)
273
- for _, row in others.iterrows():
274
- lon, lat = row.geometry.x, row.geometry.y
275
- raw_name = row.get("name", "POI")
276
- name = str(raw_name) if raw_name is not None else "POI"
277
- folium.CircleMarker(
278
- location=[lat, lon],
279
- radius=3,
280
- color="gray",
281
- fill=True,
282
- fill_opacity=0.6,
283
- popup=name,
284
- ).add_to(fg_other)
285
- fg_other.add_to(m)
286
-
287
- folium.LayerControl().add_to(m)
288
- return m._repr_html_()
289
-
290
- except Exception as e:
291
- msg = f"Harita oluşturulurken hata oluştu: {repr(e)}"
292
- print("HARITA HATASI:", msg)
293
- return f"<pre>{msg}</pre>"
294
-
295
-
296
-
297
- # =========================
298
- # GRADIO YARDIMCI FONKSİYONLARI
299
- # =========================
300
- def load_osm_context(city, neighborhood):
301
- """
302
- Butona basıldığında:
303
- - mahalle çokgenini bul
304
- - POI'leri al
305
- - özet çıkar
306
- - harita HTML + LLM için bağlam döndür
307
- """
308
- if not city or not neighborhood:
309
- return "<b>Lütfen şehir ve mahalle girin.</b>", "Şehir/mahalle girilmedi.", ""
310
-
311
- gdf = get_neighborhood_gdf(city.strip(), neighborhood.strip())
312
- if gdf is None or len(gdf) == 0:
313
- return "<b>Bu mahalle bulunamadı.</b>", "Bu mahalle için veri bulunamadı.", ""
314
-
315
- pois = get_pois_within(gdf)
316
- summary = summarize_pois(gdf, pois)
317
- stats_text = build_stats_text(summary)
318
- map_html = create_map(gdf, pois)
319
-
320
- # LLM için bağlam:
321
- llm_context = (
322
- f"Şehir: {city}, Mahalle: {neighborhood}\n"
323
- f"Bu mahalle için sayısal özet:\n{stats_text}"
324
- )
325
- return map_html, stats_text, llm_context
326
-
327
  def respond(
328
  message,
329
- history,
330
  system_message,
331
  max_tokens,
332
  temperature,
333
  top_p,
334
- osm_context, # gr.State ile gelecek
335
  ):
336
- # OSM bağlamını sistem mesajına ekle
337
- full_system = system_message
338
- if osm_context:
339
- full_system += (
340
- "\n\nAşağıda, konuştuğumuz mahalleyle ilgili "
341
- "coğrafi ve POI istatistikleri var. "
342
- "Kullanıcı soru sorarsa bunlara dayanarak cevap ver:\n"
343
- f"{osm_context}"
344
- )
345
 
346
- messages = [{"role": "system", "content": full_system}]
 
347
  messages.extend(history)
348
  messages.append({"role": "user", "content": message})
349
 
350
  response = ""
 
 
351
  for chunk in client.chat_completion(
352
  messages=messages,
353
  max_tokens=max_tokens,
@@ -363,73 +55,27 @@ def respond(
363
  response += token_text
364
  yield response
365
 
366
- # =========================
367
- # GRADIO ARAYÜZÜ
368
- # =========================
369
- with gr.Blocks() as demo:
370
- gr.Markdown("## OSM Destekli Mahalle Sohbet Botu")
371
-
372
- # OSM bağlamını saklamak için state
373
- osm_state = gr.State("")
374
-
375
- with gr.Row():
376
- # Sol: Chat
377
- with gr.Column(scale=2):
378
- chatbot = gr.ChatInterface(
379
- respond,
380
- type="messages",
381
- additional_inputs=[
382
- gr.Textbox(
383
- value="Sen şehir planlama ve mahalleler hakkında bilgi veren yardımsever bir asistansın.",
384
- label="System message",
385
- ),
386
- gr.Slider(
387
- minimum=1,
388
- maximum=2048,
389
- value=512,
390
- step=1,
391
- label="Max new tokens",
392
- ),
393
- gr.Slider(
394
- minimum=0.0,
395
- maximum=2.0, # <-- en fazla 2 olmalı modele gore
396
- value=0.7,
397
- step=0.1,
398
- label="Temperature",
399
- ),
400
- gr.Slider(
401
- minimum=0.1,
402
- maximum=1.0,
403
- value=0.95,
404
- step=0.05,
405
- label="Top-p (nucleus sampling)",
406
- ),
407
- osm_state, # >>> buradan respond() içine gidiyor
408
- ],
409
- )
410
-
411
- # Sağ: Harita + parametreler
412
- with gr.Column(scale=1):
413
- gr.Markdown("### Mahalle Seçimi / Harita")
414
 
415
- city_in = gr.Textbox(label="Şehir", value="İstanbul")
416
- neigh_in = gr.Textbox(label="Mahalle / Semt", value="Kadıköy")
417
-
418
- load_btn = gr.Button("Haritayı Yükle")
419
-
420
- map_html = gr.HTML(label="Harita")
421
- stats_box = gr.Textbox(
422
- label="Mahalle Özeti (LLM Bağlamı)",
423
- lines=8,
424
- )
 
 
 
 
 
 
 
 
425
 
426
- # Buton: OSM verisini yükle, haritayı ve state'i güncelle
427
- load_btn.click(
428
- fn=load_osm_context,
429
- inputs=[city_in, neigh_in],
430
- outputs=[map_html, stats_box, osm_state],
431
- )
432
 
433
  if __name__ == "__main__":
434
- demo.launch()
435
-
 
1
  import os
2
  import gradio as gr
 
 
 
 
 
 
 
 
 
3
  from huggingface_hub import InferenceClient, login
4
 
5
+
6
+ # ---- HF token & login integration ----
 
7
  HF_TOKEN = (os.environ.get("HUGGINGFACE_HUB_TOKEN", "") or "").strip()
8
+
9
  if HF_TOKEN:
10
+ # Authenticate this environment (useful for gated models, higher rate limits, etc.)
11
  login(token=HF_TOKEN)
12
  else:
13
+ print("UYARI: HF_TOKEN / HUGGINGFACE_HUB_TOKEN bulunamadı, gated modellere erişilemeyebilir.")
14
+
15
 
16
+ # Create a single shared client (reuse across requests)
17
  client = InferenceClient(
18
  model="openai/gpt-oss-20b",
19
+ token=HF_TOKEN if HF_TOKEN else None, # will still work for public models without token
20
  )
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  def respond(
23
  message,
24
+ history: list[dict[str, str]],
25
  system_message,
26
  max_tokens,
27
  temperature,
28
  top_p,
 
29
  ):
30
+ """
31
+ Streaming chat using Hugging Face Inference API.
32
+ History is a list of {"role": "...", "content": "..."} dicts.
33
+ """
 
 
 
 
 
34
 
35
+ # Build messages list
36
+ messages = [{"role": "system", "content": system_message}]
37
  messages.extend(history)
38
  messages.append({"role": "user", "content": message})
39
 
40
  response = ""
41
+
42
+ # Stream tokens from the model
43
  for chunk in client.chat_completion(
44
  messages=messages,
45
  max_tokens=max_tokens,
 
55
  response += token_text
56
  yield response
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
+ chatbot = gr.ChatInterface(
60
+ respond,
61
+ type="messages",
62
+ title="Basit Chat Botu",
63
+ description="Küçük bir sohbet botu, HF Inference API ile çalışıyor.",
64
+ additional_inputs=[
65
+ gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
66
+ gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
67
+ gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
68
+ gr.Slider(
69
+ minimum=0.1,
70
+ maximum=1.0,
71
+ value=0.95,
72
+ step=0.05,
73
+ label="Top-p (nucleus sampling)",
74
+ ),
75
+ ],
76
+ )
77
 
78
+ demo = chatbot # no login UI needed now
 
 
 
 
 
79
 
80
  if __name__ == "__main__":
81
+ demo.launch()
 
app_bk2.py ADDED
@@ -0,0 +1,435 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import geopandas as gpd
4
+ import folium
5
+
6
+ # osmnx isteğe bağlı (fallback için)
7
+ try:
8
+ import osmnx as ox
9
+ except ImportError:
10
+ ox = None
11
+
12
+ from huggingface_hub import InferenceClient, login
13
+
14
+ # ================
15
+ # HF TOKEN & MODEL
16
+ # ================
17
+ HF_TOKEN = (os.environ.get("HUGGINGFACE_HUB_TOKEN", "") or "").strip()
18
+ if HF_TOKEN:
19
+ login(token=HF_TOKEN)
20
+ else:
21
+ print("UYARI: HUGGINGFACE_HUB_TOKEN bulunamadı, kamuya açık modellerle sınırlı olabilirsiniz.")
22
+
23
+ client = InferenceClient(
24
+ model="openai/gpt-oss-20b",
25
+ token=HF_TOKEN if HF_TOKEN else None,
26
+ )
27
+
28
+ # =========================
29
+ # ÖNCEDEN HAZIRLANMIŞ OSM VERİSİ
30
+ # =========================
31
+ NEIGH_PATH = "data/neighborhoods.geojson"
32
+ POIS_PATH = "data/pois.geojson"
33
+
34
+ if not (os.path.exists(NEIGH_PATH) and os.path.exists(POIS_PATH)):
35
+ print("UYARI: data/ klasöründe neighborhoods.geojson / pois.geojson bulunamadı!")
36
+ neighborhoods_gdf = None
37
+ pois_gdf = None
38
+ else:
39
+ neighborhoods_gdf = gpd.read_file(NEIGH_PATH)
40
+ pois_gdf = gpd.read_file(POIS_PATH)
41
+ print(f"{len(neighborhoods_gdf)} mahalle/semt, {len(pois_gdf)} POI yüklendi.")
42
+
43
+
44
+ DEFAULT_TAGS = {
45
+ "amenity": ["school", "pharmacy", "hospital", "restaurant", "cafe", "bank"],
46
+ "leisure": ["park", "playground"],
47
+ "shop": True,
48
+ }
49
+
50
+
51
+ # =========================
52
+ # OSM / CBS FONKSİYONLARI
53
+ # =========================
54
+ def get_neighborhood_gdf(city: str, neighborhood: str):
55
+ if neighborhoods_gdf is not None:
56
+ mask = (
57
+ (neighborhoods_gdf["city"] == city)
58
+ & (neighborhoods_gdf["neighborhood"] == neighborhood)
59
+ )
60
+ gdf_local = neighborhoods_gdf[mask]
61
+ if gdf_local is not None and len(gdf_local) > 0:
62
+ return gdf_local
63
+
64
+ if ox is None:
65
+ print("OSM fallback kullanılamıyor: osmnx yüklü değil.")
66
+ return None
67
+
68
+ query = f"{neighborhood}, {city}, Türkiye"
69
+ print(f"OSM fallback: {query}")
70
+ try:
71
+ gdf_osm = ox.geocode_to_gdf(query)
72
+ except Exception as e:
73
+ print("Mahalle geocode hatası (OSM fallback):", e)
74
+ return None
75
+
76
+ if gdf_osm is None or len(gdf_osm) == 0:
77
+ return None
78
+
79
+ gdf_osm = gdf_osm.copy()
80
+ gdf_osm["city"] = city
81
+ gdf_osm["neighborhood"] = neighborhood
82
+ return gdf_osm
83
+
84
+
85
+ def get_pois_within(gdf, tags=None):
86
+ if gdf is None:
87
+ return None
88
+
89
+ if tags is None:
90
+ tags = DEFAULT_TAGS
91
+
92
+ if pois_gdf is not None and "city" in gdf.columns and "neighborhood" in gdf.columns:
93
+ row = gdf.iloc[0]
94
+ city = row["city"]
95
+ neighborhood = row["neighborhood"]
96
+
97
+ mask = (
98
+ (pois_gdf["city"] == city)
99
+ & (pois_gdf["neighborhood"] == neighborhood)
100
+ )
101
+ pois_local = pois_gdf[mask]
102
+
103
+ if pois_local is not None and len(pois_local) > 0:
104
+ return pois_local
105
+
106
+ if ox is None:
107
+ print("OSM POI fallback kullanılamıyor: osmnx yüklü değil.")
108
+ return None
109
+
110
+ try:
111
+ polygon = gdf.geometry.iloc[0]
112
+ pois_osm = ox.features_from_polygon(polygon, tags)
113
+ return pois_osm
114
+ except Exception as e:
115
+ print("POI hatası (OSM fallback):", e)
116
+ return None
117
+
118
+
119
+ def summarize_pois(gdf, pois):
120
+ summary = {}
121
+
122
+ try:
123
+ area_m2 = gdf.to_crs(epsg=3857).geometry.iloc[0].area
124
+ summary["alan_m2"] = float(area_m2)
125
+ summary["alan_km2"] = float(area_m2 / 1_000_000)
126
+ except Exception as e:
127
+ print("Alan hesaplama hatası:", e)
128
+ summary["alan_m2"] = None
129
+ summary["alan_km2"] = None
130
+
131
+ if pois is None or len(pois) == 0:
132
+ summary["toplam_poi"] = 0
133
+ return summary
134
+
135
+ summary["toplam_poi"] = int(len(pois))
136
+
137
+ if "amenity" in pois.columns:
138
+ for k, v in pois["amenity"].value_counts().to_dict().items():
139
+ summary[f"amenity_{k}"] = int(v)
140
+
141
+ if "leisure" in pois.columns:
142
+ for k, v in pois["leisure"].value_counts().to_dict().items():
143
+ summary[f"leisure_{k}"] = int(v)
144
+
145
+ if "shop" in pois.columns:
146
+ for k, v in pois["shop"].value_counts().to_dict().items():
147
+ summary[f"shop_{k}"] = int(v)
148
+
149
+ return summary
150
+
151
+
152
+ def build_stats_text(summary: dict) -> str:
153
+ if not summary:
154
+ return "Veri bulunamadı."
155
+
156
+ alan = summary.get("alan_km2", 0) or 0.0
157
+ toplam_poi = summary.get("toplam_poi", 0)
158
+ okul = summary.get("amenity_school", 0)
159
+ park = summary.get("leisure_park", 0)
160
+ eczane = summary.get("amenity_pharmacy", 0)
161
+ cafe = summary.get("amenity_cafe", 0)
162
+ restoran = summary.get("amenity_restaurant", 0)
163
+
164
+ lines = [
165
+ f"- Tahmini alan: {alan:.2f} km²",
166
+ f"- Toplam POI (ilgi noktası): {toplam_poi}",
167
+ f"- Okul sayısı: {okul}",
168
+ f"- Park sayısı: {park}",
169
+ f"- Eczane sayısı: {eczane}",
170
+ f"- Kafe sayısı: {cafe}",
171
+ f"- Restoran sayısı: {restoran}",
172
+ ]
173
+ return "\n".join(lines)
174
+
175
+
176
+ def create_map(gdf, pois):
177
+ """
178
+ Mahalle poligonu + POI noktalarını, veri tipine göre
179
+ farklı katman ve renklerde gösteren Folium haritası.
180
+ """
181
+ try:
182
+ polygon = gdf.geometry.iloc[0]
183
+ centroid = polygon.centroid
184
+
185
+ m = folium.Map(location=[centroid.y, centroid.x], zoom_start=15)
186
+
187
+ # --- Mahalle poligonu (tek katman) ---
188
+ folium.GeoJson(
189
+ gdf.geometry.__geo_interface__,
190
+ name="Mahalle"
191
+ ).add_to(m)
192
+
193
+ # POI yoksa direkt döndür
194
+ if pois is None or len(pois) == 0:
195
+ folium.LayerControl().add_to(m)
196
+ return m._repr_html_()
197
+
198
+ # Sadece nokta geometriler
199
+ pois_points = pois[pois.geometry.type == "Point"].copy()
200
+ if len(pois_points) == 0:
201
+ folium.LayerControl().add_to(m)
202
+ return m._repr_html_()
203
+
204
+ # -------------------------
205
+ # KATMAN / RENK TANIMLARI
206
+ # -------------------------
207
+ layer_defs = [
208
+ ("Okullar", ("amenity", "school"), "blue"),
209
+ ("Hastaneler", ("amenity", "hospital"), "red"),
210
+ ("Eczaneler", ("amenity", "pharmacy"), "darkred"),
211
+ ("Kafeler", ("amenity", "cafe"), "purple"),
212
+ ("Restoranlar", ("amenity", "restaurant"), "orange"),
213
+ ("Bankalar", ("amenity", "bank"), "darkblue"),
214
+ ("Parklar", ("leisure", "park"), "green"),
215
+ ("Oyun Alanları",("leisure", "playground"), "lightgreen"),
216
+ ("Dükkanlar", ("shop", None), "cadetblue"),
217
+ ]
218
+
219
+ used_indexes = set()
220
+
221
+ for layer_name, (col, value), color in layer_defs:
222
+ if col not in pois_points.columns:
223
+ continue
224
+
225
+ if value is None:
226
+ mask = pois_points[col].notna()
227
+ else:
228
+ mask = (pois_points[col] == value)
229
+
230
+ layer_gdf = pois_points[mask]
231
+ if layer_gdf.empty:
232
+ continue
233
+
234
+ fg = folium.FeatureGroup(name=layer_name, show=True)
235
+
236
+ for idx, row in layer_gdf.iterrows():
237
+ used_indexes.add(idx)
238
+ lon, lat = row.geometry.x, row.geometry.y
239
+
240
+ # name kolonunda NaN / sayı vs. olabilir → str'e çevir
241
+ raw_name = row.get("name", layer_name[:-1] if layer_name.endswith("lar") else "POI")
242
+ name = str(raw_name) if raw_name is not None else "POI"
243
+
244
+ popup_lines = [name]
245
+
246
+ # biraz daha bilgi ekleyelim – hepsini str'e çeviriyoruz
247
+ if "amenity" in row and isinstance(row["amenity"], str):
248
+ popup_lines.append(f"amenity: {row['amenity']}")
249
+ if "leisure" in row and isinstance(row["leisure"], str):
250
+ popup_lines.append(f"leisure: {row['leisure']}")
251
+ if "shop" in row and isinstance(row["shop"], str):
252
+ popup_lines.append(f"shop: {row['shop']}")
253
+
254
+ # HER ŞEYİN string olduğundan emin ol
255
+ popup_lines = [str(x) for x in popup_lines]
256
+ popup_text = "<br>".join(popup_lines)
257
+
258
+ folium.CircleMarker(
259
+ location=[lat, lon],
260
+ radius=4,
261
+ color=color,
262
+ fill=True,
263
+ fill_opacity=0.8,
264
+ popup=folium.Popup(popup_text, max_width=250),
265
+ ).add_to(fg)
266
+
267
+ fg.add_to(m)
268
+
269
+ # Diğer POI'ler
270
+ others = pois_points[~pois_points.index.isin(used_indexes)]
271
+ if not others.empty:
272
+ fg_other = folium.FeatureGroup(name="Diğer POI'ler", show=False)
273
+ for _, row in others.iterrows():
274
+ lon, lat = row.geometry.x, row.geometry.y
275
+ raw_name = row.get("name", "POI")
276
+ name = str(raw_name) if raw_name is not None else "POI"
277
+ folium.CircleMarker(
278
+ location=[lat, lon],
279
+ radius=3,
280
+ color="gray",
281
+ fill=True,
282
+ fill_opacity=0.6,
283
+ popup=name,
284
+ ).add_to(fg_other)
285
+ fg_other.add_to(m)
286
+
287
+ folium.LayerControl().add_to(m)
288
+ return m._repr_html_()
289
+
290
+ except Exception as e:
291
+ msg = f"Harita oluşturulurken hata oluştu: {repr(e)}"
292
+ print("HARITA HATASI:", msg)
293
+ return f"<pre>{msg}</pre>"
294
+
295
+
296
+
297
+ # =========================
298
+ # GRADIO YARDIMCI FONKSİYONLARI
299
+ # =========================
300
+ def load_osm_context(city, neighborhood):
301
+ """
302
+ Butona basıldığında:
303
+ - mahalle çokgenini bul
304
+ - POI'leri al
305
+ - özet çıkar
306
+ - harita HTML + LLM için bağlam döndür
307
+ """
308
+ if not city or not neighborhood:
309
+ return "<b>Lütfen şehir ve mahalle girin.</b>", "Şehir/mahalle girilmedi.", ""
310
+
311
+ gdf = get_neighborhood_gdf(city.strip(), neighborhood.strip())
312
+ if gdf is None or len(gdf) == 0:
313
+ return "<b>Bu mahalle bulunamadı.</b>", "Bu mahalle için veri bulunamadı.", ""
314
+
315
+ pois = get_pois_within(gdf)
316
+ summary = summarize_pois(gdf, pois)
317
+ stats_text = build_stats_text(summary)
318
+ map_html = create_map(gdf, pois)
319
+
320
+ # LLM için bağlam:
321
+ llm_context = (
322
+ f"Şehir: {city}, Mahalle: {neighborhood}\n"
323
+ f"Bu mahalle için sayısal özet:\n{stats_text}"
324
+ )
325
+ return map_html, stats_text, llm_context
326
+
327
+ def respond(
328
+ message,
329
+ history,
330
+ system_message,
331
+ max_tokens,
332
+ temperature,
333
+ top_p,
334
+ osm_context, # gr.State ile gelecek
335
+ ):
336
+ # OSM bağlamını sistem mesajına ekle
337
+ full_system = system_message
338
+ if osm_context:
339
+ full_system += (
340
+ "\n\nAşağıda, konuştuğumuz mahalleyle ilgili "
341
+ "coğrafi ve POI istatistikleri var. "
342
+ "Kullanıcı soru sorarsa bunlara dayanarak cevap ver:\n"
343
+ f"{osm_context}"
344
+ )
345
+
346
+ messages = [{"role": "system", "content": full_system}]
347
+ messages.extend(history)
348
+ messages.append({"role": "user", "content": message})
349
+
350
+ response = ""
351
+ for chunk in client.chat_completion(
352
+ messages=messages,
353
+ max_tokens=max_tokens,
354
+ stream=True,
355
+ temperature=temperature,
356
+ top_p=top_p,
357
+ ):
358
+ choices = chunk.choices
359
+ token_text = ""
360
+ if len(choices) and choices[0].delta.content:
361
+ token_text = choices[0].delta.content
362
+
363
+ response += token_text
364
+ yield response
365
+
366
+ # =========================
367
+ # GRADIO ARAYÜZÜ
368
+ # =========================
369
+ with gr.Blocks() as demo:
370
+ gr.Markdown("## OSM Destekli Mahalle Sohbet Botu")
371
+
372
+ # OSM bağlamını saklamak için state
373
+ osm_state = gr.State("")
374
+
375
+ with gr.Row():
376
+ # Sol: Chat
377
+ with gr.Column(scale=2):
378
+ chatbot = gr.ChatInterface(
379
+ respond,
380
+ type="messages",
381
+ additional_inputs=[
382
+ gr.Textbox(
383
+ value="Sen şehir planlama ve mahalleler hakkında bilgi veren yardımsever bir asistansın.",
384
+ label="System message",
385
+ ),
386
+ gr.Slider(
387
+ minimum=1,
388
+ maximum=2048,
389
+ value=512,
390
+ step=1,
391
+ label="Max new tokens",
392
+ ),
393
+ gr.Slider(
394
+ minimum=0.0,
395
+ maximum=2.0, # <-- en fazla 2 olmalı modele gore
396
+ value=0.7,
397
+ step=0.1,
398
+ label="Temperature",
399
+ ),
400
+ gr.Slider(
401
+ minimum=0.1,
402
+ maximum=1.0,
403
+ value=0.95,
404
+ step=0.05,
405
+ label="Top-p (nucleus sampling)",
406
+ ),
407
+ osm_state, # >>> buradan respond() içine gidiyor
408
+ ],
409
+ )
410
+
411
+ # Sağ: Harita + parametreler
412
+ with gr.Column(scale=1):
413
+ gr.Markdown("### Mahalle Seçimi / Harita")
414
+
415
+ city_in = gr.Textbox(label="Şehir", value="İstanbul")
416
+ neigh_in = gr.Textbox(label="Mahalle / Semt", value="Kadıköy")
417
+
418
+ load_btn = gr.Button("Haritayı Yükle")
419
+
420
+ map_html = gr.HTML(label="Harita")
421
+ stats_box = gr.Textbox(
422
+ label="Mahalle Özeti (LLM Bağlamı)",
423
+ lines=8,
424
+ )
425
+
426
+ # Buton: OSM verisini yükle, haritayı ve state'i güncelle
427
+ load_btn.click(
428
+ fn=load_osm_context,
429
+ inputs=[city_in, neigh_in],
430
+ outputs=[map_html, stats_box, osm_state],
431
+ )
432
+
433
+ if __name__ == "__main__":
434
+ demo.launch()
435
+