cwadayi commited on
Commit
90ced7e
·
verified ·
1 Parent(s): 30d5343

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +9 -26
app.py CHANGED
@@ -1,4 +1,7 @@
1
  import os
 
 
 
2
  import uuid
3
  import tempfile
4
  from datetime import datetime, timedelta, timezone
@@ -17,9 +20,9 @@ from linebot.v3.webhooks import MessageEvent, TextMessageContent
17
  import requests
18
  import pandas as pd
19
 
20
- # --- Matplotlib (no GUI) ---
21
  import matplotlib
22
- matplotlib.use("Agg") # headless backend
23
  import matplotlib.pyplot as plt
24
  from matplotlib.colors import Normalize
25
  import matplotlib.cm as cm
@@ -29,7 +32,7 @@ CHANNEL_ACCESS_TOKEN = os.getenv("CHANNEL_ACCESS_TOKEN")
29
  CHANNEL_SECRET = os.getenv("CHANNEL_SECRET")
30
  HF_SPACE_URL = os.getenv("SPACEURL") # e.g., https://<space>.hf.space
31
 
32
- # --- Writable static directory (avoid PermissionError) ---
33
  STATIC_DIR = os.getenv("STATIC_DIR", os.path.join(tempfile.gettempdir(), "static"))
34
  os.makedirs(STATIC_DIR, exist_ok=True)
35
 
@@ -67,7 +70,6 @@ def home():
67
  def healthz():
68
  return "ok"
69
 
70
- # Serve files from our writable static dir (e.g., /tmp/static)
71
  @app.route("/static/<path:filename>")
72
  def serve_static(filename):
73
  return send_from_directory(STATIC_DIR, filename)
@@ -145,12 +147,9 @@ def fetch_taiwan_df_this_year(min_mag=5.0) -> pd.DataFrame | str:
145
  except Exception as e:
146
  return f"❌ 查詢失敗: {e}"
147
 
148
- # --- Map (PNG via Matplotlib, no Chrome needed) ---
149
  def create_and_save_map(df: pd.DataFrame) -> str:
150
- # Figure
151
  fig, ax = plt.subplots(figsize=(9, 6), dpi=150)
152
-
153
- # Taiwan bounding box & grid
154
  lon_min, lon_max = 118.5, 123.5
155
  lat_min, lat_max = 20.5, 26.8
156
  ax.set_xlim(lon_min, lon_max)
@@ -158,17 +157,13 @@ def create_and_save_map(df: pd.DataFrame) -> str:
158
  ax.set_xlabel("Longitude (°E)")
159
  ax.set_ylabel("Latitude (°N)")
160
  ax.set_title(f"今年 ({datetime.now(timezone.utc).year}) 台灣區域顯著地震 (M≥5.0) — UTC")
161
-
162
  ax.grid(True, linestyle="--", linewidth=0.5, alpha=0.4)
163
 
164
- # Scatter colored by magnitude
165
  mags = df["magnitude"].astype(float).clip(lower=0)
166
  norm = Normalize(vmin=max(4.5, mags.min()), vmax=max(6.5, mags.max()))
167
  cmap = cm.get_cmap("YlOrRd")
168
  colors = cmap(norm(mags.values))
169
-
170
- # Size scale (points^2): tune for LINE preview
171
- sizes = 15 + (mags - mags.min()) * 25 # 15–approx 140
172
 
173
  sc = ax.scatter(
174
  df["longitude"].values,
@@ -180,16 +175,13 @@ def create_and_save_map(df: pd.DataFrame) -> str:
180
  alpha=0.9,
181
  )
182
 
183
- # Colorbar
184
  cbar = fig.colorbar(cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax, pad=0.02)
185
  cbar.set_label("Magnitude")
186
 
187
- # Legend example (size ~ mag)
188
  for m in [5.0, 6.0, 7.0]:
189
  ax.scatter([], [], s=15 + (m - mags.min()) * 25, c="none", edgecolor="k", label=f"M {m:.1f}")
190
  ax.legend(title="Size ∝ Magnitude", loc="lower right", framealpha=0.9)
191
 
192
- # Save
193
  filename = f"map_{uuid.uuid4().hex}.png"
194
  filepath = os.path.join(STATIC_DIR, filename)
195
  fig.tight_layout()
@@ -221,7 +213,6 @@ def handle_message(event):
221
  with ApiClient(configuration) as api_client:
222
  line_bot_api = MessagingApi(api_client)
223
 
224
- # Taiwan map command
225
  if ("臺灣地震畫圖" in user_message) or ("台灣地震畫圖" in user_message):
226
  result = fetch_taiwan_df_this_year()
227
  if isinstance(result, pd.DataFrame):
@@ -245,7 +236,6 @@ def handle_message(event):
245
  line_bot_api.reply_message_with_http_info(reply)
246
  return
247
 
248
- # Help
249
  if user_message == "/help":
250
  text = (
251
  "📖 地震預警 dayichen 指令說明\n\n"
@@ -260,7 +250,6 @@ def handle_message(event):
260
  )
261
  return
262
 
263
- # Taiwan list
264
  if ("臺灣地震" in user_message) or ("台灣地震" in user_message):
265
  result = fetch_taiwan_df_this_year()
266
  if isinstance(result, pd.DataFrame):
@@ -274,13 +263,11 @@ def handle_message(event):
274
  reply_text = "\n\n".join(lines)
275
  else:
276
  reply_text = result
277
-
278
  line_bot_api.reply_message_with_http_info(
279
  ReplyMessageRequest(reply_token=event.reply_token, messages=[TextMessage(text=reply_text)])
280
  )
281
  return
282
 
