【人机交互 6-10】第 9/25 课

🤖 第09课:情感识别

📌 情感识别概述

情感识别让服务机器人读懂人心——不是冰冷的命令执行器,而是有温度的服务者:

💡 情感识别价值

场景用户情绪机器人策略
配送延迟愤怒/焦虑道歉+加速+补偿
迷路求助困惑/焦虑耐心引导+确认理解
完成任务开心/满意热情回应+推荐服务
投诉不满愤怒认真倾听+升级处理

📌 文本情感检测

import math, random

class TextEmotionDetector:
    """文本情感检测"""
    def __init__(self):
        self.emotion_words = {
            "happy": ["开心","高兴","满意","谢谢","棒","好","太好了","不错","喜欢","赞"],
            "angry": ["生气","不满","差","太差了","投诉","退","垃圾","烦","讨厌","够了"],
            "sad": ["失望","难过","不好","可惜","遗憾","伤心","郁闷","沮丧","唉"],
            "anxious": ["着急","急","快点","赶紧","来不及","等不了","催","慢"],
            "confused": ["什么","不懂","不明白","怎么","哪里","搞不懂","迷糊","晕"],
            "neutral": [],
        }
        self.emotion_icons = {"happy":"😊","angry":"😠","sad":"😢","anxious":"😰","confused":"🤔","neutral":"😐"}

    def detect(self, text):
        scores = {}
        for emotion, words in self.emotion_words.items():
            if emotion == "neutral": continue
            score = sum(1 for w in words if w in text)
            scores[emotion] = score

        total = sum(scores.values())
        if total == 0:
            return {"emotion": "neutral", "confidence": 0.8, "scores": scores}
        
        for e in scores: scores[e] /= total
        best = max(scores, key=scores.get)
        return {"emotion": best, "confidence": scores[best], "scores": scores}

    def get_response_strategy(self, emotion):
        strategies = {
            "happy": {"tone": "热情", "action": "可提供额外服务", "priority": "normal"},
            "angry": {"tone": "道歉+安抚", "action": "优先处理+补偿建议", "priority": "high"},
            "sad": {"tone": "温暖关心", "action": "提供便利+少打扰", "priority": "normal"},
            "anxious": {"tone": "快速高效", "action": "加速处理+进度汇报", "priority": "high"},
            "confused": {"tone": "耐心解释", "action": "简化步骤+确认理解", "priority": "normal"},
            "neutral": {"tone": "专业标准", "action": "按流程执行", "priority": "normal"},
        }
        return strategies.get(emotion, strategies["neutral"])

detector = TextEmotionDetector()
print("文本情感检测模拟")
print("=" * 55)

tests = [
    "太好了!谢谢你帮我送到",
    "太差了!等了这么久还没到,我要投诉",
    "唉,算了,没什么",
    "快点快点,我赶时间!",
    "我不明白这个怎么操作",
    "请带我去3楼会议室",
]
for text in tests:
    result = detector.detect(text)
    icon = detector.emotion_icons[result["emotion"]]
    strategy = detector.get_response_strategy(result["emotion"])
    print(f"\n💬 \"{text}\"")
    print(f"   情感: {icon} {result['emotion']} (置信度:{result['confidence']:.0%})")
    print(f"   策略: 语气={strategy['tone']}, 优先级={strategy['priority']}")

print("\n✅ 情感检测验证通过")
✅ 验证通过 文本情感检测模拟 ======================================================= 💬 "太好了!谢谢你帮我送到" 情感: 😊 happy (置信度:100%) 策略: 语气=热情, 优先级=normal 💬 "太差了!等了这么久还没到,我要投诉" 情感: 😠 angry (置信度:100%) 策略: 语气=道歉+安抚, 优先级=high 💬 "唉,算了,没什么" 情感: 😢 sad (置信度:50%) 策略: 语气=温暖关心, 优先级=normal 💬 "快点快点,我赶时间!" 情感: 😰 anxious (置信度:100%) 策略: 语气=快速高效, 优先级=high 💬 "我不明白这个怎么操作" 情感: 🤔 confused (置信度:100%) 策略: 语气=耐心解释, 优先级=normal 💬 "请带我去3楼会议室" 情感: 😐 neutral (置信度:80%) 策略: 语气=专业标准, 优先级=normal ✅ 情感检测验证通过

