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
RSK World
weather-chatbot
Weather Chatbot - Python + Flask + OpenWeatherMap + OpenAI + Weather Forecast + Weather Alerts + Natural Language Processing
weather-chatbot
  • __pycache__
  • cache
  • logs
  • scripts
  • sessions
  • static
  • templates
  • tests
  • utils
  • .dockerignore778 B
  • .env.example1.5 KB
  • .gitignore2.4 KB
  • .pre-commit-config.yaml1 KB
  • API.md7.9 KB
  • CHANGELOG.md2.4 KB
  • CHECKLIST.md5.4 KB
  • CONTRIBUTING.md1.9 KB
  • Dockerfile1.4 KB
  • FEATURES.md7.1 KB
  • FINAL_CHECK.md6.7 KB
  • GITHUB_RELEASE_INSTRUCTIONS.md5.4 KB
  • INSTALL.md4 KB
  • LICENSE1.3 KB
  • MANIFEST.in553 B
  • Makefile2 KB
  • PROJECT_SUMMARY.md12.9 KB
  • README.md7.2 KB
  • RELEASE_NOTES_v1.0.0.md8.9 KB
  • VERIFICATION_REPORT.md9.2 KB
  • app.py22.2 KB
  • chatbot.py1.7 KB
  • config.py4.9 KB
  • docker-compose.yml2.2 KB
  • nginx.conf2.3 KB
  • pytest.ini549 B
  • requirements.txt1.9 KB
  • run.py3.1 KB
  • setup.py3.1 KB
  • weather_api.py578 B
ADVANCED_FEATURES.mdCONTRIBUTING.mddemo.htmlDockerfile.env.examplerun.pyapp.py
CONTRIBUTING.md
Raw Download

CONTRIBUTING.md

# Contributing to Weather Chatbot
## ===============================

