|
|
@@ -22,6 +22,7 @@ from http_pool import http_pool # 🔥 使用连接池管理器
|
|
|
from scenario_config import is_special_ab_experiment_user
|
|
|
from prompt_constants import AB_TASK_EMOTION_APPENDIX
|
|
|
from ab_experiment_media_config import resolve_llm_model, resolve_tts_params, TtsParams
|
|
|
+from emotion_text_utils import parse_emotion_from_text, strip_emotion_from_text
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@@ -393,64 +394,48 @@ Output ONLY the greeting line.
|
|
|
buffer += content
|
|
|
full_response += content
|
|
|
|
|
|
- # 🎯 优先检测情感标记(如果还没检测到)
|
|
|
- if detected_emotion == "neutral" and "[EMOTION:" in full_response:
|
|
|
- emotion_start = full_response.find("[EMOTION:")
|
|
|
- emotion_end = full_response.find("]", emotion_start)
|
|
|
- if emotion_end > emotion_start:
|
|
|
- emotion_str = full_response[emotion_start + 9:emotion_end].strip().lower()
|
|
|
- valid_emotions = ["neutral", "happy", "sad", "excited", "angry", "surprised", "thoughtful", "encouraging", "confused", "worried", "satisfied", "friendly", "sorry"]
|
|
|
- if emotion_str in valid_emotions:
|
|
|
- detected_emotion = emotion_str
|
|
|
- logger.info(f"[LLM情感检测] ✅ 检测到情感标签: {emotion_str}, 原始片段: {full_response[:200]}")
|
|
|
- else:
|
|
|
- # 🔥 未知情感词,默认映射为 neutral,但仍然移除标签
|
|
|
- logger.warning(f"[LLM] 未知情感词: {emotion_str},已映射为 neutral, 原始片段: {full_response[:200]}")
|
|
|
- detected_emotion = "neutral"
|
|
|
-
|
|
|
- # 🚀 立即 yield 空句子传递情感(减少延迟)
|
|
|
- if not emotion_yielded:
|
|
|
- yield ("", detected_emotion) # 空句子,仅传递情感
|
|
|
- emotion_yielded = True
|
|
|
+ # 🎯 优先检测情感([EMOTION:xxx] 或首行裸词,大小写不敏感)
|
|
|
+ if not emotion_yielded:
|
|
|
+ parsed = parse_emotion_from_text(full_response)
|
|
|
+ if parsed:
|
|
|
+ detected_emotion = parsed # type: ignore[assignment]
|
|
|
+ logger.info(
|
|
|
+ f"[LLM情感检测] ✅ 检测到情感: {parsed}, 原始片段: {full_response[:200]}"
|
|
|
+ )
|
|
|
+ yield ("", detected_emotion)
|
|
|
+ emotion_yielded = True
|
|
|
|
|
|
- # ✅ v0.3: 保留情感标签在文本中(前端需要),只从buffer中提取句子
|
|
|
- # 检测句子边界(完整的句子)
|
|
|
- # 注意:buffer 中可能包含情感标签,但我们保留它
|
|
|
+ # 检测句子边界;yield 前剥离情感标签/裸词
|
|
|
if self._is_complete_sentence(buffer):
|
|
|
- sentence = buffer.strip()
|
|
|
+ sentence = strip_emotion_from_text(buffer.strip())
|
|
|
+ buffer = ""
|
|
|
+ if not sentence:
|
|
|
+ continue
|
|
|
sentence_count += 1
|
|
|
- # 使用已检测到的情感,但保留情感标签在文本中
|
|
|
yield (sentence, detected_emotion)
|
|
|
- buffer = ""
|
|
|
|
|
|
- # ✅ v0.3: 保留情感标签在文本中(前端需要)
|
|
|
- # 处理buffer中的剩余内容(已输出句子之后的部分)
|
|
|
- remaining = buffer.strip()
|
|
|
+ remaining = strip_emotion_from_text(buffer.strip())
|
|
|
if remaining:
|
|
|
sentence_count += 1
|
|
|
yield (remaining, detected_emotion)
|
|
|
elif not remaining and sentence_count == 0:
|
|
|
- # 如果一个句子都没输出,输出完整内容(保留情感标签)
|
|
|
- if full_response.strip():
|
|
|
- yield (full_response.strip(), detected_emotion)
|
|
|
+ cleaned_full = strip_emotion_from_text(full_response.strip())
|
|
|
+ if cleaned_full:
|
|
|
+ yield (cleaned_full, detected_emotion)
|
|
|
else:
|
|
|
- # 🔥 兜底逻辑:LLM没有返回任何文本(只返回了情感标记)
|
|
|
default_response = "I understand. Could you tell me more?"
|
|
|
yield (default_response, detected_emotion)
|
|
|
|
|
|
- # 🔍 调试日志:记录LLM完整响应和情感检测结果
|
|
|
logger.debug(
|
|
|
f"[LLM完整响应] 总chunk数={chunk_count}, "
|
|
|
f"检测到的情感={detected_emotion}, "
|
|
|
- f"是否包含[EMOTION:={'[EMOTION:' in full_response}, "
|
|
|
f"完整响应长度={len(full_response)}, "
|
|
|
f"响应前500字符={full_response[:500]}"
|
|
|
)
|
|
|
|
|
|
- # ⚠️ 警告:如果没有检测到情感标签
|
|
|
- if detected_emotion == "neutral" and "[EMOTION:" not in full_response:
|
|
|
+ if not parse_emotion_from_text(full_response):
|
|
|
logger.warning(
|
|
|
- f"[LLM情感检测] ⚠️ 未检测到情感标签,LLM可能没有生成。"
|
|
|
+ f"[LLM情感检测] ⚠️ 未检测到情感标签,将使用默认 neutral。"
|
|
|
f"完整响应长度={len(full_response)}, "
|
|
|
f"响应前500字符={full_response[:500]}"
|
|
|
)
|
|
|
@@ -547,30 +532,14 @@ Output ONLY the greeting line.
|
|
|
|
|
|
full_response = response.choices[0].message.content or ""
|
|
|
|
|
|
- # 提取情感标签
|
|
|
- emotion: EmotionType = "neutral"
|
|
|
- response_text = full_response
|
|
|
-
|
|
|
- # 查找情感标签
|
|
|
- if "[EMOTION:" in full_response:
|
|
|
- emotion_start = full_response.find("[EMOTION:")
|
|
|
- emotion_end = full_response.find("]", emotion_start)
|
|
|
- if emotion_end > emotion_start:
|
|
|
- emotion_str = full_response[emotion_start + 9:emotion_end].strip().lower()
|
|
|
- # 验证情感类型
|
|
|
- valid_emotions = ["neutral", "happy", "sad", "excited", "angry", "surprised", "thoughtful", "encouraging", "confused", "worried", "satisfied", "friendly", "sorry", "gentle"]
|
|
|
- if emotion_str in valid_emotions:
|
|
|
- emotion = emotion_str
|
|
|
- else:
|
|
|
- # 🔥 未知情感词,默认映射为 neutral
|
|
|
- logger.warning(f"[LLM] 未知情感词: {emotion_str},已映射为 neutral")
|
|
|
- # 移除情感标签(不发送给TTS)
|
|
|
- response_text = full_response[:emotion_start].strip()
|
|
|
+ parsed = parse_emotion_from_text(full_response)
|
|
|
+ emotion: EmotionType = parsed or "neutral" # type: ignore[assignment]
|
|
|
+ response_text = strip_emotion_from_text(full_response)
|
|
|
|
|
|
- # 如果没有文本内容,使用默认回复
|
|
|
if not response_text:
|
|
|
response_text = "I understand. Please tell me more!"
|
|
|
- emotion = "neutral"
|
|
|
+ if not parsed:
|
|
|
+ emotion = "neutral"
|
|
|
|
|
|
return (response_text, emotion)
|
|
|
|