help@rskworld.in +91 93305 39277
RSK World
  • Home
  • Development
    • Web Development
    • Mobile Apps
    • Software
    • Games
    • Project
  • Technologies
    • Data Science
    • AI Development
    • Cloud Development
    • Blockchain
    • Cyber Security
    • Dev Tools
    • Testing Tools
  • Blog
  • About
  • Contact

Theme Settings

Color Scheme
Display Options
Font Size
100%
Back to Project
RSK World
weather-chatbot
/
utils
RSK World
weather-chatbot
Weather Chatbot - Python + Flask + OpenWeatherMap + OpenAI + Weather Forecast + Weather Alerts + Natural Language Processing
utils
  • __pycache__
  • __init__.py3.9 KB
  • advanced_nlp.py28.4 KB
  • analytics.py22 KB
  • auth.py17.8 KB
  • comparison.py24.2 KB
  • database.py24.6 KB
  • geolocation.py20.1 KB
  • multilang.py22 KB
  • notifications.py34.1 KB
  • rate_limiting.py24.3 KB
  • weather_maps.py29.6 KB
  • weather_utils.py12.9 KB
handlers.cpython-313.pycconfig.pysecurity.cpython-313.pycentity_extractor.pyPhysicsCalculatorService.swift.gitignoregeolocation.py
config.py
Raw Download
Find: Go to:
#!/usr/bin/env python3
"""
Weather Chatbot Configuration
============================

Author: RSK World (https://rskworld.in)
Founded by: Molla Samser
Designer & Tester: Rima Khatun
Contact: +91 93305 39277, hello@rskworld.in, support@rskworld.in
Location: Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India, 713147
Year: 2026

Description: Configuration settings for the Weather Chatbot application
"""

import os
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

class Config:
    """Base configuration class for Weather Chatbot"""
    
    # Basic Flask Configuration
    SECRET_KEY = os.getenv('SECRET_KEY', 'weather-chatbot-secret-key-2026')
    DEBUG = os.getenv('FLASK_DEBUG', 'True').lower() == 'true'
    
    # Server Configuration
    HOST = os.getenv('HOST', '0.0.0.0')
    PORT = int(os.getenv('PORT', 5000))
    
    # API Keys
    OPENWEATHER_API_KEY = os.getenv('OPENWEATHER_API_KEY')
    OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
    
    # Weather API Configuration
    WEATHER_UNITS = os.getenv('WEATHER_UNITS', 'metric')
    WEATHER_LANGUAGE = os.getenv('WEATHER_LANGUAGE', 'en')
    DEFAULT_CITY = os.getenv('DEFAULT_CITY', 'London')
    
    # OpenWeatherMap API URLs
    OPENWEATHER_BASE_URL = "https://api.openweathermap.org/data/2.5"
    OPENWEATHER_GEO_URL = "http://api.openweathermap.org/geo/1.0"
    
    # Logging Configuration
    LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
    LOG_FILE = os.getenv('LOG_FILE', 'logs/weather_chatbot.log')
    
    # Rate Limiting
    RATE_LIMIT_ENABLED = os.getenv('RATE_LIMIT_ENABLED', 'True').lower() == 'true'
    RATE_LIMIT_PER_MINUTE = int(os.getenv('RATE_LIMIT_PER_MINUTE', 30))
    
    # Cache Configuration
    CACHE_ENABLED = os.getenv('CACHE_ENABLED', 'False').lower() == 'true'
    CACHE_TTL = int(os.getenv('CACHE_TTL', 300))  # 5 minutes
    
    # Database Configuration (for chat history)
    DATABASE_URL = os.getenv('DATABASE_URL', 'sqlite:///weather_chatbot.db')
    
    # CORS Configuration
    CORS_ORIGINS = os.getenv('CORS_ORIGINS', '*').split(',')
    
    # Security Configuration
    SESSION_COOKIE_SECURE = os.getenv('SESSION_COOKIE_SECURE', 'False').lower() == 'true'
    SESSION_COOKIE_HTTPONLY = os.getenv('SESSION_COOKIE_HTTPONLY', 'True').lower() == 'true'
    SESSION_COOKIE_SAMESITE = os.getenv('SESSION_COOKIE_SAMESITE', 'Lax')
    
    # Application Information
    APP_NAME = "Weather Chatbot"
    APP_VERSION = "1.0.0"
    APP_AUTHOR = "RSK World"
    APP_WEBSITE = "https://rskworld.in"
    APP_YEAR = "2026"
    
    # Supported Cities for Quick Access
    SUPPORTED_CITIES = [
        'London', 'New York', 'Paris', 'Tokyo', 'Delhi', 'Mumbai', 
        'Kolkata', 'Chennai', 'Bangalore', 'Sydney', 'Moscow', 
        'Beijing', 'Dubai', 'Singapore', 'Hong Kong'
    ]
    
    # Weather Alert Thresholds
    ALERT_TEMPERATURE_HIGH = 40.0  # Celsius
    ALERT_TEMPERATURE_LOW = -10.0  # Celsius
    ALERT_WIND_SPEED_HIGH = 20.0   # m/s
    ALERT_HUMIDITY_HIGH = 90.0     # Percentage
    
    @staticmethod
    def validate_config():
        """Validate required configuration settings"""
        errors = []
        
        if not Config.OPENWEATHER_API_KEY:
            errors.append("OPENWEATHER_API_KEY is required")
        
        if errors:
            raise ValueError("Configuration validation failed: " + ", ".join(errors))
        
        return True
    
    @staticmethod
    def get_app_info():
        """Get application information"""
        return {
            'name': Config.APP_NAME,
            'version': Config.APP_VERSION,
            'author': Config.APP_AUTHOR,
            'website': Config.APP_WEBSITE,
            'year': Config.APP_YEAR,
            'contact': {
                'phone': '+91 93305 39277',
                'email': 'hello@rskworld.in',
                'support': 'support@rskworld.in'
            },
            'location': 'Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India, 713147'
        }

