Song
commited on
Commit
·
b3c381d
1
Parent(s):
841b5e8
hi
Browse files
app.py
CHANGED
|
@@ -82,7 +82,7 @@ def estimate_tokens(messages: List[Dict[str, str]]) -> int:
|
|
| 82 |
total += len(msg["content"].split()) * 1.3
|
| 83 |
return int(total)
|
| 84 |
|
| 85 |
-
# ----------
|
| 86 |
def perform_web_search(query: str, max_results: int = 5) -> str:
|
| 87 |
print(f"開始網路搜尋:查詢詞 = '{query}'")
|
| 88 |
try:
|
|
@@ -113,7 +113,7 @@ def perform_web_search(query: str, max_results: int = 5) -> str:
|
|
| 113 |
|
| 114 |
for i, (score, result) in enumerate(relevant_with_scores[:5], 1):
|
| 115 |
print(f"結果 {i}: 標題='{result['title']}',相似度={score:.2f},來源={result['url']}")
|
| 116 |
-
search_summary += f"{i}. [{score:.2f}] {result['title']}\n {result['content'][:
|
| 117 |
|
| 118 |
return search_summary
|
| 119 |
|
|
@@ -135,7 +135,7 @@ class ChatPipeline:
|
|
| 135 |
)
|
| 136 |
|
| 137 |
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
|
| 138 |
-
def _llm_call(self, messages: List[Dict[str, str]]) -> str:
|
| 139 |
token_est = estimate_tokens(messages)
|
| 140 |
if token_est > 50000:
|
| 141 |
raise ValueError("輸入過長")
|
|
@@ -143,13 +143,31 @@ class ChatPipeline:
|
|
| 143 |
response = self.llm_client.chat.completions.create(
|
| 144 |
model=LLM_MODEL_CONFIG["model"],
|
| 145 |
messages=messages,
|
| 146 |
-
max_tokens=LLM_MODEL_CONFIG["max_tokens"],
|
| 147 |
temperature=LLM_MODEL_CONFIG["temperature"],
|
| 148 |
seed=LLM_MODEL_CONFIG["seed"],
|
| 149 |
timeout=30.0,
|
| 150 |
)
|
| 151 |
return response.choices[0].message.content or ""
|
| 152 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
def get_conversation_history(self, user_id: str) -> List[Dict[str, str]]:
|
| 154 |
return conversations.get(user_id, [])
|
| 155 |
|
|
@@ -165,23 +183,32 @@ class ChatPipeline:
|
|
| 165 |
self.clear_conversation_history(user_id)
|
| 166 |
return "對話紀錄已清除!現在開始新的對話。"
|
| 167 |
|
| 168 |
-
search_results = perform_web_search(user_text)
|
| 169 |
-
|
| 170 |
history = self.get_conversation_history(user_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
|
| 172 |
messages.extend(history)
|
| 173 |
messages.append({"role": "user", "content": user_text})
|
| 174 |
|
| 175 |
-
if "沒有找到" not in search_results:
|
| 176 |
-
messages.append({"role": "system", "content": f"
|
| 177 |
|
| 178 |
response = self._llm_call(messages)
|
| 179 |
response = response.replace('*', '')
|
| 180 |
|
|
|
|
| 181 |
history.append({"role": "user", "content": user_text})
|
| 182 |
history.append({"role": "assistant", "content": response})
|
| 183 |
self.update_conversation_history(user_id, history)
|
| 184 |
|
|
|
|
| 185 |
chunks = split_text_for_line(response)
|
| 186 |
if len(chunks) > 5:
|
| 187 |
summary_prompt = [
|
|
|
|
| 82 |
total += len(msg["content"].split()) * 1.3
|
| 83 |
return int(total)
|
| 84 |
|
| 85 |
+
# ---------- 網路搜尋 ----------
|
| 86 |
def perform_web_search(query: str, max_results: int = 5) -> str:
|
| 87 |
print(f"開始網路搜尋:查詢詞 = '{query}'")
|
| 88 |
try:
|
|
|
|
| 113 |
|
| 114 |
for i, (score, result) in enumerate(relevant_with_scores[:5], 1):
|
| 115 |
print(f"結果 {i}: 標題='{result['title']}',相似度={score:.2f},來源={result['url']}")
|
| 116 |
+
search_summary += f"{i}. [{score:.2f}] {result['title']}\n {result['content'][:400]}...\n 來源: {result['url']}\n\n"
|
| 117 |
|
| 118 |
return search_summary
|
| 119 |
|
|
|
|
| 135 |
)
|
| 136 |
|
| 137 |
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
|
| 138 |
+
def _llm_call(self, messages: List[Dict[str, str]], max_tokens: int = None) -> str:
|
| 139 |
token_est = estimate_tokens(messages)
|
| 140 |
if token_est > 50000:
|
| 141 |
raise ValueError("輸入過長")
|
|
|
|
| 143 |
response = self.llm_client.chat.completions.create(
|
| 144 |
model=LLM_MODEL_CONFIG["model"],
|
| 145 |
messages=messages,
|
| 146 |
+
max_tokens=max_tokens or LLM_MODEL_CONFIG["max_tokens"],
|
| 147 |
temperature=LLM_MODEL_CONFIG["temperature"],
|
| 148 |
seed=LLM_MODEL_CONFIG["seed"],
|
| 149 |
timeout=30.0,
|
| 150 |
)
|
| 151 |
return response.choices[0].message.content or ""
|
| 152 |
|
| 153 |
+
def _needs_search(self, user_text: str, history: List[Dict[str, str]]) -> bool:
|
| 154 |
+
"""輕量判斷是否需要網路搜尋"""
|
| 155 |
+
router_prompt = [
|
| 156 |
+
{"role": "system", "content": "你只需要判斷用戶問題是否需要最新的網路資訊來回答。"
|
| 157 |
+
"如果是永恆知識(如聖經、數學原理、哲學、歷史經典等),回答 no。"
|
| 158 |
+
"如果是時事、新聞、最新研究、實時數據、當前事件等,回答 yes。"
|
| 159 |
+
"只回覆單字:yes 或 no。不要解釋。"},
|
| 160 |
+
*history,
|
| 161 |
+
{"role": "user", "content": user_text}
|
| 162 |
+
]
|
| 163 |
+
try:
|
| 164 |
+
decision = self._llm_call(router_prompt, max_tokens=10).strip().lower()
|
| 165 |
+
print(f"搜尋需求判斷:{decision}(問題:{user_text})")
|
| 166 |
+
return decision == "yes"
|
| 167 |
+
except Exception as e:
|
| 168 |
+
print(f"搜尋判斷失敗,預設不搜尋:{e}")
|
| 169 |
+
return False
|
| 170 |
+
|
| 171 |
def get_conversation_history(self, user_id: str) -> List[Dict[str, str]]:
|
| 172 |
return conversations.get(user_id, [])
|
| 173 |
|
|
|
|
| 183 |
self.clear_conversation_history(user_id)
|
| 184 |
return "對話紀錄已清除!現在開始新的對話。"
|
| 185 |
|
|
|
|
|
|
|
| 186 |
history = self.get_conversation_history(user_id)
|
| 187 |
+
|
| 188 |
+
# ---- 新增:判斷是否需要搜尋 ----
|
| 189 |
+
needs_search = self._needs_search(user_text, history)
|
| 190 |
+
|
| 191 |
+
search_results = None
|
| 192 |
+
if needs_search:
|
| 193 |
+
search_results = perform_web_search(user_text)
|
| 194 |
+
|
| 195 |
+
# ---- 建構最終 prompt ----
|
| 196 |
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
|
| 197 |
messages.extend(history)
|
| 198 |
messages.append({"role": "user", "content": user_text})
|
| 199 |
|
| 200 |
+
if search_results and "沒有找到" not in search_results and "錯誤" not in search_results:
|
| 201 |
+
messages.append({"role": "system", "content": f"網路搜尋結果(僅在高度相關時使用):{search_results}"})
|
| 202 |
|
| 203 |
response = self._llm_call(messages)
|
| 204 |
response = response.replace('*', '')
|
| 205 |
|
| 206 |
+
# 更新歷史(包含最終回應)
|
| 207 |
history.append({"role": "user", "content": user_text})
|
| 208 |
history.append({"role": "assistant", "content": response})
|
| 209 |
self.update_conversation_history(user_id, history)
|
| 210 |
|
| 211 |
+
# 長回應處理
|
| 212 |
chunks = split_text_for_line(response)
|
| 213 |
if len(chunks) > 5:
|
| 214 |
summary_prompt = [
|