Skip to content

Commit

Permalink
v0.7 - added WeatherAPI support
Browse files Browse the repository at this point in the history
  • Loading branch information
FlyingFathead committed May 25, 2024
1 parent c26fdff commit 781fddb
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 8 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
- A simple-to-use, quick-to-deploy Python-based Telegram bot for OpenAI API
- **Supports transcribed voice messages over Whisper API**
- (auto-transcriptions, translations, and other messages to the bot over TG's voice messages)
- **Supports real-time weather info via OpenWeatherMap API**
- **Supports real-time weather info, weather alerts, detailed weather data via OpenWeatherMap API and WeatherAPI**
- **Supports geolocation and map lookups via MapTiler API**
- (with weather forecasts around the world in all OpenAI API supported languages)
- **Supports navigation instructions via Openrouteservice API**
Expand Down Expand Up @@ -53,6 +53,7 @@ yt-dlp>=2024.3.10
- Use the `configmerger.py` to update old configuration files into a newer version's `config.ini`. You can do this by creating a copy of your existing config to i.e. a file named `myconfig.txt` and including in it the lines you want to keep for the newer version. Then, just run `python configmerger.py config.ini myconfig.txt` and all your existing config lines will be migrated to the new one. Works in most cases, but remember to be careful and double-check any migration issues with i.e. `diff`!

# Changelog
- v0.7 - WeatherAPI support added, to enable, get an API key from weatherapi.com
- v0.61 - improved handling of weather and time/data data globally
- v0.60 - url info pre-parsing and additional info fetching for media sources, i.e. with `yt-dlp`
- v0.59 - custom function calling via Elasticsearch RAG (if enabled)
Expand Down
34 changes: 28 additions & 6 deletions api_get_openweathermap.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# github.com/FlyingFathead/TelegramBot-OpenAI-API/
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# >>> this weather fetcher module version: v0.45
# >>> this weather fetcher module version: v0.46 (25-May-2024)
#
# This API functionality requires both OpenWeatherMap and MapTiler API keys.
# You can get both from the corresponding service providers.
Expand All @@ -22,7 +22,8 @@
from timezonefinder import TimezoneFinder
import pytz

# get the combined weather
# Stuff we want to get via WeatherAPI:
from api_get_weatherapi import get_moon_phase, get_timezone, get_daily_forecast

# get the combined weather
async def get_weather(city_name, country, exclude='', units='metric', lang='fi'):
Expand Down Expand Up @@ -56,7 +57,9 @@ async def get_weather(city_name, country, exclude='', units='metric', lang='fi')
if current_weather_response.status_code == 200 and forecast_response.status_code == 200:
current_weather_data = current_weather_response.json()
forecast_data = forecast_response.json()
return await combine_weather_data(city_name, country, lat, lon, current_weather_data, forecast_data)
moon_phase_data = await get_moon_phase(lat, lon)
daily_forecast_data = await get_daily_forecast(f"{lat},{lon}")
return await combine_weather_data(city_name, country, lat, lon, current_weather_data, forecast_data, moon_phase_data, daily_forecast_data)
else:
logging.error(f"Failed to fetch weather data: {current_weather_response.text} / {forecast_response.text}")
return "[Inform the user that data fetching from OpenWeatherMap API failed, current information could not be fetched. Reply in the user's language.]"
Expand Down Expand Up @@ -188,7 +191,7 @@ def degrees_to_cardinal(d):
return dirs[ix % 16]

# combined weather data
async def combine_weather_data(city_name, country, lat, lon, current_weather_data, forecast_data):
async def combine_weather_data(city_name, country, lat, lon, current_weather_data, forecast_data, moon_phase_data, daily_forecast_data):
tf = TimezoneFinder()
timezone_str = tf.timezone_at(lat=lat, lng=lon) # get timezone using the coordinates
local_timezone = pytz.timezone(timezone_str)
Expand Down Expand Up @@ -239,9 +242,28 @@ async def combine_weather_data(city_name, country, lat, lon, current_weather_dat
f"Lumisade (viimeisen 1h aikana): {snow_1h} mm, "
f"Auringonnousu: {sunrise_time_local_str}, "
f"Auringonlasku: {sunset_time_local_str}, "
f"Koordinaatit: {coordinates_info} (Maa: {country_info})"
f"Koordinaatit: {coordinates_info} (Maa: {country_info}), "
f"Kuun vaihe: {moon_phase_data}"
)


# Include additional WeatherAPI data (daily forecast, air quality, and alerts)
if daily_forecast_data:
air_quality_data = daily_forecast_data['air_quality']
alerts = daily_forecast_data['alerts']

air_quality_info = "\nIlmanlaatu:\n" + "\n".join(
[f"{key}: {value}" for key, value in air_quality_data.items()]
)

alerts_info = "\nSäävaroitukset:\n" + (
"\n".join(
[f"Alert: {alert['headline']}\nDescription: {alert['desc']}\nInstructions: {alert['instruction']}\n"
for alert in alerts['alert']]
) if 'alert' in alerts and alerts['alert'] else "No weather alerts."
)

detailed_weather_info += f"{air_quality_info}\n{alerts_info}"

# 3-hour forecast details
forecasts = forecast_data['list']
formatted_forecasts = []
Expand Down
106 changes: 106 additions & 0 deletions api_get_weatherapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# api_get_weatherapi.py
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# github.com/FlyingFathead/TelegramBot-OpenAI-API/
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# This API functionality requires WeatherAPI key.
# You can get the API key from the corresponding service provider.
# Once you have the API key, add it to your environment variables:
# export WEATHERAPI_KEY="<your API key>"
# (or on i.e. Linux, add to your `~/.bashrc`: export WEATHERAPI_KEY="<your API key>" )

import httpx
import os
import logging

# Function to check for WeatherAPI key
def get_weatherapi_key():
api_key = os.getenv('WEATHERAPI_KEY')
if not api_key:
logging.error("[WARNING] WeatherAPI key not set. You need to set the 'WEATHERAPI_KEY' environment variable to use WeatherAPI functionalities!")
return None
return api_key

# get moon phase data
async def get_moon_phase(lat, lon):
api_key = get_weatherapi_key()
if not api_key:
return None

logging.info(f"Fetching moon phase data for coordinates: Latitude: {lat}, Longitude: {lon}")
base_url = 'http:https://api.weatherapi.com/v1/astronomy.json'
url = f"{base_url}?key={api_key}&q={lat},{lon}"

async with httpx.AsyncClient() as client:
response = await client.get(url)
logging.info(f"Moon phase response status: {response.status_code}")

if response.status_code == 200:
data = response.json()
logging.info(f"Moon phase data: {data}")
moon_phase = data['astronomy']['astro']['moon_phase']
return moon_phase
else:
logging.error(f"Failed to fetch moon phase data: {response.text}")
return None

# get timezone for the coordinates
async def get_timezone(lat, lon):
api_key = get_weatherapi_key()
if not api_key:
return None

logging.info(f"Fetching timezone data for coordinates: Latitude: {lat}, Longitude: {lon}")
base_url = 'http:https://api.weatherapi.com/v1/timezone.json'
url = f"{base_url}?key={api_key}&q={lat},{lon}"

async with httpx.AsyncClient() as client:
response = await client.get(url)
logging.info(f"Timezone response status: {response.status_code}")

if response.status_code == 200:
data = response.json()
logging.info(f"Timezone data: {data}")
timezone = data['location']['tz_id']
return timezone
else:
logging.error(f"Failed to fetch timezone data: {response.text}")
return None

# get daily forecast, safety alerts, and air quality index
async def get_daily_forecast(location):
api_key = get_weatherapi_key()
if not api_key:
return None

logging.info(f"Fetching daily forecast data for location: {location}")
base_url = 'http:https://api.weatherapi.com/v1/forecast.json'
url = f"{base_url}?key={api_key}&q={location}&days=1&alerts=yes&aqi=yes"

async with httpx.AsyncClient() as client:
response = await client.get(url)
logging.info(f"Daily forecast response status: {response.status_code}")

if response.status_code == 200:
data = response.json()
logging.info(f"Daily forecast data: {data}")
forecast = data['forecast']['forecastday'][0]
current = data['current']
alerts = data.get('alerts', {})
air_quality = current['air_quality']

return {
'date': forecast['date'],
'temperature': forecast['day']['avgtemp_c'],
'condition': forecast['day']['condition']['text'],
'wind': forecast['day']['maxwind_kph'],
'precipitation': forecast['day']['totalprecip_mm'],
'uv_index': forecast['day']['uv'],
'air_quality': air_quality,
'alerts': alerts
}
else:
logging.error(f"Failed to fetch daily forecast data: {response.text}")
return None

# Additional WeatherAPI-related functions can be added here
2 changes: 1 addition & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# https://github.com/FlyingFathead/TelegramBot-OpenAI-API
#
# version of this program
version_number = "0.611"
version_number = "0.7"

# experimental modules
import requests
Expand Down

0 comments on commit 781fddb

Please sign in to comment.