cwadayi commited on
Commit
8302d50
·
verified ·
1 Parent(s): ed12f36

Update weather_service.py

Browse files
Files changed (1) hide show
  1. weather_service.py +70 -47
weather_service.py CHANGED
@@ -1,70 +1,93 @@
1
  # weather_service.py
2
  import requests
3
  from config import CWA_AUTH_KEY
 
4
 
5
- CWA_WEATHER_API = "https://opendata.cwa.gov.tw/api/v1/rest/datastore/O-A0003-001"
 
6
 
7
- def fetch_weather_by_location(location_name: str) -> str:
8
- """根據地點名稱查詢即時天氣資訊。"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  if not CWA_AUTH_KEY:
10
- return "❌ 天氣查詢失敗:管理者尚未設定 CWA_AUTH_KEY。"
11
 
 
 
12
  params = {
13
  "Authorization": CWA_AUTH_KEY,
14
  "format": "JSON",
15
- # [修改] 移除 locationName,一次獲取所有測站資料
16
- "elementName": "TEMP,HUMD,Weather",
17
  }
 
18
  try:
19
- r = requests.get(CWA_WEATHER_API, params=params, timeout=15)
20
  r.raise_for_status()
21
  data = r.json()
22
 
23
- if not data.get("records") or not data["records"].get("location"):
24
- return "無法獲取任何天氣觀測站資料。"
25
 
26
- all_locations = data["records"]["location"]
27
-
28
- # [新增] 遍歷所有測站,尋找符合使用者輸入的地點
29
- # 處理 "臺" 和 "台" 的異體字,並移除 "市"
30
- normalized_input = location_name.replace("臺", "台").replace("市", "")
31
 
32
- target_location = None
33
- for loc in all_locations:
34
- normalized_loc_name = loc["locationName"].replace("臺", "台")
35
- if normalized_input == normalized_loc_name:
36
- target_location = loc
37
- break # 找到完全符合的就停止
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
- # 如果沒有完全符合的,則找名稱包含的
40
- if not target_location:
41
- for loc in all_locations:
42
- normalized_loc_name = loc["locationName"].replace("臺", "台")
43
- if normalized_input in normalized_loc_name:
44
- target_location = loc
45
- break
46
-
47
- if not target_location:
48
- return f"找不到與「{location_name}」相關的即時天氣資訊,請試試看其他縣市或地區。"
49
 
50
- # --- 找到地點後,格式化輸出 ---
51
- loc_data = target_location
52
- elements = {elem["elementName"]: elem["elementValue"] for elem in loc_data["weatherElement"]}
53
-
54
- temp = elements.get("TEMP", "未知")
55
- humidity = float(elements.get("HUMD", -1)) * 100
56
- weather_desc = elements.get("Weather", "未知")
57
-
58
- return (
59
- f"📍 {loc_data['locationName']} 即時天氣:\n"
60
- f"天氣狀況:{weather_desc}\n"
61
- f"溫度:{temp}°C\n"
62
- f"相對濕度:{humidity:.0f}%"
63
- )
64
 
65
  except requests.exceptions.HTTPError as e:
66
  if e.response.status_code == 401:
67
- return "❌ 天氣查詢失敗:CWA 授權金鑰 (API Key) 無效。"
68
- return f"❌ 天氣查詢失敗:{e}"
69
  except Exception as e:
70
- return f"❌ 天氣查詢失敗:{e}"
 
 
1
  # weather_service.py
2
  import requests
3
  from config import CWA_AUTH_KEY
4
+ from datetime import datetime
5
 
6
+ # [修改] API 端點更新為 36 小時預報
7
+ CWA_FORECAST_API = "https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001"
8
 
9
+ def _normalize_location_name(loc_name: str) -> str:
10
+ """自動校正縣市名稱,以符合 API 要求 (例如 台北 -> 臺北市)"""
11
+ loc_name = loc_name.replace("台", "臺")
12
+ if loc_name.endswith("市") or loc_name.endswith("縣"):
13
+ return loc_name
14
+
15
+ # 根據 API 文件支援的主要縣市列表進行校正
16
+ major_cities = "臺北,桃園,新竹,臺中,嘉義,臺南,高雄,基隆".split(',')
17
+ if any(city in loc_name for city in major_cities):
18
+ return f"{loc_name}市"
19
+
20
+ return f"{loc_name}縣"
21
+
22
+ def _format_time_period(start_str: str, end_str: str) -> str:
23
+ """將時間格式化為易讀的時段名稱"""
24
+ start_dt = datetime.fromisoformat(start_str)
25
+ start_hour = start_dt.hour
26
+
27
+ if start_hour >= 18 or start_hour < 6:
28
+ return f"{start_dt.strftime('%m/%d')} 晚上至隔日清晨"
29
+ elif start_hour >= 6 and start_hour < 18:
30
+ return f"{start_dt.strftime('%m/%d')} 白天"
31
+ return f"{start_dt.strftime('%m/%d %H:%M')}"
32
+
33
+
34
+ def fetch_forecast_by_location(location_name: str) -> str:
35
+ """根據地點名稱查詢未來 36 小時天氣預報。"""
36
  if not CWA_AUTH_KEY:
37
+ return "❌ 天氣預報查詢失敗:管理者尚未設定 CWA_AUTH_KEY。"
38
 
39
+ normalized_loc = _normalize_location_name(location_name)
40
+
41
  params = {
42
  "Authorization": CWA_AUTH_KEY,
43
  "format": "JSON",
44
+ "locationName": normalized_loc,
45
+ "elementName": "Wx,PoP,MinT,MaxT", # 天氣現象,降雨機率,最低溫,最高溫
46
  }
47
+
48
  try:
49
+ r = requests.get(CWA_FORECAST_API, params=params, timeout=10)
50
  r.raise_for_status()
51
  data = r.json()
52
 
53
+ if not data.get("records") or not data["records"]["location"]:
54
+ return f"找不到「{location_name}」的預報資訊。\n請確認是否為台灣的縣市名稱 (例如: 臺北市, 花蓮縣)。"
55
 
56
+ loc_data = data["records"]["location"][0]
57
+ elements = {elem["elementName"]: elem["time"] for elem in loc_data["weatherElement"]}
 
 
 
58
 
59
+ forecasts = []
60
+ # API 會回傳 3 個時間段的預報
61
+ for i in range(3):
62
+ try:
63
+ start_time = elements["Wx"][i]["startTime"]
64
+ end_time = elements["Wx"][i]["endTime"]
65
+ wx = elements["Wx"][i]["parameter"]["parameterName"]
66
+ pop = elements["PoP"][i]["parameter"]["parameterName"]
67
+ min_t = elements["MinT"][i]["parameter"]["parameterName"]
68
+ max_t = elements["MaxT"][i]["parameter"]["parameterName"]
69
+
70
+ period_name = _format_time_period(start_time, end_time)
71
+
72
+ forecast_str = (
73
+ f"➢ {period_name}:\n"
74
+ f" 天氣:{wx}\n"
75
+ f" 氣溫:{min_t}°C - {max_t}°C\n"
76
+ f" 降雨機率:{pop}%"
77
+ )
78
+ forecasts.append(forecast_str)
79
+ except (IndexError, KeyError):
80
+ continue
81
 
82
+ if not forecasts:
83
+ return f"無法解析「{location_name}」的預報資料。"
 
 
 
 
 
 
 
 
84
 
85
+ return f"📍 {loc_data['locationName']} 未來 36 小時天氣預報:\n\n" + "\n\n".join(forecasts)
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  except requests.exceptions.HTTPError as e:
88
  if e.response.status_code == 401:
89
+ return "❌ 預報查詢失敗:CWA 授權金鑰 (API Key) 無效。"
90
+ return f"❌ 預報查詢失敗:{e}"
91
  except Exception as e:
92
+ return f"❌ 預報查詢失敗:{e}"
93
+