File size: 6,293 Bytes
1a2b0fa
a3b49e8
684c8a3
 
f899746
4abc17c
1a2b0fa
a3b49e8
1a2b0fa
 
a3b49e8
1a2b0fa
 
 
 
 
 
 
 
 
 
 
 
 
 
a3b49e8
 
 
1a2b0fa
a3b49e8
 
 
1a2b0fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a3b49e8
1a2b0fa
 
 
a3b49e8
1a2b0fa
 
 
 
 
 
 
 
684c8a3
1a2b0fa
 
 
 
 
684c8a3
 
1a2b0fa
 
 
a3b49e8
 
1a2b0fa
 
 
 
 
 
 
a3b49e8
 
 
1a2b0fa
 
a3b49e8
1a2b0fa
 
 
 
 
 
 
4abc17c
 
 
684c8a3
 
f899746
684c8a3
 
 
 
 
 
 
 
 
 
f899746
 
 
 
 
 
 
 
 
 
 
 
 
 
684c8a3
 
 
 
 
 
 
 
 
 
 
 
 
f899746
684c8a3
 
 
4abc17c
 
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
# 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