103 lines
4.0 KiB
Python
103 lines
4.0 KiB
Python
import os
|
|
import requests
|
|
import logging
|
|
from collections import defaultdict
|
|
from datetime import datetime
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
WEATHER_API_KEY = os.getenv("WEATHER_API_KEY")
|
|
BASE_URL = "https://api.openweathermap.org/data/2.5"
|
|
TIMEOUT = 10
|
|
|
|
def get_current_weather(city: str) -> dict:
|
|
url = f"{BASE_URL}/weather"
|
|
params = {
|
|
"q": city,
|
|
"appid": WEATHER_API_KEY,
|
|
"units": "metric",
|
|
"lang": "ru"
|
|
}
|
|
|
|
try:
|
|
response = requests.get(url, params=params, timeout=TIMEOUT)
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
return {
|
|
"success": True,
|
|
"city": data["name"],
|
|
"temp": data["main"]["temp"],
|
|
"desc": data["weather"][0]["description"].capitalize()
|
|
}
|
|
elif response.status_code == 404:
|
|
return {"success": False, "error": f"Город '{city}' не найден."}
|
|
else:
|
|
logger.error(f"API Error: Code {response.status_code} for city {city}")
|
|
return {"success": False, "error": "Ошибка связи с сервером погоды."}
|
|
except requests.exceptions.RequestException as e:
|
|
logger.error(f"Request exception: {e}")
|
|
return {"success": False, "error": "Превышено время ожидания или ошибка сети."}
|
|
|
|
def get_forecast(city: str, days: int) -> dict:
|
|
url = f"{BASE_URL}/forecast"
|
|
params = {
|
|
"q": city,
|
|
"appid": WEATHER_API_KEY,
|
|
"units": "metric",
|
|
"lang": "ru"
|
|
}
|
|
|
|
try:
|
|
response = requests.get(url, params=params, timeout=TIMEOUT)
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
city_name = data["city"]["name"]
|
|
|
|
# Агрегация данных по дням
|
|
daily_data = defaultdict(lambda: {"temps": [], "descs": []})
|
|
|
|
for item in data["list"]:
|
|
# дата в формате 'YYYY-MM-DD HH:MM:SS'
|
|
date_str = item["dt_txt"].split(" ")[0]
|
|
daily_data[date_str]["temps"].append(item["main"]["temp"])
|
|
daily_data[date_str]["descs"].append(item["weather"][0]["description"])
|
|
|
|
# Сортируем дни
|
|
sorted_dates = sorted(daily_data.keys())
|
|
|
|
# Ограничиваем количество дней
|
|
target_dates = sorted_dates[:days]
|
|
|
|
result = []
|
|
for date_str in target_dates:
|
|
temps = daily_data[date_str]["temps"]
|
|
descs = daily_data[date_str]["descs"]
|
|
|
|
min_temp = min(temps)
|
|
max_temp = max(temps)
|
|
|
|
# Самое частое описание погоды за день
|
|
most_common_desc = max(set(descs), key=descs.count).capitalize()
|
|
|
|
# Перевод даты в читаемый формат
|
|
date_obj = datetime.strptime(date_str, "%Y-%m-%d")
|
|
formatted_date = date_obj.strftime("%d.%m.%Y")
|
|
|
|
result.append({
|
|
"date": formatted_date,
|
|
"min_temp": min_temp,
|
|
"max_temp": max_temp,
|
|
"desc": most_common_desc
|
|
})
|
|
|
|
return {"success": True, "city": city_name, "forecast": result}
|
|
|
|
elif response.status_code == 404:
|
|
return {"success": False, "error": f"Город '{city}' не найден."}
|
|
else:
|
|
logger.error(f"API Error (Forecast): Code {response.status_code} for city {city}")
|
|
return {"success": False, "error": "Ошибка связи с сервером погоды."}
|
|
except requests.exceptions.RequestException as e:
|
|
logger.error(f"Request exception (Forecast): {e}")
|
|
return {"success": False, "error": "Превышено время ожидания или ошибка сети."}
|