# app/utils/demo_gps.py """ Demo GPS Generator - Hackathon uchun fake GPS ma'lumotlar """ import logging import random import json from pathlib import Path from typing import Dict, Optional logger = logging.getLogger(__name__) # Tashkent districts faylining yo'li DISTRICTS_FILE = Path("data/tashkent_districts.json") # Toshkent chegaralari TASHKENT_LAT_MIN = 41.20 TASHKENT_LAT_MAX = 41.35 TASHKENT_LON_MIN = 69.10 TASHKENT_LON_MAX = 69.35 def generate_random_tashkent_gps() -> Dict[str, float]: """ Tasodifiy Tashkent koordinatalarini yaratish Returns: {"lat": 41.2856, "lon": 69.2034} """ try: lat = round(random.uniform(TASHKENT_LAT_MIN, TASHKENT_LAT_MAX), 6) lon = round(random.uniform(TASHKENT_LON_MIN, TASHKENT_LON_MAX), 6) logger.info(f"🎲 Tasodifiy GPS yaratildi: {lat}, {lon}") return { "lat": lat, "lon": lon } except Exception as e: logger.error(f"❌ Tasodifiy GPS yaratishda xatolik: {e}") # Fallback: Toshkent markazi return { "lat": 41.2995, "lon": 69.2401 } def get_gps_for_district(district_name: str) -> Optional[Dict[str, float]]: """ Tuman nomi bo'yicha markaz koordinatalarini olish Args: district_name: "Chilonzor" yoki "chilonzor" (case-insensitive) Returns: {"lat": 41.2767, "lon": 69.2095} yoki None """ try: if not DISTRICTS_FILE.exists(): logger.error(f"❌ Districts fayli topilmadi: {DISTRICTS_FILE}") return None with open(DISTRICTS_FILE, 'r', encoding='utf-8') as f: data = json.load(f) districts = data.get('districts', []) # District nomini normallashtirish district_name_lower = district_name.lower().strip() district_name_lower = district_name_lower.replace(' tumani', '').replace(' Tumani', '') # District ni topish for district in districts: district_id = district.get('id', '').lower() district_full_name = district.get('name', '').lower() if (district_name_lower in district_id or district_name_lower in district_full_name or district_id in district_name_lower): gps = { "lat": district.get('center_lat'), "lon": district.get('center_lon') } logger.info(f"✅ {district_name} uchun GPS topildi: {gps['lat']}, {gps['lon']}") return gps logger.warning(f"⚠️ District topilmadi: {district_name}") return None except json.JSONDecodeError as e: logger.error(f"❌ JSON parse xatoligi (tashkent_districts.json): {e}") return None except Exception as e: logger.error(f"❌ District GPS olishda xatolik: {e}") return None def add_gps_noise(lat: float, lon: float, noise_km: float = 0.5) -> Dict[str, float]: """ GPS koordinatalariga tasodifiy "shovqin" qo'shish (realistik qilish uchun) Args: lat: Asl latitude lon: Asl longitude noise_km: Maksimal shovqin masofasi (km) Returns: {"lat": ..., "lon": ...} - shovqinli koordinatalar """ try: # 1 km ~ 0.009 daraja (taxminan) noise_degrees = noise_km * 0.009 lat_noise = random.uniform(-noise_degrees, noise_degrees) lon_noise = random.uniform(-noise_degrees, noise_degrees) noisy_lat = round(lat + lat_noise, 6) noisy_lon = round(lon + lon_noise, 6) logger.debug(f"🔊 GPS'ga shovqin qo'shildi: ({lat}, {lon}) → ({noisy_lat}, {noisy_lon})") return { "lat": noisy_lat, "lon": noisy_lon } except Exception as e: logger.error(f"❌ GPS shovqin qo'shishda xatolik: {e}") return {"lat": lat, "lon": lon} def get_all_districts() -> list: """ Barcha tumanlar ro'yxatini olish (dropdown uchun) Returns: [ {"id": "chilonzor", "name": "Chilonzor tumani"}, ... ] """ try: if not DISTRICTS_FILE.exists(): logger.error(f"❌ Districts fayli topilmadi: {DISTRICTS_FILE}") return [] with open(DISTRICTS_FILE, 'r', encoding='utf-8') as f: data = json.load(f) districts = data.get('districts', []) # Faqat kerakli maydonlarni qaytarish result = [ { "id": d.get('id'), "name": d.get('name') } for d in districts ] logger.info(f"✅ {len(result)} ta tuman ro'yxati tayyorlandi") return result except Exception as e: logger.error(f"❌ Tumanlar ro'yxatini olishda xatolik: {e}") return [] def generate_gps_near_location(target_lat: float, target_lon: float, radius_km: float = 2.0) -> Dict[str, float]: """ Berilgan nuqtaga yaqin tasodifiy GPS yaratish Args: target_lat: Maqsad latitude target_lon: Maqsad longitude radius_km: Radius (km) Returns: {"lat": ..., "lon": ...} """ try: # Tasodifiy burchak (0-360 daraja) angle = random.uniform(0, 2 * 3.14159) # Tasodifiy masofa (0 - radius_km) distance = random.uniform(0, radius_km) # 1 km ~ 0.009 daraja distance_degrees = distance * 0.009 # Yangi koordinatalar new_lat = target_lat + distance_degrees * random.choice([-1, 1]) new_lon = target_lon + distance_degrees * random.choice([-1, 1]) # Toshkent chegarasida ekanligini tekshirish new_lat = max(TASHKENT_LAT_MIN, min(TASHKENT_LAT_MAX, new_lat)) new_lon = max(TASHKENT_LON_MIN, min(TASHKENT_LON_MAX, new_lon)) logger.debug(f"📍 Yaqin GPS yaratildi: {distance:.2f}km uzoqlikda") return { "lat": round(new_lat, 6), "lon": round(new_lon, 6) } except Exception as e: logger.error(f"❌ Yaqin GPS yaratishda xatolik: {e}") return {"lat": target_lat, "lon": target_lon}