OppaAI commited on
Commit
1526efa
·
1 Parent(s): 63512d9

fix: correct wttr.in endpoint usage and improve timezone resolution logic for diverse location inputs

Browse files
Files changed (1) hide show
  1. core/tools.py +59 -6
core/tools.py CHANGED
@@ -292,9 +292,11 @@ def get_weather(location: str) -> str:
292
  Returns a concise summary string.
293
  """
294
  try:
 
 
295
  resp = httpx.get(
296
- "https://wttr.in/",
297
- params={"format": "j1", "q": location},
298
  timeout=10,
299
  headers={"User-Agent": "Mozilla/5.0"},
300
  )
@@ -328,6 +330,7 @@ def get_weather(location: str) -> str:
328
  def get_timezone(location: str) -> str:
329
  from datetime import datetime
330
  from zoneinfo import ZoneInfo
 
331
 
332
  _CITY_MAP = {
333
  "tokyo": "Asia/Tokyo", "osaka": "Asia/Tokyo",
@@ -343,14 +346,64 @@ def get_timezone(location: str) -> str:
343
  "vancouver": "America/Vancouver",
344
  }
345
 
346
- tz_name = _CITY_MAP.get(location.lower().strip())
 
 
 
 
 
 
347
  if not tz_name:
348
  try:
349
  import zoneinfo
350
  all_zones = zoneinfo.available_timezones()
351
- loc_lower = location.lower().replace(" ", "_")
352
- matches = [z for z in all_zones if loc_lower in z.lower()]
353
- tz_name = matches[0] if matches else None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  except Exception:
355
  pass
356
 
 
292
  Returns a concise summary string.
293
  """
294
  try:
295
+ # wttr.in requires the location as a path parameter (e.g., https://wttr.in/Paris)
296
+ # using q=location query parameters returns 500 server errors
297
  resp = httpx.get(
298
+ f"https://wttr.in/{location}",
299
+ params={"format": "j1"},
300
  timeout=10,
301
  headers={"User-Agent": "Mozilla/5.0"},
302
  )
 
330
  def get_timezone(location: str) -> str:
331
  from datetime import datetime
332
  from zoneinfo import ZoneInfo
333
+ import re
334
 
335
  _CITY_MAP = {
336
  "tokyo": "Asia/Tokyo", "osaka": "Asia/Tokyo",
 
346
  "vancouver": "America/Vancouver",
347
  }
348
 
349
+ loc_clean = location.lower().strip()
350
+ tz_name = None
351
+
352
+ # 1. Exact map check
353
+ if loc_clean in _CITY_MAP:
354
+ tz_name = _CITY_MAP[loc_clean]
355
+
356
  if not tz_name:
357
  try:
358
  import zoneinfo
359
  all_zones = zoneinfo.available_timezones()
360
+
361
+ # 2. Match full string with underscores in timezone name
362
+ loc_underscore = loc_clean.replace(" ", "_")
363
+ matches = [z for z in all_zones if loc_underscore in z.lower()]
364
+ if matches:
365
+ tz_name = matches[0]
366
+
367
+ # 3. Handle region/country suffixes (e.g. "Tokyo, Japan" -> "Tokyo")
368
+ if not tz_name and "," in loc_clean:
369
+ city_part = loc_clean.split(",")[0].strip()
370
+ if city_part in _CITY_MAP:
371
+ tz_name = _CITY_MAP[city_part]
372
+ else:
373
+ city_underscore = city_part.replace(" ", "_")
374
+ matches = [z for z in all_zones if city_underscore in z.lower()]
375
+ if matches:
376
+ tz_name = matches[0]
377
+
378
+ # 4. Fallback: match sub-phrases of words
379
+ if not tz_name:
380
+ words = [w for w in re.split(r"[\s,;_]+", loc_clean) if w]
381
+ # Prioritize exact match with the city component of the zone
382
+ for length in range(len(words), 0, -1):
383
+ for i in range(len(words) - length + 1):
384
+ phrase = "_".join(words[i : i + length])
385
+ if len(phrase) > 2:
386
+ matches = [z for z in all_zones if z.lower().split("/")[-1] == phrase]
387
+ if matches:
388
+ tz_name = matches[0]
389
+ break
390
+ if tz_name:
391
+ break
392
+
393
+ # Fallback to substring match on city component (excluding common words)
394
+ if not tz_name:
395
+ for length in range(len(words), 0, -1):
396
+ for i in range(len(words) - length + 1):
397
+ phrase = "_".join(words[i : i + length])
398
+ if len(phrase) > 2:
399
+ if phrase in {"the", "what", "time", "date", "local", "zone", "city"}:
400
+ continue
401
+ matches = [z for z in all_zones if phrase in z.lower().split("/")[-1]]
402
+ if matches:
403
+ tz_name = matches[0]
404
+ break
405
+ if tz_name:
406
+ break
407
  except Exception:
408
  pass
409