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 | |
| import re | |
| 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() | |
| # 🔥🔥🔥 [Regex 強力修正] 🔥🔥🔥 | |
| # 說明: | |
| # ^---\s*\n -> 匹配開頭的 --- (允許後面有空白) 和 換行 | |
| # .*? -> 非貪婪匹配中間的所有內容 (包含換行) | |
| # \n---\s*\n? -> 匹配結尾的換行 + --- + 結尾可能有的換行 | |
| # re.DOTALL -> 讓 . 可以匹配換行符號 | |
| # re.MULTILINE-> 讓 ^ 可以匹配檔案開頭 | |
| yaml_pattern = r"^---\s*\n.*?\n---\s*\n?" | |
| # 使用 sub 將匹配到的 YAML 區塊替換為空字串 | |
| clean_content = re.sub(yaml_pattern, "", raw_content, count=1, flags=re.DOTALL | re.MULTILINE) | |
| doc_content = clean_content.strip() | |
| else: | |
| doc_content = "## ⚠️ Documentation Not Found" | |
| except Exception as e: | |
| doc_content = f"## ❌ Error Loading Documentation\n\n{str(e)}" | |
| 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) | |
| 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 |