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
  • 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
comparison.py
utils/comparison.py
Raw Download
Find: Go to:
#!/usr/bin/env python3
"""
Weather Chatbot City Comparison 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: Weather comparison between multiple cities
"""

import json
import statistics
from typing import Dict, List, Optional, Tuple
from datetime import datetime
from .analytics import WeatherAnalytics
from .weather_utils import format_temperature, format_wind_speed, get_weather_emoji

class WeatherComparison:
    """Advanced weather comparison between multiple cities"""
    
    def __init__(self):
        self.analytics = WeatherAnalytics()
    
    def compare_current_weather(self, cities_data: Dict[str, Dict]) -> Dict:
        """
        Compare current weather between multiple cities.
        
        Args:
            cities_data: Dictionary with city names as keys and weather data as values
            
        Returns:
            Comprehensive comparison analysis
        """
        if not cities_data:
            return {'error': 'No city data provided for comparison'}
        
        # Filter out cities with errors
        valid_cities = {city: data for city, data in cities_data.items() 
                       if 'error' not in data and data}
        
        if len(valid_cities) < 2:
            return {'error': 'At least 2 valid cities required for comparison'}
        
        comparison = {
            'comparison_type': 'current_weather',
            'cities_compared': list(valid_cities.keys()),
            'total_cities': len(valid_cities),
            'timestamp': datetime.now().isoformat(),
            'rankings': {},
            'metrics': {},
            'insights': [],
            'best_cities': {},
            'summary': {}
        }
        
        # Extract metrics for comparison
        temperatures = {}
        humidity_levels = {}
        wind_speeds = {}
        pressure_levels = {}
        visibility_levels = {}
        feels_like_temps = {}
        
        for city, data in valid_cities.items():
            temperatures[city] = data.get('temperature', 0)
            humidity_levels[city] = data.get('humidity', 0)
            wind_speeds[city] = data.get('wind_speed', 0)
            pressure_levels[city] = data.get('pressure', 0)
            visibility_levels[city] = data.get('visibility', 0)
            feels_like_temps[city] = data.get('feels_like', 0)
        
        # Temperature rankings
        if temperatures:
            comparison['metrics']['temperature'] = temperatures
            comparison['rankings']['hottest'] = max(temperatures, key=temperatures.get)
            comparison['rankings']['coldest'] = min(temperatures, key=temperatures.get)
            comparison['rankings']['most_comfortable'] = self._find_most_comfortable_temperature(temperatures)
            
            # Temperature insights
            temp_range = max(temperatures.values()) - min(temperatures.values())
            comparison['insights'].append({
                'type': 'temperature_range',
                'title': 'Temperature Range',
                'message': f"Temperature difference: {round(temp_range, 1)}°C between {comparison['rankings']['hottest']} and {comparison['rankings']['coldest']}",
                'icon': '🌡️'
            })
        
        # Humidity rankings
        if humidity_levels:
            comparison['metrics']['humidity'] = humidity_levels
            comparison['rankings']['most_humid'] = max(humidity_levels, key=humidity_levels.get)
            comparison['rankings']['least_humid'] = min(humidity_levels, key=humidity_levels.get)
        
        # Wind rankings
        if wind_speeds:
            comparison['metrics']['wind_speed'] = wind_speeds
            comparison['rankings']['windiest'] = max(wind_speeds, key=wind_speeds.get)
            comparison['rankings']['calmest'] = min(wind_speeds, key=wind_speeds.get)
        
        # Pressure rankings
        if pressure_levels:
            comparison['metrics']['pressure'] = pressure_levels
            comparison['rankings']['highest_pressure'] = max(pressure_levels, key=pressure_levels.get)
            comparison['rankings']['lowest_pressure'] = min(pressure_levels, key=pressure_levels.get)
        
        # Visibility rankings
        if visibility_levels:
            comparison['metrics']['visibility'] = visibility_levels
            comparison['rankings']['best_visibility'] = max(visibility_levels, key=visibility_levels.get)
            comparison['rankings']['worst_visibility'] = min(visibility_levels, key=visibility_levels.get)
        
        # Determine best cities for different activities
        comparison['best_cities'] = self._determine_best_cities(valid_cities)
        
        # Generate summary statistics
        comparison['summary'] = self._generate_summary_stats(valid_cities)
        
        # Add weather condition analysis
        comparison['conditions_analysis'] = self._analyze_weather_conditions(valid_cities)
        
        return comparison
    
    def compare_forecasts(self, cities_forecasts: Dict[str, List[Dict]]) -> Dict:
        """
        Compare weather forecasts between multiple cities.
        
        Args:
            cities_forecasts: Dictionary with city names as keys and forecast data as values
            
        Returns:
            Forecast comparison analysis
        """
        if not cities_forecasts:
            return {'error': 'No forecast data provided for comparison'}
        
        valid_forecasts = {city: data for city, data in cities_forecasts.items() 
                          if 'error' not in data and data and 'forecasts' in data}
        
        if len(valid_forecasts) < 2:
            return {'error': 'At least 2 valid cities required for forecast comparison'}
        
        comparison = {
            'comparison_type': 'forecasts',
            'cities_compared': list(valid_forecasts.keys()),
            'total_cities': len(valid_forecasts),
            'timestamp': datetime.now().isoformat(),
            'forecast_periods': {},
            'trends': {},
            'precipitation_analysis': {},
            'temperature_changes': {},
            'recommendations': []
        }
        
        # Analyze forecast periods
        all_forecasts = {}
        for city, data in valid_forecasts.items():
            forecasts = data.get('forecasts', [])
            all_forecasts[city] = forecasts
        
        # Compare next 24 hours (first 8 forecast periods)
        next_24h = {}
        for city, forecasts in all_forecasts.items():
            next_24h[city] = forecasts[:8]
        
        # Temperature trends
        temp_trends = {}
        for city, forecasts in next_24h.items():
            temps = [f.get('temperature', 0) for f in forecasts]
            if temps:
                temp_trends[city] = {
                    'start_temp': temps[0],
                    'end_temp': temps[-1],
                    'max_temp': max(temps),
                    'min_temp': min(temps),
                    'avg_temp': statistics.mean(temps),
                    'trend': 'rising' if temps[-1] > temps[0] else 'falling' if temps[-1] < temps[0] else 'stable',
                    'volatility': statistics.stdev(temps) if len(temps) > 1 else 0
                }
        
        comparison['forecast_periods']['next_24h'] = temp_trends
        
        # Precipitation analysis
        precipitation = {}
        for city, forecasts in next_24h.items():
            rain_total = sum(f.get('rain', 0) for f in forecasts)
            snow_total = sum(f.get('snow', 0) for f in forecasts)
            rain_periods = len([f for f in forecasts if f.get('rain', 0) > 0])
            snow_periods = len([f for f in forecasts if f.get('snow', 0) > 0])
            
            precipitation[city] = {
                'rain_total_mm': rain_total,
                'snow_total_mm': snow_total,
                'rain_periods': rain_periods,
                'snow_periods': snow_periods,
                'precipitation_probability': (rain_periods + snow_periods) / len(forecasts) * 100
            }
        
        comparison['precipitation_analysis'] = precipitation
        
        # Generate recommendations
        comparison['recommendations'] = self._generate_forecast_recommendations(valid_forecasts, temp_trends, precipitation)
        
        return comparison
    
    def _find_most_comfortable_temperature(self, temperatures: Dict[str, float]) -> str:
        """Find city with most comfortable temperature (20-25°C)"""
        comfort_scores = {}
        
        for city, temp in temperatures.items():
            if 20 <= temp <= 25:
                comfort_scores[city] = 100
            elif 15 <= temp <= 30:
                comfort_scores[city] = 80
            elif 10 <= temp <= 35:
                comfort_scores[city] = 60
            else:
                comfort_scores[city] = 30
        
        return max(comfort_scores, key=comfort_scores.get) if comfort_scores else max(temperatures, key=temperatures.get)
    
    def _determine_best_cities(self, cities_data: Dict[str, Dict]) -> Dict:
        """Determine best cities for different activities"""
        best_cities = {}
        
        # Best for warm weather
        temps = {city: data.get('temperature', 0) for city, data in cities_data.items()}
        if temps:
            best_cities['warm_weather'] = max(temps, key=temps.get)
            best_cities['cool_weather'] = min(temps, key=temps.get)
        
        # Best for outdoor activities (based on comfort index)
        comfort_scores = {}
        for city, data in cities_data.items():
            comfort = self.analytics.calculate_comfort_index(data)
            comfort_scores[city] = comfort.get('comfort_index', 0)
        
        if comfort_scores:
            best_cities['outdoor_activities'] = max(comfort_scores, key=comfort_scores.get)
        
        # Best for clear skies
        clear_skies = {}
        for city, data in cities_data.items():
            description = data.get('description', '').lower()
            if 'clear' in description:
                clear_skies[city] = 100
            elif 'cloud' in description:
                clear_skies[city] = 50
            else:
                clear_skies[city] = 25
        
        if clear_skies:
            best_cities['clear_skies'] = max(clear_skies, key=clear_skies.get)
        
        # Best for low wind (good for outdoor dining)
        wind_speeds = {city: data.get('wind_speed', 0) for city, data in cities_data.items()}
        if wind_speeds:
            best_cities['calm_conditions'] = min(wind_speeds, key=wind_speeds.get)
        
        # Best for good visibility
        visibility = {city: data.get('visibility', 0) for city, data in cities_data.items()}
        if visibility:
            best_cities['best_visibility'] = max(visibility, key=visibility.get)
        
        return best_cities
    
    def _generate_summary_stats(self, cities_data: Dict[str, Dict]) -> Dict:
        """Generate summary statistics for comparison"""
        summary = {
            'average_temperature': 0,
            'average_humidity': 0,
            'average_wind_speed': 0,
            'average_pressure': 0,
            'temperature_range': 0,
            'humidity_range': 0,
            'most_common_condition': '',
            'condition_distribution': {}
        }
        
        # Calculate averages
        temperatures = [data.get('temperature', 0) for data in cities_data.values()]
        humidity = [data.get('humidity', 0) for data in cities_data.values()]
        wind_speeds = [data.get('wind_speed', 0) for data in cities_data.values()]
        pressure = [data.get('pressure', 0) for data in cities_data.values()]
        
        if temperatures:
            summary['average_temperature'] = round(statistics.mean(temperatures), 1)
            summary['temperature_range'] = round(max(temperatures) - min(temperatures), 1)
        
        if humidity:
            summary['average_humidity'] = round(statistics.mean(humidity), 1)
            summary['humidity_range'] = round(max(humidity) - min(humidity), 1)
        
        if wind_speeds:
            summary['average_wind_speed'] = round(statistics.mean(wind_speeds), 1)
        
        if pressure:
            summary['average_pressure'] = round(statistics.mean(pressure), 1)
        
        # Analyze weather conditions
        conditions = [data.get('description', '') for data in cities_data.values()]
        condition_counts = {}
        
        for condition in conditions:
            if condition:
                condition_counts[condition] = condition_counts.get(condition, 0) + 1
        
        if condition_counts:
            summary['most_common_condition'] = max(condition_counts, key=condition_counts.get)
            summary['condition_distribution'] = condition_counts
        
        return summary
    
    def _analyze_weather_conditions(self, cities_data: Dict[str, Dict]) -> Dict:
        """Analyze weather conditions across cities"""
        analysis = {
            'clear_cities': [],
            'cloudy_cities': [],
            'rainy_cities': [],
            'snowy_cities': [],
            'stormy_cities': [],
            'condition_summary': {}
        }
        
        for city, data in cities_data.items():
            description = data.get('description', '').lower()
            
            if 'clear' in description:
                analysis['clear_cities'].append(city)
            elif 'cloud' in description:
                analysis['cloudy_cities'].append(city)
            elif 'rain' in description or 'shower' in description:
                analysis['rainy_cities'].append(city)
            elif 'snow' in description:
                analysis['snowy_cities'].append(city)
            elif 'thunder' in description or 'storm' in description:
                analysis['stormy_cities'].append(city)
        
        # Create summary
        total_cities = len(cities_data)
        analysis['condition_summary'] = {
            'clear_percentage': round(len(analysis['clear_cities']) / total_cities * 100, 1),
            'cloudy_percentage': round(len(analysis['cloudy_cities']) / total_cities * 100, 1),
            'rainy_percentage': round(len(analysis['rainy_cities']) / total_cities * 100, 1),
            'snowy_percentage': round(len(analysis['snowy_cities']) / total_cities * 100, 1),
            'stormy_percentage': round(len(analysis['stormy_cities']) / total_cities * 100, 1)
        }
        
        return analysis
    
    def _generate_forecast_recommendations(self, cities_forecasts: Dict, temp_trends: Dict, precipitation: Dict) -> List[Dict]:
        """Generate recommendations based on forecast comparison"""
        recommendations = []
        
        # Temperature-based recommendations
        if temp_trends:
            rising_cities = [city for city, trend in temp_trends.items() if trend['trend'] == 'rising']
            falling_cities = [city for city, trend in temp_trends.items() if trend['trend'] == 'falling']
            
            if rising_cities:
                recommendations.append({
                    'type': 'temperature',
                    'title': 'Warming Trend',
                    'message': f"Temperatures rising in: {', '.join(rising_cities)}",
                    'icon': '🔺'
                })
            
            if falling_cities:
                recommendations.append({
                    'type': 'temperature',
                    'title': 'Cooling Trend',
                    'message': f"Temperatures falling in: {', '.join(falling_cities)}",
                    'icon': '🔻'
                })
        
        # Precipitation-based recommendations
        if precipitation:
            rainy_cities = [city for city, precip in precipitation.items() if precip['rain_total_mm'] > 0]
            snowy_cities = [city for city, precip in precipitation.items() if precip['snow_total_mm'] > 0]
            
            if rainy_cities:
                recommendations.append({
                    'type': 'precipitation',
                    'title': 'Rain Expected',
                    'message': f"Rain expected in: {', '.join(rainy_cities)}",
                    'icon': '🌧️'
                })
            
            if snowy_cities:
                recommendations.append({
                    'type': 'precipitation',
                    'title': 'Snow Expected',
                    'message': f"Snow expected in: {', '.join(snowy_cities)}",
                    'icon': '❄️'
                })
        
        # Best travel destination
        if cities_forecasts:
            best_destination = self._find_best_travel_destination(cities_forecasts, temp_trends, precipitation)
            if best_destination:
                recommendations.append({
                    'type': 'travel',
                    'title': 'Best Travel Destination',
                    'message': f"Best weather for travel: {best_destination}",
                    'icon': '✈️'
                })
        
        return recommendations
    
    def _find_best_travel_destination(self, cities_forecasts: Dict, temp_trends: Dict, precipitation: Dict) -> Optional[str]:
        """Find best city for travel based on forecasts"""
        travel_scores = {}
        
        for city in cities_forecasts.keys():
            score = 100  # Start with perfect score
            
            # Check temperature trend
            if city in temp_trends:
                trend = temp_trends[city]
                temp = trend['avg_temp']
                
                # Prefer comfortable temperatures (18-24°C)
                if 18 <= temp <= 24:
                    score += 10
                elif 15 <= temp <= 28:
                    score += 5
                else:
                    score -= 10
                
                # Prefer stable temperatures
                if trend['volatility'] < 5:
                    score += 5
                elif trend['volatility'] > 10:
                    score -= 5
            
            # Check precipitation
            if city in precipitation:
                precip = precipitation[city]
                
                # Lower precipitation is better for travel
                if precip['precipitation_probability'] < 20:
                    score += 10
                elif precip['precipitation_probability'] > 60:
                    score -= 15
            
            travel_scores[city] = score
        
        return max(travel_scores, key=travel_scores.get) if travel_scores else None
    
    def create_comparison_table(self, comparison_data: Dict) -> str:
        """Create a formatted comparison table"""
        if 'error' in comparison_data:
            return f"Error: {comparison_data['error']}"
        
        table = f"""
🌍 WEATHER COMPARISON REPORT
{'='*60}

Cities Compared: {', '.join(comparison_data.get('cities_compared', []))}
Comparison Type: {comparison_data.get('comparison_type', 'Unknown')}
Generated: {comparison_data.get('timestamp', 'Unknown')}

{'='*60}

"""
        
        # Add rankings
        rankings = comparison_data.get('rankings', {})
        if rankings:
            table += "🏆 RANKINGS:\n"
            for ranking_type, city in rankings.items():
                table += f"  • {ranking_type.replace('_', ' ').title()}: {city}\n"
            table += "\n"
        
        # Add best cities
        best_cities = comparison_data.get('best_cities', {})
        if best_cities:
            table += "⭐ BEST CITIES FOR:\n"
            for activity, city in best_cities.items():
                table += f"  • {activity.replace('_', ' ').title()}: {city}\n"
            table += "\n"
        
        # Add metrics
        metrics = comparison_data.get('metrics', {})
        if metrics:
            table += "📊 METRICS:\n"
            for metric_type, values in metrics.items():
                table += f"  {metric_type.replace('_', ' ').title()}:\n"
                for city, value in values.items():
                    if 'temperature' in metric_type:
                        formatted_value = f"{value}°C"
                    elif 'wind' in metric_type:
                        formatted_value = f"{value} m/s"
                    elif 'humidity' in metric_type:
                        formatted_value = f"{value}%"
                    elif 'pressure' in metric_type:
                        formatted_value = f"{value} hPa"
                    elif 'visibility' in metric_type:
                        formatted_value = f"{value} km"
                    else:
                        formatted_value = str(value)
                    
                    table += f"    {city}: {formatted_value}\n"
            table += "\n"
        
        # Add insights
        insights = comparison_data.get('insights', [])
        if insights:
            table += "💡 INSIGHTS:\n"
            for insight in insights:
                table += f"  {insight.get('icon', '📊')} {insight.get('title', '')}: {insight.get('message', '')}\n"
            table += "\n"
        
        # Add summary
        summary = comparison_data.get('summary', {})
        if summary:
            table += "📈 SUMMARY:\n"
            for key, value in summary.items():
                if isinstance(value, dict):
                    table += f"  {key.replace('_', ' ').title()}:\n"
                    for sub_key, sub_value in value.items():
                        table += f"    {sub_key}: {sub_value}\n"
                else:
                    table += f"  {key.replace('_', ' ').title()}: {value}\n"
        
        table += f"\n{'='*60}\n"
        table += f"Report generated by Weather Chatbot - RSK World (https://rskworld.in)\n"
        table += f"© 2026 RSK World. All rights reserved.\n"
        
        return table
    
    def export_comparison_data(self, comparison_data: Dict, format_type: str = 'json') -> str:
        """Export comparison data in different formats"""
        if format_type == 'json':
            return json.dumps(comparison_data, indent=2, default=str)
        elif format_type == 'table':
            return self.create_comparison_table(comparison_data)
        elif format_type == 'csv':
            return self._create_csv_export(comparison_data)
        else:
            return json.dumps(comparison_data, indent=2, default=str)
    
    def _create_csv_export(self, comparison_data: Dict) -> str:
        """Create CSV export of comparison data"""
        import csv
        import io
        
        output = io.StringIO()
        
        if comparison_data.get('comparison_type') == 'current_weather':
            writer = csv.writer(output)
            
            # Header
            writer.writerow(['City', 'Temperature (°C)', 'Feels Like (°C)', 'Humidity (%)', 
                           'Wind Speed (m/s)', 'Pressure (hPa)', 'Visibility (km)', 'Description'])
            
            # Data rows
            metrics = comparison_data.get('metrics', {})
            cities = comparison_data.get('cities_compared', [])
            
            for city in cities:
                row = [city]
                row.append(metrics.get('temperature', {}).get(city, 'N/A'))
                row.append(metrics.get('feels_like', {}).get(city, 'N/A'))
                row.append(metrics.get('humidity', {}).get(city, 'N/A'))
                row.append(metrics.get('wind_speed', {}).get(city, 'N/A'))
                row.append(metrics.get('pressure', {}).get(city, 'N/A'))
                row.append(metrics.get('visibility', {}).get(city, 'N/A'))
                row.append('N/A')  # Description would need to be added to metrics
                writer.writerow(row)
        
        return output.getvalue()
577 lines•24.2 KB
python

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