File size: 7,938 Bytes
2dcae4b
1b65622
a024ea5
 
1b65622
 
2dcae4b
 
 
 
 
 
 
 
a024ea5
2dcae4b
a024ea5
 
 
2dcae4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a024ea5
 
 
ef3829e
a024ea5
2dcae4b
a024ea5
 
ef3829e
ebf8ad6
 
 
 
2dcae4b
ebf8ad6
 
 
2dcae4b
ebf8ad6
 
a024ea5
ebf8ad6
 
 
 
a024ea5
ebf8ad6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a024ea5
ebf8ad6
 
 
 
 
2dcae4b
ebf8ad6
 
 
 
2dcae4b
ebf8ad6
 
 
 
 
 
 
 
 
2dcae4b
ebf8ad6
 
 
 
 
 
 
 
 
 
2dcae4b
ebf8ad6
 
 
 
 
 
 
a024ea5
2dcae4b
 
 
 
 
 
 
 
 
 
 
d584c36
1b65622
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
# ui/layouts.py (最終完整版)
import gradio as gr
from config import content, data, defaults
from core import callbacks

def create_ui(visit_count_html: str, theme: gr.Theme):
    """
    Creates and returns the Gradio UI Blocks.
    
    Args:
        visit_count_html: The Markdown string to display the visit count.
        theme: The Gradio theme object to apply to the UI.
    """
    
    with gr.Blocks(theme=theme, title="地球物理學") as demo:
        # --- 自訂頂部 Header ---
        gr.Markdown(
            """
            <style>
            .custom-header {
                background: linear-gradient(135deg, #005f73, #0a9396);
                color: #fff;
                padding: 4rem 2rem;
                text-align: center;
                border-radius: 0 0 20px 20px;
                margin-bottom: 2rem;
                box-shadow: 0 8px 15px rgba(0,0,0,0.1);
            }
            .custom-header h1 {
                font-size: 3.5rem;
                font-weight: 700;
                margin-bottom: 0.8rem;
                line-height: 1.2;
            }
            .custom-header p {
                font-size: 1.6rem;
                font-weight: 400;
                opacity: 0.9;
                margin-top: 0;
            }
            @media (max-width: 768px) {
                .custom-header {
                    padding: 3rem 1rem;
                    border-radius: 0;
                }
                .custom-header h1 {
                    font-size: 2.5rem;
                }
                .custom-header p {
                    font-size: 1.2rem;
                }
            }
            </style>
            <div class="custom-header">
                <h1>地球物理概論</h1>
                <p>在這裡,您不僅能學習理論,更能透過「互動實驗室」親手編寫程式碼、視覺化地震資料,並隨時向「AI 助教」提問,獲取課程解答與即時的全球地震資訊。立即開始您的地球物理探索之旅吧!</p>
            </div>
            """
        )

        # --- 主導覽列 Tab 容器 ---
        with gr.Tabs(selected=0):
        
            with gr.TabItem("🎯 課程目標"):
                gr.Markdown(content.course_goals_md)

            with gr.TabItem("🗓️ 課程進度"):
                gr.Markdown("### 每週課程安排")
                gr.DataFrame(data.schedule_df, wrap=True)

            with gr.TabItem("💯 成績計算"):
                gr.Markdown(content.grading_policy_md)

            with gr.TabItem("🚀 互動體驗區 (程式碼實驗室)"):
                gr.Markdown("## 🚀 互動程式碼實驗室")
                gr.Markdown("歡迎來到這裡!直接修改下方的 Python 程式碼,點擊「執行」,即可在右側看到成果。這是學習程式與地球物理最直接的方式!")
                gr.Info("注意:執行環境已受限,僅支援資料視覺化相關操作。請勿嘗試檔案讀寫或網路請求。")

                with gr.Accordion("🌍 地圖繪製實驗室 (PyGMT/Cartopy 概念)", open=True):
                    with gr.Row():
                        with gr.Column(scale=2):
                            gr.Markdown("### 說明\n這段程式碼使用 `cartopy` 和 `matplotlib` 函式庫來繪製地理地圖。\n\n**您可以試著:**\n1. 修改 `center_lon`, `center_lat` 來改變地圖中心。\n2. 調整 `extent_lon`, `extent_lat` 來縮放地圖。\n3. 將 `coastline_color` 改成 'red' 或其他顏色。\n4. **在 `symbols` 列表中新增或修改字典,來繪製自訂的符號(例如:標示您所在的城市)。**")
                            map_code = gr.Code(label="可編輯的 Python 程式碼", value=defaults.DEFAULT_MAP_CODE, language="python", lines=25)
                            map_run_button = gr.Button("執行程式碼", variant="primary")
                        with gr.Column(scale=3):
                            map_plot_output = gr.Plot(label="地圖輸出")
                            map_console_output = gr.Textbox(label="執行結果 / 錯誤訊息", lines=8, interactive=False)
                
                with gr.Accordion("📈 震波圖繪製實驗室 (ObsPy 概念)", open=False):
                    with gr.Row():
                        with gr.Column(scale=2):
                            gr.Markdown("### 說明\n這段程式碼使用 `numpy` 產生模擬的地震波數據,並用 `matplotlib` 將其視覺化。\n\n**您可以試著:**\n1. 修改 `p_wave_arrival` 和 `s_wave_arrival` 來改變 P/S 波的抵達時間。\n2. 調整 `main_freq` 來改變地震波的頻率(數值越大,波形越密集)。\n3. 將 `decay_rate` 調小,觀察振幅衰減變慢的效果。")
                            seismo_code = gr.Code(label="可編輯的 Python 程式碼", value=defaults.DEFAULT_SEISMO_CODE, language="python", lines=25)
                            seismo_run_button = gr.Button("執行程式碼", variant="primary")
                        with gr.Column(scale=3):
                            seismo_plot_output = gr.Plot(label="震波圖輸出")
                            seismo_console_output = gr.Textbox(label="執行結果 / 錯誤訊息", lines=8, interactive=False)

            with gr.TabItem("🤖 AI 課程助教"):
                with gr.Group():
                    gr.Markdown("### 🤖 AI 課程助教 (知識庫 & 即時資訊強化版)")
                    gr.Markdown("""
                    歡迎使用課程 AI 助教!我整合了靜態的課程知識與多種即時資訊來源,您可以隨時向我提問。

                    ---
                    
                    #### 📚 **課程知識庫**
                    我可以回答關於本課程的各種問題,例如:`「這門課的評分標準是什麼?」`

                    ---
                    
                    #### ⚡ **即時資訊查詢**
                    我還能幫您查詢最新的動態資訊,試著問我:
                    - **📰 今日新聞**:`「今天有什麼重要新聞?」`
                    - **🚨 地震報告**:`「最新的 CWA 顯著地震報告」` 或 `「最近全球有哪些大地震?」`
                    - **📢 災害預警**:`「現在有地震預警嗎?」`
                    
                    ---

                    #### 🔎 **進階地震查詢**
                    您也可以指定日期與規模來查詢全球地震紀錄,請**完全依照以下格式**提問:
                    - `查詢 2024-04-01 到 2024-04-07 規模 6.0 以上地震`
                    """)
                    
                    custom_textbox = gr.Textbox(
                        placeholder="對課程有什麼問題嗎?或查詢即時資訊...",
                        show_label=False,
                        container=False,
                    )

                    gr.ChatInterface(
                        callbacks.ai_chatbot_with_kb,
                        chatbot=gr.Chatbot(height=450, type="messages", avatar_images=(None, "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png")),
                        title="課程AI助教",
                        description="由結構化知識庫與即時工具驅動的問答機器人",
                        textbox=custom_textbox,
                    )

        # --- 連接按鈕與後端執行函式 ---
        map_run_button.click(
            fn=lambda code: callbacks.execute_user_code(code, "地圖繪製"),
            inputs=[map_code],
            outputs=[map_plot_output, map_console_output]
        )
        seismo_run_button.click(
            fn=lambda code: callbacks.execute_user_code(code, "震波圖"),
            inputs=[seismo_code],
            outputs=[seismo_plot_output, seismo_console_output]
        )
            
    return demo