Spaces:
Sleeping
Sleeping
Commit ·
757aa6c
1
Parent(s): f89f516
Demo
Browse files- app.py +11 -31
- core/emotion_care_manager.py +26 -9
app.py
CHANGED
|
@@ -1064,37 +1064,12 @@ async def websocket_endpoint_with_jwt(
|
|
| 1064 |
if transcription:
|
| 1065 |
logger.info(f"🤖 處理即時轉錄結果: {transcription}")
|
| 1066 |
|
| 1067 |
-
# 音頻情緒辨識(
|
| 1068 |
audio_emotion = None
|
|
|
|
| 1069 |
if audio_buffer:
|
| 1070 |
-
|
| 1071 |
-
|
| 1072 |
-
logger.info(f"🎭 開始音頻情緒辨識,音頻大小: {len(audio_buffer)} bytes")
|
| 1073 |
-
audio_emotion = await audio_emotion_service.predict_from_bytes(audio_buffer)
|
| 1074 |
-
|
| 1075 |
-
if audio_emotion.get("success"):
|
| 1076 |
-
emotion_label = audio_emotion.get("emotion")
|
| 1077 |
-
confidence = audio_emotion.get("confidence", 0.0)
|
| 1078 |
-
logger.info(f"✅ 音頻情緒: {emotion_label} (置信度: {confidence:.4f})")
|
| 1079 |
-
|
| 1080 |
-
# 發送音頻情緒給前端
|
| 1081 |
-
await websocket.send_json({
|
| 1082 |
-
"type": "audio_emotion_detected",
|
| 1083 |
-
"emotion": emotion_label,
|
| 1084 |
-
"confidence": confidence,
|
| 1085 |
-
"all_emotions": audio_emotion.get("all_emotions", {}),
|
| 1086 |
-
"source": "audio"
|
| 1087 |
-
})
|
| 1088 |
-
else:
|
| 1089 |
-
logger.warning(f"⚠️ 音頻情緒辨識失敗: {audio_emotion.get('error')}")
|
| 1090 |
-
audio_emotion = None
|
| 1091 |
-
except Exception as e:
|
| 1092 |
-
logger.error(f"❌ 音頻情緒辨識異常: {e}")
|
| 1093 |
-
audio_emotion = None
|
| 1094 |
-
finally:
|
| 1095 |
-
# 清理音頻緩衝
|
| 1096 |
-
client_info.pop("audio_buffer", None)
|
| 1097 |
-
manager.set_client_info(user_id, client_info)
|
| 1098 |
|
| 1099 |
# 通知前端開始思考
|
| 1100 |
await websocket.send_json({"type": "typing", "message": "thinking"})
|
|
@@ -1346,17 +1321,22 @@ async def handle_message(user_message, user_id, chat_id, messages, request_id: s
|
|
| 1346 |
# 提取情緒與關懷模式資訊(新增)
|
| 1347 |
emotion = res.meta.get('emotion') if res.meta else None
|
| 1348 |
care_mode = res.meta.get('care_mode', False) if res.meta else False
|
|
|
|
|
|
|
| 1349 |
|
| 1350 |
# 立即返回完整結果(包含工具信息與情緒)
|
|
|
|
| 1351 |
if tool_name or tool_data or emotion or care_mode:
|
|
|
|
| 1352 |
return {
|
| 1353 |
'message': res.text,
|
| 1354 |
'tool_name': tool_name,
|
| 1355 |
'tool_data': tool_data,
|
| 1356 |
-
'emotion': emotion,
|
| 1357 |
-
'care_mode': care_mode
|
| 1358 |
}
|
| 1359 |
else:
|
|
|
|
| 1360 |
return res.text
|
| 1361 |
|
| 1362 |
|
|
|
|
| 1064 |
if transcription:
|
| 1065 |
logger.info(f"🤖 處理即時轉錄結果: {transcription}")
|
| 1066 |
|
| 1067 |
+
# 音頻情緒辨識已禁用(改用文字情緒偵測)
|
| 1068 |
audio_emotion = None
|
| 1069 |
+
# 清理音頻緩衝
|
| 1070 |
if audio_buffer:
|
| 1071 |
+
client_info.pop("audio_buffer", None)
|
| 1072 |
+
manager.set_client_info(user_id, client_info)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1073 |
|
| 1074 |
# 通知前端開始思考
|
| 1075 |
await websocket.send_json({"type": "typing", "message": "thinking"})
|
|
|
|
| 1321 |
# 提取情緒與關懷模式資訊(新增)
|
| 1322 |
emotion = res.meta.get('emotion') if res.meta else None
|
| 1323 |
care_mode = res.meta.get('care_mode', False) if res.meta else False
|
| 1324 |
+
|
| 1325 |
+
logger.info(f"🎭 handle_message 情緒: emotion={emotion}, care_mode={care_mode}, meta={res.meta}")
|
| 1326 |
|
| 1327 |
# 立即返回完整結果(包含工具信息與情緒)
|
| 1328 |
+
# 注意:即使 emotion 是 "neutral" 也要返回 dict,確保前端收到情緒資訊
|
| 1329 |
if tool_name or tool_data or emotion or care_mode:
|
| 1330 |
+
logger.info(f"📤 返回 dict 格式: emotion={emotion}")
|
| 1331 |
return {
|
| 1332 |
'message': res.text,
|
| 1333 |
'tool_name': tool_name,
|
| 1334 |
'tool_data': tool_data,
|
| 1335 |
+
'emotion': emotion,
|
| 1336 |
+
'care_mode': care_mode
|
| 1337 |
}
|
| 1338 |
else:
|
| 1339 |
+
logger.info(f"📤 返回純文字格式(無情緒資訊)")
|
| 1340 |
return res.text
|
| 1341 |
|
| 1342 |
|
core/emotion_care_manager.py
CHANGED
|
@@ -17,20 +17,37 @@ class EmotionCareManager:
|
|
| 17 |
|
| 18 |
# 極端情緒定義(需要進入關懷模式的情緒)
|
| 19 |
EXTREME_EMOTIONS = {"sad", "angry", "fear"}
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
# 模式存活與冷卻(避免反覆觸發)
|
| 22 |
-
CARE_TTL_SECONDS =
|
| 23 |
-
COOLDOWN_SECONDS =
|
| 24 |
|
| 25 |
# 解除關懷模式的關鍵字
|
| 26 |
RELEASE_KEYWORDS = [
|
| 27 |
-
# 繁體
|
| 28 |
"我沒事了", "我好了", "沒事了", "好多了", "好一點了",
|
| 29 |
"我好些了", "沒關係了", "我ok了", "我可以了",
|
| 30 |
-
"不用擔心", "別擔心我",
|
| 31 |
-
|
|
|
|
|
|
|
| 32 |
"我没事了", "没事了", "好一点了", "没关系了",
|
| 33 |
-
"不用担心", "别担心我",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
]
|
| 35 |
|
| 36 |
# 用戶關懷狀態
|
|
@@ -107,15 +124,15 @@ class EmotionCareManager:
|
|
| 107 |
if not state or not state.get("in_care_mode", False):
|
| 108 |
return False
|
| 109 |
|
| 110 |
-
# 優先檢查情緒:如果偵測到
|
| 111 |
-
if emotion and emotion.lower()
|
| 112 |
original_emotion = state.get("emotion", "unknown")
|
| 113 |
duration = time.time() - state.get("start_time", 0)
|
| 114 |
|
| 115 |
state["in_care_mode"] = False
|
| 116 |
state["last_exit_time"] = time.time()
|
| 117 |
|
| 118 |
-
logger.info(f"✅ 用戶 {user_id}(chat={chat_id or 'default'})情緒恢復為
|
| 119 |
return True
|
| 120 |
|
| 121 |
# 檢查是否包含解除關鍵字
|
|
|
|
| 17 |
|
| 18 |
# 極端情緒定義(需要進入關懷模式的情緒)
|
| 19 |
EXTREME_EMOTIONS = {"sad", "angry", "fear"}
|
| 20 |
+
|
| 21 |
+
# 正面情緒定義(可以解除關懷模式的情緒)
|
| 22 |
+
POSITIVE_EMOTIONS = {"neutral", "happy", "surprise"}
|
| 23 |
|
| 24 |
# 模式存活與冷卻(避免反覆觸發)
|
| 25 |
+
CARE_TTL_SECONDS = 10 * 60 # 10 分鐘自動失效(從 20 分鐘縮短)
|
| 26 |
+
COOLDOWN_SECONDS = 5 * 60 # 5 分鐘內不重入(從 10 分鐘縮短)
|
| 27 |
|
| 28 |
# 解除關懷模式的關鍵字
|
| 29 |
RELEASE_KEYWORDS = [
|
| 30 |
+
# 繁體中文
|
| 31 |
"我沒事了", "我好了", "沒事了", "好多了", "好一點了",
|
| 32 |
"我好些了", "沒關係了", "我ok了", "我可以了",
|
| 33 |
+
"不用擔心", "別擔心我", "謝謝關心", "感謝你",
|
| 34 |
+
"我很好", "心情好多了", "開心", "快樂", "高興",
|
| 35 |
+
"沒問題", "放心", "安心了", "舒服多了",
|
| 36 |
+
# 簡體中文
|
| 37 |
"我没事了", "没事了", "好一点了", "没关系了",
|
| 38 |
+
"不用担心", "别担心我", "谢谢关心", "感谢你",
|
| 39 |
+
"我很好", "心情好多了", "开心", "快乐", "高兴",
|
| 40 |
+
"没问题", "放心", "安心了", "舒服多了",
|
| 41 |
+
# 英文
|
| 42 |
+
"i'm fine", "i am fine", "i'm ok", "i am ok", "i'm okay", "i am okay",
|
| 43 |
+
"i feel better", "feeling better", "much better", "all good",
|
| 44 |
+
"don't worry", "no worries", "thank you", "thanks",
|
| 45 |
+
# 日文
|
| 46 |
+
"大丈夫", "元気", "ありがとう", "心配しないで",
|
| 47 |
+
# 印尼文
|
| 48 |
+
"saya baik", "tidak apa-apa", "terima kasih",
|
| 49 |
+
# 越南文
|
| 50 |
+
"tôi ổn", "không sao", "cảm ơn",
|
| 51 |
]
|
| 52 |
|
| 53 |
# 用戶關懷狀態
|
|
|
|
| 124 |
if not state or not state.get("in_care_mode", False):
|
| 125 |
return False
|
| 126 |
|
| 127 |
+
# 優先檢查情緒:如果偵測到正面情緒(neutral, happy, surprise),立即解除關懷模式
|
| 128 |
+
if emotion and emotion.lower() in cls.POSITIVE_EMOTIONS:
|
| 129 |
original_emotion = state.get("emotion", "unknown")
|
| 130 |
duration = time.time() - state.get("start_time", 0)
|
| 131 |
|
| 132 |
state["in_care_mode"] = False
|
| 133 |
state["last_exit_time"] = time.time()
|
| 134 |
|
| 135 |
+
logger.info(f"✅ 用戶 {user_id}(chat={chat_id or 'default'})情緒恢復為 {emotion}({original_emotion} → {emotion}),解除關懷模式(持續 {duration:.1f}秒)")
|
| 136 |
return True
|
| 137 |
|
| 138 |
# 檢查是否包含解除關鍵字
|