cwadayi commited on
Commit
b640204
·
verified ·
1 Parent(s): 022e486

Update ai_service.py

Browse files
Files changed (1) hide show
  1. ai_service.py +18 -36
ai_service.py CHANGED
@@ -1,4 +1,4 @@
1
- # ai_service.py (Implements robust API key validation and rotation)
2
  import json
3
  import os
4
  import random
@@ -10,46 +10,29 @@ from gradio_client import Client
10
  # 從設定檔匯入金鑰和 URL
11
  from config import MCP_SERVER_URL
12
 
13
- # --- 1. [核心修改] API 金鑰健康檢查與輪替機制 ---
14
-
15
- # 從環境變數讀取您設定的兩組金鑰
16
  key1 = os.getenv("GEMINI_API_KEY")
17
  key2 = os.getenv("GEMINI_API_KEY2")
18
-
19
  all_keys = []
20
- if key1 and "YOUR_GEMINI_API_KEY" not in key1:
21
- all_keys.append(key1)
22
- if key2 and "YOUR_GEMINI_API_KEY" not in key2:
23
- all_keys.append(key2)
24
 
25
- # 建立一個存放 "健康" (有效) 金鑰的列表
26
  healthy_keys = []
27
  if all_keys:
28
  print(f"--- Found {len(all_keys)} Gemini API Key(s). Starting validation... ---")
29
  for key in all_keys:
30
  try:
31
- # 嘗試用每個 key 來設定並初始化一個模型,以驗證其有效性
32
  genai.configure(api_key=key)
33
- # 嘗試發送一個非常簡單的測試請求
34
  test_model = genai.GenerativeModel('gemini-1.5-flash')
35
  test_model.generate_content("test", request_options={'timeout': 10})
36
-
37
- # 如果成功,將此 key 加入健康列表
38
  healthy_keys.append(key)
39
  print(f"--- Key ending in ...{key[-4:]} is VALID and added to the pool. ---")
40
- except google_exceptions.PermissionDenied as e:
41
- print(f"--- Key ending in ...{key[-4:]} is INVALID (Permission Denied). Skipping. ---")
42
- print(f" Error details: {e}")
43
  except Exception as e:
44
- # 捕捉其他可能的錯誤,例如超時、額度用盡等
45
- print(f"--- Key ending in ...{key[-4:]} failed validation. Skipping. ---")
46
- print(f" Error details: {e}")
47
-
48
  if not healthy_keys:
49
  print("--- CRITICAL: No valid Gemini API Keys found. AI Service will be disabled. ---")
50
 
51
- # --- 2. 工具函式 (Tool Functions) --- (此區塊維持不變)
52
-
53
  def call_mcp_earthquake_search(start_date: str, end_date: str, min_magnitude: float = 4.0, max_magnitude: float = 9.0) -> str:
54
  try:
55
  client = Client(src=MCP_SERVER_URL)
@@ -67,36 +50,35 @@ def call_mcp_pws_search() -> str:
67
  return result[0] if isinstance(result, tuple) and len(result) > 0 else str(result)
68
  except Exception as e: return f"工具執行失敗,錯誤訊息: {e}"
69
 
70
- # --- 3. 向 Gemini 定義工具 (Tool Declarations) --- (此區塊維持不變)
71
- # ... (此處省略與上一版相同的工具定義程式碼)
72
  earthquake_search_tool_declaration = { "name": "call_earthquake_search_tool", "description": "從台灣中央氣象署的資料庫中搜尋地震事件。", "parameters": { "type": "OBJECT", "properties": { "start_date": { "type": "STRING", "description": "搜尋的開始日期 (格式 'YYYY-MM-DD')。模型應根據使用者問題中的相對時間(例如:昨天、上個月、去年)或絕對時間(例如:2024年)來主動推斷此日期。" }, "end_date": { "type": "STRING", "description": "搜尋的結束日期 (格式 'YYYY-MM-DD')。模型應根據使用者問題中的相對時間或絕對時間來主動推斷此日期。" }, }, "required": ["start_date", "end_date"] } }
73
  pws_search_tool_declaration = { "name": "call_mcp_pws_search", "description": "查詢最新的 PWS (Public Weather Service) 公共天氣服務發布情形。", "parameters": { "type": "OBJECT", "properties": {} } }
74
  available_tools = { "call_earthquake_search_tool": call_mcp_earthquake_search, "call_mcp_pws_search": call_mcp_pws_search }
75
 
76
  # --- 4. 主要的 AI 文字生成函式 ---
77
-
78
  def generate_ai_text(user_prompt: str) -> str:
79
- # [核心修改] 每次呼叫時,都從健康的金鑰池中隨機選取
80
  if not healthy_keys:
81
  return "🤖 AI (Gemini) 服務錯誤:沒有任何有效的 API 金鑰可供使用。"
82
 
83
  try:
84
- # 從健康池中隨機選擇一個 key
85
  selected_key = random.choice(healthy_keys)
86
  print(f"--- Handling request with key ending in: ...{selected_key[-4:]} ---")
87
 
88
- # 使用選定的 key 建立模型實例
89
  genai.configure(api_key=selected_key)
 
 
 
 
 
 
 
 
 
 