**Author:** RSK World (https://rskworld.in)
**Year:** 2026

Thank you for your interest in contributing to Weather Chatbot! This document provides guidelines and instructions for contributing.

## How to Contribute

### Reporting Bugs

1. Check if the bug has already been reported in the Issues section
2. Create a new issue with a clear title and description
3. Include steps to reproduce the bug
4. Include error messages and logs if applicable
5. Specify your environment (OS, Python version, etc.)

### Suggesting Features

1. Check if the feature has already been suggested
2. Create a new issue with the `enhancement` label
3. Describe the feature and its use case
4. Explain why it would be useful

### Pull Requests

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Write or update tests if needed
5. Ensure all tests pass (`pytest`)
6. Update documentation if needed
7. Commit your changes (`git commit -m 'Add amazing feature'`)
8. Push to your branch (`git push origin feature/amazing-feature`)
9. Open a Pull Request

## Code Style

- Follow PEP 8 style guide
- Use meaningful variable and function names
- Add docstrings to functions and classes
- Keep functions focused and single-purpose
- Write comments for complex logic

## Testing

- Write tests for new features
- Ensure all tests pass before submitting PR
- Aim for good test coverage
- Include both unit and integration tests

## Documentation

- Update README.md if adding new features
- Update API.md for API changes
- Add docstrings to new functions/classes
- Include examples in documentation

## Questions?

For questions, contact:
- Email: hello@rskworld.in
- Phone: +91 93305 39277
- Website: https://rskworld.in

---

**Ā© 2026 RSK World. All rights reserved.**
Dockerfile
Raw Download
Find: Go to:
# Weather Chatbot Dockerfile
# ==========================
#
# 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: Docker configuration for Weather Chatbot application

# Use Python 3.11 slim image
FROM python:3.11-slim

# Set working directory
WORKDIR /app

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV FLASK_APP=app.py
ENV FLASK_ENV=production

# Install system dependencies
RUN apt-get update && apt-get install -y \
    gcc \
    g++ \
    make \
    libffi-dev \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

# Copy requirements file
COPY requirements.txt .

# Install Python dependencies
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt

# Copy application files
COPY . .

# Create necessary directories
RUN mkdir -p logs static/uploads cache sessions

# Set permissions
RUN chmod -R 755 /app

# Expose port
EXPOSE 5000

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD python -c "import requests; requests.get('http://localhost:5000/health')"

# Run the application
CMD ["python", "run.py"]
59 lines•1.4 KB
text
.env.example
Raw Download
Find: Go to:
# Weather Chatbot Environment 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
#
# Copy this file to .env and fill in your actual API keys and configuration

# OpenWeatherMap API Key
# Get your free API key from: https://openweathermap.org/api
OPENWEATHER_API_KEY=your_openweathermap_api_key_here

# OpenAI API Key (Optional - for natural language processing)
# Get your API key from: https://platform.openai.com/api-keys
OPENAI_API_KEY=your_openai_api_key_here

# Flask Configuration
SECRET_KEY=your_secret_key_here_for_flask_sessions
FLASK_ENV=development
FLASK_DEBUG=True

# Server Configuration
HOST=0.0.0.0
PORT=5000

# Logging Configuration
LOG_LEVEL=INFO
LOG_FILE=logs/weather_chatbot.log

# Rate Limiting
RATE_LIMIT_ENABLED=True
RATE_LIMIT_PER_MINUTE=30

# Weather API Configuration
WEATHER_UNITS=metric
WEATHER_LANGUAGE=en
DEFAULT_CITY=London

# Cache Configuration (optional)
CACHE_ENABLED=False
CACHE_TTL=300

# Database Configuration (optional - for chat history)
DATABASE_URL=sqlite:///weather_chatbot.db

# CORS Configuration
CORS_ORIGINS=*

# Security Configuration
SESSION_COOKIE_SECURE=False
SESSION_COOKIE_HTTPONLY=True
SESSION_COOKIE_SAMESITE=Lax
57 lines•1.5 KB
text
run.py
Raw Download
Find: Go to:
#!/usr/bin/env python3
"""
Weather Chatbot Runner
======================

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: Entry point for the Weather Chatbot application
"""

import os
import sys
from app import app

def main():
    """Main entry point for the Weather Chatbot application"""
    
    # Print startup banner
    print("=" * 60)
    print("šŸŒ¤ļø  Weather Chatbot - RSK World")
    print("=" * 60)
    print("Author: RSK World (https://rskworld.in)")
    print("Founded by: Molla Samser")
    print("Designer & Tester: Rima Khatun")
    print("Contact: +91 93305 39277")
    print("Email: hello@rskworld.in, support@rskworld.in")
    print("Location: Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India")
    print("Year: 2026")
    print("=" * 60)
    print("Features:")
    print("• Real-time weather data")
    print("• Weather forecasts")
    print("• Weather alerts")
    print("• Natural language processing")
    print("• Web interface")
    print("=" * 60)
    
    # Check environment variables
    openweather_key = os.getenv('OPENWEATHER_API_KEY')
    openai_key = os.getenv('OPENAI_API_KEY')
    
    if not openweather_key:
        print("āš ļø  Warning: OPENWEATHER_API_KEY not found in environment variables")
        print("   Get your free API key from: https://openweathermap.org/api")
        print("   Set it in your .env file or environment variables")
    else:
        print("āœ… OpenWeatherMap API key configured")
    
    if not openai_key:
        print("āš ļø  Warning: OPENAI_API_KEY not found (optional)")
        print("   Chatbot will work with keyword matching")
        print("   For enhanced NLP, get API key from: https://platform.openai.com/api-keys")
    else:
        print("āœ… OpenAI API key configured")
    
    print("=" * 60)
    
    # Get configuration
    host = os.getenv('HOST', '0.0.0.0')
    port = int(os.getenv('PORT', 5000))
    debug = os.getenv('FLASK_DEBUG', 'True').lower() == 'true'
    
    print(f"šŸš€ Starting Weather Chatbot on http://{host}:{port}")
    print("šŸ“± Web Interface: http://localhost:5000")
    print("šŸ”— API Endpoints:")
    print("   • GET  /health - Health check")
    print("   • POST /chat   - Chat interface")
    print("   • GET  /weather/<city> - Current weather")
    print("   • GET  /forecast/<city> - Weather forecast")
    print("   • GET  /alerts/<city> - Weather alerts")
    print("=" * 60)
    print("Press Ctrl+C to stop the server")
    print("=" * 60)
    
    try:
        # Start the Flask application
        app.run(host=host, port=port, debug=debug)
    except KeyboardInterrupt:
        print("\nšŸ‘‹ Weather Chatbot stopped by user")
        print("Ā© 2026 RSK World. All rights reserved.")
        sys.exit(0)
    except Exception as e:
        print(f"āŒ Error starting server: {e}")
        sys.exit(1)

if __name__ == '__main__':
    main()
93 lines•3.1 KB
python
app.py
Raw Download
Find: Go to:
#!/usr/bin/env python3
"""
Weather Chatbot Application
===========================

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: A weather chatbot providing forecasts, alerts, and weather information
using OpenWeatherMap API and OpenAI API for natural language processing.
"""

import os
import json
import requests
from datetime import datetime
from flask import Flask, render_template, request, jsonify
from flask_cors import CORS
from werkzeug.utils import secure_filename
from werkzeug.middleware.proxy_fix import ProxyFix
import openai
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'weather-chatbot-secret-key-2026')

