File size: 6,477 Bytes
79f2ada
071beff
ce425c0
 
 
79f2ada
ce425c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139ddee
ce425c0
 
 
 
 
 
 
 
 
 
 
 
 
97ce441
ce425c0
 
 
139ddee
ce425c0
 
139ddee
ce425c0
 
 
139ddee
ce425c0
 
97ce441
ce425c0
 
 
 
 
 
 
 
 
139ddee
ce425c0
 
 
 
139ddee
 
ce425c0
97ce441
ce425c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# command_handler.py
import pandas as pd
from linebot.v3.messaging import TextMessage, ImageMessage

# 匯入服務函式
from cwa_service import fetch_cwa_alarm_list, fetch_significant_earthquakes, fetch_local_earthquakes, fetch_latest_significant_earthquake
from usgs_service import fetch_global_last24h_text, fetch_taiwan_df_this_year
from plotting_service import create_and_save_map
from ai_service import generate_ai_text
from config import CURRENT_YEAR, HF_SPACE_URL

def get_help_message() -> TextMessage:
    """回傳包含所有可用指令的說明訊息。"""
    text = (
        "📖 指令列表\n\n"
        "【地震資訊】\n"
        "• /latest - 查詢最新一筆顯著地震(含圖)\n"
        "• /global - 查詢全球近24小時顯著地震\n"
        "• /taiwan - 顯示今年台灣顯著地震列表\n"
        "• /map - 取得台灣顯著地震地圖連結\n"
        "• /alert - 獲取 CWA 最新地震預警\n"
        "• /significant - CWA 最新顯著有感地震\n"
        "• /local <縣市> - 小區域地震 (可選填縣市)\n\n"
        "【AI 與工具】\n"
        "• /ai <問題> - 與 AI 助理對話\n\n"
        "【基本指令】\n"
        "• /info - 關於此機器人\n"
        "• /help - 顯示此說明"
    )
    return TextMessage(text=text)

def get_info_message() -> TextMessage:
    """回傳機器人資訊。"""
    text = (
        "🤖 關於我\n\n"
        "我是一個多功能助理機器人,提供地震查詢與 AI 對話功能。\n\n"
        "• 版本: 2.5\n"
        "• 資料來源: CWA, USGS, Hugging Face\n"
        "• 開發者: dayichen"
    )
    return TextMessage(text=text)

def get_taiwan_earthquake_list() -> TextMessage:
    """回傳近期的台灣地震文字列表。"""
    result = fetch_taiwan_df_this_year()
    if isinstance(result, pd.DataFrame):
        count = len(result)
        lines = [f"🇹🇼 今年 ({CURRENT_YEAR} 年) 台灣區域顯著地震 (M≥5.0),共 {count} 筆:", "-" * 20]
        for _, row in result.head(15).iterrows():
            t = row["time_utc"].strftime("%Y-%m-%d %H:%M")
            lines.append(
                f"規模: {row['magnitude']:.1f} | 日期時間: {t} (UTC)\n"
                f"地點: {row['place']}\n"
                f"報告連結: {row.get('url', '無')}"
            )
        if count > 15:
            lines.append(f"... (還有 {count - 15} 筆,請用 /map 查看全部)")
        reply_text = "\n\n".join(lines)
    else:
        reply_text = result
    return TextMessage(text=reply_text)

def get_taiwan_earthquake_map(base_url: str) -> list:
    """產生地震地圖,並回傳包含連結的文字訊息。"""
    result = fetch_taiwan_df_this_year()
    if isinstance(result, pd.DataFrame):
        filename = create_and_save_map(result)
        image_url = f"{(HF_SPACE_URL or base_url)}/static/{filename}"
        reply_text = (
            "🗺️ 已為您繪製地震分佈圖。\n\n"
            "請點擊以下連結查看圖片:\n"
            f"{image_url}"
        )
        return [TextMessage(text=reply_text)]
    else:
        return [TextMessage(text=result)]

def get_latest_earthquake_reply() -> list:
    """獲取最新地震資訊並組合成 LINE 訊息"""
    try:
        latest_eq = fetch_latest_significant_earthquake()
        if not latest_eq:
            return [TextMessage(text="✅ 近期無顯著有感地震報告。")]

        mag_str = f"{latest_eq['Magnitude']:.1f}" if latest_eq.get('Magnitude') is not None else "—"
        depth_str = f"{latest_eq['Depth']:.0f}" if latest_eq.get('Depth') is not None else "—"
        
        text_message_content = (
            f"🚨 CWA 最新顯著有感地震\n"
            f"----------------------------------\n"
            f"時間: {latest_eq.get('TimeStr', '—')}\n"
            f"地點: {latest_eq.get('Location', '—')}\n"
            f"規模: M{mag_str} | 深度: {depth_str} km\n"
            f"報告: {latest_eq.get('URL', '無')}"
        )
        reply_messages = [TextMessage(text=text_message_content)]

        if latest_eq.get("ImageURL"):
            image_url = latest_eq["ImageURL"]
            reply_messages.append(
                ImageMessage(original_content_url=image_url, preview_image_url=image_url)
            )
        
        return reply_messages
    except Exception as e:
        return [TextMessage(text=f"❌ 查詢最新地震失敗:{e}")]

def process_message(user_message_raw: str, request_base_url: str) -> list:
    """處理使用者的文字訊息並回傳一個包含回覆訊息的列表。"""
    user_message = (user_message_raw or "").strip()
    
    # 將舊指令對應到新指令,提供向下相容
    if user_message.lower() in ["地震", "quake"]:
        user_message = "/global"
    elif user_message.lower() in ["台灣地震", "臺灣地震"]:
        user_message = "/taiwan"
    elif user_message.lower() in ["台灣地震畫圖", "臺灣地震畫圖"]:
        user_message = "/map"
    elif user_message.lower() == "地震預警":
        user_message = "/alert"

    if user_message.startswith('/'):
        parts = user_message.split(' ', 1)
        command = parts[0].lower()
        arg = parts[1] if len(parts) > 1 else ""

        if command == '/help':
            return [get_help_message()]
        elif command == '/info':
            return [get_info_message()]
        elif command == '/latest':
            return get_latest_earthquake_reply()
        elif command == '/global':
            return [TextMessage(text=fetch_global_last24h_text())]
        elif command == '/taiwan':
            return [get_taiwan_earthquake_list()]
        elif command == '/map':
            return get_taiwan_earthquake_map(request_base_url)
        elif command == '/alert':
            return [TextMessage(text=fetch_cwa_alarm_list(limit=5))]
        elif command == '/significant':
            return [TextMessage(text=fetch_significant_earthquakes(limit=5))]
        elif command == '/local':
            return [TextMessage(text=fetch_local_earthquakes(area_name=arg))]
        elif command == '/ai':
            if not arg:
                return [TextMessage(text="請輸入問題,例如:/ai 台灣最高的山是哪座?")]
            return [TextMessage(text=generate_ai_text(arg))]

    # 若非指令,則預設交給 AI 處理 (作為備援)
    return [TextMessage(text=generate_ai_text(user_message))]