Spaces:
Sleeping
Sleeping
Update ai_service.py
Browse files- ai_service.py +54 -20
ai_service.py
CHANGED
|
@@ -1,12 +1,9 @@
|
|
| 1 |
-
# ai_service.py (
|
| 2 |
import json
|
| 3 |
from datetime import datetime
|
| 4 |
import google.generativeai as genai
|
| 5 |
from gradio_client import Client
|
| 6 |
|
| 7 |
-
# [修正] 移除 'Part' 的 import,因為它導致了錯誤
|
| 8 |
-
# from google.generativeai.types import Part
|
| 9 |
-
|
| 10 |
# 從設定檔匯入金鑰和 URL
|
| 11 |
from config import GEMINI_API_KEY, MCP_SERVER_URL
|
| 12 |
|
|
@@ -14,7 +11,9 @@ from config import GEMINI_API_KEY, MCP_SERVER_URL
|
|
| 14 |
if GEMINI_API_KEY and "YOUR_GEMINI_API_KEY" not in GEMINI_API_KEY:
|
| 15 |
genai.configure(api_key=GEMINI_API_KEY)
|
| 16 |
|
| 17 |
-
# --- 2. 工具函式 (
|
|
|
|
|
|
|
| 18 |
def call_mcp_earthquake_search(
|
| 19 |
start_date: str,
|
| 20 |
end_date: str,
|
|
@@ -51,21 +50,59 @@ def call_mcp_earthquake_search(
|
|
| 51 |
print(f"呼叫 MCP 伺服器失敗: {e}")
|
| 52 |
return f"工具執行失敗,錯誤訊息: {e}"
|
| 53 |
|
| 54 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
earthquake_search_tool_declaration = {
|
| 56 |
"name": "call_earthquake_search_tool",
|
| 57 |
"description": "根據指定的條件(時間、地點、規模等)從台灣中央氣象署的資料庫中搜尋地震事件。預設搜尋台灣周邊地區。",
|
| 58 |
"parameters": {
|
| 59 |
"type": "OBJECT", "properties": {
|
| 60 |
-
"start_date": {"type": "STRING", "description": "搜尋的開始日期 (格式 'YYYY-MM-DD')
|
| 61 |
-
"end_date": {"type": "STRING", "description": "搜尋的結束日期 (格式 'YYYY-MM-DD')
|
| 62 |
-
"min_magnitude": {"type": "NUMBER", "description": "
|
| 63 |
-
"max_magnitude": {"type": "NUMBER", "description": "
|
| 64 |
}, "required": ["start_date", "end_date"]
|
| 65 |
}
|
| 66 |
}
|
| 67 |
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
# --- 4. 建立 Gemini 模型 ---
|
| 71 |
model = None
|
|
@@ -73,20 +110,19 @@ if GEMINI_API_KEY and "YOUR_GEMINI_API_KEY" not in GEMINI_API_KEY:
|
|
| 73 |
try:
|
| 74 |
system_instruction = (
|
| 75 |
"You are a helpful AI assistant. You must answer in Traditional Chinese."
|
| 76 |
-
"You have access to tools. When a tool returns data
|
| 77 |
-
"you must analyze the
|
| 78 |
-
"For example, if the user asks for the largest earthquake, use the search tool for the relevant date range "
|
| 79 |
-
"and then find the entry with the highest magnitude from the JSON results before answering."
|
| 80 |
)
|
|
|
|
| 81 |
model = genai.GenerativeModel(
|
| 82 |
model_name="gemini-1.5-flash",
|
| 83 |
-
tools=[earthquake_search_tool_declaration],
|
| 84 |
system_instruction=system_instruction
|
| 85 |
)
|
| 86 |
except Exception as e:
|
| 87 |
print(f"建立 Gemini 模型失敗: {e}")
|
| 88 |
|
| 89 |
-
# --- 5. 主要的 AI 文字生成函式 ---
|
| 90 |
def generate_ai_text(user_prompt: str) -> str:
|
| 91 |
if not model:
|
| 92 |
return "🤖 AI (Gemini) 服務尚未設定 API 金鑰,或金鑰無效。"
|
|
@@ -110,7 +146,6 @@ def generate_ai_text(user_prompt: str) -> str:
|
|
| 110 |
tool_result = tool_function(**dict(function_call.args))
|
| 111 |
print("--- 將工具結果回傳給 Gemini ---")
|
| 112 |
|
| 113 |
-
# [修正] 直接傳送包含 function_response 的字典,不再使用 Part 類別
|
| 114 |
response = chat.send_message(
|
| 115 |
{"function_response": {"name": function_call.name, "response": {"result": tool_result}}}
|
| 116 |
)
|
|
@@ -119,5 +154,4 @@ def generate_ai_text(user_prompt: str) -> str:
|
|
| 119 |
return response.text
|
| 120 |
except Exception as e:
|
| 121 |
print(f"與 Gemini AI 互動時發生錯誤: {e}")
|
| 122 |
-
return f"🤖 AI 服務發生錯誤: {e}"
|
| 123 |
-
|
|
|
|
| 1 |
+
# ai_service.py (已整合 PWS 查詢工具)
|
| 2 |
import json
|
| 3 |
from datetime import datetime
|
| 4 |
import google.generativeai as genai
|
| 5 |
from gradio_client import Client
|
| 6 |
|
|
|
|
|
|
|
|
|
|
| 7 |
# 從設定檔匯入金鑰和 URL
|
| 8 |
from config import GEMINI_API_KEY, MCP_SERVER_URL
|
| 9 |
|
|
|
|
| 11 |
if GEMINI_API_KEY and "YOUR_GEMINI_API_KEY" not in GEMINI_API_KEY:
|
| 12 |
genai.configure(api_key=GEMINI_API_KEY)
|
| 13 |
|
| 14 |
+
# --- 2. 工具函式 (Tool Functions) ---
|
| 15 |
+
|
| 16 |
+
# [既有] 地震查詢工具函式
|
| 17 |
def call_mcp_earthquake_search(
|
| 18 |
start_date: str,
|
| 19 |
end_date: str,
|
|
|
|
| 50 |
print(f"呼叫 MCP 伺服器失敗: {e}")
|
| 51 |
return f"工具執行失敗,錯誤訊息: {e}"
|
| 52 |
|
| 53 |
+
# [新增] PWS 查詢工具函式
|
| 54 |
+
def call_mcp_pws_search() -> str:
|
| 55 |
+
"""從遠端伺服器查詢最新的 PWS (Public Weather Service) 發布情形。"""
|
| 56 |
+
try:
|
| 57 |
+
print(f"--- 正在呼叫遠端 PWS MCP 伺服器 (由 Gemini 觸發) ---")
|
| 58 |
+
# 連線到使用者指定的 Gradio 應用程式
|
| 59 |
+
client = Client("cwadayi/MCP-pws")
|
| 60 |
+
# 假設 Gradio API 不需要參數,直接呼叫 predict
|
| 61 |
+
result = client.predict(api_name="/predict")
|
| 62 |
+
|
| 63 |
+
# Gradio client 回傳的結果通常是元組 (tuple),取出第一個元素
|
| 64 |
+
if isinstance(result, tuple) and len(result) > 0:
|
| 65 |
+
report = result[0]
|
| 66 |
+
else:
|
| 67 |
+
report = str(result)
|
| 68 |
+
|
| 69 |
+
print(f"--- PWS MCP 伺服器成功回傳 ---")
|
| 70 |
+
return report
|
| 71 |
+
except Exception as e:
|
| 72 |
+
print(f"呼叫 PWS MCP 伺服器失敗: {e}")
|
| 73 |
+
return f"工具執行失敗,錯誤訊息: {e}"
|
| 74 |
+
|
| 75 |
+
# --- 3. 向 Gemini 定義工具 (Tool Declarations) ---
|
| 76 |
+
|
| 77 |
+
# [既有] 地震查詢工具定義
|
| 78 |
earthquake_search_tool_declaration = {
|
| 79 |
"name": "call_earthquake_search_tool",
|
| 80 |
"description": "根據指定的條件(時間、地點、規模等)從台灣中央氣象署的資料庫中搜尋地震事件。預設搜尋台灣周邊地區。",
|
| 81 |
"parameters": {
|
| 82 |
"type": "OBJECT", "properties": {
|
| 83 |
+
"start_date": {"type": "STRING", "description": "搜尋的開始日期 (格式 'YYYY-MM-DD')。"},
|
| 84 |
+
"end_date": {"type": "STRING", "description": "搜尋的結束日期 (格式 'YYYY-MM-DD')。"},
|
| 85 |
+
"min_magnitude": {"type": "NUMBER", "description": "要搜尋的最小地震規模。"},
|
| 86 |
+
"max_magnitude": {"type": "NUMBER", "description": "要搜尋的最大地震規模。"},
|
| 87 |
}, "required": ["start_date", "end_date"]
|
| 88 |
}
|
| 89 |
}
|
| 90 |
|
| 91 |
+
# [新增] PWS 查詢工具定義
|
| 92 |
+
pws_search_tool_declaration = {
|
| 93 |
+
"name": "call_mcp_pws_search",
|
| 94 |
+
"description": "查詢最新的 PWS (Public Weather Service) 公共天氣服務發布情形。",
|
| 95 |
+
"parameters": {
|
| 96 |
+
"type": "OBJECT",
|
| 97 |
+
"properties": {} # 此工具不需要參數
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
# [修改] 將所有可用的工具函式註冊在此
|
| 102 |
+
available_tools = {
|
| 103 |
+
"call_earthquake_search_tool": call_mcp_earthquake_search,
|
| 104 |
+
"call_mcp_pws_search": call_mcp_pws_search
|
| 105 |
+
}
|
| 106 |
|
| 107 |
# --- 4. 建立 Gemini 模型 ---
|
| 108 |
model = None
|
|
|
|
| 110 |
try:
|
| 111 |
system_instruction = (
|
| 112 |
"You are a helpful AI assistant. You must answer in Traditional Chinese."
|
| 113 |
+
"You have access to tools. When a tool returns data, "
|
| 114 |
+
"you must analyze the data to fully answer the user's question."
|
|
|
|
|
|
|
| 115 |
)
|
| 116 |
+
# [修改] 初始化模型時,提供所有工具的定義
|
| 117 |
model = genai.GenerativeModel(
|
| 118 |
model_name="gemini-1.5-flash",
|
| 119 |
+
tools=[earthquake_search_tool_declaration, pws_search_tool_declaration],
|
| 120 |
system_instruction=system_instruction
|
| 121 |
)
|
| 122 |
except Exception as e:
|
| 123 |
print(f"建立 Gemini 模型失敗: {e}")
|
| 124 |
|
| 125 |
+
# --- 5. 主要的 AI 文字生成函式 (此部分維持不變) ---
|
| 126 |
def generate_ai_text(user_prompt: str) -> str:
|
| 127 |
if not model:
|
| 128 |
return "🤖 AI (Gemini) 服務尚未設定 API 金鑰,或金鑰無效。"
|
|
|
|
| 146 |
tool_result = tool_function(**dict(function_call.args))
|
| 147 |
print("--- 將工具結果回傳給 Gemini ---")
|
| 148 |
|
|
|
|
| 149 |
response = chat.send_message(
|
| 150 |
{"function_response": {"name": function_call.name, "response": {"result": tool_result}}}
|
| 151 |
)
|
|
|
|
| 154 |
return response.text
|
| 155 |
except Exception as e:
|
| 156 |
print(f"與 Gemini AI 互動時發生錯誤: {e}")
|
| 157 |
+
return f"🤖 AI 服務發生錯誤: {e}"
|
|
|