📌 面部表情情感识别

FACS(面部动作编码系统)将面部表情分解为动作单元(AU)

import math

class FacialEmotionSimulator:
    """面部表情情感模拟"""
    def __init__(self):
        self.au_weights = {
            "happy":  {"au6":0.9,"au12":0.9,"au25":0.3},
            "sad":    {"au1":0.7,"au4":0.6,"au15":0.5},
            "angry":  {"au4":0.9,"au5":0.7,"au23":0.8,"au24":0.6},
            "surprise":{"au1":0.8,"au2":0.8,"au5":0.9,"au27":0.7},
            "fear":   {"au1":0.6,"au2":0.6,"au4":0.5,"au20":0.5,"au26":0.4},
            "disgust":{"au9":0.7,"au10":0.6,"au17":0.5},
            "neutral":{"au1":0.0,"au4":0.0,"au12":0.0},
        }
        self.descriptions = {
            "happy": "嘴角上扬+眼角皱纹",
            "sad": "眉毛内侧上扬+嘴角下垂",
            "angry": "眉毛下压+嘴唇紧抿",
            "surprise": "眉毛上扬+嘴巴张开",
            "fear": "眉毛上扬+嘴唇紧张",
            "disgust": "鼻子皱起+上唇上扬",
            "neutral": "面部肌肉放松",
        }

    def classify(self, detected_aus):
        """根据检测到的AU分类情感"""
        best_emotion = "neutral"
        best_score = -1
        for emotion, au_pattern in self.au_weights.items():
            score = 0; total_weight = 0
            for au, weight in au_pattern.items():
                detected = detected_aus.get(au, 0)
                score += weight * detected
                total_weight += weight
            if total_weight > 0:
                normalized = score / total_weight
                if normalized > best_score:
                    best_score = normalized; best_emotion = emotion
        return {"emotion": best_emotion, "confidence": best_score,
                "description": self.descriptions[best_emotion]}

    def simulate_detection(self, true_emotion, noise=0.1):
        """模拟面部检测(含噪声)"""
        true_aus = self.au_weights.get(true_emotion, {})
        detected = {}
        for au, weight in true_aus.items():
            import random
            detected[au] = max(0, min(1, weight + random.gauss(0, noise)))
        return detected

sim = FacialEmotionSimulator()
print("面部表情情感模拟")
print("=" * 55)

emotions = ["happy","sad","angry","surprise","neutral"]
for true_emotion in emotions:
    detected_aus = sim.simulate_detection(true_emotion, noise=0.15)
    result = sim.classify(detected_aus)
    correct = "✅" if result["emotion"] == true_emotion else "❌"
    print(f"\n{correct} 真实:{true_emotion} → 检测:{result['emotion']} "
          f"(置信度:{result['confidence']:.2f})")
    print(f"   特征: {result['description']}")

print("\n✅ 面部情感检测验证通过")
✅ 验证通过 面部表情情感模拟 ======================================================= ✅ 真实:happy → 检测:happy (置信度:0.91) 特征: 嘴角上扬+眼角皱纹 ✅ 真实:sad → 检测:sad (置信度:0.78) 特征: 眉毛内侧上扬+嘴角下垂 ✅ 真实:angry → 检测:angry (置信度:0.67) 特征: 眉毛下压+嘴唇紧抿 ✅ 真实:surprise → 检测:surprise (置信度:0.74) 特征: 眉毛上扬+嘴巴张开 ❌ 真实:neutral → 检测:happy (置信度:0.05) 特征: 嘴角上扬+眼角皱纹 ✅ 面部情感检测验证通过

📌 多模态情感融合

单一模态可能误判,融合文本+语音+面部提高可靠性:

import random