90
  model = genai.GenerativeModel(
91
  model_name="gemini-1.5-flash",
92
  tools=[earthquake_search_tool_declaration, pws_search_tool_declaration],
93
- system_instruction=(
94
- "You are a helpful AI assistant. You must answer in Traditional Chinese."
95
- "When the user asks for the 'largest' or 'strongest' earthquake, "
96
- "you MUST assume they mean by magnitude. You should then analyze the JSON data returned by the tool, "
97
- "find the single entry with the highest 'magnitude' value, and present that specific earthquake's details as the answer."
98
- "Do not simply show all the data; find the maximum and answer the question directly."
99
- )
100
  )
101
 
102
  chat = model.start_chat()
 
1
+ # ai_service.py (Instructs AI to execute tool calls without asking for confirmation)
2
  import json
3
  import os
4
  import random
 
10
  # 從設定檔匯入金鑰和 URL
11
  from config import MCP_SERVER_URL
12
 
13
+ # --- 1. API 金鑰健康檢查與輪替機制 ---
 
 
14
  key1 = os.getenv("GEMINI_API_KEY")
15
  key2 = os.getenv("GEMINI_API_KEY2")
 
16
  all_keys = []
17
+ if key1 and "YOUR_GEMINI_API_KEY" not in key1: all_keys.append(key1)
18
+ if key2 and "YOUR_GEMINI_API_KEY" not in key2: all_keys.append(key2)
 
 
19
 
 
20
  healthy_keys = []
21
  if all_keys:
22
  print(f"--- Found {len(all_keys)} Gemini API Key(s). Starting validation... ---")
23
  for key in all_keys:
24
  try:
 
25
  genai.configure(api_key=key)
 
26
  test_model = genai.GenerativeModel('gemini-1.5-flash')
27
  test_model.generate_content("test", request_options={'timeout': 10})
 
 
28
  healthy_keys.append(key)
29
  print(f"--- Key ending in ...{key[-4:]} is VALID and added to the pool. ---")
 
 
 
30
  except Exception as e:
31
+ print(f"--- Key ending in ...{key[-4:]} failed validation. Skipping. Error: {e} ---")
 
 
 
32
  if not healthy_keys:
33
  print("--- CRITICAL: No valid Gemini API Keys found. AI Service will be disabled. ---")
34
 
35
+ # --- 2. 工具函式 (Tool Functions) ---
 
36
  def call_mcp_earthquake_search(start_date: str, end_date: str, min_magnitude: float = 4.0, max_magnitude: float = 9.0) -> str:
37
  try:
38
  client = Client(src=MCP_SERVER_URL)
 
50
  return result[0] if isinstance(result, tuple) and len(result) > 0 else str(result)
51
  except Exception as e: return f"工具執行失敗,錯誤訊息: {e}"
52
 
53
+ # --- 3. 向 Gemini 定義工具 (Tool Declarations) ---
 
54
  earthquake_search_tool_declaration = { "name": "call_earthquake_search_tool", "description": "從台灣中央氣象署的資料庫中搜尋地震事件。", "parameters": { "type": "OBJECT", "properties": { "start_date": { "type": "STRING", "description": "搜尋的開始日期 (格式 'YYYY-MM-DD')。模型應根據使用者問題中的相對時間(例如:昨天、上個月、去年)或絕對時間(例如:2024年)來主動推斷此日期。" }, "end_date": { "type": "STRING", "description": "搜尋的結束日期 (格式 'YYYY-MM-DD')。模型應根據使用者問題中的相對時間或絕對時間來主動推斷此日期。" }, }, "required": ["start_date", "end_date"] } }
55
  pws_search_tool_declaration = { "name": "call_mcp_pws_search", "description": "查詢最新的 PWS (Public Weather Service) 公共天氣服務發布情形。", "parameters": { "type": "OBJECT", "properties": {} } }
56
  available_tools = { "call_earthquake_search_tool": call_mcp_earthquake_search, "call_mcp_pws_search": call_mcp_pws_search }
57
 
58
  # --- 4. 主要的 AI 文字生成函式 ---
 
59
  def generate_ai_text(user_prompt: str) -> str:
 
60
  if not healthy_keys:
61
  return "🤖 AI (Gemini) 服務錯誤:沒有任何有效的 API 金鑰可供使用。"
62
 
63
  try:
 
64
  selected_key = random.choice(healthy_keys)
65
  print(f"--- Handling request with key ending in: ...{selected_key[-4:]} ---")
66
 
 
67
  genai.configure(api_key=selected_key)
68
+
69
+ # [*** 核心修正 ***]
70
+ # 在系統指令中,明確要求 AI 在推斷出參數後「不要提問,直接執行」
71
+ system_instruction = (
72
+ "You are a helpful AI assistant. You must answer in Traditional Chinese."
73
+ "When a user's query can be answered by a tool, you MUST infer the parameters from the query and call the tool immediately without asking for confirmation. Do not ask the user to confirm the parameters you have inferred."
74
+ "When the user asks for the 'largest' or 'strongest' earthquake, you MUST assume they mean by magnitude. You should then analyze the JSON data returned by the tool, "
75
+ "find the single entry with the highest 'magnitude' value, and present that specific earthquake's details as the answer."
76
+ )
77
+
78
  model = genai.GenerativeModel(
79
  model_name="gemini-1.5-flash",
80
  tools=[earthquake_search_tool_declaration, pws_search_tool_declaration],
81
+ system_instruction=system_instruction
 
 
 
 
 
 
82
  )
83
 
84
  chat = model.start_chat()