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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -14
app.py CHANGED
@@ -1,5 +1,5 @@
1
  import os
2
- # ✅ Fix Matplotlib config/cache permission issue in read-only containers
3
  os.environ["MPLCONFIGDIR"] = "/tmp/matplotlib"
4
 
5
  import uuid
@@ -20,17 +20,35 @@ from linebot.v3.webhooks import MessageEvent, TextMessageContent
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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  # --- Environment Variables ---
31
  CHANNEL_ACCESS_TOKEN = os.getenv("CHANNEL_ACCESS_TOKEN")
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"))
@@ -41,7 +59,7 @@ app = Flask(__name__)
41
  configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
42
  handler = WebhookHandler(CHANNEL_SECRET)
43
 
44
- # --- Welcome & Health ---
45
  @app.route("/", methods=["GET"])
46
  def home():
47
  return """
@@ -74,7 +92,7 @@ def healthz():
74
  def serve_static(filename):
75
  return send_from_directory(STATIC_DIR, filename)
76
 
77
- # --- Earthquake Query Logic ---
78
  USGS_API_BASE_URL = "https://earthquake.usgs.gov/fdsnws/event/1/query"
79
 
80
  def _iso(dt: datetime) -> str:
@@ -147,7 +165,7 @@ def fetch_taiwan_df_this_year(min_mag=5.0) -> pd.DataFrame | str:
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
@@ -156,7 +174,7 @@ def create_and_save_map(df: pd.DataFrame) -> str:
156
  ax.set_ylim(lat_min, lat_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)
@@ -165,7 +183,7 @@ def create_and_save_map(df: pd.DataFrame) -> str:
165
  colors = cmap(norm(mags.values))
166
  sizes = 15 + (mags - mags.min()) * 25
167
 
168
- sc = ax.scatter(
169
  df["longitude"].values,
170
  df["latitude"].values,
171
  s=sizes,
@@ -178,10 +196,6 @@ def create_and_save_map(df: pd.DataFrame) -> str:
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()
@@ -190,6 +204,7 @@ def create_and_save_map(df: pd.DataFrame) -> str:
190
  return filename
191
 
192
  def _base_url_for_images() -> str:
 
193
  if HF_SPACE_URL:
194
  return HF_SPACE_URL.rstrip("/")
195
  return request.url_root.rstrip("/")
@@ -241,7 +256,7 @@ def handle_message(event):
241
  "📖 地震預警 dayichen 指令說明\n\n"
242
  "➡️ /help\n 說明:顯示此幫助訊息。\n\n"
243
  "➡️ 地震\n 說明:查詢全球最近 24 小時內,M≥5.0 的顯著地震。\n\n"
244
- "➡️ 臺灣地震 / 台灣地震\n 說明:查詢今年以來台灣區域 (21–26°N, 119–123°E) M≥5.0 地震。\n\n"
245
  "➡️ 臺灣地震畫圖 / 台灣地震畫圖\n 說明:繪製今年台灣區域 M≥5.0 地震分佈圖並回傳圖片。\n\n"
246
  "➡️ 你好\n 說明:顯示歡迎訊息。"
247
  )
 
1
  import os
2
+ # ✅ Avoid permission issues for Matplotlib config/cache
3
  os.environ["MPLCONFIGDIR"] = "/tmp/matplotlib"
4
 
5
  import uuid
 
20
  import requests
21
  import pandas as pd
22
 
23
+ # --- Matplotlib (headless) ---
24
  import matplotlib
25
+ matplotlib.use("Agg")
26
  import matplotlib.pyplot as plt
27
  from matplotlib.colors import Normalize
28
  import matplotlib.cm as cm
29
+ from matplotlib import font_manager as fm
30
+
31
+ # ✅ Try to set a CJK-capable font for Chinese text
32
+ # Install fonts-noto-cjk in container for best result
33
+ possible_fonts = [
34
+ "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
35
+ "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
36
+ "/usr/share/fonts/truetype/arphic/ukai.ttc",
37
+ "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
38
+ ]
39
+ for font_path in possible_fonts:
40
+ if os.path.exists(font_path):
41
+ font_prop = fm.FontProperties(fname=font_path)
42
+ matplotlib.rcParams["font.family"] = font_prop.get_name()
43
+ print(f"✅ Using CJK font: {font_prop.get_name()}")
44
+ break
45
+ else:
46
+ print("⚠️ No CJK font found, Chinese glyphs may not display correctly.")
47
 
48
  # --- Environment Variables ---
49
  CHANNEL_ACCESS_TOKEN = os.getenv("CHANNEL_ACCESS_TOKEN")
50
  CHANNEL_SECRET = os.getenv("CHANNEL_SECRET")
51
+ HF_SPACE_URL = os.getenv("SPACEURL") # e.g., https://your-space.hf.space
52
 
53
  # --- Writable static directory ---
54
  STATIC_DIR = os.getenv("STATIC_DIR", os.path.join(tempfile.gettempdir(), "static"))
 
59
  configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
60
  handler = WebhookHandler(CHANNEL_SECRET)
61
 
62
+ # --- Routes ---
63
  @app.route("/", methods=["GET"])
64
  def home():
65
  return """
 