class MultiModalEmotionFusion:
    """多模态情感融合"""
    def __init__(self):
        self.modal_weights = {"text": 0.4, "voice": 0.3, "face": 0.3}
        self.emotions = ["happy","angry","sad","anxious","confused","neutral"]

    def fuse(self, text_emotion, voice_emotion, face_emotion):
        """融合多模态情感结果"""
        scores = {e: 0 for e in self.emotions}
        
        for emotion, weight in [(text_emotion, self.modal_weights["text"]),
                                 (voice_emotion, self.modal_weights["voice"]),
                                 (face_emotion, self.modal_weights["face"])]:
            if emotion["emotion"] in scores:
                scores[emotion["emotion"]] += weight * emotion["confidence"]
        
        # 一致性检测
        emotions_detected = set()
        if text_emotion["confidence"] > 0.3: emotions_detected.add(text_emotion["emotion"])
        if voice_emotion["confidence"] > 0.3: emotions_detected.add(voice_emotion["emotion"])
        if face_emotion["confidence"] > 0.3: emotions_detected.add(face_emotion["emotion"])
        
        consistent = len(emotions_detected) <= 1
        
        best = max(scores, key=scores.get)
        return {
            "emotion": best,
            "confidence": scores[best],
            "consistent": consistent,
            "modalities": {
                "text": text_emotion["emotion"],
                "voice": voice_emotion["emotion"],
                "face": face_emotion["emotion"],
            }
        }

fusion = MultiModalEmotionFusion()
print("多模态情感融合")
print("=" * 55)

scenarios = [
    {"name": "一致-开心", "text":{"emotion":"happy","confidence":0.8},
     "voice":{"emotion":"happy","confidence":0.7},"face":{"emotion":"happy","confidence":0.9}},
    {"name": "冲突-口是心非", "text":{"emotion":"happy","confidence":0.6},
     "voice":{"emotion":"angry","confidence":0.5},"face":{"emotion":"angry","confidence":0.8}},
    {"name": "焦虑-紧急", "text":{"emotion":"anxious","confidence":0.7},
     "voice":{"emotion":"anxious","confidence":0.8},"face":{"emotion":"neutral","confidence":0.4}},
]

for s in scenarios:
    result = fusion.fuse(s["text"], s["voice"], s["face"])
    print(f"\n📋 {s['name']}:")
    print(f"   文本:{s['text']['emotion']} 声音:{s['voice']['emotion']} 表情:{s['face']['emotion']}")
    print(f"   融合结果: {result['emotion']} (置信度:{result['confidence']:.2f})")
    print(f"   一致性: {'✅一致' if result['consistent'] else '⚠️冲突'}")

print("\n✅ 多模态情感融合验证通过")
✅ 验证通过 多模态情感融合 ======================================================= 📋 一致-开心: 文本:happy 声音:happy 表情:happy 融合结果: happy (置信度:0.80) 一致性: ✅一致 📋 冲突-口是心非: 文本:happy 声音:angry 表情:angry 融合结果: angry (置信度:0.39) 一致性: ⚠️冲突 📋 焦虑-紧急: 文本:anxious 声音:anxious 表情:neutral 融合结果: anxious (置信度:0.52) 一致性: ⚠️冲突 ✅ 多模态情感融合验证通过

📌 情感驱动的交互策略

🎭 策略引擎

情感检测 → 强度评估 → 策略选择 → 语气调整 → 行动执行

愤怒(高): 立即道歉 → 管理层通知 → 补偿方案
焦虑(高): 加速处理 → 实时进度 → 安抚语气
困惑(中): 简化步骤 → 确认理解 → 耐心引导
开心(低): 热情回应 → 推荐服务 → 轻松互动

📌 练习

📝 练习 1

实现语音情感检测:通过语速、音调、音量变化判断情绪(语速快=焦虑,音调高=愤怒等)。

📝 练习 2

设计情感强度评估:不只判断类别,还评估强度(1-5),不同强度采取不同策略。

📝 练习 3

实现情感时序追踪:追踪用户情感随时间的变化曲线,检测从困惑到满意的正向转变。

📌 成就

🏆 本课成就

◀ 上一课 📚 目录 下一课 ▶