import os import pickle import numpy as np import lightgbm as lgb import requests import json import time from sklearn.preprocessing import StandardScaler # Geocoding API (adres -> koordinat) GEOCODING_API_URL = "https://nominatim.openstreetmap.org/search" CACHE_DIR = os.path.join(os.path.dirname(__file__), "cache") os.makedirs(CACHE_DIR, exist_ok=True) # Model dosya yolu MODEL_PATH = os.path.join(os.path.dirname(__file__), "model.pkl") SCALER_PATH = os.path.join(os.path.dirname(__file__), "scaler.pkl") # Zemin türleri ve risk faktörleri SOIL_TYPES = { "kaya": 0.1, "sert": 0.3, "orta": 0.5, "yumuşak": 0.7, "alüvyon": 0.9 } # Bina yaşı risk faktörleri BUILDING_AGE_FACTORS = { "0-10": 0.2, "11-20": 0.4, "21-30": 0.6, "31-40": 0.8, "41+": 1.0 } # Türkiye'deki deprem bölgeleri (basitleştirilmiş) EARTHQUAKE_ZONES = { "İstanbul": 0.9, "İzmir": 0.8, "Ankara": 0.5, "Bursa": 0.7, "Kocaeli": 0.9, "Sakarya": 0.9, "Düzce": 0.9, "Bolu": 0.8, "Yalova": 0.9, "Çanakkale": 0.7, "Balıkesir": 0.8, "Manisa": 0.8, "Aydın": 0.7, "Muğla": 0.6, "Denizli": 0.7, "Antalya": 0.6, "Adana": 0.6, "Hatay": 0.7, "Osmaniye": 0.7, "Kahramanmaraş": 0.9, "Gaziantep": 0.8, "Kilis": 0.7, "Şanlıurfa": 0.6, "Diyarbakır": 0.6, "Mardin": 0.5, "Batman": 0.6, "Siirt": 0.6, "Şırnak": 0.6, "Hakkari": 0.7, "Van": 0.8, "Bitlis": 0.7, "Muş": 0.7, "Ağrı": 0.6, "Iğdır": 0.6, "Kars": 0.5, "Ardahan": 0.5, "Erzurum": 0.6, "Erzincan": 0.9, "Tunceli": 0.7, "Bingöl": 0.8, "Elazığ": 0.8, "Malatya": 0.8, "Sivas": 0.6, "Kayseri": 0.5, "Nevşehir": 0.5, "Kırşehir": 0.5, "Aksaray": 0.5, "Niğde": 0.5, "Konya": 0.4, "Karaman": 0.5, "Mersin": 0.6, "Adıyaman": 0.8, "Afyonkarahisar": 0.6, "Kütahya": 0.7, "Uşak": 0.6, "Eskişehir": 0.6, "Bilecik": 0.7, "Çankırı": 0.5, "Karabük": 0.5, "Zonguldak": 0.6, "Bartın": 0.6, "Kastamonu": 0.5, "Çorum": 0.5, "Amasya": 0.5, "Tokat": 0.6, "Ordu": 0.5, "Giresun": 0.5, "Trabzon": 0.5, "Rize": 0.5, "Artvin": 0.5, "Gümüşhane": 0.5, "Bayburt": 0.5, "Samsun": 0.5, "Sinop": 0.5, "Kırıkkale": 0.5, "Yozgat": 0.5, "Kırklareli": 0.4, "Edirne": 0.4, "Tekirdağ": 0.7, # Diğer iller için varsayılan değer "default": 0.5 } def geocode_address(address, use_cache=True): """Adresi koordinatlara dönüştür""" # Cache kontrolü cache_file = os.path.join(CACHE_DIR, f"geocode_{address.replace(' ', '_').replace('/', '_')}.json") if use_cache and os.path.exists(cache_file): try: with open(cache_file, 'r', encoding='utf-8') as f: return json.load(f) except Exception as e: print(f"Cache loading error: {e}") params = { "q": address, "format": "json", "limit": 1, "countrycodes": "tr" # Türkiye ile sınırla } try: response = requests.get(GEOCODING_API_URL, params=params, timeout=10) response.raise_for_status() data = response.json() if data and len(data) > 0: lat = float(data[0]["lat"]) lon = float(data[0]["lon"]) display_name = data[0]["display_name"] # İl bilgisini çıkar address_parts = display_name.split(", ") province = None for part in reversed(address_parts): if "Province" in part or "İli" in part: province = part.replace(" Province", "").replace(" İli", "") break if not province and len(address_parts) > 1: province = address_parts[-2] result = { "latitude": lat, "longitude": lon, "display_name": display_name, "province": province } # Cache'e kaydet with open(cache_file, 'w', encoding='utf-8') as f: json.dump(result, f, ensure_ascii=False) return result else: return None except Exception as e: print(f"Geocoding error: {e}") return None def get_soil_type(lat, lon): """Koordinatlara göre zemin türünü tahmin et (gerçek API olmadığı için simüle ediyoruz)""" # Gerçek uygulamada burada bir zemin türü API'si kullanılabilir # Şimdilik rastgele bir zemin türü döndürelim soil_types = list(SOIL_TYPES.keys()) # Deterministik olması için koordinatları seed olarak kullan seed = int((lat * 1000 + lon * 1000) % 100) np.random.seed(seed) soil_type = np.random.choice(soil_types, p=[0.2, 0.3, 0.3, 0.15, 0.05]) return soil_type def get_building_age(address): """Adrese göre bina yaşını tahmin et (gerçek API olmadığı için simüle ediyoruz)""" # Gerçek uygulamada burada bir bina yaşı API'si kullanılabilir # Şimdilik rastgele bir bina yaşı döndürelim # Deterministik olması için adresi seed olarak kullan seed = sum(ord(c) for c in address) % 100 np.random.seed(seed) age_categories = list(BUILDING_AGE_FACTORS.keys()) age_category = np.random.choice(age_categories, p=[0.1, 0.2, 0.3, 0.2, 0.2]) return age_category def get_historical_earthquakes(lat, lon, radius_km=50): """Belirli bir koordinat çevresindeki geçmiş depremleri getir (gerçek API olmadığı için simüle ediyoruz)""" # Gerçek uygulamada burada AFAD veya USGS API'si kullanılabilir # Şimdilik rastgele deprem sayısı ve büyüklüğü döndürelim # Deterministik olması için koordinatları seed olarak kullan seed = int((lat * 1000 + lon * 1000) % 100) np.random.seed(seed) # Bölgeye göre deprem sayısı ve büyüklüğünü ayarla province_factor = 0.5 # Varsayılan for province, factor in EARTHQUAKE_ZONES.items(): if province.lower() in f"{lat},{lon}".lower(): province_factor = factor break num_earthquakes = int(np.random.randint(5, 50) * province_factor * 2) max_magnitude = np.random.uniform(4.0, 7.0) * province_factor avg_magnitude = np.random.uniform(3.0, max_magnitude - 0.5) return { "count": num_earthquakes, "max_magnitude": max_magnitude, "avg_magnitude": avg_magnitude } def extract_features(address): """Adresten özellik vektörü çıkar""" # Adresi koordinatlara dönüştür geo_data = geocode_address(address) if not geo_data: print(f"Adres bulunamadı: {address}") return None lat = geo_data["latitude"] lon = geo_data["longitude"] province = geo_data["province"] # Zemin türü soil_type = get_soil_type(lat, lon) soil_factor = SOIL_TYPES[soil_type] # Bina yaşı building_age = get_building_age(address) age_factor = BUILDING_AGE_FACTORS[building_age] # Deprem bölgesi risk faktörü if province in EARTHQUAKE_ZONES: zone_factor = EARTHQUAKE_ZONES[province] else: zone_factor = EARTHQUAKE_ZONES["default"] # Geçmiş depremler historical_eq = get_historical_earthquakes(lat, lon) # Özellik vektörü oluştur features = { "latitude": lat, "longitude": lon, "soil_factor": soil_factor, "age_factor": age_factor, "zone_factor": zone_factor, "eq_count": historical_eq["count"], "eq_max_magnitude": historical_eq["max_magnitude"], "eq_avg_magnitude": historical_eq["avg_magnitude"] } return features def prepare_features(address): """Adresten model için özellik vektörü hazırla""" # Özellikleri çıkar features = extract_features(address) if not features: return None # DataFrame'e dönüştür feature_array = np.array([[ features["latitude"], features["longitude"], features["soil_factor"], features["age_factor"], features["zone_factor"], features["eq_count"], features["eq_max_magnitude"], features["eq_avg_magnitude"] ]]) # Scaler yükle veya oluştur if os.path.exists(SCALER_PATH): with open(SCALER_PATH, "rb") as f: scaler = pickle.load(f) else: # Gerçek uygulamada scaler eğitim verisiyle oluşturulmalı scaler = StandardScaler() # Varsayılan değerlerle fit et sample_data = np.array([ [41.0082, 28.9784, 0.5, 0.6, 0.7, 20, 5.5, 4.2], [39.9334, 32.8597, 0.3, 0.4, 0.5, 10, 4.5, 3.5], [38.4192, 27.1287, 0.7, 0.8, 0.8, 30, 6.0, 4.8] ]) scaler.fit(sample_data) # Scaler'ı kaydet with open(SCALER_PATH, "wb") as f: pickle.dump(scaler, f) # Özellikleri normalize et scaled_features = scaler.transform(feature_array) return scaled_features def load_or_create_model(): """Model dosyasını yükle veya yeni bir model oluştur""" if os.path.exists(MODEL_PATH): # Mevcut modeli yükle with open(MODEL_PATH, "rb") as f: model = pickle.load(f) print(f"Model loaded: {MODEL_PATH}") else: # Yeni model oluştur (gerçek uygulamada eğitim verisiyle eğitilmeli) print("Model not found, creating a new model...") # LightGBM modeli oluştur params = { "objective": "regression", "metric": "rmse", "num_leaves": 31, "learning_rate": 0.05, "feature_fraction": 0.9, "bagging_fraction": 0.8, "bagging_freq": 5, "verbose": -1 } model = lgb.LGBMRegressor(**params) # Basit bir veri seti ile eğit (gerçek uygulamada gerçek veri kullanılmalı) # Türkiye'nin farklı bölgelerinden örnek veri X = np.array([ # [latitude, longitude, soil_factor, age_factor, zone_factor, eq_count, eq_max_magnitude, eq_avg_magnitude] [41.0082, 28.9784, 0.7, 0.8, 0.9, 35, 6.8, 5.2], # İstanbul [39.9334, 32.8597, 0.3, 0.4, 0.5, 12, 4.8, 3.7], # Ankara [38.4192, 27.1287, 0.6, 0.7, 0.8, 28, 6.2, 4.9], # İzmir [37.0000, 35.3213, 0.5, 0.6, 0.6, 18, 5.5, 4.3], # Adana [40.1885, 29.0610, 0.6, 0.7, 0.7, 22, 5.8, 4.5], # Bursa [36.8841, 30.7056, 0.4, 0.5, 0.6, 15, 5.2, 4.0], # Antalya [37.9144, 40.2306, 0.5, 0.6, 0.6, 20, 5.6, 4.4], # Diyarbakır [38.7312, 35.4787, 0.4, 0.5, 0.5, 14, 5.0, 3.9], # Kayseri [41.2867, 36.3300, 0.3, 0.4, 0.5, 10, 4.5, 3.5], # Samsun [40.6560, 29.2840, 0.8, 0.9, 0.9, 40, 7.0, 5.5], # Kocaeli [40.7560, 30.3780, 0.8, 0.9, 0.9, 38, 6.9, 5.4], # Sakarya [40.8380, 31.1630, 0.8, 0.9, 0.9, 36, 6.8, 5.3], # Düzce [39.7167, 39.4833, 0.7, 0.8, 0.9, 32, 6.6, 5.1], # Erzincan [38.6823, 39.2262, 0.7, 0.8, 0.8, 30, 6.5, 5.0], # Elazığ [38.3552, 38.3095, 0.7, 0.8, 0.8, 29, 6.4, 5.0], # Malatya [37.5833, 36.9333, 0.8, 0.9, 0.9, 34, 6.7, 5.2], # Kahramanmaraş [37.0662, 37.3833, 0.7, 0.8, 0.8, 27, 6.3, 4.9], # Gaziantep [36.2000, 36.1667, 0.7, 0.8, 0.7, 26, 6.2, 4.8], # Hatay [38.5000, 43.4000, 0.7, 0.8, 0.8, 31, 6.5, 5.0], # Van ]) # Risk skorları (0-1 arası, bölgesel risk faktörlerine göre) y = np.array([ 0.85, # İstanbul 0.45, # Ankara 0.75, # İzmir 0.60, # Adana 0.70, # Bursa 0.55, # Antalya 0.60, # Diyarbakır 0.50, # Kayseri 0.45, # Samsun 0.90, # Kocaeli 0.90, # Sakarya 0.90, # Düzce 0.85, # Erzincan 0.80, # Elazığ 0.80, # Malatya 0.85, # Kahramanmaraş 0.75, # Gaziantep 0.70, # Hatay 0.75, # Van ]) model.fit(X, y) # Modeli kaydet os.makedirs(os.path.dirname(MODEL_PATH), exist_ok=True) with open(MODEL_PATH, "wb") as f: pickle.dump(model, f) print(f"New model created and saved: {MODEL_PATH}") return model def predict_risk(address): """Adres için deprem risk skorunu tahmin et""" # Özellikleri hazırla features = prepare_features(address) if features is None: print(f"Features could not be extracted for address: {address}") return None # Modeli yükle model = load_or_create_model() # Tahmin yap risk_score = model.predict(features)[0] # Skoru 0-1 aralığına normalize et risk_score = max(0, min(1, risk_score)) return risk_score def get_risk_category(risk_score): """Risk skoruna göre kategori belirle""" if risk_score < 0.2: return "Çok Düşük" elif risk_score < 0.4: return "Düşük" elif risk_score < 0.6: return "Orta" elif risk_score < 0.8: return "Yüksek" else: return "Çok Yüksek" def get_risk_explanation(risk_score, address): """Risk skoru için açıklama oluştur""" category = get_risk_category(risk_score) explanations = { "Çok Düşük": f"{address} için deprem riski çok düşük seviyededir. Bölgenizde büyük depremler nadiren görülür ve zemin yapısı genellikle sağlamdır.", "Düşük": f"{address} için deprem riski düşük seviyededir. Bölgenizde orta büyüklükte depremler görülebilir, ancak sık değildir.", "Orta": f"{address} için deprem riski orta seviyededir. Bölgenizde zaman zaman orta ve büyük depremler görülebilir. Temel deprem hazırlıklarını yapmanız önerilir.", "Yüksek": f"{address} için deprem riski yüksek seviyededir. Bölgenizde büyük depremler görülme olasılığı yüksektir. Kapsamlı deprem hazırlıkları yapmanız ve binanızın durumunu kontrol ettirmeniz önerilir.", "Çok Yüksek": f"{address} için deprem riski çok yüksek seviyededir. Bölgenizde büyük depremler sık görülür. Acil deprem hazırlıkları yapmanız, binanızın depreme dayanıklılığını kontrol ettirmeniz ve gerekirse güçlendirme çalışmaları yaptırmanız önerilir." } return explanations[category] def predict_risk_with_details(address): """Adres için deprem risk skorunu ve detayları döndür""" # Risk skorunu tahmin et risk_score = predict_risk(address) if risk_score is None: return { "success": False, "message": f"Adres bulunamadı veya risk hesaplanamadı: {address}" } # Kategori ve açıklama category = get_risk_category(risk_score) explanation = get_risk_explanation(risk_score, address) # Adres detayları geo_data = geocode_address(address) # Zemin türü soil_type = get_soil_type(geo_data["latitude"], geo_data["longitude"]) # Bina yaşı building_age = get_building_age(address) return { "success": True, "address": address, "display_name": geo_data["display_name"], "province": geo_data["province"], "latitude": geo_data["latitude"], "longitude": geo_data["longitude"], "risk_score": risk_score, "risk_category": category, "explanation": explanation, "soil_type": soil_type, "building_age": building_age } # Test if __name__ == "__main__": # Test adresi test_address = "İstanbul, Kadıköy" # Risk skorunu tahmin et result = predict_risk_with_details(test_address) if result["success"]: print(f"Adres: {result['address']}") print(f"Tam Adres: {result['display_name']}") print(f"İl: {result['province']}") print(f"Koordinatlar: {result['latitude']}, {result['longitude']}") print(f"Zemin Türü: {result['soil_type']}") print(f"Bina Yaşı: {result['building_age']}") print(f"Risk Skoru: {result['risk_score']:.4f}") print(f"Risk Kategorisi: {result['risk_category']}") print(f"Açıklama: {result['explanation']}") else: print(result["message"])