import streamlit as st import google.generativeai as genai import os # 0. 頁面配置與 CSS 注入(隱藏側邊欄捲軸) st.set_page_config(page_title="育兒成 - 兒童發展線上小助手", page_icon="🧸", layout="wide") st.markdown( """ """, 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. 基礎設定與連結 HOME_URL = "https://kidaid.org.tw/" # 設定本地端的 MD 檔案對應字典 (大小寫必須與上傳的檔名完全一致) KNOWLEDGE_MAP = { "🧠 認知發展": "Cognition_Content.md", "🗣️ 語言發展": "Language.md", "🏃 粗大動作": "GrossMotor.md", "🖐️ 精細動作": "FineMotor.md", "❤️ 社會情緒": "Emotion.md", "🥦 飲食對策": "CountermeasuresDietary.md", "🧩 ASD/早療對策": "CountermeasuresADHD.md" } # 2. 批量讀取本地端檔案內容 (使用絕對路徑) def fetch_all_knowledge(): combined_knowledge = "" # 自動獲取 app.py 所在的資料夾絕對路徑,確保雲端環境找得到檔案 base_dir = os.path.dirname(os.path.abspath(__file__)) with st.spinner("正在載入育兒發展與療育資訊..."): for category, filename in KNOWLEDGE_MAP.items(): # 將資料夾路徑與檔案名稱結合 file_path = os.path.join(base_dir, filename) try: with open(file_path, "r", encoding="utf-8") as f: combined_knowledge += f"\n\n## 【領域:{category}】\n" combined_knowledge += f.read() except FileNotFoundError: st.warning(f"無法載入 {category}:系統在路徑 `{file_path}` 找不到檔案,請確認檔名大小寫與上傳位置。") except Exception as e: st.error(f"讀取 {filename} 時發生錯誤:{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.title("⚙️ 知識庫狀態") st.caption("以下資料嘗試從系統載入中:") for category, filename in KNOWLEDGE_MAP.items(): st.markdown(f"📄 **{category}** (`{filename}`)") st.markdown("---") st.markdown(f"🔗 [前往 育兒成 官方網站]({HOME_URL})") if st.button("🔄 重新載入知識庫"): st.session_state.knowledge = fetch_all_knowledge() st.success("資料已重新載入!") st.markdown("---") # 開發者偵錯工具:按下去可以看到系統當下資料夾裡到底有哪些檔案 with st.expander("🛠️ 開發者偵錯:檢查檔案列表"): base_dir = os.path.dirname(os.path.abspath(__file__)) st.write(f"目前工作目錄:`{base_dir}`") st.write("目前資料夾內的所有檔案與資料夾:") try: st.write(os.listdir(base_dir)) except Exception as e: st.write(f"無法讀取目錄內容:{e}") # 4. 主介面與範例問句 st.title("🧸 育兒成 - 線上衛教小助手") st.caption("關於 0-5 歲兒童的認知、語言、動作、情緒、飲食及早療對策,歡迎直接詢問!(資料來源:育兒成 | 全方位兒童發展整合照護平臺)") # 顯示專屬範例問句按鈕 example_cols = st.columns(5) examples = [ "🥦 小孩挑食不吃青菜,有什麼應對的小撇步嗎?", "🏃 2-3歲的孩子粗大動作應該發展到什麼程度?", "🖐️ 怎麼訓練 4-5 歲幼兒的握筆姿勢?", "🧩 ASD 孩子一直重複旋轉硬幣,我該立刻制止他嗎?", "❤️ 孩子生氣時容易崩潰,該怎麼設立冷靜角落?" ] for col, ex in zip(example_cols, examples): if col.button(ex): st.session_state.example_prompt = ex # 5. 模型回覆邏輯(設定專業衛教師人設) def get_gemini_response(user_input): system_instruction = f""" 你現在是『育兒成 | 全方位兒童發展整合照護平臺』的專業線上客服與育兒小助手。 你的說話風格溫柔、有耐心、具備同理心,且充滿專業知識,就像一位溫暖的早期療育專家或兒童發展衛教師。 以下是本平台最新的衛教資訊(包含認知、語言、粗大動作、精細動作、社會情緒、飲食、ASD早療對策等): --- {st.session_state.knowledge} --- 請嚴格基於上述提供的資訊來回答家長的問題。將複雜的衛教知識轉化為容易理解的實作建議。 如果家長問了超出了上述資訊範圍的醫療診斷問題,請溫和地告知:「小助手目前手邊沒有相關資訊。每個孩子的發展狀況不同,建議您可以諮詢專業的小兒科醫師或尋求早期療育評估喔!」 """ try: 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目前詢問的家長較多,小助手稍微忙不過來了!請您稍等幾分鐘後再試喔!" else: return f"❌ **發生預期外錯誤**\n\n訊息:{error_msg}" # 6. 對話邏輯 prompt = st.chat_input("想詢問哪個年齡層或什麼發展領域的建議呢?") 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"])