File size: 7,493 Bytes
404eda8
4044773
 
1df899f
404eda8
f253795
d247393
4044773
f253795
 
 
9109b74
d76c9c6
 
 
 
 
 
f253795
9109b74
d76c9c6
f253795
d76c9c6
 
 
 
 
d247393
d76c9c6
 
 
 
 
d247393
4b00872
d76c9c6
 
 
 
 
 
f253795
9109b74
d76c9c6
 
 
 
4b00872
 
 
 
 
d76c9c6
 
4b00872
d76c9c6
9109b74
f253795
 
 
 
 
ac5b826
1df899f
 
f253795
4044773
 
1df899f
4044773
ac5b826
d247393
a1df044
d247393
ac5b826
d247393
ac5b826
d247393
 
 
 
ac5b826
4044773
 
ac5b826
4044773
 
d247393
ac5b826
4044773
ac5b826
4044773
 
 
 
e351eeb
4044773
 
f253795
4044773
 
 
 
 
 
f253795
 
 
ac5b826
4044773
d247393
4044773
ac5b826
 
 
 
4044773
d247393
4044773
ac5b826
4044773
f253795
d247393
 
4044773
e351eeb
d247393
f253795
d247393
 
 
 
 
 
f253795
 
 
 
 
 
d247393
4044773
 
d247393
 
e351eeb
d247393
4044773
 
 
d247393
 
4044773
f253795
d247393
f253795
ddcc970
f253795
 
 
 
 
 
 
 
d247393
f253795
 
 
 
d247393
4044773
f253795
 
e351eeb
4044773
f253795
4044773
f253795
 
 
 
4044773
 
 
 
 
f253795
e351eeb
f253795
 
 
 
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import streamlit as st
import google.generativeai as genai
import requests
import os

# 0. 頁面配置與 CSS 注入(隱藏側邊欄捲軸)
st.set_page_config(page_title="S.H.I.E.L.D. 戰情小助手", page_icon="🛡️", layout="wide")

st.markdown(
    """
    <style>
    /* 1. 隱藏側邊欄捲軸 */
    [data-testid="stSidebar"] section::-webkit-scrollbar { display: none; }
    [data-testid="stSidebar"] section { -ms-overflow-style: none; scrollbar-width: none; }
    
    /* 🚀 2. 全域字體縮小,適應手機螢幕 */
    html, body, [class*="st-"] {
        font-size: 14px !important;
    }
    
    /* 🚀 3. 調整範例按鈕樣式:變矮、字體變小、支援多行自動折行 */
    .stButton button {
        width: 100%;
        padding: 6px 10px; /* 縮小上下內距 */
        border-radius: 12px;
        border: 1px solid #D4AF37;
        color: #D4AF37;
        background-color: transparent;
        font-size: 13px !important; /* 讓按鈕字體再小一點 */
        line-height: 1.3;
        min-height: auto;
        white-space: normal; /* 允許長句子自動折行,避免撐爆寬度 */
        height: auto;
    }
    
    /* 4. 極度壓縮主畫面空白 */
    .block-container {
        padding-top: 1.2rem !important;
        padding-bottom: 5rem !important; 
        padding-left: 0.8rem !important;
        padding-right: 0.8rem !important;
    }
    
    /* 5. 隱藏 Header 背景與右側選單,但保留左側展開按鈕 */
    header[data-testid="stHeader"] {
        background-color: rgba(0,0,0,0) !important; 
    }
    header[data-testid="stHeader"] #MainMenu {
        visibility: hidden;
    }
    div[data-testid="collapsedControl"] {
        visibility: visible !important;
        background-color: #1A1A1A !important;
        color: #D4AF37 !important;
        border-radius: 0 5px 5px 0;
        top: 5px;
    }
    </style>
    """,
    unsafe_allow_html=True
)

# 從環境變數中取得 API Key
api_key = os.environ.get("GEMINI_API_KEY")
if not api_key:
    st.error("請確認已經在 Space 的 Settings 設定了 GEMINI_API_KEY")
    st.stop()

genai.configure(api_key=api_key)

# 1. 基礎設定與連結
# 抓取 Deep Learning 101 的 Logo (你也可以換成 SHIELD 專屬 Logo)
LOGO_URL = "https://huggingface.co/spaces/DeepLearning101/shield-chatbot/resolve/main/shield-logo.jpg"
HOME_URL = "https://deep-learning-101.github.io/SHIELD/"

# 將知識庫指向 S.H.I.E.L.D. 的 README.md
KNOWLEDGE_MAP = {
    "🛡️ S.H.I.E.L.D. 系統白皮書": {
        "raw_url": "https://raw.githubusercontent.com/Deep-Learning-101/SHIELD/main/README.md",
        "page_url": "https://deep-learning-101.github.io/SHIELD/",
        "repo_url": "https://github.com/Deep-Learning-101/SHIELD"
    }
}

