XiaoBai1221 commited on
Commit
d8085e0
·
1 Parent(s): fa7dc28
core/pipeline.py CHANGED
@@ -124,11 +124,15 @@ class ChatPipeline:
124
  collect_texts(translated_data)
125
 
126
  if not texts_to_translate:
 
127
  return tool_data
128
 
129
  # 批量翻譯(讓 GPT 自動判斷目標語言)
130
  import services.ai_service as ai_service
131
 
 
 
 
132
  combined_text = "\n---\n".join(texts_to_translate)
133
  messages = [
134
  {
@@ -138,12 +142,14 @@ class ChatPipeline:
138
  {"role": "user", "content": combined_text}
139
  ]
140
 
 
141
  translated = await ai_service.generate_response_async(
142
  messages=messages,
143
- model="gpt-5-nano",
144
- reasoning_effort="minimal",
145
  max_tokens=800,
146
  )
 
147
 
148
  if translated:
149
  translated_parts = translated.strip().split("---")
@@ -219,7 +225,11 @@ class ChatPipeline:
219
 
220
  # 提取情緒(雙軌制:音頻情緒優先,文字情緒輔助)
221
  text_emotion = intent_data.get("emotion", "neutral") if intent_data else "neutral"
222
-
 
 
 
 
223
  # 情緒融合邏輯
224
  if audio_emotion and audio_emotion.get("success"):
225
  audio_emotion_label = audio_emotion.get("emotion", "neutral")
@@ -319,8 +329,16 @@ class ChatPipeline:
319
  return PipelineResult(text="抱歉,功能處理沒有產出結果。", is_fallback=True, reason="feature-empty")
320
 
321
  # 簡化翻譯:非中文用戶 → 翻譯工具卡片
322
- if not self._is_chinese_message(user_message) and tool_data:
 
 
 
323
  tool_data = await self._translate_tool_data(tool_data, user_message)
 
 
 
 
 
324
 
325
  # 返回帶有工具元數據的結果(包含情緒)
326
  meta_dict = {}
 
124
  collect_texts(translated_data)
125
 
126
  if not texts_to_translate:
127
+ logger.info(f"🌐 無需翻譯的文字,直接返回原始資料")
128
  return tool_data
129
 
130
  # 批量翻譯(讓 GPT 自動判斷目標語言)
131
  import services.ai_service as ai_service
132
 
133
+ logger.info(f"🌐 收集到 {len(texts_to_translate)} 個需要翻譯的文字")
134
+ logger.debug(f"🌐 待翻譯文字: {texts_to_translate[:3]}...") # 只顯示前3個
135
+
136
  combined_text = "\n---\n".join(texts_to_translate)
137
  messages = [
138
  {
 
142
  {"role": "user", "content": combined_text}
143
  ]
144
 
145
+ logger.info(f"🌐 呼叫 GPT 翻譯,模型: gpt-4o-mini")
146
  translated = await ai_service.generate_response_async(
147
  messages=messages,
148
+ model="gpt-4o-mini", # 升級到 gpt-4o-mini 以提升翻譯品質
149
+ reasoning_effort=None, # gpt-4o-mini 不支援此參數
150
  max_tokens=800,
151
  )
152
+ logger.info(f"🌐 GPT 翻譯完成,結果長度: {len(translated) if translated else 0}")
153
 
154
  if translated:
155
  translated_parts = translated.strip().split("---")
 
225
 
226
  # 提取情緒(雙軌制:音頻情緒優先,文字情緒輔助)
227
  text_emotion = intent_data.get("emotion", "neutral") if intent_data else "neutral"
228
+
229
+ # DEBUG: 顯示 audio_emotion 的完整內容
230
+ logger.info(f"🐛 [DEBUG] audio_emotion = {audio_emotion}")
231
+ logger.info(f"🐛 [DEBUG] text_emotion = {text_emotion}")
232
+
233
  # 情緒融合邏輯
234
  if audio_emotion and audio_emotion.get("success"):
235
  audio_emotion_label = audio_emotion.get("emotion", "neutral")
 
329
  return PipelineResult(text="抱歉,功能處理沒有產出結果。", is_fallback=True, reason="feature-empty")
330
 
331
  # 簡化翻譯:非中文用戶 → 翻譯工具卡片
332
+ is_chinese = self._is_chinese_message(user_message)
333
+ logger.info(f"🌐 語言檢測: user_message='{user_message}', is_chinese={is_chinese}")
334
+ if not is_chinese and tool_data:
335
+ logger.info(f"🌐 開始翻譯工具卡片: {len(str(tool_data))} chars")
336
  tool_data = await self._translate_tool_data(tool_data, user_message)
337
+ logger.info(f"🌐 翻譯完成: {len(str(tool_data))} chars")
338
+ elif is_chinese:
339
+ logger.info(f"🌐 用戶使用中文,不翻譯工具卡片")
340
+ elif not tool_data:
341
+ logger.info(f"🌐 無工具資料,跳過翻譯")
342
 
343
  # 返回帶有工具元數據的結果(包含情緒)
344
  meta_dict = {}
features/mcp/agent_bridge.py CHANGED
@@ -1150,7 +1150,8 @@ YouBike 查詢(重要!參數提取規則):
1150
  "【核心原則】\n"
1151
  "⭐ 只回答使用者問的問題,不要把所有數據都說出來\n"
1152
  "⭐ 分析使用者的核心意圖(問溫度?天氣?時間?地點?數量?)\n"
1153
- "⭐ 從工具數據中只提取相關資訊,無關資訊一律省略\n\n"
 
1154
  "【回應要求】\n"
1155
  "1. 使用口語化、親切的語氣(可以用「喔」「呢」「哦」等語氣詞)\n"
1156
  "2. 不要列表式的羅列數據,而是用對話方式描述\n"
@@ -1181,15 +1182,13 @@ YouBike 查詢(重要!參數提取規則):
1181
  {"role": "user", "content": user_prompt}
1182
  ]
1183
 
1184
- # 格式化回應使用 low reasoning(不需深度推理)
1185
- optimal_effort = get_optimal_reasoning_effort("format_response")
1186
-
1187
  response = await ai_service.generate_response_for_user(
1188
  messages=messages,
1189
  user_id="format_response",
1190
- model="gpt-5-nano",
1191
  chat_id=None,
1192
- reasoning_effort=optimal_effort
1193
  )
1194
 
1195
  return response
 
1150
  "【核心原則】\n"
1151
  "⭐ 只回答使用者問的問題,不要把所有數據都說出來\n"
1152
  "⭐ 分析使用者的核心意圖(問溫度?天氣?時間?地點?數量?)\n"
1153
+ "⭐ 從工具數據中只提取相關資訊,無關資訊一律省略\n"
1154
+ "⭐ **注意:用什麼語言提問,就用什麼語言回答**(日文問→日文答,英文問→英文答)\n\n"
1155
  "【回應要求】\n"
1156
  "1. 使用口語化、親切的語氣(可以用「喔」「呢」「哦」等語氣詞)\n"
1157
  "2. 不要列表式的羅列數據,而是用對話方式描述\n"
 
1182
  {"role": "user", "content": user_prompt}
1183
  ]
