Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
import os
|
| 2 |
import uuid
|
|
|
|
| 3 |
from datetime import datetime, timedelta, timezone
|
| 4 |
|
| 5 |
from flask import Flask, request, abort, send_from_directory
|
|
@@ -10,7 +11,6 @@ from linebot.v3.messaging import (
|
|
| 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 |
|
|
@@ -21,12 +21,14 @@ 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") #
|
| 25 |
|
| 26 |
-
# ---
|
| 27 |
-
|
| 28 |
-
os.makedirs(
|
| 29 |
|
|
|
|
|
|
|
| 30 |
configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
|
| 31 |
handler = WebhookHandler(CHANNEL_SECRET)
|
| 32 |
|
|
@@ -59,9 +61,10 @@ def home():
|
|
| 59 |
def healthz():
|
| 60 |
return "ok"
|
| 61 |
|
|
|
|
| 62 |
@app.route("/static/<path:filename>")
|
| 63 |
def serve_static(filename):
|
| 64 |
-
return send_from_directory(
|
| 65 |
|
| 66 |
# --- Earthquake Query Logic ---
|
| 67 |
USGS_API_BASE_URL = "https://earthquake.usgs.gov/fdsnws/event/1/query"
|
|
@@ -136,9 +139,8 @@ def fetch_taiwan_df_this_year(min_mag=5.0) -> pd.DataFrame | str:
|
|
| 136 |
except Exception as e:
|
| 137 |
return f"❌ 查詢失敗: {e}"
|
| 138 |
|
| 139 |
-
# ---
|
| 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",
|
|
@@ -164,14 +166,14 @@ def create_and_save_map(df: pd.DataFrame) -> str:
|
|
| 164 |
countrycolor="#aaa",
|
| 165 |
)
|
| 166 |
filename = f"map_{uuid.uuid4().hex}.png"
|
| 167 |
-
filepath = os.path.join(
|
| 168 |
-
#
|
| 169 |
-
fig.write_image(filepath, scale=2, width=900, height=600)
|
| 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 ---
|
|
@@ -270,5 +272,5 @@ def handle_message(event):
|
|
| 270 |
)
|
| 271 |
return
|
| 272 |
|
| 273 |
-
#
|
| 274 |
return
|
|
|
|
| 1 |
import os
|
| 2 |
import uuid
|
| 3 |
+
import tempfile
|
| 4 |
from datetime import datetime, timedelta, timezone
|
| 5 |
|
| 6 |
from flask import Flask, request, abort, send_from_directory
|
|
|
|
| 11 |
Configuration, ApiClient, MessagingApi,
|
| 12 |
ReplyMessageRequest, TextMessage
|
| 13 |
)
|
|
|
|
| 14 |
from linebot.v3.messaging.models import ImageMessage
|
| 15 |
from linebot.v3.webhooks import MessageEvent, TextMessageContent
|
| 16 |
|
|
|
|
| 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") # e.g., https://<space>.hf.space
|
| 25 |
|
| 26 |
+
# --- Writable static directory (avoid PermissionError) ---
|
| 27 |
+
STATIC_DIR = os.getenv("STATIC_DIR", os.path.join(tempfile.gettempdir(), "static"))
|
| 28 |
+
os.makedirs(STATIC_DIR, exist_ok=True)
|
| 29 |
|
| 30 |
+
# --- Flask & LINE Bot ---
|
| 31 |
+
app = Flask(__name__)
|
| 32 |
configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
|
| 33 |
handler = WebhookHandler(CHANNEL_SECRET)
|
| 34 |
|
|
|
|
| 61 |
def healthz():
|
| 62 |
return "ok"
|
| 63 |
|
| 64 |
+
# Serve files from our writable static dir (e.g., /tmp/static)
|
| 65 |
@app.route("/static/<path:filename>")
|
| 66 |
def serve_static(filename):
|
| 67 |
+
return send_from_directory(STATIC_DIR, filename)
|
| 68 |
|
| 69 |
# --- Earthquake Query Logic ---
|
| 70 |
USGS_API_BASE_URL = "https://earthquake.usgs.gov/fdsnws/event/1/query"
|
|
|
|
| 139 |
except Exception as e:
|
| 140 |
return f"❌ 查詢失敗: {e}"
|
| 141 |
|
| 142 |
+
# --- Map (PNG via kaleido) ---
|
| 143 |
def create_and_save_map(df: pd.DataFrame) -> str:
|
|
|
|
| 144 |
fig = px.scatter_geo(
|
| 145 |
df,
|
| 146 |
lat="latitude",
|
|
|
|
| 166 |
countrycolor="#aaa",
|
| 167 |
)
|
| 168 |
filename = f"map_{uuid.uuid4().hex}.png"
|
| 169 |
+
filepath = os.path.join(STATIC_DIR, filename)
|
| 170 |
+
fig.write_image(filepath, scale=2, width=900, height=600) # needs kaleido
|
|
|
|
| 171 |
return filename
|
| 172 |
|
| 173 |
def _base_url_for_images() -> str:
|
| 174 |
if HF_SPACE_URL:
|
| 175 |
return HF_SPACE_URL.rstrip("/")
|
| 176 |
+
# request.url_root includes trailing slash; safe if running behind proxy
|
| 177 |
return request.url_root.rstrip("/")
|
| 178 |
|
| 179 |
# --- LINE Webhook ---
|
|
|
|
| 272 |
)
|
| 273 |
return
|
| 274 |
|
| 275 |
+
# Unmatched: no-op
|
| 276 |
return
|