283
- # Global last 24h
284
  if ("地震" in user_message) or ("quake" in user_message):
285
  reply_text = fetch_global_last24h_text()
286
  line_bot_api.reply_message_with_http_info(
@@ -288,7 +275,6 @@ def handle_message(event):
288
  )
289
  return
290
 
291
- # Greeting
292
  if ("你好" in user_message) or ("hi" in user_message):
293
  line_bot_api.reply_message_with_http_info(
294
  ReplyMessageRequest(
@@ -296,7 +282,4 @@ def handle_message(event):
296
  messages=[TextMessage(text="👋 你好!我是地震查詢機器人���\n\n輸入 /help 查看所有指令。")]
297
  )
298
  )
299
- return
300
-
301
- # Unmatched: no-op
302
- return
 
1
  import os
2
+ # ✅ Fix Matplotlib config/cache permission issue in read-only containers
3
+ os.environ["MPLCONFIGDIR"] = "/tmp/matplotlib"
4
+
5
  import uuid
6
  import tempfile
7
  from datetime import datetime, timedelta, timezone
 
20
  import requests
21
  import pandas as pd
22
 
23
+ # --- Matplotlib (headless)
24
  import matplotlib
25
+ matplotlib.use("Agg") # Use Agg backend (no display server required)
26
  import matplotlib.pyplot as plt
27
  from matplotlib.colors import Normalize
28
  import matplotlib.cm as cm
 
32
  CHANNEL_SECRET = os.getenv("CHANNEL_SECRET")
33
  HF_SPACE_URL = os.getenv("SPACEURL") # e.g., https://<space>.hf.space
34
 
35
+ # --- Writable static directory ---
36
  STATIC_DIR = os.getenv("STATIC_DIR", os.path.join(tempfile.gettempdir(), "static"))
37
  os.makedirs(STATIC_DIR, exist_ok=True)
38
 
 
70
  def healthz():
71
  return "ok"
72
 
 
73
  @app.route("/static/<path:filename>")
74
  def serve_static(filename):
75
  return send_from_directory(STATIC_DIR, filename)
 
147
  except Exception as e:
148
  return f"❌ 查詢失敗: {e}"
149
 
150
+ # --- Map with Matplotlib ---
151
  def create_and_save_map(df: pd.DataFrame) -> str:
 
152
  fig, ax = plt.subplots(figsize=(9, 6), dpi=150)
 
 
153
  lon_min, lon_max = 118.5, 123.5
154
  lat_min, lat_max = 20.5, 26.8
155
  ax.set_xlim(lon_min, lon_max)
 
157
  ax.set_xlabel("Longitude (°E)")
158
  ax.set_ylabel("Latitude (°N)")
159
  ax.set_title(f"今年 ({datetime.now(timezone.utc).year}) 台灣區域顯著地震 (M≥5.0) — UTC")
 
160
  ax.grid(True, linestyle="--", linewidth=0.5, alpha=0.4)
161
 
 
162
  mags = df["magnitude"].astype(float).clip(lower=0)
163
  norm = Normalize(vmin=max(4.5, mags.min()), vmax=max(6.5, mags.max()))
164
  cmap = cm.get_cmap("YlOrRd")
165
  colors = cmap(norm(mags.values))
166
+ sizes = 15 + (mags - mags.min()) * 25
 
 
167
 
168
  sc = ax.scatter(
169
  df["longitude"].values,
 
175
  alpha=0.9,
176
  )
177
 
 
178
  cbar = fig.colorbar(cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax, pad=0.02)
179
  cbar.set_label("Magnitude")
180
 
 
181
  for m in [5.0, 6.0, 7.0]:
182
  ax.scatter([], [], s=15 + (m - mags.min()) * 25, c="none", edgecolor="k", label=f"M {m:.1f}")
183
  ax.legend(title="Size ∝ Magnitude", loc="lower right", framealpha=0.9)
184
 
 
185
  filename = f"map_{uuid.uuid4().hex}.png"
186
  filepath = os.path.join(STATIC_DIR, filename)
187
  fig.tight_layout()
 
213
  with ApiClient(configuration) as api_client:
214
  line_bot_api = MessagingApi(api_client)
215
 
 
216
  if ("臺灣地震畫圖" in user_message) or ("台灣地震畫圖" in user_message):
217
  result = fetch_taiwan_df_this_year()
218
  if isinstance(result, pd.DataFrame):
 
236
  line_bot_api.reply_message_with_http_info(reply)
237
  return
238
 
 
239
  if user_message == "/help":
240
  text = (
241
  "📖 地震預警 dayichen 指令說明\n\n"
 
250
  )
251
  return
252
 
 
253
  if ("臺灣地震" in user_message) or ("台灣地震" in user_message):
254
  result = fetch_taiwan_df_this_year()
255
  if isinstance(result, pd.DataFrame):
 
263
  reply_text = "\n\n".join(lines)
264
  else:
265
  reply_text = result
 
266
  line_bot_api.reply_message_with_http_info(
267
  ReplyMessageRequest(reply_token=event.reply_token, messages=[TextMessage(text=reply_text)])
268
  )
269
  return
270
 
 
271
  if ("地震" in user_message) or ("quake" in user_message):
272
  reply_text = fetch_global_last24h_text()
273
  line_bot_api.reply_message_with_http_info(
 
275
  )
276
  return
277
 
 
278
  if ("你好" in user_message) or ("hi" in user_message):
279
  line_bot_api.reply_message_with_http_info(
280
  ReplyMessageRequest(
 
282
  messages=[TextMessage(text="👋 你好!我是地震查詢機器人���\n\n輸入 /help 查看所有指令。")]
283
  )
284
  )
285
+ return