# 2. 批量抓取內容
def fetch_all_knowledge():
    combined_knowledge = ""
    with st.spinner("正在同步 S.H.I.E.L.D. 戰情資料庫..."):
        for category, info in KNOWLEDGE_MAP.items():
            try:
                response = requests.get(info["raw_url"])
                response.raise_for_status()
                combined_knowledge += f"\n\n## 【領域:{category}】\n"
                combined_knowledge += response.text
            except Exception as e:
                st.warning(f"無法同步 {category} 的資料:請確認 GitHub 路徑是否正確。錯誤訊息:{e}")
    return combined_knowledge

# 初始化 Session State
if "knowledge" not in st.session_state:
    st.session_state.knowledge = fetch_all_knowledge()

if "messages" not in st.session_state:
    st.session_state.messages = []

if "example_prompt" not in st.session_state:
    st.session_state.example_prompt = None

# 3. 側邊欄設計
with st.sidebar:
    st.markdown(f'<a href="{HOME_URL}" target="_blank"><img src="{LOGO_URL}" width="100%" style="margin-bottom:20px;"></a>', unsafe_allow_html=True)
    st.title("⚙️ 知識庫狀態")
    for category, info in KNOWLEDGE_MAP.items():
        with st.expander(category):
            st.markdown(f"🔗 [瀏覽網頁]({info['page_url']})")
            st.markdown(f"📂 [GitHub 原始碼]({info['repo_url']})")
    st.markdown("---")
    if st.button("🔄 手動更新情資庫"):
        st.session_state.knowledge = fetch_all_knowledge()
        st.success("資料已重新抓取!")

# 4. 主介面與範例問句
st.title("🤖 S.H.I.E.L.D. 戰情小助手")
st.caption("我是 Deep Learning 101 的主權 AI 戰情官,專注於解答 S.H.I.E.L.D. 的架構與防禦機制。")

# 顯示專屬範例問句按鈕
example_cols = st.columns(6)
examples = [
    "🧠 傳統 AI 常有幻覺,雙腦架構如何落實 AI 治理?",
    "🏭 企業機密文檔,如何無損轉化為 AI 微調燃料?",
    "⚔️ 揭秘「紅藍隊自主對抗」與動態語意防火牆",
    "🕸️ 知識圖譜發威:如何秒級推演受災爆炸半徑?",
    "🚀 捨棄傳統向量庫?解析 S.H.I.E.L.D. 雙引擎檢索",
    "🤖 從給建議到「自動修補」:Agent 如何執行 ChatOps?"
]

for col, ex in zip(example_cols, examples):
    if col.button(ex):
        st.session_state.example_prompt = ex

# 5. 模型回覆邏輯(設定資安 AI 架構師人設)
def get_gemini_response(user_input):
    system_instruction = f"""
    你現在是 Deep Learning 101 開發的『S.H.I.E.L.D. 戰情小助手』。
    你的說話風格專業、精確,帶有資安專家與 AI 架構師的科技感,致力於推廣企業主權 AI 防禦理念。
    
    以下是從 GitHub 同步的 S.H.I.E.L.D. 系統白皮書與技術架構資訊:
    ---
    {st.session_state.knowledge}
    ---
    請嚴格基於上述提供的資訊來回答使用者的問題。
    如果使用者問了超出 S.H.I.E.L.D. 白皮書範圍的問題,請禮貌地告知:「目前的戰情資料庫尚未收錄此資訊,建議您查閱 Deep Learning 101 的其他專案或直接聯繫維護團隊。」
    """
    try:
        # 建議使用 1.5-flash,對於技術長文的理解力較強
        model = genai.GenerativeModel(
            model_name="gemini-flash-lite-latest",
            system_instruction=system_instruction
        )
        chat = model.start_chat(history=[])
        response = chat.send_message(user_input)
        return response.text
    except Exception as e:
        error_msg = str(e)
        if "429" in error_msg or "quota" in error_msg.lower():
            return "⚠️ **系統提示:**\n\n目前 API 請求已達上限,戰情中心通訊稍有延遲!請稍等幾分鐘後再試。"
        else:
            return f"❌ **發生預期外錯誤**\n\n訊息:{error_msg}"

# 6. 對話邏輯
prompt = st.chat_input("請輸入您對 S.H.I.E.L.D. 系統的疑問...")

if st.session_state.example_prompt:
    prompt = st.session_state.example_prompt
    st.session_state.example_prompt = None

if prompt:
    st.session_state.messages.append({"role": "user", "content": prompt})
    
    for message in st.session_state.messages:
        with st.chat_message(message["role"]):
            st.markdown(message["content"])

    with st.chat_message("assistant"):
        response_text = get_gemini_response(prompt)
        st.markdown(response_text)
    
    st.session_state.messages.append({"role": "assistant", "content": response_text})
    st.rerun()
else:
    for message in st.session_state.messages:
        with st.chat_message(message["role"]):
            st.markdown(message["content"])