class DevelopmentConfig(Config):
    """Development configuration"""
    DEBUG = True
    LOG_LEVEL = 'DEBUG'

class ProductionConfig(Config):
    """Production configuration"""
    DEBUG = False
    SESSION_COOKIE_SECURE = True
    LOG_LEVEL = 'WARNING'

class TestingConfig(Config):
    """Testing configuration"""
    TESTING = True
    DEBUG = True
    OPENWEATHER_API_KEY = 'test_key'
    OPENAI_API_KEY = 'test_key'

# Configuration mapping
config_map = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'testing': TestingConfig,
    'default': DevelopmentConfig
}

def get_config(config_name=None):
    """Get configuration based on environment"""
    if config_name is None:
        config_name = os.getenv('FLASK_ENV', 'default')
    
    return config_map.get(config_name, DevelopmentConfig)
151 lines•4.9 KB
python
.gitignore
Raw Download
Find: Go to:
# Weather Chatbot Git Ignore File
# =================================
#
# Author: RSK World (https://rskworld.in)
# Founded by: Molla Samser
# Designer & Tester: Rima Khatun
# Contact: +91 93305 39277, hello@rskworld.in, support@rskworld.in
# Location: Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India, 713147
# Year: 2026

# Environment variables
.env
.env.local
.env.development
.env.test
.env.production

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Virtual environments
venv/
env/
ENV/
.venv/
.env/

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Coverage directory used by tools like istanbul
coverage/
*.lcov

# nyc test coverage
.nyc_output

# Dependency directories
node_modules/
jspm_packages/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
public

# Storybook build outputs
.out
.storybook-out

# Temporary folders
tmp/
temp/

# Database files
*.db
*.sqlite
*.sqlite3

# Flask specific
instance/
.webassets-cache

# Pytest
.pytest_cache/
.coverage
htmlcov/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# pipenv
Pipfile.lock

# PEP 582
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# Application specific
uploads/
static/uploads/
cache/
sessions/

# API Keys and secrets
secrets.json
config.json
api_keys.txt

# Backup files
*.bak
*.backup
*.old

# Compressed files
*.zip
*.tar.gz
*.rar

# Documentation build
docs/_build/

# Local development
local/
dev/
test_data/
201 lines•2.4 KB
text
utils/geolocation.py
Raw Download
Find: Go to:
#!/usr/bin/env python3
"""
Weather Chatbot Geolocation Module
===================================

Author: RSK World (https://rskworld.in)
Founded by: Molla Samser
Designer & Tester: Rima Khatun
Contact: +91 93305 39277, hello@rskworld.in, support@rskworld.in
Location: Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India, 713147
Year: 2026

Description: Location detection and geolocation services
"""

