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"]) |