# Enable CORS
cors_origins = os.getenv('CORS_ORIGINS', '*').split(',')
CORS(app, origins=cors_origins, supports_credentials=True)

# Proxy fix for production (if behind reverse proxy)
if os.getenv('PROXY_FIX', 'False').lower() == 'true':
    app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

# Security headers
@app.after_request
def set_security_headers(response):
    """Add security headers to responses."""
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'SAMEORIGIN'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    if not app.debug:
        response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    return response

class WeatherChatbot:
    """
    Weather Chatbot class for handling weather queries and providing forecasts.
    Integrates with OpenWeatherMap API and OpenAI for natural language processing.
    """
    
    def __init__(self):
        self.openweather_api_key = os.getenv('OPENWEATHER_API_KEY')
        self.openai_api_key = os.getenv('OPENAI_API_KEY')
        self.base_url = "https://api.openweathermap.org/data/2.5"
        
        if not self.openweather_api_key:
            print("Warning: OpenWeatherMap API key not found in environment variables")
        
        if not self.openai_api_key:
            print("Warning: OpenAI API key not found in environment variables")
        else:
            self.openai_client = openai.OpenAI(api_key=self.openai_api_key)
    
    def get_weather_by_city(self, city):
        """
        Get current weather data for a specific city.
        
        Args:
            city (str): Name of the city
            
        Returns:
            dict: Weather data or error message
        """
        try:
            url = f"{self.base_url}/weather"
            params = {
                'q': city,
                'appid': self.openweather_api_key,
                'units': 'metric'
            }
            
            response = requests.get(url, params=params)
            response.raise_for_status()
            
            data = response.json()
            
            # Handle visibility (may be None or missing)
            visibility_meters = data.get('visibility')
            if visibility_meters is None:
                visibility_km = 0
            else:
                visibility_km = visibility_meters / 1000 if visibility_meters > 0 else 0
            
            # Handle wind speed (may be missing)
            wind_speed = data.get('wind', {}).get('speed', 0)
            
            # Handle weather array (may be empty or missing)
            weather_array = data.get('weather', [])
            if weather_array and len(weather_array) > 0:
                weather_main = weather_array[0]
                description = weather_main.get('description', 'Unknown')
                icon = weather_main.get('icon', '')
            else:
                description = 'Unknown conditions'
                icon = ''
            
            weather_info = {
                'city': data.get('name', 'Unknown'),
                'country': data.get('sys', {}).get('country', ''),
                'temperature': data.get('main', {}).get('temp', 0),
                'feels_like': data.get('main', {}).get('feels_like', 0),
                'humidity': data.get('main', {}).get('humidity', 0),
                'pressure': data.get('main', {}).get('pressure', 0),
                'description': description,
                'icon': icon,
                'wind_speed': wind_speed,
                'visibility': visibility_km,
                'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            }
            
            return weather_info
            
        except requests.exceptions.RequestException as e:
            return {'error': f'Failed to fetch weather data: {str(e)}'}
        except KeyError as e:
            return {'error': f'Invalid weather data format: {str(e)}'}
    
    def get_forecast_by_city(self, city, days=5):
        """
        Get weather forecast for a specific city.
        
        Args:
            city (str): Name of the city
            days (int): Number of days to forecast (max 5)
            
        Returns:
            dict: Forecast data or error message
        """
        try:
            url = f"{self.base_url}/forecast"
            params = {
                'q': city,
                'appid': self.openweather_api_key,
                'units': 'metric',
                'cnt': days * 8  # 8 forecasts per day (3-hour intervals)
            }
            
            response = requests.get(url, params=params)
            response.raise_for_status()
            
            data = response.json()
            
            forecasts = []
            for item in data.get('list', []):
                # Safely extract wind speed (may be missing)
                wind_data = item.get('wind', {})
                wind_speed = wind_data.get('speed', 0) if isinstance(wind_data, dict) else 0
                
                # Safely extract weather information (may be missing or empty)
                weather_array = item.get('weather', [])
                if weather_array and len(weather_array) > 0:
                    weather_main = weather_array[0]
                    description = weather_main.get('description', '')
                    icon = weather_main.get('icon', '')
                else:
                    description = 'Unknown conditions'
                    icon = ''
                
                forecast = {
                    'datetime': item.get('dt_txt', ''),
                    'temperature': item.get('main', {}).get('temp', 0),
                    'feels_like': item.get('main', {}).get('feels_like', 0),
                    'humidity': item.get('main', {}).get('humidity', 0),
                    'description': description,
                    'icon': icon,
                    'wind_speed': wind_speed,
                    'rain': item.get('rain', {}).get('3h', 0) if isinstance(item.get('rain'), dict) else 0,
                    'snow': item.get('snow', {}).get('3h', 0) if isinstance(item.get('snow'), dict) else 0
                }
                forecasts.append(forecast)
            
            return {
                'city': data['city']['name'],
                'country': data['city']['country'],
                'forecasts': forecasts
            }
            
        except requests.exceptions.RequestException as e:
            return {'error': f'Failed to fetch forecast data: {str(e)}'}
        except KeyError as e:
            return {'error': f'Invalid forecast data format: {str(e)}'}
    
    def get_weather_alerts(self, city):
        """
        Get weather alerts for a specific city.
        
        Args:
            city (str): Name of the city
            
        Returns:
            dict: Weather alerts or error message
        """
        try:
            # First get coordinates for the city
            geo_url = f"http://api.openweathermap.org/geo/1.0/direct"
            geo_params = {
                'q': city,
                'limit': 1,
                'appid': self.openweather_api_key
            }
            
            geo_response = requests.get(geo_url, params=geo_params)
            geo_response.raise_for_status()
            
            geo_data = geo_response.json()
            if not geo_data:
                return {'error': 'City not found'}
            
            lat, lon = geo_data[0]['lat'], geo_data[0]['lon']
            
            # Get weather alerts using One Call API (Note: Requires One Call API subscription)
            # If not available, return empty alerts
            alerts_url = f"{self.base_url}/onecall"
            alerts_params = {
                'lat': lat,
                'lon': lon,
                'appid': self.openweather_api_key,
                'exclude': 'minutely,hourly,daily'
            }
            
            try:
                alerts_response = requests.get(alerts_url, params=alerts_params, timeout=10)
                alerts_response.raise_for_status()
                alerts_data = alerts_response.json()
            except requests.exceptions.HTTPError as e:
                # One Call API might not be available (requires subscription)
                if e.response.status_code == 401:
                    return {
                        'city': city,
                        'alerts': [],
                        'has_alerts': False,
                        'message': 'Weather alerts API not available. One Call API subscription required.'
                    }
                raise
            
            alerts = []
            if 'alerts' in alerts_data and isinstance(alerts_data['alerts'], list):
                for alert in alerts_data['alerts']:
                    try:
                        alert_info = {
                            'event': alert.get('event', 'Weather Alert'),
                            'start': datetime.fromtimestamp(alert.get('start', 0)).strftime('%Y-%m-%d %H:%M:%S') if alert.get('start') else '',
                            'end': datetime.fromtimestamp(alert.get('end', 0)).strftime('%Y-%m-%d %H:%M:%S') if alert.get('end') else '',
                            'description': alert.get('description', ''),
                            'severity': alert.get('severity', 'unknown')
                        }
                        alerts.append(alert_info)
                    except (ValueError, TypeError, KeyError) as e:
                        # Skip invalid alert entries
                        continue
            
            return {
                'city': city,
                'alerts': alerts,
                'has_alerts': len(alerts) > 0
            }
            
        except requests.exceptions.RequestException as e:
            return {'error': f'Failed to fetch weather alerts: {str(e)}'}
        except KeyError as e:
            return {'error': f'Invalid alerts data format: {str(e)}'}
    
    def process_natural_language_query(self, query):
        """
        Process natural language weather queries using OpenAI.
        
        Args:
            query (str): Natural language weather query
            
        Returns:
            dict: Processed query result with city and query type
        """
        if not self.openai_api_key:
            # Fallback to simple keyword matching
            query_lower = query.lower()
            
            # Extract city name (simple approach)
            cities = ['london', 'new york', 'paris', 'tokyo', 'delhi', 'mumbai', 'kolkata', 'chennai', 'bangalore']
            found_city = None
            for city in cities:
                if city in query_lower:
                    found_city = city
                    break
            
            # Determine query type
            query_type = 'current'
            if 'forecast' in query_lower or 'tomorrow' in query_lower or 'next' in query_lower:
                query_type = 'forecast'
            elif 'alert' in query_lower or 'warning' in query_lower:
                query_type = 'alerts'
            
            return {
                'city': found_city or 'unknown',
                'query_type': query_type,
                'confidence': 0.5
            }
        
        try:
            prompt = f"""
            Analyze this weather query and extract the city and query type:
            
            Query: "{query}"
            
            Respond with JSON format:
            {{
                "city": "city_name",
                "query_type": "current|forecast|alerts",
                "confidence": 0.0-1.0
            }}
            
            Query types:
            - "current": for current weather conditions
            - "forecast": for weather forecasts
            - "alerts": for weather alerts and warnings
            """
            
            response = self.openai_client.chat.completions.create(
                model="gpt-3.5-turbo",
                messages=[
                    {"role": "system", "content": "You are a weather query analyzer. Extract city and query type from user queries."},
                    {"role": "user", "content": prompt}
                ],
                max_tokens=100,
                temperature=0.3
            )
            
            content = response.choices[0].message.content.strip()
            
            # Try to parse JSON response
            try:
                result = json.loads(content)
                return result
            except json.JSONDecodeError:
                # If response is not JSON, try to extract information from text
                return {'error': 'Could not parse OpenAI response as JSON', 'raw_response': content}
            
        except Exception as e:
            print(f"OpenAI API error: {str(e)}")
            return {'error': f'Failed to process natural language query: {str(e)}'}
    
    def chat(self, user_query):
        """
        Main chat function to handle user queries.
        
        Args:
            user_query (str): User's weather query
            
        Returns:
            dict: Response with weather information
        """
        # Process the query
        processed = self.process_natural_language_query(user_query)
        
        if 'error' in processed:
            return processed
        
        city = processed.get('city')
        query_type = processed.get('query_type')
        
        if not city or city == 'unknown':
            return {'error': 'Could not determine city from your query. Please specify a city name.'}
        
        # Get appropriate weather data
        if query_type == 'current':
            weather_data = self.get_weather_by_city(city)
            return weather_data
        elif query_type == 'forecast':
            forecast_data = self.get_forecast_by_city(city)
            return forecast_data
        elif query_type == 'alerts':
            alert_data = self.get_weather_alerts(city)
            return alert_data
        else:
            return {'error': 'Unknown query type'}

# Initialize chatbot
chatbot = WeatherChatbot()

@app.route('/')
def index():
    """Render the main chat interface."""
    return render_template('index.html')

@app.route('/robots.txt')
def robots_txt():
    """Serve robots.txt file."""
    return app.send_static_file('robots.txt')

@app.route('/chat', methods=['POST'])
def chat():
    """Handle chat requests."""
    try:
        user_query = request.form.get('message', '').strip()
        
        if not user_query:
            return jsonify({'error': 'Please enter a message'})
        
        response = chatbot.chat(user_query)
        return jsonify(response)
        
    except Exception as e:
        return jsonify({'error': f'An error occurred: {str(e)}'})

@app.route('/weather/<city>')
def weather(city):
    """Get weather for a specific city."""
    try:
        weather_data = chatbot.get_weather_by_city(city)
        return jsonify(weather_data)
    except Exception as e:
        return jsonify({'error': str(e)})

@app.route('/forecast/<city>')
def forecast(city):
    """Get forecast for a specific city."""
    try:
        forecast_data = chatbot.get_forecast_by_city(city)
        return jsonify(forecast_data)
    except Exception as e:
        return jsonify({'error': str(e)})

@app.route('/alerts/<city>')
def alerts(city):
    """Get weather alerts for a specific city."""
    try:
        alert_data = chatbot.get_weather_alerts(city)
        return jsonify(alert_data)
    except Exception as e:
        return jsonify({'error': str(e)})

@app.route('/health')
def health():
    """Health check endpoint."""
    return jsonify({
        'status': 'healthy',
        'timestamp': datetime.now().isoformat(),
        'version': '1.0.0',
        'app': 'Weather Chatbot'
    })

@app.route('/api/status')
def api_status():
    """API status and information endpoint."""
    return jsonify({
        'status': 'operational',
        'version': '1.0.0',
        'app_name': 'Weather Chatbot',
        'author': 'RSK World',
        'website': 'https://rskworld.in',
        'timestamp': datetime.now().isoformat(),
        'endpoints': {
            'chat': '/chat',
            'weather': '/weather/<city>',
            'forecast': '/forecast/<city>',
            'alerts': '/alerts/<city>',
            'health': '/health',
            'status': '/api/status'
        },
        'features': [
            'current_weather',
            'weather_forecast',
            'weather_alerts',
            'natural_language_processing',
            'location_detection'
        ]
    })

@app.route('/api/search/cities', methods=['GET'])
def search_cities():
    """Search for cities by name."""
    try:
        query = request.args.get('q', '').strip()
        
        if not query:
            return jsonify({'error': 'Query parameter "q" is required'}), 400
        
        if len(query) < 2:
            return jsonify({'error': 'Query must be at least 2 characters long'}), 400
        
        # Use geolocation service to search for cities
        from utils.geolocation import GeolocationService
        geo_service = GeolocationService(openweather_api_key=os.getenv('OPENWEATHER_API_KEY'))
        
        results = geo_service.search_locations(query, limit=10)
        
        if 'error' in results:
            return jsonify(results), 500
        
        return jsonify({
            'query': query,
            'results': results.get('results', []),
            'count': results.get('count', 0)
        })
        
    except Exception as e:
        return jsonify({'error': f'Search failed: {str(e)}'}), 500

@app.route('/api/compare', methods=['POST'])
def compare_cities():
    """Compare weather between multiple cities."""
    try:
        data = request.get_json()
        
        if not data or 'cities' not in data:
            return jsonify({'error': 'Cities list is required'}), 400
        
        cities = data.get('cities', [])
        
        if not isinstance(cities, list) or len(cities) < 2:
            return jsonify({'error': 'At least 2 cities are required for comparison'}), 400
        
        if len(cities) > 5:
            return jsonify({'error': 'Maximum 5 cities allowed for comparison'}), 400
        
        # Get weather data for all cities
        cities_data = {}
        for city in cities:
            weather_data = chatbot.get_weather_by_city(city)
            cities_data[city] = weather_data
        
        # Use comparison utility
        from utils.comparison import WeatherComparison
        comparison_service = WeatherComparison()
        
        comparison_result = comparison_service.compare_current_weather(cities_data)
        
        return jsonify(comparison_result)
        
    except Exception as e:
        return jsonify({'error': f'Comparison failed: {str(e)}'}), 500

@app.route('/api/stats', methods=['GET'])
def api_stats():
    """Get API usage statistics."""
    try:
        # This would typically come from database/analytics
        # For now, return basic stats
        return jsonify({
            'status': 'operational',
            'uptime': 'N/A',
            'total_requests': 0,
            'successful_requests': 0,
            'failed_requests': 0,
            'average_response_time': 0,
            'timestamp': datetime.now().isoformat()
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.errorhandler(404)
def not_found_error(error):
    """Handle 404 errors."""
    if request.path.startswith('/api/') or request.accept_mimetypes.accept_json:
        return jsonify({'error': 'Endpoint not found', 'status': 404}), 404
    return render_template('errors/404.html'), 404

@app.errorhandler(500)
def internal_error(error):
    """Handle 500 errors."""
    app.logger.error(f'Server Error: {error}', exc_info=True)
    if request.path.startswith('/api/') or request.accept_mimetypes.accept_json:
        return jsonify({
            'error': 'Internal server error',
            'status': 500,
            'message': 'An unexpected error occurred. Please try again later.'
        }), 500
    return render_template('errors/500.html', error=str(error) if app.debug else None), 500

@app.errorhandler(403)
def forbidden_error(error):
    """Handle 403 errors."""
    if request.path.startswith('/api/') or request.accept_mimetypes.accept_json:
        return jsonify({'error': 'Forbidden', 'status': 403}), 403
    return jsonify({'error': 'Access forbidden', 'status': 403}), 403

@app.errorhandler(429)
def rate_limit_error(error):
    """Handle rate limit errors."""
    return jsonify({
        'error': 'Rate limit exceeded',
        'status': 429,
        'message': 'Too many requests. Please try again later.'
    }), 429

if __name__ == '__main__':
    print("Starting Weather Chatbot...")
    print("RSK World - Weather Chatbot Application")
    print("https://rskworld.in")
    print("Ā© 2026 RSK World. All rights reserved.")
    
    app.run(debug=True, host='0.0.0.0', port=5000)
610 lines•22.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