import requests
import json
from typing import Dict, Optional, Tuple
from urllib.parse import quote

class GeolocationService:
    """Geolocation service for location-based weather services"""
    
    def __init__(self, ipinfo_api_key: str = None, openweather_api_key: str = None):
        self.ipinfo_api_key = ipinfo_api_key
        self.openweather_api_key = openweather_api_key
        self.ipinfo_url = "https://ipinfo.io"
        self.openweather_geo_url = "http://api.openweathermap.org/geo/1.0"
    
    def get_location_by_ip(self, ip_address: str = None) -> Dict:
        """
        Get location information by IP address.
        
        Args:
            ip_address: IP address (if None, uses current IP)
            
        Returns:
            Location information dictionary
        """
        try:
            url = f"{self.ipinfo_url}/{ip_address}" if ip_address else self.ipinfo_url
            params = {}
            
            if self.ipinfo_api_key:
                params['token'] = self.ipinfo_api_key
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            data = response.json()
            
            location_info = {
                'ip': data.get('ip'),
                'city': data.get('city'),
                'region': data.get('region'),
                'country': data.get('country'),
                'location': data.get('loc'),  # lat,lon
                'postal': data.get('postal'),
                'timezone': data.get('timezone'),
                'org': data.get('org'),  # ISP/organization
                'source': 'ipinfo'
            }
            
            # Parse coordinates
            if data.get('loc'):
                try:
                    lat, lon = data['loc'].split(',')
                    location_info['latitude'] = float(lat)
                    location_info['longitude'] = float(lon)
                except:
                    location_info['latitude'] = None
                    location_info['longitude'] = None
            
            return location_info
            
        except requests.exceptions.RequestException as e:
            return {'error': f'Failed to get location by IP: {str(e)}'}
        except Exception as e:
            return {'error': f'Error processing location data: {str(e)}'}
    
    def get_coordinates_by_city(self, city: str, country: str = None, state: str = None) -> Dict:
        """
        Get coordinates for a city using OpenWeatherMap Geocoding API.
        
        Args:
            city: City name
            country: Country code (optional)
            state: State code (optional, for US cities)
            
        Returns:
            Coordinates and location information
        """
        try:
            # Build query string
            query_parts = [city]
            if state:
                query_parts.append(state)
            if country:
                query_parts.append(country)
            
            query = ','.join(query_parts)
            
            url = f"{self.openweather_geo_url}/direct"
            params = {
                'q': query,
                'limit': 5,  # Get multiple results for disambiguation
                'appid': self.openweather_api_key
            }
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            data = response.json()
            
            if not data:
                return {'error': 'City not found'}
            
            # Return the first (most relevant) result
            result = data[0]
            
            return {
                'city': result.get('name'),
                'country': result.get('country'),
                'state': result.get('state'),
                'latitude': result.get('lat'),
                'longitude': result.get('lon'),
                'source': 'openweathermap',
                'alternatives': data[1:] if len(data) > 1 else []
            }
            
        except requests.exceptions.RequestException as e:
            return {'error': f'Failed to get coordinates: {str(e)}'}
        except Exception as e:
            return {'error': f'Error processing coordinates: {str(e)}'}
    
    def get_city_by_coordinates(self, lat: float, lon: float, limit: int = 1) -> Dict:
        """
        Get city information by coordinates using reverse geocoding.
        
        Args:
            lat: Latitude
            lon: Longitude
            limit: Number of results to return
            
        Returns:
            City information
        """
        try:
            url = f"{self.openweather_geo_url}/reverse"
            params = {
                'lat': lat,
                'lon': lon,
                'limit': limit,
                'appid': self.openweather_api_key
            }
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            data = response.json()
            
            if not data:
                return {'error': 'No location found for coordinates'}
            
            # Return the first result
            result = data[0]
            
            return {
                'city': result.get('name'),
                'country': result.get('country'),
                'state': result.get('state'),
                'latitude': result.get('lat'),
                'longitude': result.get('lon'),
                'source': 'openweathermap_reverse',
                'alternatives': data[1:] if len(data) > 1 else []
            }
            
        except requests.exceptions.RequestException as e:
            return {'error': f'Failed to get city by coordinates: {str(e)}'}
        except Exception as e:
            return {'error': f'Error processing reverse geocoding: {str(e)}'}
    
    def search_locations(self, query: str, limit: int = 5) -> Dict:
        """
        Search for locations by name.
        
        Args:
            query: Search query
            limit: Maximum number of results
            
        Returns:
            List of matching locations
        """
        try:
            url = f"{self.openweather_geo_url}/direct"
            params = {
                'q': query,
                'limit': limit,
                'appid': self.openweather_api_key
            }
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            data = response.json()
            
            if not data:
                return {'results': [], 'message': 'No locations found'}
            
            results = []
            for result in data:
                location = {
                    'city': result.get('name'),
                    'country': result.get('country'),
                    'state': result.get('state'),
                    'latitude': result.get('lat'),
                    'longitude': result.get('lon'),
                    'display_name': self._format_location_name(result)
                }
                results.append(location)
            
            return {
                'results': results,
                'count': len(results),
                'source': 'openweathermap'
            }
            
        except requests.exceptions.RequestException as e:
            return {'error': f'Failed to search locations: {str(e)}'}
        except Exception as e:
            return {'error': f'Error processing search: {str(e)}'}
    
    def _format_location_name(self, location_data: Dict) -> str:
        """Format location name for display"""
        parts = [location_data.get('name', '')]
        
        if location_data.get('state'):
            parts.append(location_data['state'])
        
        if location_data.get('country'):
            parts.append(location_data['country'])
        
        return ', '.join(parts)
    
    def calculate_distance(self, lat1: float, lon1: float, lat2: float, lon2: float) -> float:
        """
        Calculate distance between two coordinates using Haversine formula.
        
        Args:
            lat1, lon1: First point coordinates
            lat2, lon2: Second point coordinates
            
        Returns:
            Distance in kilometers
        """
        import math
        
        # Convert to radians
        lat1_rad = math.radians(lat1)
        lon1_rad = math.radians(lon1)
        lat2_rad = math.radians(lat2)
        lon2_rad = math.radians(lon2)
        
        # Haversine formula
        dlat = lat2_rad - lat1_rad
        dlon = lon2_rad - lon1_rad
        
        a = (math.sin(dlat/2)**2 + 
             math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlon/2)**2)
        c = 2 * math.asin(math.sqrt(a))
        
        # Earth's radius in kilometers
        r = 6371
        
        return c * r
    
    def find_nearby_cities(self, lat: float, lon: float, radius_km: float = 50, limit: int = 10) -> Dict:
        """
        Find cities near a given location.
        
        Args:
            lat, lon: Center coordinates
            radius_km: Search radius in kilometers
            limit: Maximum number of results
            
        Returns:
            List of nearby cities with distances
        """
        try:
            # Get current city first
            current_city = self.get_city_by_coordinates(lat, lon, limit=1)
            
            if 'error' in current_city:
                return current_city
            
            # Search for nearby locations (this is a simplified approach)
            # In practice, you might want to use a dedicated geospatial database
            search_query = f"{current_city['city']}"
            
            search_results = self.search_locations(search_query, limit=limit * 2)
            
            if 'error' in search_results:
                return search_results
            
            # Calculate distances and filter by radius
            nearby_cities = []
            
            for location in search_results['results']:
                # Skip the exact same location
                if (abs(location['latitude'] - lat) < 0.01 and 
                    abs(location['longitude'] - lon) < 0.01):
                    continue
                
                distance = self.calculate_distance(
                    lat, lon, 
                    location['latitude'], location['longitude']
                )
                
                if distance <= radius_km:
                    location['distance_km'] = round(distance, 1)
                    nearby_cities.append(location)
            
            # Sort by distance and limit results
            nearby_cities.sort(key=lambda x: x['distance_km'])
            nearby_cities = nearby_cities[:limit]
            
            return {
                'center_location': current_city,
                'nearby_cities': nearby_cities,
                'radius_km': radius_km,
                'count': len(nearby_cities)
            }
            
        except Exception as e:
            return {'error': f'Error finding nearby cities: {str(e)}'}
    
    def get_timezone_info(self, lat: float, lon: float) -> Dict:
        """
        Get timezone information for coordinates.
        
        Args:
            lat, lon: Coordinates
            
        Returns:
            Timezone information
        """
        try:
            if not self.openweather_api_key:
                return {'error': 'OpenWeatherMap API key required'}
            
            url = f"http://api.openweathermap.org/data/2.5/weather"
            params = {
                'lat': lat,
                'lon': lon,
                'appid': self.openweather_api_key
            }
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            data = response.json()
            
            timezone_offset = data.get('timezone', 0)  # Offset in seconds
            
            # Convert to hours
            timezone_hours = timezone_offset / 3600
            
            # Determine timezone name (simplified)
            timezone_name = self._get_timezone_name(timezone_hours)
            
            return {
                'timezone_offset_seconds': timezone_offset,
                'timezone_offset_hours': timezone_hours,
                'timezone_name': timezone_name,
                'utc_offset': f"{'+' if timezone_hours >= 0 else ''}{timezone_hours}:00",
                'source': 'openweathermap'
            }
            
        except requests.exceptions.RequestException as e:
            return {'error': f'Failed to get timezone info: {str(e)}'}
        except Exception as e:
            return {'error': f'Error processing timezone: {str(e)}'}
    
    def _get_timezone_name(self, offset_hours: float) -> str:
        """Get timezone name from UTC offset (simplified)"""
        timezone_map = {
            -12: 'UTC-12 (Baker Island Time)',
            -11: 'UTC-11 (Niue Time)',
            -10: 'UTC-10 (Hawaii-Aleutian Standard Time)',
            -9: 'UTC-9 (Alaska Standard Time)',
            -8: 'UTC-8 (Pacific Standard Time)',
            -7: 'UTC-7 (Mountain Standard Time)',
            -6: 'UTC-6 (Central Standard Time)',
            -5: 'UTC-5 (Eastern Standard Time)',
            -4: 'UTC-4 (Atlantic Standard Time)',
            -3: 'UTC-3 (Brazil Time)',
            -2: 'UTC-2 (Fernando de Noronha Time)',
            -1: 'UTC-1 (Azores Time)',
            0: 'UTC (Greenwich Mean Time)',
            1: 'UTC+1 (Central European Time)',
            2: 'UTC+2 (Eastern European Time)',
            3: 'UTC+3 (Moscow Time)',
            4: 'UTC+4 (Gulf Standard Time)',
            5: 'UTC+5 (Pakistan Standard Time)',
            5.5: 'UTC+5:30 (India Standard Time)',
            6: 'UTC+6 (Bangladesh Standard Time)',
            7: 'UTC+7 (Indochina Time)',
            8: 'UTC+8 (China Standard Time)',
            9: 'UTC+9 (Japan Standard Time)',
            10: 'UTC+10 (Australian Eastern Time)',
            11: 'UTC+11 (Solomon Islands Time)',
            12: 'UTC+12 (New Zealand Time)',
        }
        
        # Find closest match
        closest_offset = min(timezone_map.keys(), key=lambda x: abs(x - offset_hours))
        
        if abs(closest_offset - offset_hours) < 0.5:
            return timezone_map[closest_offset]
        else:
            return f"UTC{offset_hours:+.1f}"
    
    def validate_coordinates(self, lat: float, lon: float) -> Dict:
        """
        Validate latitude and longitude coordinates.
        
        Args:
            lat: Latitude
            lon: Longitude
            
        Returns:
            Validation result
        """
        try:
            # Check ranges
            if not (-90 <= lat <= 90):
                return {'valid': False, 'error': 'Latitude must be between -90 and 90'}
            
            if not (-180 <= lon <= 180):
                return {'valid': False, 'error': 'Longitude must be between -180 and 180'}
            
            # Check data types
            if not isinstance(lat, (int, float)) or not isinstance(lon, (int, float)):
                return {'valid': False, 'error': 'Coordinates must be numeric'}
            
            # Check for NaN or infinity
            import math
            if math.isnan(lat) or math.isnan(lon) or math.isinf(lat) or math.isinf(lon):
                return {'valid': False, 'error': 'Invalid coordinate values'}
            
            return {
                'valid': True,
                'latitude': lat,
                'longitude': lon,
                'formatted': f"{lat:.6f}, {lon:.6f}"
            }
            
        except Exception as e:
            return {'valid': False, 'error': f'Error validating coordinates: {str(e)}'}
    
    def get_location_summary(self, ip_address: str = None) -> Dict:
        """
        Get comprehensive location summary.
        
        Args:
            ip_address: IP address (optional)
            
        Returns:
            Complete location information
        """
        try:
            # Get IP-based location
            ip_location = self.get_location_by_ip(ip_address)
            
            if 'error' in ip_location:
                return ip_location
            
            summary = {
                'ip_info': ip_location,
                'coordinates': {
                    'latitude': ip_location.get('latitude'),
                    'longitude': ip_location.get('longitude')
                },
                'address': {
                    'city': ip_location.get('city'),
                    'region': ip_location.get('region'),
                    'country': ip_location.get('country'),
                    'postal': ip_location.get('postal')
                },
                'network': {
                    'ip': ip_location.get('ip'),
                    'isp': ip_location.get('org'),
                    'timezone': ip_location.get('timezone')
                }
            }
            
            # Add timezone info if coordinates are available
            if ip_location.get('latitude') and ip_location.get('longitude'):
                timezone_info = self.get_timezone_info(
                    ip_location['latitude'], 
                    ip_location['longitude']
                )
                summary['timezone'] = timezone_info
            
            # Find nearby cities if coordinates are available
            if ip_location.get('latitude') and ip_location.get('longitude'):
                nearby = self.find_nearby_cities(
                    ip_location['latitude'], 
                    ip_location['longitude'], 
                    radius_km=25, 
                    limit=5
                )
                summary['nearby_cities'] = nearby
            
            return summary
            
        except Exception as e:
            return {'error': f'Error generating location summary: {str(e)}'}

