Add weather forecast module with OpenWeatherMap integration#35
Add weather forecast module with OpenWeatherMap integration#35
Conversation
Co-authored-by: vannu07 <161148074+vannu07@users.noreply.github.com>
Co-authored-by: vannu07 <161148074+vannu07@users.noreply.github.com>
Co-authored-by: vannu07 <161148074+vannu07@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This pull request adds a weather forecast module to the Jarvis voice assistant, integrating with the OpenWeatherMap API to provide real-time weather updates and multi-day forecasts. The implementation includes a standalone weather fetcher module, voice command integration, configuration management for API keys, and documentation updates.
Key changes:
- New weather fetching module with current weather and 5-day forecast capabilities
- Voice command handlers for weather queries with city name extraction
- Configuration support for OpenWeatherMap API key
- Comprehensive README documentation with usage examples and setup instructions
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| weather_fetcher.py | Core weather module implementing OpenWeatherMap API integration with current weather and forecast fetching, including error handling and formatting functions |
| testing/weather_test.py | Manual integration tests for weather functionality requiring live API credentials |
| backend/feature.py | Added get_weather and get_weather_forecast functions with voice response integration |
| backend/command.py | Extended command parser to recognize and route weather/forecast queries |
| backend/config_manager.py | Added openweathermap_api_key property to configuration manager |
| backend/config.py | Exposed OPENWEATHERMAP_API_KEY constant for use throughout the application |
| README.md | Added weather feature documentation including setup instructions, usage examples, and feature list |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| except requests.exceptions.HTTPError as e: | ||
| if e.response.status_code == 404: | ||
| print(f"City '{city}' not found.") | ||
| else: | ||
| print(f"HTTP error: {e}") | ||
| return None | ||
| except requests.exceptions.RequestException as e: | ||
| print(f"Network error: {e}") | ||
| return None | ||
| except KeyError as e: | ||
| print(f"Unexpected API response format: {e}") | ||
| return None |
There was a problem hiding this comment.
Error messages are printed directly to console rather than being returned to the caller. This makes it difficult to properly handle errors in the integration with the voice assistant, as the calling code in backend/feature.py cannot distinguish between different error types (network error vs. invalid city vs. API format issue). Consider returning error information that the caller can handle appropriately, especially for voice feedback.
| from backend.feature import get_weather, get_weather_forecast | ||
|
|
||
| # Extract city name from query | ||
| city = query.replace("weather", "").replace("forecast", "").replace("in", "").replace("for", "").strip() |
There was a problem hiding this comment.
The command parsing logic is fragile. Using multiple chained replace() calls can lead to incorrect parsing. For example, "weather forecast in paris" would have both "weather" and "forecast" removed, making it ambiguous. Additionally, if a city name contains these words (e.g., "Weatherford, Texas" or "Forecast, Australia"), they would be incorrectly stripped. Consider using a more robust parsing approach with regex or the existing parse_command function from backend.nlp.command_parser.
| from weather_fetcher import WeatherFetcher | ||
|
|
||
| if not OPENWEATHERMAP_API_KEY: | ||
| speak("Weather API key is not configured. Please set OPENWEATHERMAP_API_KEY in your environment.") | ||
| return | ||
|
|
||
| fetcher = WeatherFetcher(OPENWEATHERMAP_API_KEY) |
There was a problem hiding this comment.
The WeatherFetcher is instantiated on every call to get_weather and get_weather_forecast. This is inefficient as the fetcher only holds the API key and could be reused. Consider creating a module-level instance of WeatherFetcher that's initialized once, similar to how other features in the file might handle their dependencies.
| from weather_fetcher import WeatherFetcher | ||
|
|
||
| if not OPENWEATHERMAP_API_KEY: | ||
| speak("Weather API key is not configured. Please set OPENWEATHERMAP_API_KEY in your environment.") | ||
| return | ||
|
|
||
| fetcher = WeatherFetcher(OPENWEATHERMAP_API_KEY) |
There was a problem hiding this comment.
The WeatherFetcher is instantiated again here, duplicating the instantiation pattern from get_weather. This creates unnecessary object creation overhead and makes the code harder to maintain if the initialization logic needs to change. Consider creating a shared instance or a helper function to get the fetcher instance.
| params = { | ||
| "q": city, | ||
| "appid": self.api_key, | ||
| "units": "metric" # Use Celsius |
There was a problem hiding this comment.
The API key is passed directly in URL parameters without any validation or sanitization. While this follows the OpenWeatherMap API specification, consider adding validation to ensure the API key is set and non-empty before making requests. This would provide clearer error messages when the API key is misconfigured rather than getting cryptic API errors.
| except requests.exceptions.HTTPError as e: | ||
| if e.response.status_code == 404: | ||
| print(f"City '{city}' not found.") | ||
| else: | ||
| print(f"HTTP error: {e}") | ||
| return None | ||
| except requests.exceptions.RequestException as e: | ||
| print(f"Network error: {e}") | ||
| return None | ||
| except KeyError as e: | ||
| print(f"Unexpected API response format: {e}") | ||
| return None |
There was a problem hiding this comment.
The same error handling pattern with console prints is repeated here. Error messages are printed directly rather than being returned to the caller. This duplicates the error handling issue from fetch_current_weather and makes the code harder to maintain. Consider extracting common error handling logic into a helper method that returns structured error information.
Co-authored-by: vannu07 <161148074+vannu07@users.noreply.github.com>
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ting Co-authored-by: vannu07 <161148074+vannu07@users.noreply.github.com>
Co-authored-by: vannu07 <161148074+vannu07@users.noreply.github.com>
Weather Forecast Module - PR Review Feedback Addressed ✅
Summary
All PR review comments have been addressed with comprehensive improvements to error handling, testing, and code quality.
✅ Addressed PR Review Comments
1. README.md:418 - news_fetcher.py documentation
2-3. weather_fetcher.py Error Handling (Comments 2656550174, 2656550189)
fetch_current_weather()to return tuple(data, error)instead of printing errorsfetch_forecast()to return tuple(forecast_list, error)instead of printing errorsbackend/feature.pyto properly handle returned errors4. backend/command.py:92 - Fragile City Parsing (Comment 2656550175)
replace()calls with robust regex-based parsing\b(?:in|for)\s+(.+)to extract city names after prepositions5-6. backend/feature.py - WeatherFetcher Instantiation (Comments 2656550179, 2656550182)
_weather_fetchervariable with lazy initializationget_weather_fetcher()helper function for reusable instanceget_weather()andget_weather_forecast()now reuse the same instance7. testing/weather_test.py - Proper Testing Framework (Comment 2656550183)
unittestframeworkunittest.mockfor API responses8. weather_fetcher.py:28-31 - API Key Validation (Comment 2656550184)
__init__()to ensure API key is set and non-emptyValueErrorwith clear message when API key is missing/empty9. weather_fetcher.py:46 - Wind Speed Precision (Comment 2656550185)
round(speed * 3.6, 1)toround(speed * 3.6)10. weather_fetcher.py:186 - Docstring Accuracy (Comment 2656550190)
__main__block functionality11. backend/feature.py:317 - Forecast "Today" Assumption (Comment 2656550192)
📊 Changes Summary
✅ Testing
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.