1184
 
1185
+ # 格式化回應使用 gpt-4o-mini(支援多語言,不需 reasoning_effort)
 
 
1186
  response = await ai_service.generate_response_for_user(
1187
  messages=messages,
1188
  user_id="format_response",
1189
+ model="gpt-4o-mini", # 升級到 gpt-4o-mini 以支援多語言
1190
  chat_id=None,
1191
+ reasoning_effort=None # gpt-4o-mini 不支援此參數
1192
  )
1193
 
1194
  return response
services/ai_service.py CHANGED
@@ -505,10 +505,14 @@ async def generate_response_async(
505
  "max_completion_tokens": max_tokens if max_tokens else 2000, # 關懷模式可自訂 tokens
506
  }
507
 
508
- # 加入 reasoning_effort 控制(GPT-5 系列)
509
- if reasoning_effort:
 
 
510
  request_kwargs["reasoning_effort"] = reasoning_effort
511
  logger.info(f"🧠 設定 reasoning_effort: {reasoning_effort}")
 
 
512
 
513
  # 優先使用 Structured Outputs(2025年最佳實踐)
514
  if use_structured_outputs and response_schema:
 
505
  "max_completion_tokens": max_tokens if max_tokens else 2000, # 關懷模式可自訂 tokens
506
  }
507
 
508
+ # 加入 reasoning_effort 控制(僅 o1 系列和 gpt-5 系列支援)
509
+ # gpt-4o-mini 等模型不支援此參數,需要過濾
510
+ reasoning_models = model.startswith("o1") or model.startswith("gpt-5")
511
+ if reasoning_effort and reasoning_models:
512
  request_kwargs["reasoning_effort"] = reasoning_effort
513
  logger.info(f"🧠 設定 reasoning_effort: {reasoning_effort}")
514
+ elif reasoning_effort and not reasoning_models:
515
+ logger.debug(f"⚠️ 模型 {model} 不支援 reasoning_effort,已忽略")
516
 
517
  # 優先使用 Structured Outputs(2025年最佳實踐)
518
  if use_structured_outputs and response_schema:
static/frontend/js/websocket.js CHANGED
@@ -629,6 +629,21 @@ function initializeWebSocket(token) {
629
  }
630
  break;
631
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
632
  default:
633
  console.log('🔍 未處理的訊息類型:', data.type);
634
  }
 
629
  }
630
  break;
631
 
632
+ case 'audio_emotion_detected':
633
+ // 音頻情緒檢測結果(新增)
634
+ console.log('🎭 檢測到音頻情緒:', data.emotion, '置信度:', data.confidence, 'source:', data.source);
635
+
636
+ // 如果置信度 >= 0.5,應用情緒主題
637
+ if (data.emotion && data.confidence >= 0.5 && typeof applyEmotion === 'function') {
638
+ applyEmotion(data.emotion);
639
+ console.log('✅ 音頻情緒主題已套用:', data.emotion, `(置信度: ${data.confidence.toFixed(2)})`);
640
+ } else if (data.confidence < 0.5) {
641
+ console.log('⚠️ 音頻情緒置信度過低,不套用主題:', data.confidence.toFixed(2));
642
+ } else {
643
+ console.warn('⚠️ applyEmotion 函數未定義或情緒值無效');
644
+ }
645
+ break;
646
+
647
  default:
648
  console.log('🔍 未處理的訊息類型:', data.type);
649
  }