Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -18,9 +18,8 @@ import gradio as gr
|
|
| 18 |
import pandas as pd
|
| 19 |
import google.generativeai as genai
|
| 20 |
from typing import Type
|
| 21 |
-
|
| 22 |
-
from collections import defaultdict, OrderedDict
|
| 23 |
from typing import List, Dict
|
|
|
|
| 24 |
|
| 25 |
# LangChain & SentenceTransformers
|
| 26 |
from langchain_community.vectorstores import FAISS
|
|
@@ -116,15 +115,15 @@ def load_data(file_path: str = EXCEL_FILE_PATH) -> pd.DataFrame:
|
|
| 116 |
|
| 117 |
def batch_find_relevant_tables(api_key: str, sub_queries: list[str], top_k: int = 1) -> dict:
|
| 118 |
"""
|
| 119 |
-
|
| 120 |
"""
|
| 121 |
-
print("🧠
|
| 122 |
|
| 123 |
-
# Step 1: 為每個子問題獨立獲取候選表,並存入字典
|
| 124 |
query_to_candidates_map = {}
|
| 125 |
for query in sub_queries:
|
| 126 |
print(f" -> 正在處理: '{query}'")
|
| 127 |
-
# 為每個子問題找回
|
| 128 |
candidates_per_query = extract_project_names_from_rag_manual_mix(query, db_jb, db_sim, top_k=20)
|
| 129 |
# test
|
| 130 |
print(candidates_per_query)
|
|
@@ -140,7 +139,7 @@ def batch_find_relevant_tables(api_key: str, sub_queries: list[str], top_k: int
|
|
| 140 |
|
| 141 |
# --- Step 2: 動態建構一個新的、結構化的 Prompt ---
|
| 142 |
|
| 143 |
-
#
|
| 144 |
tasks_text_parts = []
|
| 145 |
for i, (query, candidates) in enumerate(query_to_candidates_map.items()):
|
| 146 |
# 將候選表列表格式化
|
|
@@ -161,8 +160,7 @@ def batch_find_relevant_tables(api_key: str, sub_queries: list[str], top_k: int
|
|
| 161 |
你是一個專業的數據庫助理。你的任務是從下方的「待處理的配對任務清單」中,根據每一個query,找出最相關的資料表。其餘捨棄。
|
| 162 |
你必須依[輸出範例]回傳問題及表名,不要有任何多餘的文字、編號、引號或說明。
|
| 163 |
|
| 164 |
-
特殊情形:如query為高雄市或各行政區整體(全部)
|
| 165 |
-
|
| 166 |
|
| 167 |
[待處理的配對任務清單]:
|
| 168 |
{tasks_text}
|
|
@@ -177,10 +175,10 @@ def batch_find_relevant_tables(api_key: str, sub_queries: list[str], top_k: int
|
|
| 177 |
}}
|
| 178 |
""".strip()
|
| 179 |
|
| 180 |
-
# --- Step 3: 呼叫 Gemini
|
| 181 |
try:
|
| 182 |
print("--- Structured Batch Prompt to Gemini ---")
|
| 183 |
-
# print(repr(batch_prompt)) #
|
| 184 |
print("---------------------------------------")
|
| 185 |
|
| 186 |
response_text = reply(api_key, "", batch_prompt)
|
|
@@ -195,7 +193,7 @@ def batch_find_relevant_tables(api_key: str, sub_queries: list[str], top_k: int
|
|
| 195 |
|
| 196 |
def batch_parse_sub_queries_with_gemini(api_key: str, sub_queries: List[str]) -> Dict[str, Dict]:
|
| 197 |
"""
|
| 198 |
-
|
| 199 |
回傳一個以子問題為鍵(key)的字典。
|
| 200 |
"""
|
| 201 |
print(f"🤖 正在請求 Gemini 批次解析 {len(sub_queries)} 個子問題...")
|
|
@@ -214,7 +212,6 @@ def batch_parse_sub_queries_with_gemini(api_key: str, sub_queries: List[str]) ->
|
|
| 214 |
1. **時間正規化**:當使用者輸入的時間包含 "年底"、"年中"、"年初"、"年度" 等描述時,請將 `time_query` 正規化為年份。例如,"113年底" 應轉換為 "113年"。
|
| 215 |
2. **時間校正**:當使用者輸入的時間包含 "年底"、"年中"、"年初" 等描述時,如該問題是有關學校類型(國中小、補習班等概況),請將 `time_query` 修正為學年。例如,"113年" 應轉換為 "113學年"。
|
| 216 |
3. `district_query` 為可選項目,若無則設為"高雄市全區"。如為"高雄市"或"高雄"等泛指整體者,亦設為"高雄市全區"
|
| 217 |
-
4. 當使用者問題為高雄市或未指定行政區時,item_query: 「總計」+ (time_query轉為西元表示的時間) + <查詢項目文字>
|
| 218 |
4. 請勿遺漏使用者輸入的任何關鍵詞。
|
| 219 |
|
| 220 |
**情境二:問題模糊,無法查詢**
|
|
@@ -230,8 +227,8 @@ def batch_parse_sub_queries_with_gemini(api_key: str, sub_queries: List[str]) ->
|
|
| 230 |
---
|
| 231 |
[規則]:
|
| 232 |
1. **時間正規化**:當使用者輸入的時間包含 "年底"、"年中"、"年初"、"年度" 等描述時,請將 `time_query` 正規化為年份。例如,"113年底" 應轉換為 "113年"。
|
| 233 |
-
2. **時間校正**:當使用者輸入的時間包含 "年底"、"年中"、"年初"
|
| 234 |
-
3. `district_query`
|
| 235 |
4. 請勿遺漏使用者輸入的任何關鍵詞。
|
| 236 |
---
|
| 237 |
[輸出格式]:
|
|
@@ -267,17 +264,17 @@ def batch_parse_sub_queries_with_gemini(api_key: str, sub_queries: List[str]) ->
|
|
| 267 |
# --- 動態查詢工具 ---
|
| 268 |
def semantic_query_logic(time_query: str, item_query: str, project_name: str, district_query: str = "") -> str:
|
| 269 |
"""
|
| 270 |
-
|
| 271 |
"""
|
| 272 |
print(f"--- 執行查詢: 表名='{project_name}', 時間='{time_query}', 地區='{district_query}', 項目='{item_query}' ---")
|
| 273 |
df = load_data()
|
| 274 |
if df is None: return "[]"
|
| 275 |
|
| 276 |
-
# 步驟 1:
|
| 277 |
filtered_df = df[df['表名'] == project_name].copy()
|
| 278 |
|
| 279 |
if filtered_df.empty:
|
| 280 |
-
#
|
| 281 |
return "[]"
|
| 282 |
|
| 283 |
# 步驟 2: 在已縮小的範圍內,進行時間和地區的篩選
|
|
@@ -294,16 +291,16 @@ def semantic_query_logic(time_query: str, item_query: str, project_name: str, di
|
|
| 294 |
if filtered_df.empty: return "[]"
|
| 295 |
|
| 296 |
# 關鍵安全閥
|
| 297 |
-
MAX_CANDIDATES =
|
| 298 |
if len(filtered_df) > MAX_CANDIDATES:
|
| 299 |
print(f"⚠️ 篩選結果超過{MAX_CANDIDATES}筆({len(filtered_df)}),僅取前{MAX_CANDIDATES}筆進行向量分析以節省資源。")
|
| 300 |
filtered_df = filtered_df.head(MAX_CANDIDATES)
|
| 301 |
|
| 302 |
-
# 步驟 3:
|
| 303 |
print(f"向量化階段:對 {len(filtered_df)} 筆資料進行向量化...")
|
| 304 |
combined_texts = (filtered_df['表名'].astype(str) + " " + filtered_df['表首資訊'].astype(str) + " " + filtered_df['表側資訊'].astype(str)).tolist()
|
| 305 |
|
| 306 |
-
#
|
| 307 |
prefixed_passage_texts = [f"passage: {t}" for t in combined_texts]
|
| 308 |
prefixed_query_text = f"query: {item_query}"
|
| 309 |
|
|
@@ -319,7 +316,7 @@ def semantic_query_logic(time_query: str, item_query: str, project_name: str, di
|
|
| 319 |
|
| 320 |
results.sort(key=lambda x: x['語意分數'], reverse=True)
|
| 321 |
|
| 322 |
-
FINAL_K =
|
| 323 |
top_results = results[:FINAL_K]
|
| 324 |
|
| 325 |
print("--- semantic_query_logic 執行完畢 ---")
|
|
@@ -331,7 +328,7 @@ from langchain.tools import StructuredTool
|
|
| 331 |
semantic_query_tool = StructuredTool.from_function(
|
| 332 |
func=semantic_query_logic,
|
| 333 |
name="semantic_query_tool",
|
| 334 |
-
description="
|
| 335 |
)
|
| 336 |
|
| 337 |
# =======================================================================
|
|
@@ -344,7 +341,6 @@ system_reviewer = """
|
|
| 344 |
1. 涉及高雄市以外或全國性資料,請直接回傳:「抱歉~我是高雄市查詢機器人,無法查詢高雄以外資料。」
|
| 345 |
2. 未提及明確時間(如112年、113年3月),請回傳:「抱歉~請問查詢的資料時間。」
|
| 346 |
📌 明確時間=出現「具體年份」、「年月」、「季」或「學年」。模糊詞(平均、近年、目前、歷年等)皆視為未指定。
|
| 347 |
-
3. 問題中的「高雄市」字樣請略過,例如「113年底高雄市人口」視為「113年總人口」。
|
| 348 |
|
| 349 |
📌 回傳格式(**僅限 JSON 陣列**,不得加上任何文字):
|
| 350 |
[
|
|
@@ -390,9 +386,9 @@ system_integration = """
|
|
| 390 |
4. **條列推論**:逐項列出比較結果,明確指出最高、最低、差異。
|
| 391 |
5. **禁止**:不得使用科學記號、英文、原欄位名稱;不得補資料或推論未查到的年份。
|
| 392 |
### 二、一般整合型問題(如「113年底苓雅區人口?」):
|
| 393 |
-
1. **條件驗證**:若資料年份不同,請說明「您問的是 113 年,我找到的是 114
|
| 394 |
2. **缺資料處理**:無資料請說「資料缺乏,無法回答」;不���用其他時間資料代替。
|
| 395 |
-
3. **作答格式**:300
|
| 396 |
---
|
| 397 |
## 📌 共通禁止事項(適用所有問題):
|
| 398 |
- ❌ 不得推論或補未查到的資料
|
|
@@ -409,7 +405,7 @@ system_integration = """
|
|
| 409 |
|
| 410 |
def reply(api_key: str, system: str, prompt: str, model: str = "gemini-2.0-flash-lite"):
|
| 411 |
"""
|
| 412 |
-
|
| 413 |
"""
|
| 414 |
try:
|
| 415 |
genai.configure(api_key=api_key)
|
|
@@ -449,9 +445,8 @@ def extract_json(text: str) -> list | dict:
|
|
| 449 |
raise ValueError(f"清理後仍然無法解析 JSON。原始錯誤: {e}")
|
| 450 |
|
| 451 |
|
| 452 |
-
def reflect_post(api_key, user_input):
|
| 453 |
"""
|
| 454 |
-
(最終優化版 / Gemini批次解析 / 非串流)
|
| 455 |
API 呼叫總次數固定為 4 次。
|
| 456 |
"""
|
| 457 |
# Step 1:拆解子問題 (API Call #1)
|
|
@@ -478,7 +473,7 @@ def reflect_post(api_key, user_input):
|
|
| 478 |
return all_querys_summary, "⚠️ 系統無法為您的查詢匹配到合適的資料表。"
|
| 479 |
|
| 480 |
# Step 3: 批次解析所有子問題的參數 (API Call #3)
|
| 481 |
-
params_map = batch_parse_sub_queries_with_gemini(
|
| 482 |
if not params_map:
|
| 483 |
return all_querys_summary, "⚠️ 系統無法解析您問題中的查詢參數。"
|
| 484 |
|
|
@@ -514,7 +509,7 @@ def reflect_post(api_key, user_input):
|
|
| 514 |
|
| 515 |
# Step 5:整合分析 (API Call #4)
|
| 516 |
integration_prompt = f"使用者問題:{user_input}\n\n查詢資料如下:\n{combined_context}"
|
| 517 |
-
integration_result = reply(
|
| 518 |
return all_querys_summary, integration_result
|
| 519 |
|
| 520 |
# =======================================================================
|
|
@@ -522,8 +517,9 @@ def reflect_post(api_key, user_input):
|
|
| 522 |
# =======================================================================
|
| 523 |
|
| 524 |
def gradio_interface(user_input):
|
| 525 |
-
"""Gradio
|
| 526 |
api_key = os.getenv('Gemini')
|
|
|
|
| 527 |
if not api_key:
|
| 528 |
return "❌ 查詢失敗", "錯誤:未在伺服器環境中設定 'Gemini' API 金鑰。"
|
| 529 |
|
|
@@ -546,6 +542,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="orange"))
|
|
| 546 |
"""
|
| 547 |
# 🤖 高雄市公務統計資料智慧查詢
|
| 548 |
歡迎使用!您可以透過自然語言提出關於高雄市的公務統計問題,系統將盡力為您查找相關資訊。
|
|
|
|
| 549 |
"""
|
| 550 |
)
|
| 551 |
|
|
@@ -553,15 +550,16 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="orange"))
|
|
| 553 |
with gr.Column(scale=1):
|
| 554 |
user_input_box = gr.Textbox(
|
| 555 |
label="請在此輸入您的問題",
|
| 556 |
-
placeholder="例如:113
|
| 557 |
lines=5
|
| 558 |
)
|
| 559 |
gr.Examples(
|
| 560 |
examples=[
|
| 561 |
-
"113
|
| 562 |
"110-113年高雄市總人口數趨勢?",
|
| 563 |
"110-113年失業率情形",
|
| 564 |
-
"
|
|
|
|
| 565 |
],
|
| 566 |
inputs=user_input_box,
|
| 567 |
label="💡 範例問題"
|
|
|
|
| 18 |
import pandas as pd
|
| 19 |
import google.generativeai as genai
|
| 20 |
from typing import Type
|
|
|
|
|
|
|
| 21 |
from typing import List, Dict
|
| 22 |
+
from collections import defaultdict, OrderedDict
|
| 23 |
|
| 24 |
# LangChain & SentenceTransformers
|
| 25 |
from langchain_community.vectorstores import FAISS
|
|
|
|
| 115 |
|
| 116 |
def batch_find_relevant_tables(api_key: str, sub_queries: list[str], top_k: int = 1) -> dict:
|
| 117 |
"""
|
| 118 |
+
為每個子問題獨立查找候選表,並將完整的配對結構交由 Gemini 判斷。
|
| 119 |
"""
|
| 120 |
+
print("🧠 正在為每個子問題獨立查找其相對應候選表...")
|
| 121 |
|
| 122 |
+
# --- Step 1: 為每個子問題獨立獲取候選表,並存入字典 ---
|
| 123 |
query_to_candidates_map = {}
|
| 124 |
for query in sub_queries:
|
| 125 |
print(f" -> 正在處理: '{query}'")
|
| 126 |
+
# 為每個子問題找回 20 個最相關的候選表
|
| 127 |
candidates_per_query = extract_project_names_from_rag_manual_mix(query, db_jb, db_sim, top_k=20)
|
| 128 |
# test
|
| 129 |
print(candidates_per_query)
|
|
|
|
| 139 |
|
| 140 |
# --- Step 2: 動態建構一個新的、結構化的 Prompt ---
|
| 141 |
|
| 142 |
+
# 建立任務描述文字
|
| 143 |
tasks_text_parts = []
|
| 144 |
for i, (query, candidates) in enumerate(query_to_candidates_map.items()):
|
| 145 |
# 將候選表列表格式化
|
|
|
|
| 160 |
你是一個專業的數據庫助理。你的任務是從下方的「待處理的配對任務清單」中,根據每一個query,找出最相關的資料表。其餘捨棄。
|
| 161 |
你必須依[輸出範例]回傳問題及表名,不要有任何多餘的文字、編號、引號或說明。
|
| 162 |
|
| 163 |
+
特殊情形:如query為高雄市或各行政區整體(全部)人口數,請一律查詢表名"高雄市戶數、人口密度及性比例"
|
|
|
|
| 164 |
|
| 165 |
[待處理的配對任務清單]:
|
| 166 |
{tasks_text}
|
|
|
|
| 175 |
}}
|
| 176 |
""".strip()
|
| 177 |
|
| 178 |
+
# --- Step 3: 呼叫 Gemini 並解析結果 ---
|
| 179 |
try:
|
| 180 |
print("--- Structured Batch Prompt to Gemini ---")
|
| 181 |
+
# print(repr(batch_prompt)) # 如需偵錯,可取消註解
|
| 182 |
print("---------------------------------------")
|
| 183 |
|
| 184 |
response_text = reply(api_key, "", batch_prompt)
|
|
|
|
| 193 |
|
| 194 |
def batch_parse_sub_queries_with_gemini(api_key: str, sub_queries: List[str]) -> Dict[str, Dict]:
|
| 195 |
"""
|
| 196 |
+
批次解析所有子問題,提取時間、地區及查詢項目。
|
| 197 |
回傳一個以子問題為鍵(key)的字典。
|
| 198 |
"""
|
| 199 |
print(f"🤖 正在請求 Gemini 批次解析 {len(sub_queries)} 個子問題...")
|
|
|
|
| 212 |
1. **時間正規化**:當使用者輸入的時間包含 "年底"、"年中"、"年初"、"年度" 等描述時,請將 `time_query` 正規化為年份。例如,"113年底" 應轉換為 "113年"。
|
| 213 |
2. **時間校正**:當使用者輸入的時間包含 "年底"、"年中"、"年初" 等描述時,如該問題是有關學校類型(國中小、補習班等概況),請將 `time_query` 修正為學年。例如,"113年" 應轉換為 "113學年"。
|
| 214 |
3. `district_query` 為可選項目,若無則設為"高雄市全區"。如為"高雄市"或"高雄"等泛指整體者,亦設為"高雄市全區"
|
|
|
|
| 215 |
4. 請勿遺漏使用者輸入的任何關鍵詞。
|
| 216 |
|
| 217 |
**情境二:問題模糊,無法查詢**
|
|
|
|
| 227 |
---
|
| 228 |
[規則]:
|
| 229 |
1. **時間正規化**:當使用者輸入的時間包含 "年底"、"年中"、"年初"、"年度" 等描述時,請將 `time_query` 正規化為年份。例如,"113年底" 應轉換為 "113年"。
|
| 230 |
+
2. **時間校正**:當使用者輸入的時間包含 "年底"、"年中"、"年初" 等描述時,如該問題是有關學校類型(國中小、補習班等概況),請將 `time_query` 修正為學年。例如,"113年" 應轉換為 "113學年"。
|
| 231 |
+
3. `district_query` 為可選項目,若無則設為"高雄市全區"。如為"高雄市"或"高雄"等泛指整體者,亦設為"高雄市全區"
|
| 232 |
4. 請勿遺漏使用者輸入的任何關鍵詞。
|
| 233 |
---
|
| 234 |
[輸出格式]:
|
|
|
|
| 264 |
# --- 動態查詢工具 ---
|
| 265 |
def semantic_query_logic(time_query: str, item_query: str, project_name: str, district_query: str = "") -> str:
|
| 266 |
"""
|
| 267 |
+
直接以已匹配好的表名、時間及統計指標查詢合併資料。
|
| 268 |
"""
|
| 269 |
print(f"--- 執行查詢: 表名='{project_name}', 時間='{time_query}', 地區='{district_query}', 項目='{item_query}' ---")
|
| 270 |
df = load_data()
|
| 271 |
if df is None: return "[]"
|
| 272 |
|
| 273 |
+
# 步驟 1: 先用精確的表名進行篩選,大幅縮小範圍
|
| 274 |
filtered_df = df[df['表名'] == project_name].copy()
|
| 275 |
|
| 276 |
if filtered_df.empty:
|
| 277 |
+
# 如果表名就找不到任何資料,直接返回
|
| 278 |
return "[]"
|
| 279 |
|
| 280 |
# 步驟 2: 在已縮小的範圍內,進行時間和地區的篩選
|
|
|
|
| 291 |
if filtered_df.empty: return "[]"
|
| 292 |
|
| 293 |
# 關鍵安全閥
|
| 294 |
+
MAX_CANDIDATES = 300
|
| 295 |
if len(filtered_df) > MAX_CANDIDATES:
|
| 296 |
print(f"⚠️ 篩選結果超過{MAX_CANDIDATES}筆({len(filtered_df)}),僅取前{MAX_CANDIDATES}筆進行向量分析以節省資源。")
|
| 297 |
filtered_df = filtered_df.head(MAX_CANDIDATES)
|
| 298 |
|
| 299 |
+
# 步驟 3: 對最終篩選出的結果進行向量化與語意比對
|
| 300 |
print(f"向量化階段:對 {len(filtered_df)} 筆資料進行向量化...")
|
| 301 |
combined_texts = (filtered_df['表名'].astype(str) + " " + filtered_df['表首資訊'].astype(str) + " " + filtered_df['表側資訊'].astype(str)).tolist()
|
| 302 |
|
| 303 |
+
# 加上前綴
|
| 304 |
prefixed_passage_texts = [f"passage: {t}" for t in combined_texts]
|
| 305 |
prefixed_query_text = f"query: {item_query}"
|
| 306 |
|
|
|
|
| 316 |
|
| 317 |
results.sort(key=lambda x: x['語意分數'], reverse=True)
|
| 318 |
|
| 319 |
+
FINAL_K = 50
|
| 320 |
top_results = results[:FINAL_K]
|
| 321 |
|
| 322 |
print("--- semantic_query_logic 執行完畢 ---")
|
|
|
|
| 328 |
semantic_query_tool = StructuredTool.from_function(
|
| 329 |
func=semantic_query_logic,
|
| 330 |
name="semantic_query_tool",
|
| 331 |
+
description="直接使用向量語意模型進行檢索排序。
|
| 332 |
)
|
| 333 |
|
| 334 |
# =======================================================================
|
|
|
|
| 341 |
1. 涉及高雄市以外或全國性資料,請直接回傳:「抱歉~我是高雄市查詢機器人,無法查詢高雄以外資料。」
|
| 342 |
2. 未提及明確時間(如112年、113年3月),請回傳:「抱歉~請問查詢的資料時間。」
|
| 343 |
📌 明確時間=出現「具體年份」、「年月」、「季」或「學年」。模糊詞(平均、近年、目前、歷年等)皆視為未指定。
|
|
|
|
| 344 |
|
| 345 |
📌 回傳格式(**僅限 JSON 陣列**,不得加上任何文字):
|
| 346 |
[
|
|
|
|
| 386 |
4. **條列推論**:逐項列出比較結果,明確指出最高、最低、差異。
|
| 387 |
5. **禁止**:不得使用科學記號、英文、原欄位名稱;不得補資料或推論未查到的年份。
|
| 388 |
### 二、一般整合型問題(如「113年底苓雅區人口?」):
|
| 389 |
+
1. **條件驗證**:若資料年份不同,請說明「您問的是 113 年,我找到的是 114 年…」。
|
| 390 |
2. **缺資料處理**:無資料請說「資料缺乏,無法回答」;不���用其他時間資料代替。
|
| 391 |
+
3. **作答格式**:300 字內、結論先行、條列清楚、千分位數字,不使用科學記號。開頭統一:「關於您提出的問題,綜合參考資料如下:」,結尾列出參考資料表名:「參考資料:高雄市原住民戶口數」。
|
| 392 |
---
|
| 393 |
## 📌 共通禁止事項(適用所有問題):
|
| 394 |
- ❌ 不得推論或補未查到的資料
|
|
|
|
| 405 |
|
| 406 |
def reply(api_key: str, system: str, prompt: str, model: str = "gemini-2.0-flash-lite"):
|
| 407 |
"""
|
| 408 |
+
獲取 Gemini 回應。
|
| 409 |
"""
|
| 410 |
try:
|
| 411 |
genai.configure(api_key=api_key)
|
|
|
|
| 445 |
raise ValueError(f"清理後仍然無法解析 JSON。原始錯誤: {e}")
|
| 446 |
|
| 447 |
|
| 448 |
+
def reflect_post(api_key, api_key2, user_input):
|
| 449 |
"""
|
|
|
|
| 450 |
API 呼叫總次數固定為 4 次。
|
| 451 |
"""
|
| 452 |
# Step 1:拆解子問題 (API Call #1)
|
|
|
|
| 473 |
return all_querys_summary, "⚠️ 系統無法為您的查詢匹配到合適的資料表。"
|
| 474 |
|
| 475 |
# Step 3: 批次解析所有子問題的參數 (API Call #3)
|
| 476 |
+
params_map = batch_parse_sub_queries_with_gemini(api_key2, sub_query_texts)
|
| 477 |
if not params_map:
|
| 478 |
return all_querys_summary, "⚠️ 系統無法解析您問題中的查詢參數。"
|
| 479 |
|
|
|
|
| 509 |
|
| 510 |
# Step 5:整合分析 (API Call #4)
|
| 511 |
integration_prompt = f"使用者問題:{user_input}\n\n查詢資料如下:\n{combined_context}"
|
| 512 |
+
integration_result = reply(api_key2, system_integration, integration_prompt)
|
| 513 |
return all_querys_summary, integration_result
|
| 514 |
|
| 515 |
# =======================================================================
|
|
|
|
| 517 |
# =======================================================================
|
| 518 |
|
| 519 |
def gradio_interface(user_input):
|
| 520 |
+
"""Gradio 主要處理函式"""
|
| 521 |
api_key = os.getenv('Gemini')
|
| 522 |
+
api_key2 = os.getenv('Gemini2')
|
| 523 |
if not api_key:
|
| 524 |
return "❌ 查詢失敗", "錯誤:未在伺服器環境中設定 'Gemini' API 金鑰。"
|
| 525 |
|
|
|
|
| 542 |
"""
|
| 543 |
# 🤖 高雄市公務統計資料智慧查詢
|
| 544 |
歡迎使用!您可以透過自然語言提出關於高雄市的公務統計問題,系統將盡力為您查找相關資訊。
|
| 545 |
+
本系統運作於2v cpu & 16 GB RAM 免費資源,系統速度稍慢(產生結果時間依問題複雜度而定,一般為10至15秒)。
|
| 546 |
"""
|
| 547 |
)
|
| 548 |
|
|
|
|
| 550 |
with gr.Column(scale=1):
|
| 551 |
user_input_box = gr.Textbox(
|
| 552 |
label="請在此輸入您的問題",
|
| 553 |
+
placeholder="例如:113年底前金區人口數?",
|
| 554 |
lines=5
|
| 555 |
)
|
| 556 |
gr.Examples(
|
| 557 |
examples=[
|
| 558 |
+
"113年底前金區人口數?",
|
| 559 |
"110-113年高雄市總人口數趨勢?",
|
| 560 |
"110-113年失業率情形",
|
| 561 |
+
"113學年國小一年級學生人數",
|
| 562 |
+
"113年底鹽埕區、三民區、前鎮區、林園區及美濃區人口數"
|
| 563 |
],
|
| 564 |
inputs=user_input_box,
|
| 565 |
label="💡 範例問題"
|