Spaces:
Running
Running
File size: 8,173 Bytes
43ea1a5 37b38a7 | 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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | import requests
from datetime import datetime, timedelta
import re
OPEN_METEO_FORECAST = "https://api.open-meteo.com/v1/forecast"
OPEN_METEO_ARCHIVE = "https://archive-api.open-meteo.com/v1/archive"
# Default testing coordinates for Chennai
DEFAULT_LAT = 13.0827
DEFAULT_LON = 80.2707
def _ensure_datetime(d):
"""Ensure d is a full datetime object, not just a date."""
if d is None:
return None
if isinstance(d, datetime):
return d
return datetime(d.year, d.month, d.day)
def _infer_past_date_from_query(query: str):
current_year = datetime.now().year
m = re.search(r'\b(19\d{2}|20\d{2})\b', query.lower())
if m:
year = int(m.group(1))
if year < current_year:
now = datetime.utcnow()
try:
return datetime(year, now.month, now.day)
except ValueError:
return datetime(year, now.month, 28)
return None
def _extract_all_past_years(query: str):
current_year = datetime.now().year
now = datetime.now()
q = query.lower()
seen = set()
years_to_process = []
range_matches = re.finditer(r'\b(19\d{2}|20\d{2})\s*(?:to|-|and)\s*(19\d{2}|20\d{2})\b', q)
for m in range_matches:
start_y = int(m.group(1))
end_y = int(m.group(2))
if start_y > end_y:
start_y, end_y = end_y, start_y
for y in range(start_y, end_y + 1):
if y < current_year and y not in seen:
seen.add(y)
years_to_process.append(y)
single_matches = re.finditer(r'\b(19\d{2}|20\d{2}|2[0-5])\b', q)
for m in single_matches:
val = m.group(1)
y = 2000 + int(val) if len(val) == 2 else int(val)
if y < current_year and y not in seen:
seen.add(y)
years_to_process.append(y)
years_to_process = sorted(years_to_process, reverse=True)[:6]
years_to_process.sort()
past_dates = []
for year in years_to_process:
try:
past_dates.append(datetime(year, now.month, now.day))
except ValueError:
past_dates.append(datetime(year, now.month, 28))
return past_dates
def execute_plan(plan):
"""
Executes the deterministic plan generated by the Planner.
Routes to the correct external APIs or internal ML modules.
"""
intent = plan.get("intent", "weather")
all_intents = plan.get("all_intents", [intent])
target_date = _ensure_datetime(plan.get("date"))
ctx = plan.get("context", {})
query = plan.get("query", "")
# Fallback: infer past date from query year
if target_date is None and intent in ["weather_history", "weather"]:
inferred = _infer_past_date_from_query(query)
if inferred:
target_date = inferred
intent = "weather_history"
plan["intent"] = intent
execution_result = {
"weather": None,
"forecast": None,
"historical_weather": None,
"historical_comparison": None,
"cyclone": None,
"earthquake": None,
"tsunami": None,
"models": None
}
try:
from weather_service import (get_cyclones, get_earthquakes, get_tsunamis,
get_weather, get_forecast, fetch_historical_weather)
now = datetime.utcnow().date()
# ββ DISASTER ROUTE ββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Full report: always fetch weather + forecast + cyclones + earthquakes
if "disaster" in all_intents:
execution_result["weather"] = get_weather()
execution_result["forecast"] = get_forecast()
execution_result["cyclone"] = get_cyclones()
execution_result["earthquake"] = get_earthquakes()
execution_result["tsunami"] = get_tsunamis()
# Don't return early β other intents below may add more data
# ββ COMPARISON ROUTE ββββββββββββββββββββββββββββββββββββββββββββββββββ
if intent == "weather_comparison" or ctx.get("wants_comparison"):
execution_result["weather"] = get_weather()
past_dates = _extract_all_past_years(query)
if not past_dates and target_date:
target_dt_only = target_date.date() if isinstance(target_date, datetime) else target_date
if target_dt_only < now:
past_dates = [target_date]
if past_dates:
comparison_results = []
for past_dt in past_dates:
past_date_only = past_dt.date()
archive_limit = datetime.utcnow().date() - timedelta(days=5)
if past_date_only <= archive_limit:
hist = fetch_historical_weather(past_dt, days_range=1)
if hist and "error" not in hist:
hist["queried_year"] = past_dt.year
hist["queried_date"] = past_dt.strftime("%Y-%m-%d")
comparison_results.append(hist)
if comparison_results:
execution_result["historical_comparison"] = comparison_results
execution_result["historical_weather"] = comparison_results[0]
execution_result["forecast"] = get_forecast()
# ββ STANDARD WEATHER / HISTORY / PREDICTION ROUTE ββββββββββββββββββββ
elif intent in ["weather_history", "weather", "prediction"]:
if target_date:
target_date_only = target_date.date() if isinstance(target_date, datetime) else target_date
if target_date_only < now:
execution_result["historical_weather"] = fetch_historical_weather(target_date, days_range=1)
elif target_date_only > now and (target_date_only - now).days <= 7:
execution_result["forecast"] = get_forecast()
target_date_only = target_date.date() if target_date and isinstance(target_date, datetime) else target_date
if not target_date or target_date_only == now:
execution_result["weather"] = get_weather()
if not target_date and intent in ["weather", "prediction"]:
execution_result["forecast"] = get_forecast()
# ββ CYCLONE ROUTE βββββββββββββββββββββββββββββββββββββββββββββββββββββ
if "cyclone" in all_intents and execution_result["cyclone"] is None:
cy_name = ctx.get("cyclone_name")
cy_year = ctx.get("year")
c_data = get_cyclones(name=cy_name, year=cy_year)
if ctx.get("wants_recent") and not cy_name:
cyc_list = sorted(c_data.get("cyclones", []), key=lambda c: c["year"], reverse=True)[:3]
c_data["cyclones"] = cyc_list
execution_result["cyclone"] = c_data
# ββ EARTHQUAKE ROUTE ββββββββββββββββββββββββββββββββββββββββββββββββββ
if "earthquake" in all_intents and execution_result["earthquake"] is None:
execution_result["earthquake"] = get_earthquakes()
# ββ TSUNAMI ROUTE βββββββββββββββββββββββββββββββββββββββββββββββββββββ
if "tsunami" in all_intents and execution_result["tsunami"] is None:
execution_result["tsunami"] = get_tsunamis()
except ImportError as e:
print(f"Executor Import Error: {e}")
return execution_result |