Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -10,8 +10,8 @@ from linebot.v3.messaging import (
|
|
| 10 |
Configuration, ApiClient, MessagingApi,
|
| 11 |
ReplyMessageRequest, TextMessage
|
| 12 |
)
|
| 13 |
-
#
|
| 14 |
-
from linebot.v3.messaging.models
|
| 15 |
from linebot.v3.webhooks import MessageEvent, TextMessageContent
|
| 16 |
|
| 17 |
import requests
|
|
@@ -21,11 +21,10 @@ import plotly.express as px
|
|
| 21 |
# --- Environment Variables ---
|
| 22 |
CHANNEL_ACCESS_TOKEN = os.getenv("CHANNEL_ACCESS_TOKEN")
|
| 23 |
CHANNEL_SECRET = os.getenv("CHANNEL_SECRET")
|
| 24 |
-
HF_SPACE_URL = os.getenv("SPACEURL") # optional
|
| 25 |
|
| 26 |
# --- Flask & LINE Bot Initialization ---
|
| 27 |
app = Flask(__name__)
|
| 28 |
-
|
| 29 |
os.makedirs("static", exist_ok=True)
|
| 30 |
|
| 31 |
configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
|
|
@@ -68,7 +67,6 @@ def serve_static(filename):
|
|
| 68 |
USGS_API_BASE_URL = "https://earthquake.usgs.gov/fdsnws/event/1/query"
|
| 69 |
|
| 70 |
def _iso(dt: datetime) -> str:
|
| 71 |
-
# USGS accepts Z times; ensure RFC3339-like
|
| 72 |
return dt.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S")
|
| 73 |
|
| 74 |
def fetch_global_last24h_text(min_mag=5.0, limit=10) -> str:
|
|
@@ -140,7 +138,7 @@ def fetch_taiwan_df_this_year(min_mag=5.0) -> pd.DataFrame | str:
|
|
| 140 |
|
| 141 |
# --- Offline-friendly Map (PNG) ---
|
| 142 |
def create_and_save_map(df: pd.DataFrame) -> str:
|
| 143 |
-
#
|
| 144 |
fig = px.scatter_geo(
|
| 145 |
df,
|
| 146 |
lat="latitude",
|
|
@@ -157,7 +155,6 @@ def create_and_save_map(df: pd.DataFrame) -> str:
|
|
| 157 |
title=f"<b>今年 ({datetime.now(timezone.utc).year}) 台灣區域顯著地震 (M≥5.0)</b>",
|
| 158 |
margin=dict(r=0, t=40, l=0, b=0),
|
| 159 |
)
|
| 160 |
-
# Focus view roughly on Taiwan
|
| 161 |
fig.update_geos(
|
| 162 |
lonaxis_range=[118.5, 123.5],
|
| 163 |
lataxis_range=[20.5, 26.8],
|
|
@@ -173,10 +170,8 @@ def create_and_save_map(df: pd.DataFrame) -> str:
|
|
| 173 |
return filename
|
| 174 |
|
| 175 |
def _base_url_for_images() -> str:
|
| 176 |
-
# Prefer explicit Space URL if set, else derive from request (works on HF Spaces)
|
| 177 |
if HF_SPACE_URL:
|
| 178 |
return HF_SPACE_URL.rstrip("/")
|
| 179 |
-
# request.url_root ends with '/'
|
| 180 |
return request.url_root.rstrip("/")
|
| 181 |
|
| 182 |
# --- LINE Webhook ---
|
|
@@ -198,18 +193,17 @@ def handle_message(event):
|
|
| 198 |
with ApiClient(configuration) as api_client:
|
| 199 |
line_bot_api = MessagingApi(api_client)
|
| 200 |
|
| 201 |
-
#
|
| 202 |
if ("臺灣地震畫圖" in user_message) or ("台灣地震畫圖" in user_message):
|
| 203 |
result = fetch_taiwan_df_this_year()
|
| 204 |
if isinstance(result, pd.DataFrame):
|
| 205 |
filename = create_and_save_map(result)
|
| 206 |
image_url = f"{_base_url_for_images()}/static/{filename}"
|
| 207 |
-
|
| 208 |
reply = ReplyMessageRequest(
|
| 209 |
reply_token=event.reply_token,
|
| 210 |
messages=[
|
| 211 |
TextMessage(text="🗺️ 已為您繪製今年台灣區域 M≥5.0 地震分佈圖(UTC)。"),
|
| 212 |
-
|
| 213 |
original_content_url=image_url,
|
| 214 |
preview_image_url=image_url,
|
| 215 |
),
|
|
@@ -223,7 +217,7 @@ def handle_message(event):
|
|
| 223 |
line_bot_api.reply_message_with_http_info(reply)
|
| 224 |
return
|
| 225 |
|
| 226 |
-
#
|
| 227 |
if user_message == "/help":
|
| 228 |
text = (
|
| 229 |
"📖 地震預警 dayichen 指令說明\n\n"
|
|
@@ -238,7 +232,7 @@ def handle_message(event):
|
|
| 238 |
)
|
| 239 |
return
|
| 240 |
|
| 241 |
-
#
|
| 242 |
if ("臺灣地震" in user_message) or ("台灣地震" in user_message):
|
| 243 |
result = fetch_taiwan_df_this_year()
|
| 244 |
if isinstance(result, pd.DataFrame):
|
|
@@ -258,7 +252,7 @@ def handle_message(event):
|
|
| 258 |
)
|
| 259 |
return
|
| 260 |
|
| 261 |
-
#
|
| 262 |
if ("地震" in user_message) or ("quake" in user_message):
|
| 263 |
reply_text = fetch_global_last24h_text()
|
| 264 |
line_bot_api.reply_message_with_http_info(
|
|
@@ -266,7 +260,7 @@ def handle_message(event):
|
|
| 266 |
)
|
| 267 |
return
|
| 268 |
|
| 269 |
-
#
|
| 270 |
if ("你好" in user_message) or ("hi" in user_message):
|
| 271 |
line_bot_api.reply_message_with_http_info(
|
| 272 |
ReplyMessageRequest(
|
|
@@ -276,5 +270,5 @@ def handle_message(event):
|
|
| 276 |
)
|
| 277 |
return
|
| 278 |
|
| 279 |
-
#
|
| 280 |
return
|
|
|
|
| 10 |
Configuration, ApiClient, MessagingApi,
|
| 11 |
ReplyMessageRequest, TextMessage
|
| 12 |
)
|
| 13 |
+
# ✅ LINE v3: use ImageMessage (not ImageSendMessage)
|
| 14 |
+
from linebot.v3.messaging.models import ImageMessage
|
| 15 |
from linebot.v3.webhooks import MessageEvent, TextMessageContent
|
| 16 |
|
| 17 |
import requests
|
|
|
|
| 21 |
# --- Environment Variables ---
|
| 22 |
CHANNEL_ACCESS_TOKEN = os.getenv("CHANNEL_ACCESS_TOKEN")
|
| 23 |
CHANNEL_SECRET = os.getenv("CHANNEL_SECRET")
|
| 24 |
+
HF_SPACE_URL = os.getenv("SPACEURL") # optional: https://<space-name>.hf.space
|
| 25 |
|
| 26 |
# --- Flask & LINE Bot Initialization ---
|
| 27 |
app = Flask(__name__)
|
|
|
|
| 28 |
os.makedirs("static", exist_ok=True)
|
| 29 |
|
| 30 |
configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
|
|
|
|
| 67 |
USGS_API_BASE_URL = "https://earthquake.usgs.gov/fdsnws/event/1/query"
|
| 68 |
|
| 69 |
def _iso(dt: datetime) -> str:
|
|
|
|
| 70 |
return dt.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S")
|
| 71 |
|
| 72 |
def fetch_global_last24h_text(min_mag=5.0, limit=10) -> str:
|
|
|
|
| 138 |
|
| 139 |
# --- Offline-friendly Map (PNG) ---
|
| 140 |
def create_and_save_map(df: pd.DataFrame) -> str:
|
| 141 |
+
# scatter_geo → renders via kaleido without external tiles
|
| 142 |
fig = px.scatter_geo(
|
| 143 |
df,
|
| 144 |
lat="latitude",
|
|
|
|
| 155 |
title=f"<b>今年 ({datetime.now(timezone.utc).year}) 台灣區域顯著地震 (M≥5.0)</b>",
|
| 156 |
margin=dict(r=0, t=40, l=0, b=0),
|
| 157 |
)
|
|
|
|
| 158 |
fig.update_geos(
|
| 159 |
lonaxis_range=[118.5, 123.5],
|
| 160 |
lataxis_range=[20.5, 26.8],
|
|
|
|
| 170 |
return filename
|
| 171 |
|
| 172 |
def _base_url_for_images() -> str:
|
|
|
|
| 173 |
if HF_SPACE_URL:
|
| 174 |
return HF_SPACE_URL.rstrip("/")
|
|
|
|
| 175 |
return request.url_root.rstrip("/")
|
| 176 |
|
| 177 |
# --- LINE Webhook ---
|
|
|
|
| 193 |
with ApiClient(configuration) as api_client:
|
| 194 |
line_bot_api = MessagingApi(api_client)
|
| 195 |
|
| 196 |
+
# Taiwan map command
|
| 197 |
if ("臺灣地震畫圖" in user_message) or ("台灣地震畫圖" in user_message):
|
| 198 |
result = fetch_taiwan_df_this_year()
|
| 199 |
if isinstance(result, pd.DataFrame):
|
| 200 |
filename = create_and_save_map(result)
|
| 201 |
image_url = f"{_base_url_for_images()}/static/{filename}"
|
|
|
|
| 202 |
reply = ReplyMessageRequest(
|
| 203 |
reply_token=event.reply_token,
|
| 204 |
messages=[
|
| 205 |
TextMessage(text="🗺️ 已為您繪製今年台灣區域 M≥5.0 地震分佈圖(UTC)。"),
|
| 206 |
+
ImageMessage(
|
| 207 |
original_content_url=image_url,
|
| 208 |
preview_image_url=image_url,
|
| 209 |
),
|
|
|
|
| 217 |
line_bot_api.reply_message_with_http_info(reply)
|
| 218 |
return
|
| 219 |
|
| 220 |
+
# Help
|
| 221 |
if user_message == "/help":
|
| 222 |
text = (
|
| 223 |
"📖 地震預警 dayichen 指令說明\n\n"
|
|
|
|
| 232 |
)
|
| 233 |
return
|
| 234 |
|
| 235 |
+
# Taiwan list
|
| 236 |
if ("臺灣地震" in user_message) or ("台灣地震" in user_message):
|
| 237 |
result = fetch_taiwan_df_this_year()
|
| 238 |
if isinstance(result, pd.DataFrame):
|
|
|
|
| 252 |
)
|
| 253 |
return
|
| 254 |
|
| 255 |
+
# Global last 24h
|
| 256 |
if ("地震" in user_message) or ("quake" in user_message):
|
| 257 |
reply_text = fetch_global_last24h_text()
|
| 258 |
line_bot_api.reply_message_with_http_info(
|
|
|
|
| 260 |
)
|
| 261 |
return
|
| 262 |
|
| 263 |
+
# Greeting
|
| 264 |
if ("你好" in user_message) or ("hi" in user_message):
|
| 265 |
line_bot_api.reply_message_with_http_info(
|
| 266 |
ReplyMessageRequest(
|
|
|
|
| 270 |
)
|
| 271 |
return
|
| 272 |
|
| 273 |
+
# No-op on unmatched text (keeps reply_token free for other handlers)
|
| 274 |
return
|