92
  def serve_static(filename):
93
  return send_from_directory(STATIC_DIR, filename)
94
 
95
+ # --- Earthquake Data Functions ---
96
  USGS_API_BASE_URL = "https://earthquake.usgs.gov/fdsnws/event/1/query"
97
 
98
  def _iso(dt: datetime) -> str:
 
165
  except Exception as e:
166
  return f"❌ 查詢失敗: {e}"
167
 
168
+ # --- Map Creation ---
169
  def create_and_save_map(df: pd.DataFrame) -> str:
170
  fig, ax = plt.subplots(figsize=(9, 6), dpi=150)
171
  lon_min, lon_max = 118.5, 123.5
 
174
  ax.set_ylim(lat_min, lat_max)
175
  ax.set_xlabel("Longitude (°E)")
176
  ax.set_ylabel("Latitude (°N)")
177
+ ax.set_title(f"今年 ({datetime.now(timezone.utc).year}) 台灣區域顯著地震 (M≥5.0) — UTC")
178
  ax.grid(True, linestyle="--", linewidth=0.5, alpha=0.4)
179
 
180
  mags = df["magnitude"].astype(float).clip(lower=0)
 
183
  colors = cmap(norm(mags.values))
184
  sizes = 15 + (mags - mags.min()) * 25
185
 
186
+ ax.scatter(
187
  df["longitude"].values,
188
  df["latitude"].values,
189
  s=sizes,
 
196
  cbar = fig.colorbar(cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax, pad=0.02)
197
  cbar.set_label("Magnitude")
198
 
 
 
 
 
199
  filename = f"map_{uuid.uuid4().hex}.png"
200
  filepath = os.path.join(STATIC_DIR, filename)
201
  fig.tight_layout()
 
204
  return filename
205
 
206
  def _base_url_for_images() -> str:
207
+ # Always prefer HF_SPACE_URL for LINE
208
  if HF_SPACE_URL:
209
  return HF_SPACE_URL.rstrip("/")
210
  return request.url_root.rstrip("/")
 
256
  "📖 地震預警 dayichen 指令說明\n\n"
257
  "➡️ /help\n 說明:顯示此幫助訊息。\n\n"
258
  "➡️ 地震\n 說明:查詢全球最近 24 小時內,M≥5.0 的顯著地震。\n\n"
259
+ "➡️ 臺灣地震 / 台灣地震\n 說明:查詢今年以來台灣區域 M≥5.0 地震。\n\n"
260
  "➡️ 臺灣地震畫圖 / 台灣地震畫圖\n 說明:繪製今年台灣區域 M≥5.0 地震分佈圖並回傳圖片。\n\n"
261
  "➡️ 你好\n 說明:顯示歡迎訊息。"
262
  )