Spaces:
Running
Running
| # ui/components/modals.py | |
| import gradio as gr | |
| from config import MODEL_OPTIONS, DEFAULT_PROVIDER, DEFAULT_MODEL, GROQ_FAST_MODEL_OPTIONS | |
| from config import BASE_DIR | |
| def create_validated_input(label, placeholder, type="password"): | |
| """ | |
| Helper: 創建自動驗證的輸入框組件 (無按鈕版) | |
| 回傳: (textbox, status_markdown) | |
| """ | |
| with gr.Group(): | |
| key_input = gr.Textbox( | |
| label=label, | |
| placeholder=placeholder, | |
| type=type, | |
| elem_classes="modern-input" | |
| ) | |
| # 狀態訊息預設為空,驗證後顯示 | |
| status_output = gr.Markdown(value="", elem_classes="api-status-msg") | |
| return key_input, status_output | |
| def create_settings_modal(): | |
| with gr.Group(visible=False, elem_classes="modal-overlay", elem_id="settings-modal") as modal: | |
| with gr.Group(elem_classes="modal-box"): | |
| with gr.Row(elem_classes="modal-header"): | |
| gr.Markdown("### ⚙️ Hybrid System Configuration", elem_classes="modal-title") | |
| with gr.Column(elem_classes="modal-content"): | |
| with gr.Tabs(): | |
| # === 1. Services === | |
| with gr.TabItem("🌍 Services"): | |
| gr.Markdown("External services for maps and weather.", elem_classes="tab-desc") | |
| # 🔥 使用新 Helper (沒有按鈕了) | |
| g_key, g_stat = create_validated_input("Google Maps Key", "AIza...") | |
| w_key, w_stat = create_validated_input("OpenWeather Key", "Enter key...") | |
| # === 2. Primary Brain === | |
| with gr.TabItem("🧠 Primary Brain"): | |
| gr.Markdown("Select the main intelligence.", elem_classes="tab-desc") | |
| # 這裡佈局稍微調整,把 Key 單獨放一行,比較乾淨 | |
| llm_provider = gr.Dropdown( | |
| choices=list(MODEL_OPTIONS.keys()), | |
| value=DEFAULT_PROVIDER, | |
| label="Main Provider", | |
| interactive=True, | |
| elem_classes="modern-dropdown" | |
| ) | |
| # 主模型 Key | |
| main_key, main_stat = create_validated_input("Main Model API Key", "sk-...") | |
| model_sel = gr.Dropdown( | |
| choices=MODEL_OPTIONS[DEFAULT_PROVIDER], | |
| value=DEFAULT_MODEL, | |
| label="Main Model", | |
| interactive=True, | |
| elem_classes="modern-dropdown" | |
| ) | |
| # === 3. Acceleration === | |
| with gr.TabItem("⚡ Acceleration"): | |
| gr.Markdown("Configure Groq for speed.", elem_classes="tab-desc") | |
| fast_mode_chk = gr.Checkbox( | |
| label="Enable Fast Sub-Mode", | |
| value=False, | |
| elem_classes="modern-checkbox" | |
| ) | |
| groq_model_sel = gr.Dropdown( | |
| choices=GROQ_FAST_MODEL_OPTIONS, | |
| value=GROQ_FAST_MODEL_OPTIONS[0][1], | |
| label="Model", | |
| elem_classes="modern-dropdown", | |
| visible = False # <--- 預設隱藏 | |
| ) | |
| # Groq Key | |
| groq_key, groq_stat = create_validated_input("Groq API Key", "gsk_...") | |
| # 手動設定初始狀態為隱藏 (Gradio 小技巧: 定義後再 update) | |
| groq_key.visible = False | |
| # 全局狀態 | |
| set_stat = gr.Markdown(value="", visible=True) | |
| with gr.Row(elem_classes="modal-footer"): | |
| close_btn = gr.Button("Cancel", variant="secondary", elem_classes="btn-cancel") | |
| save_btn = gr.Button("💾 Save", variant="primary", elem_id="btn-save-config") | |
| # 🔥 回傳清單變短了 (少了 4 個按鈕) | |
| return (modal, | |
| g_key, g_stat, | |
| w_key, w_stat, | |
| llm_provider, main_key, main_stat, model_sel, | |
| fast_mode_chk, groq_model_sel, groq_key, groq_stat, | |
| close_btn, save_btn, set_stat) | |
| def create_doc_modal(): | |
| """ | |
| 創建文檔模態框 | |
| 功能:自動讀取 README.md 並【過濾掉】YAML Front Matter | |
| """ | |
| readme_path = BASE_DIR / "README.md" | |
| doc_content = "" | |
| try: | |
| if readme_path.exists(): | |
| with open(readme_path, "r", encoding="utf-8") as f: | |
| raw_content = f.read() | |
| # 🔥🔥🔥 [核心修正] 過濾 YAML Front Matter 🔥🔥🔥 | |
| # 邏輯:YAML 區塊通常夾在兩個 "---" 之間,且位於檔案最上方 | |
| if raw_content.startswith("---"): | |
| # 使用 split 切割,限制切割次數為 2 | |
| # 結果會是 ['', 'yaml內容', '剩下的Markdown內容'] | |
| parts = raw_content.split("---", 2) | |
| if len(parts) >= 3: | |
| doc_content = parts[2].strip() # 取出真正的內容並去除首尾空白 | |
| else: | |
| doc_content = raw_content # 格式不對,就顯示原文 | |
| else: | |
| doc_content = raw_content | |
| else: | |
| doc_content = "## ⚠️ Documentation Not Found" | |
| except Exception as e: | |
| doc_content = f"## ❌ Error Loading Documentation\n\n{str(e)}" | |
| # ... (後面的 UI 構建代碼保持不變) ... | |
| with gr.Group(visible=False, elem_classes="modal-overlay", elem_id="doc-modal") as doc_modal: | |
| with gr.Group(elem_classes="modal-box"): | |
| with gr.Row(elem_classes="modal-header"): | |
| gr.Markdown("### 📖 Documentation", elem_classes="modal-title") | |
| with gr.Column(elem_classes="modal-content"): | |
| gr.Markdown(doc_content) # 這裡現在只會顯示乾淨的 Markdown | |
| with gr.Row(elem_classes="modal-footer"): | |
| close_doc_btn = gr.Button("Close", variant="secondary", elem_classes="btn-cancel") | |
| return doc_modal, close_doc_btn |