Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import os | |
| # 移除 Hugging Face Inference Client 相關導入 | |
| # from huggingface_hub import InferenceClient | |
| import google.generativeai as genai # <-- 導入 Google Generative AI 庫 | |
| # 移除 Hugging Face Token 讀取和 Client 初始化 | |
| # hf_token = os.getenv("HF_TOKEN") | |
| # if not hf_token: | |
| # print("Error: Hugging Face Token (HF_TOKEN) not found...") | |
| # client = InferenceClient("...", token=hf_token) | |
| # 讀取 Google AI API 金鑰 Secret | |
| # 確保您的 Secret 名稱為 GOOGLE_API_KEY | |
| google_api_key = os.getenv("GOOGLE_API_KEY") | |
| # 檢查金鑰是否存在 | |
| if not google_api_key: | |
| # 在 Gradio 應用啟動時顯示錯誤或拋出異常 | |
| error_message = "錯誤:Google AI API Key (GOOGLE_API_KEY) Secret 未設定。請在 Hugging Face Space 設定中添加。" | |
| print(error_message) | |
| # 為了讓 Space 啟動不失敗,可以在這裡暫時顯示錯誤,但後續 API 呼叫會失敗 | |
| # 也可以選擇直接 sys.exit(1) 讓 Space 構建或啟動失敗,提示使用者設定 Secret | |
| # import sys | |
| # sys.exit(1) | |
| # 配置 genai 庫 | |
| genai.configure(api_key=google_api_key) | |
| # 選擇一個支援聊天的 Gemini 模型 | |
| # 'gemini-pro' 是常用的文字聊天模型 | |
| # 模型名稱可以在 Google AI 文檔中找到 | |
| MODEL_NAME = "gemini-pro" | |
| # System Prompt 讀取方式保持不變 (從環境變數讀取,請確保 Secret 名稱一致) | |
| # 假設你在 Hugging Face Space Secrets 中設定了一個名為 SYSTEM_PROMPT 的 Secret。 | |
| SYSTEM_PROMPT_CONTENT = os.getenv("SYSTEM_PROMPT", "你現在是一名專業的昆蟲學系的大學教授,所以你要用專業的角度簡單跟學生回答昆蟲的知識,請盡可能使用流暢的中文回答。") | |
| # 修改 respond 函數,使用 Gemini API 進行回覆生成 | |
| # 函數簽名與之前修改後的版本一致 | |
| def respond( | |
| message, | |
| history: list[tuple[str, str]], # history 包含之前的對話 [(user, assistant), ...] | |
| max_tokens, # 對應 generation_config 的 max_output_tokens | |
| temperature, | |
| top_p, | |
| ): | |
| # 如果金鑰不存在,不進行 API 呼叫,直接返回錯誤訊息 | |
| if not google_api_key: | |
| yield error_message | |
| return # 結束函數執行 | |
| # 構建發送給 Gemini API 的 messages 列表 | |
| # Gemini API 的 generate_content 方法,當包含 history 時,通常期望格式為 | |
| # [{'role': 'user', 'parts': ['...']}, {'role': 'model', 'parts': ['...']}, ...] | |
| # System Instruction 在 generate_content 中通常通過將其內容放在第一條 'user' 消息之前實現 | |
| # 或者將其作為單獨的 system_instruction 參數(如果可用且通過 generate_content 傳遞) | |
| # 這裡我們採用將 system prompt 內容放在第一條實際 user 消息前的策略(如果歷史為空) | |
| # 或直接將 system prompt 作為一個獨立的 'user'/'model' 對話對放在歷史最前面 (方便處理 Gradio history) | |
| # 雖然不太符合官方 system_instruction 參數的用法,但能適應 Gradio 的 history 結構 | |
| messages_for_gemini = [] | |
| # 將 System Prompt 內容加入消息列表的開頭 | |
| # 這是為了讓模型理解指令,儘管不是 Gemini 官方推薦的 system_instruction 參數 | |
| # 我們將其作為一個獨立的 'user' 訊息放在最前面,後面跟一個 'model' 訊息作為確認 | |
| messages_for_gemini.append({"role": "user", "parts": [SYSTEM_PROMPT_CONTENT]}) | |
| messages_for_gemini.append({"role": "model", "parts": ["好的,我明白了,請開始。"]}) # 假裝模型確認了指令 | |
| # 將 Gradio 提供的 history 轉換為 Gemini API 的格式 | |
| # Gradio history 是 [(user_msg, bot_msg), ...] | |
| for user_msg, bot_msg in history: | |
| # 確保訊息不為 None 或空字串,避免 API 錯誤 | |
| if user_msg: | |
| messages_for_gemini.append({"role": "user", "parts": [user_msg]}) | |
| if bot_msg: | |
| messages_for_gemini.append({"role": "model", "parts": [bot_msg]}) | |
| # 加入當前使用者訊息 | |
| if message: | |
| messages_for_gemini.append({"role": "user", "parts": [message]}) | |
| response = "" | |
| try: | |
| # 呼叫 Gemini API | |
| # 使用 generate_content 方法 | |
| model = genai.GenerativeModel(MODEL_NAME) | |
| # 設定生成參數 | |
| generation_config = genai.types.GenerationConfig( | |
| max_output_tokens=max_tokens, # 對應 max_tokens | |
| temperature=temperature, | |
| top_p=top_p | |
| # stop_sequences=[] # 如果需要,可以在這裡設定停止標記 | |
| ) | |
| # 呼叫 generate_content,傳入格式化好的消息列表和生成參數 | |
| # 對於 stream=True,它返回一個 Response 迭代器 | |
| stream = model.generate_content( | |
| messages_for_gemini, # <-- 傳入構建好的消息列表 | |
| generation_config=generation_config, | |
| stream=True, | |
| ) | |
| # 處理流式回覆 | |
| # 迭代 Response 迭代器,獲取 chunks | |
| for chunk in stream: | |
| # chunk.text 包含當前的文本片段 | |
| # 需要確保 chunk.text 不是 None 或空字串 | |
| if hasattr(chunk, 'text') and chunk.text: | |
| response += chunk.text | |
| yield response # 逐步返回結果 | |
| except Exception as e: | |
| print(f"Error during Gemini inference: {e}") | |
| # 顯示更詳細的錯誤信息給使用者 | |
| yield f"生成回覆時發生錯誤: {e}" | |
| # Gradio ChatInterface 設定保持不變 | |
| # additional_inputs 移除 System message 文字框 | |
| demo = gr.ChatInterface( | |
| respond, | |
| additional_inputs=[ | |
| gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"), | |
| gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"), | |
| gr.Slider( | |
| minimum=0.1, | |
| maximum=1.0, | |
| value=0.95, | |
| step=0.05, | |
| label="Top-p (nucleus sampling)", | |
| ), | |
| ], | |
| # Chatbot 组件可以考虑设置 type='messages' 并在 respond 中返回对应的格式,以消除 UserWarning | |
| # 例如 bot=gr.Chatbot(type='messages') | |
| # 这需要调整 respond 函数返回值的格式,超出当前主要任务范围,可以之后优化 | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |