# 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( """

地球物理概論

在這裡,您不僅能學習理論,更能透過「互動實驗室」親手編寫程式碼、視覺化地震資料,並隨時向「AI 助教」提問,獲取課程解答與即時的全球地震資訊。立即開始您的地球物理探索之旅吧!

""" ) with gr.Row(elem_classes="homepage-image-container"): gr.Image(value="homepage_image.png", show_label=False, interactive=False, container=False) with gr.Tabs(): with gr.TabItem("🎯 課程目標", id="goals_tab"): 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 助教說明"): gr.Markdown("## 🤖 AI 課程助教使用指南") gr.Markdown("歡迎使用課程 AI 助教!我整合了課程知識庫與多種即時資訊來源,您可以透過多種方式與我互動。") with gr.Blocks(): gr.Markdown( """

📚 課程知識庫

我可以回答關於本課程的各種靜態問題。您可以隨意提問,例如:

⚡ 即時資訊查詢

我能幫您查詢最新的動態資訊,您可以直接輸入下方的快捷指令或對應的文字問題

🔎 進階地震查詢

您可以指定日期範圍規模來查詢全球地震紀錄。輸入快捷指令 #7 可以查看格式說明,或直接依照以下格式提問:

您可以自由更換其中的日期與規模數值。

""" ) with gr.TabItem("🤖 AI 課程助教"): with gr.Group(): gr.Markdown("### 🤖 AI 課程助教") gr.Markdown("歡迎使用 AI 助教!您可以直接在下方對話框提問,或參考「❓ **AI 助教說明**」分頁了解所有支援的功能與快捷指令。") custom_textbox = gr.Textbox( placeholder="對課程有什麼問題嗎?或輸入 #1、#2... 查詢即時資訊", show_label=False, container=False, ) gr.ChatInterface( callbacks.ai_chatbot_with_kb, chatbot=gr.Chatbot(height=500, type="messages", avatar_images=(None, "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png")), title=None, description=None, 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