From 667b62ac220c0729592dcaee925022a482857417 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 1 Feb 2025 19:30:44 -0500 Subject: [PATCH 1/5] Formatted Weather to Pass Into AI AI can now read Weather gathered from NWS API I also changed the prompt slightly to conform to what I anticipated the bot to spew out --- ai.py | 47 ++++++++++++++++++++++++----------------------- main.py | 8 +++++++- weather.py | 21 +++++++++++++++++---- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/ai.py b/ai.py index fdf91e1..f9c1db3 100644 --- a/ai.py +++ b/ai.py @@ -5,28 +5,29 @@ import os from openai import OpenAI -# To authenticate with the model you will need to generate a personal access token (PAT) in your GitHub settings. -# Create your PAT token by following instructions here: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens -client = OpenAI( - base_url="https://models.inference.ai.azure.com", - api_key=os.getenv("GITHUB_TOKEN"), -) +def textGeneration(forecast): + # To authenticate with the model you will need to generate a personal access token (PAT) in your GitHub settings. + # Create your PAT token by following instructions here: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens + client = OpenAI( + base_url="https://models.inference.ai.azure.com", + api_key=os.getenv("OPENAI_API_KEY"), + ) -response = client.chat.completions.create( - messages=[ - { - "role": "system", - "content": "You are a young meteorologist explaining the next day's forecast in Syracuse NY in the morning", - }, - { - "role": "user", - "content": "Saturday, Temperature: 15, Wind Speed: 5 to 9 mph, windDirection: NW, detailedForecast: Partly sunny, with a high near 15. Wind chill values as low as -1. Northwest wind 5 to 9 mph. New snow accumulation of less than half an inch possible. ", - } - ], - model="gpt-4o", - temperature=1, - max_tokens=4096, - top_p=1 -) + response = client.chat.completions.create( + messages=[ + { + "role": "system", + "content": "You are a young meteorologist explaining the next three day's forecast in Syracuse NY in the morning(Say 'Good Morning Syracuse!'). Act like you're making a social media post. Make sure to Consildate the days into one description (don't do morning and night seperately)", + }, + { + "role": "user", + "content": forecast, + } + ], + model="gpt-4o", + temperature=1, + max_tokens=4096, + top_p=1 + ) -print(response.choices[0].message.content) + print(response.choices[0].message.content) diff --git a/main.py b/main.py index 5f2a64b..3fc3530 100644 --- a/main.py +++ b/main.py @@ -18,6 +18,7 @@ import bluesky import weather +import ai def main(): print("Loading Credentials...") @@ -29,7 +30,12 @@ def main(): print("Fetching Forecast") forecast = weather.fetch_weather_forecast() - print(forecast) + + print("Formatting Weather Data") + forecast = weather.format_weather_data(forecast) + + print("Generating AI Text") + ai.textGeneration(forecast) if __name__ == "__main__": main() \ No newline at end of file diff --git a/weather.py b/weather.py index acfc2d4..9944a83 100644 --- a/weather.py +++ b/weather.py @@ -17,7 +17,7 @@ def fetch_weather_forecast(): forecast_days = [] - for i in range(6): + for i in range(4): period = forecast[i] forecast_days.append({ "name": period.get("name"), @@ -29,15 +29,28 @@ def fetch_weather_forecast(): "detailedForecast": period.get("detailedForecast") }) - # Group forecast into three-day structure + # Group forecast into two-day structure consolidated_forecast = { "day_1": forecast_days[:2], "day_2": forecast_days[2:4], - "day_3": forecast_days[4:6] } return consolidated_forecast except requests.exceptions.RequestException as err: print("Error Fetching Weather Data: ", {err}) - return None \ No newline at end of file + return None + +def format_weather_data(weatherData): + weather_input = "" + for day, forecast in weatherData.items(): + weather_input += f"{forecast[0]["name"]} & {forecast[1]["name"]}:\n" + for period in forecast: + weather_input += ( + f"Temperature: {period["temperature"]}{period["temperatureUnit"]}\n" + f"Probability Of Precipitation: {period["probabilityOfPrecipitation"]}\n" + f"Wind Speed: {period["windSpeed"]}, Direction {period["windDirection"]}\n" + f"Detailed Forecast: {period["detailedForecast"]}\n\n" + ) + print(weather_input) + return weather_input \ No newline at end of file From 364fd5d2b35ecd81e3fe1cde1e3eda12f9a0a215 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 1 Feb 2025 19:33:15 -0500 Subject: [PATCH 2/5] Quick Fix weather_test.py unitTests will now pass --- tests/weather_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/weather_test.py b/tests/weather_test.py index 8e54e83..ea7895f 100644 --- a/tests/weather_test.py +++ b/tests/weather_test.py @@ -43,7 +43,7 @@ def test_successful_api_call(self, mock_get): self.assertIsNotNone(result) self.assertEqual(len(result), 3) self.assertEqual(result["day_1"][0]["name"], "Monday") - self.assertEqual(result["day_3"][0]["name"], "Wednesday") + self.assertEqual(result["day_2"][0]["name"], "Tuesday") @patch("requests.get") def test_api_connection_error(self, mock_get): From 03dcb67e757e1102a18ddd40c9163528b9dfc6ab Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 1 Feb 2025 20:00:11 -0500 Subject: [PATCH 3/5] Fixing Pylint Issues --- ai.py | 8 ++++++-- bluesky.py | 12 ++---------- main.py | 11 +++++++---- weather.py | 23 ++++++++++++++++------- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/ai.py b/ai.py index f9c1db3..f5eebf0 100644 --- a/ai.py +++ b/ai.py @@ -2,11 +2,15 @@ > pip install openai """ +# pylint: disable=C0301 import os from openai import OpenAI -def textGeneration(forecast): - # To authenticate with the model you will need to generate a personal access token (PAT) in your GitHub settings. +def generate_ai_text(forecast): + """ + Method that generates AI text + """ + # To authenticate with the model you will need to generate a personal access token (PAT) in your GitHub settings. # Create your PAT token by following instructions here: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens client = OpenAI( base_url="https://models.inference.ai.azure.com", diff --git a/bluesky.py b/bluesky.py index e944b96..46dc1a9 100644 --- a/bluesky.py +++ b/bluesky.py @@ -1,14 +1,6 @@ """ -The Module contains the Authentication methods for the following: - -BlueSkyAPI -NWSAPI -OpenAIAPI - -Dependencies: - -Author: -- Andrew Markarian +This module handles all interactions with the Bluesky API, including authentication, session management, +and posting formatted weather updates to the Bluesky social media platform. """ import os diff --git a/main.py b/main.py index 3fc3530..84d6af2 100644 --- a/main.py +++ b/main.py @@ -21,6 +21,9 @@ import ai def main(): + """ + This runs the main module of BlueSkyTracker + """ print("Loading Credentials...") bluesky_handle, bluesky_app_password = bluesky.load_bluesky_credentials() @@ -30,12 +33,12 @@ def main(): print("Fetching Forecast") forecast = weather.fetch_weather_forecast() - + print("Formatting Weather Data") forecast = weather.format_weather_data(forecast) print("Generating AI Text") - ai.textGeneration(forecast) - + ai.generate_ai_text(forecast) + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/weather.py b/weather.py index 9944a83..8640514 100644 --- a/weather.py +++ b/weather.py @@ -1,3 +1,9 @@ +""" +This module handles all weather-related functionality within the project. It is responsible for +fetching weather forecast data from the National Weather Service (NWS) API, parsing and extracting +relevant information, and formatting it for use in other parts of the project. +""" +# pylint: disable=C0301 import requests def fetch_weather_forecast(): @@ -9,7 +15,7 @@ def fetch_weather_forecast(): try: url = "https://api.weather.gov/gridpoints/BGM/52,99/forecast" - response = requests.get(url) + response = requests.get(url, timeout=10) response.raise_for_status() data = response.json() @@ -28,7 +34,7 @@ def fetch_weather_forecast(): "windDirection": period.get("windDirection"), "detailedForecast": period.get("detailedForecast") }) - + # Group forecast into two-day structure consolidated_forecast = { "day_1": forecast_days[:2], @@ -36,14 +42,17 @@ def fetch_weather_forecast(): } return consolidated_forecast - + except requests.exceptions.RequestException as err: print("Error Fetching Weather Data: ", {err}) return None - -def format_weather_data(weatherData): + +def format_weather_data(weather_data): + """ + This method is responsible for formatting the weather data retrieved from fetch_weather_data() + """ weather_input = "" - for day, forecast in weatherData.items(): + for forecast in weather_data.values(): weather_input += f"{forecast[0]["name"]} & {forecast[1]["name"]}:\n" for period in forecast: weather_input += ( @@ -53,4 +62,4 @@ def format_weather_data(weatherData): f"Detailed Forecast: {period["detailedForecast"]}\n\n" ) print(weather_input) - return weather_input \ No newline at end of file + return weather_input From 4572ad1aa6225298b8b27a74181c0ad50faa9c2d Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 1 Feb 2025 20:04:13 -0500 Subject: [PATCH 4/5] Fixing Pyhton Sytactic Issues --- weather.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/weather.py b/weather.py index 8640514..e0703ee 100644 --- a/weather.py +++ b/weather.py @@ -53,13 +53,13 @@ def format_weather_data(weather_data): """ weather_input = "" for forecast in weather_data.values(): - weather_input += f"{forecast[0]["name"]} & {forecast[1]["name"]}:\n" + weather_input += f"{forecast[0]['name']} & {forecast[1]['name']}:\n" for period in forecast: weather_input += ( - f"Temperature: {period["temperature"]}{period["temperatureUnit"]}\n" - f"Probability Of Precipitation: {period["probabilityOfPrecipitation"]}\n" - f"Wind Speed: {period["windSpeed"]}, Direction {period["windDirection"]}\n" - f"Detailed Forecast: {period["detailedForecast"]}\n\n" + f"Temperature: {period['temperature']}{period['temperatureUnit']}\n" + f"Probability Of Precipitation: {period['probabilityOfPrecipitation']}\n" + f"Wind Speed: {period['windSpeed']}, Direction {period['windDirection']}\n" + f"Detailed Forecast: {period['detailedForecast']}\n\n" ) print(weather_input) return weather_input From 2107ea2c9fe84933bc3dd9cee7e039e468a96772 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 1 Feb 2025 20:06:56 -0500 Subject: [PATCH 5/5] Fixing weather_test.py The method changed, so the length returns should now only be 2 --- tests/weather_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/weather_test.py b/tests/weather_test.py index ea7895f..5706d98 100644 --- a/tests/weather_test.py +++ b/tests/weather_test.py @@ -41,7 +41,7 @@ def test_successful_api_call(self, mock_get): result = fetch_weather_forecast() self.assertIsNotNone(result) - self.assertEqual(len(result), 3) + self.assertEqual(len(result), 2) self.assertEqual(result["day_1"][0]["name"], "Monday") self.assertEqual(result["day_2"][0]["name"], "Tuesday")