File size: 2,981 Bytes
6380b21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import requests
from datetime import datetime
from typing import Dict
from .config import OPENWEATHER_BASE, get_openweather_key, UNITS
from .utils import day_list


def geocode_city(city: str) -> Dict:
    url = f"{OPENWEATHER_BASE}/geo/1.0/direct"
    r = requests.get(
        url,
        params={"q": city, "limit": 1, "appid": get_openweather_key()},
        timeout=20,
    )
    r.raise_for_status()
    arr = r.json()
    if not arr:
        raise RuntimeError(f"City not found: {city}")
    d = arr[0]
    return {
        "name": d.get("name"),
        "lat": d.get("lat"),
        "lon": d.get("lon"),
        "country": d.get("country"),
    }


def forecast_5day(lat: float, lon: float, units=UNITS) -> Dict:
    # 5 day / 3-hour forecast
    url = f"{OPENWEATHER_BASE}/data/2.5/forecast"
    r = requests.get(
        url,
        params={"lat": lat, "lon": lon, "appid": get_openweather_key(), "units": units},
        timeout=25,
    )
    r.raise_for_status()
    return r.json()


def summarize_forecast_for_range(city: str, start_date, days: int) -> Dict:
    loc = geocode_city(city)
    fc = forecast_5day(loc["lat"], loc["lon"])
    daily = {}
    for item in fc.get("list", []):
        dt_txt = item.get("dt_txt")  # 'YYYY-MM-DD HH:MM:SS'
        dt = datetime.strptime(dt_txt, "%Y-%m-%d %H:%M:%S")
        dkey = dt.date().isoformat()
        temp = item.get("main", {}).get("temp")
        weather = item.get("weather", [{}])[0].get("description", "")
        wind = item.get("wind", {}).get("speed", 0)
        if dkey not in daily:
            daily[dkey] = {"temps": [], "desc": {}, "wind": []}
        daily[dkey]["temps"].append(temp)
        daily[dkey]["wind"].append(wind)
        daily[dkey]["desc"][weather] = daily[dkey]["desc"].get(weather, 0) + 1

    dates = [d.isoformat() for d in day_list(start_date, days)]
    rows = []
    for dkey in dates:
        if dkey in daily:
            temps = daily[dkey]["temps"]
            avg = sum(temps) / len(temps) if temps else None
            wavg = (
                sum(daily[dkey]["wind"]) / len(daily[dkey]["wind"]) if daily[dkey]["wind"] else 0
            )
            desc = max(daily[dkey]["desc"], key=daily[dkey]["desc"].get)
            rows.append(
                {
                    "date": dkey,
                    "temp_avg": round(avg, 1) if avg is not None else None,
                    "wind": round(wavg, 1),
                    "desc": desc,
                }
            )
        else:
            rows.append(
                {
                    "date": dkey,
                    "temp_avg": None,
                    "wind": None,
                    "desc": "No forecast (beyond 5 days)",
                }
            )
    summary_text = "\n".join(
        [
            f"{r['date']}: {r['desc']}, avg {r['temp_avg']}°C, wind {r['wind']} m/s"
            for r in rows
        ]
    )
    return {"location": loc, "daily": rows, "summary_text": summary_text}