# Utility functions for location data
def format_coordinates(lat: float, lon: float, format_type: str = 'decimal') -> str:
    """Format coordinates in different formats"""
    if format_type == 'decimal':
        return f"{lat:.6f}, {lon:.6f}"
    elif format_type == 'dms':
        return f"{_decimal_to_dms(lat, 'latitude')}, {_decimal_to_dms(lon, 'longitude')}"
    else:
        return f"{lat:.6f}, {lon:.6f}"

def _decimal_to_dms(decimal: float, coordinate_type: str) -> str:
    """Convert decimal coordinates to DMS format"""
    import math
    
    absolute = abs(decimal)
    degrees = int(absolute)
    minutes_float = (absolute - degrees) * 60
    minutes = int(minutes_float)
    seconds = (minutes_float - minutes) * 60
    
    direction = ''
    if coordinate_type == 'latitude':
        direction = 'N' if decimal >= 0 else 'S'
    else:  # longitude
        direction = 'E' if decimal >= 0 else 'W'
    
    return f"{degrees}°{minutes}'{seconds:.1f}\"{direction}"

def parse_coordinates(coord_string: str) -> Optional[Tuple[float, float]]:
    """Parse coordinate string and return (lat, lon) tuple"""
    try:
        # Remove whitespace and split
        parts = coord_string.strip().replace(' ', '').split(',')
        
        if len(parts) != 2:
            return None
        
        lat = float(parts[0])
        lon = float(parts[1])
        
        return (lat, lon)
        
    except:
        return None
564 lines•20.1 KB
python
🚀 Support RSK World

Subscribe to our YouTube channel for latest tutorials & updates!



Click subscribe & support our work ❤️

About RSK World

Founded by Molla Samser, with Designer & Tester Rima Khatun, RSK World is your one-stop destination for free programming resources, source code, and development tools.

Founder: Molla Samser
Designer & Tester: Rima Khatun

Development

  • Game Development
  • Web Development
  • Mobile Development
  • AI Development
  • Development Tools

Legal

  • Terms & Conditions
  • Privacy Policy
  • Disclaimer

Contact Info

Nutanhat, Mongolkote
Purba Burdwan, West Bengal
India, 713147

+91 93305 39277

hello@rskworld.in
support@rskworld.in

© 2026 RSK World. All rights reserved.

Content used for educational purposes only. View Disclaimer