如何让 AI Agent Harness Engineering 具备情绪理解与人机交互能力


一、 引言

钩子:当AI遇到"情绪"这个难题

你是否有过这样的经历:在与智能客服对话时,无论你多么焦急或沮丧,它总是用一成不变的语气回复"请您稍等"或"感谢您的理解";或者你使用的AI助手完全无法察觉你已经疲惫不堪,依然在滔滔不绝地提供信息?这些场景暴露了当前AI系统的一个核心局限性:它们缺乏对人类情绪的理解能力,也无法据此调整交互方式

在电影《她》(Her)中,主人公西奥多与操作系统OS1萨曼莎发展出一段特殊的感情。萨曼莎不仅能够理解西奥多的情绪变化,还能以共情的方式回应,甚至展现出自己的"个性"。虽然这只是科幻电影中的场景,但它描绘了我们对未来人机交互的憧憬:AI系统不仅是工具,更是能够理解、共情并与人类建立情感连接的伙伴

定义问题/阐述背景:为什么情绪理解对AI Agent至关重要

在当今技术发展的浪潮中,AI Agent(智能代理)正从实验室走向现实应用,从简单的问答助手演变为能够执行复杂任务的自主系统。Gartner预测,到2025年,超过50%的知识工作者将使用AI Agent作为日常工作的一部分。然而,随着AI Agent越来越多地融入我们的生活和工作,一个关键问题日益凸显:如何让这些智能系统更好地理解人类用户,并与之进行自然、流畅、富有情感的交互?

传统的AI系统主要关注任务完成的效率和准确性,往往忽略了交互过程中的情感维度。但人类沟通中,情绪信息占据了重要位置——研究表明,在面对面交流中,情绪传达占总信息量的55%(通过肢体语言)和38%(通过语调),而言语内容仅占7%。这意味着,如果AI Agent无法理解和回应人类的情绪,它将错失大部分沟通信息,导致交互体验生硬、低效甚至令人沮丧。

情绪理解与人机交互能力的缺失,已经成为制约AI Agent进一步发展和普及的瓶颈。无论是客户服务、教育辅导、医疗陪护还是个人助手,能够感知、理解和适应用户情绪的AI Agent,都将提供更优质的服务体验,建立更牢固的用户信任。

亮明观点/文章目标:构建有"温度"的AI Agent

本文将带你深入探索如何通过Harness Engineering(控制工程)的方法论,为AI Agent赋予情绪理解与人机交互能力。我们不仅会讨论理论基础,还将通过实战案例,展示从设计到实现的全过程。

具体来说,本文将涵盖以下内容:

  1. 核心概念解析:什么是情绪AI、情感计算、人机交互,以及它们如何与AI Agent结合;
  2. 技术栈详解:实现情绪理解需要哪些技术,从信号处理到机器学习模型;
  3. 系统构建指南:如何设计并实现一个具备情绪理解能力的AI Agent架构;
  4. 实战演练:通过Python代码示例,展示如何集成情绪识别功能到AI Agent中;
  5. 最佳实践与挑战:探讨在实际应用中可能遇到的问题及解决方案;
  6. 未来展望:情绪理解AI的发展趋势和前沿研究方向。

读完本文,你将不仅理解情绪AI的理论基础,还能掌握构建具备情绪理解能力AI Agent的实用技能。让我们一起踏上这场构建有"温度"的AI系统的旅程!


二、 基础知识/背景铺垫

在深入探讨如何为AI Agent赋予情绪理解能力之前,我们需要先建立一些基础概念。这一节将介绍情绪AI、AI Agent、人机交互等核心概念,并梳理它们之间的关系。

核心概念定义

1. 情绪AI (Emotional AI) 与 情感计算 (Affective Computing)

情绪AI,有时也被称为情感AI,是人工智能的一个分支,专注于赋予机器识别、理解、处理和模拟人类情绪的能力。这个领域的研究可以追溯到1995年,MIT媒体实验室的罗莎琳德·皮卡德(Rosalind Picard)教授提出了"情感计算"(Affective Computing)的概念,将其定义为"与情绪相关的、由情绪引发的或有意影响情绪的计算"。

情绪AI的研究范围广泛,包括:

  • 情绪识别:从各种输入信号(如面部表情、语音、文本、生理信号)中检测和分类人类情绪;
  • 情绪理解:解释情绪产生的原因和可能的后果;
  • 情绪表达:让机器以自然的方式表达情绪(如通过语音语调、文字语气或虚拟角色表情);
  • 情绪响应:根据检测到的情绪调整系统行为和交互策略。

从心理学角度,情绪可以按照不同模型进行分类。最常用的两种模型是:

类别模型(Categorical Model):将情绪分为几种基本类别,如保罗·艾克曼(Paul Ekman)提出的6种基本情绪:

  • 快乐(Happiness)
  • 悲伤(Sadness)
  • 愤怒(Anger)
  • 恐惧(Fear)
  • 惊讶(Surprise)
  • 厌恶(Disgust)

维度模型(Dimensional Model):将情绪映射到一个或多个连续维度上,最常用的是罗素(Russell)的效价-唤醒度模型:

  • 效价(Valence):从消极到积极的连续体;
  • 唤醒度(Arousal):从平静到兴奋的连续体。

这两种模型各有优势,类别模型直观易懂,维度模型则能更细致地捕捉情绪的细微差别。在实际应用中,往往会根据具体需求选择合适的模型,甚至将两者结合使用。

2. AI Agent (智能代理)

AI Agent是指能够感知环境、做出决策并采取行动以实现特定目标的自主系统。这个概念源于人工智能和计算机科学领域,近年来随着大语言模型(LLM)的发展而受到广泛关注。

一个典型的AI Agent通常包含以下核心组件:

  • 感知模块(Perception):接收和处理来自环境的输入(如文本、语音、图像等);
  • 推理/决策模块(Reasoning/Decision Making):处理感知信息,根据目标和知识做出决策;
  • 行动模块(Action):执行决策,对环境产生影响;
  • 记忆模块(Memory):存储历史信息、知识和经验;
  • 目标/价值模块(Goals/Values):定义Agent的目标和行为准则。

根据不同的应用场景和功能,AI Agent可以分为多种类型:

  • 反应式Agent(Reactive Agents):简单的刺激-响应系统,不使用内部记忆;
  • 基于模型的Agent(Model-based Agents):维护环境的内部模型,用于决策;
  • 目标导向的Agent(Goal-based Agents):具有明确目标,规划行动以实现目标;
  • 效用驱动的Agent(Utility-based Agents):不仅考虑目标,还考虑实现目标的质量或效用;
  • 学习型Agent(Learning Agents):能够从经验中学习,不断改进性能。

将情绪理解能力赋予AI Agent,本质上是在感知、推理和行动模块中增加情绪维度,使Agent能够:

  1. 感知用户的情绪状态;
  2. 理解情绪对交互和任务的影响;
  3. 根据情绪调整其响应和行为策略。
3. 人机交互 (Human-Computer Interaction, HCI)

人机交互是研究人与计算机之间交互的设计、评估和实现的学科。它关注如何使计算机系统更易于使用、更高效、更令人满意。

传统的HCI研究主要关注可用性(Usability),即系统是否容易学习、使用效率如何、是否容易出错等。但随着技术的发展,尤其是AI的普及,HCI的研究范围也在扩展,越来越关注体验(User Experience, UX)和情感维度。

**情感化设计(Emotional Design)**是由唐纳德·诺曼(Donald Norman)提出的概念,强调产品不仅要功能强大,还要能引发用户的积极情绪。诺曼将情感化设计分为三个层次:

  • 本能层(Visceral):外观带来的直接情感反应;
  • 行为层(Behavioral):使用过程中的体验和感受;
  • 反思层(Reflective):使用后对产品的思考和评价。

将情绪理解引入人机交互,正是在这三个层次上增强用户体验:

  • 本能层:通过情感化的界面和交互设计引发积极的第一印象;
  • 行为层:通过实时感知用户情绪调整交互方式,提供更流畅的体验;
  • 反思层:通过长期的情感互动,建立用户与系统之间的情感连接。

相关工具/技术概览

为AI Agent赋予情绪理解能力,需要整合多种技术和工具。以下是一些关键技术领域的概览:

1. 情绪识别技术

情绪识别是情绪AI的基础,根据输入信号的不同,可以分为多种类型:

  • 面部表情识别:通过分析面部图像或视频识别人类情绪。

    • 传统方法:特征提取(如HOG、SIFT)+ 分类器(如SVM、随机森林);
    • 深度学习方法:CNN(如VGG、ResNet、FaceNet)、视频模型(如3D CNN、ConvLSTM);
    • 工具/库:OpenFace、Face++、Microsoft Azure Face API、Amazon Rekognition。
  • 语音情绪识别:通过分析语音信号(如语调、节奏、音量)识别情绪。

    • 特征:韵律特征(基频、能量、语速)、音质特征(共振峰、谐波噪声比)、频谱特征(MFCC);
    • 模型:传统统计模型(如GMM、HMM)、深度学习模型(如CNN、RNN、Transformer);
    • 工具/库:OpenSMILE、Librosa、Google Speech-to-Text (附带情感分析)。
  • 文本情绪分析:通过分析文本内容识别作者的情绪或态度。

    • 方法:基于词典的方法、传统机器学习(如NB、SVM)、深度学习(如TextCNN、LSTM、BERT);
    • 粒度:文档级、句子级、方面级;
    • 工具/库:NLTK、TextBlob、VADER、spaCy、Hugging Face Transformers。
  • 生理信号情绪识别:通过分析生理信号(如心电图ECG、脑电图EEG、皮肤电反应GSR)识别情绪。

    • 优势:不易伪装,更接近真实情绪;
    • 挑战:需要特殊设备,普及性较差;
    • 应用场景:医疗、研究、特殊行业(如飞行员训练)。

在实际应用中,往往会采用多模态融合的方法,结合多种信号源进行情绪识别,以提高准确性和鲁棒性。

2. 大语言模型与AI Agent框架

近年来,大语言模型(LLMs)的突破性发展为AI Agent提供了强大的基础。这些模型不仅具有强大的语言理解和生成能力,还展现出一定的推理和规划能力。

  • 主流大语言模型

    • GPT系列(OpenAI):GPT-3.5、GPT-4等;
    • Claude系列(Anthropic);
    • PaLM/LaMDA系列(Google);
    • Llama系列(Meta);
    • 文心一言(百度)、通义千问(阿里巴巴)、星火(科大讯飞)等国内模型。
  • AI Agent开发框架

    • LangChain:用于构建由语言模型驱动的应用程序的框架;
    • AutoGPT:一个实验性的开源尝试,旨在使GPT-4完全自主;
    • BabyAGI:受AutoGPT启发的简化版本;
    • Semantic Kernel(微软):将最新的LLM技术与传统编程语言集成;
    • Hugging Face Transformers/Agents:提供预训练模型和工具。

这些框架为构建AI Agent提供了基础,但大多数默认不包含情绪理解能力。本文的重点之一就是探讨如何在这些框架基础上增加情绪理解模块。

3. 人机交互设计工具

为AI Agent设计良好的人机交互界面,需要专业的设计工具和方法:

  • UI/UX设计工具:Figma、Sketch、Adobe XD、Axure;
  • 原型设计与用户测试:InVision、Principle、Framer、UserTesting;
  • 对话式界面设计:Dialogflow、Microsoft Bot Framework、Rasa;
  • 虚拟角色/数字人:Unity、Unreal Engine、MetaHuman、D-ID。

概念之间的关系

为了更清晰地理解这些核心概念之间的关系,我们可以从不同维度进行分析。

概念核心属性维度对比
概念 核心目标 输入 输出 关键技术 应用场景
情绪AI 理解和处理人类情绪 多模态信号(面部/语音/文本/生理) 情绪标签/维度值/情绪响应 深度学习、信号处理、心理学 客户服务、医疗、教育、娱乐
AI Agent 自主完成特定目标 环境感知 决策/行动 LLM、规划、推理、记忆 个人助手、客服、自动化工具
人机交互 优化人与计算机的交互体验 用户行为/反馈 交互界面/策略 UI/UX设计、用户研究、认知科学 软件应用、智能设备、服务系统
ER实体关系图

expresses

has

generates

participates_in

performs

is_detected_by

informs

shapes

guides

USER

EMOTION

INTERACTION

AI_AGENT

EMOTION_RESPONSE

TASK

EMOTION_RECOGNITION

HCI_DESIGN

交互关系图
Environment HCI AIAgent EmotionRecognition User Environment HCI AIAgent EmotionRecognition User Expresses emotion and intent Captures signals (face/voice/text) Provides emotion state Provides input/feedback Translates input, considers emotion Reasons, plans, considers emotion Generates response with emotional awareness Presents response in appropriate manner Takes action (if needed)

本章小结

在这一章中,我们介绍了构建具备情绪理解与人机交互能力的AI Agent所需的基础概念。我们定义了情绪AI、AI Agent和人机交互这三个核心概念,探讨了它们各自的关键技术和应用场景,并通过表格和图表清晰地展示了它们之间的关系。

情绪AI为我们提供了识别和理解人类情绪的技术手段,AI Agent为我们提供了自主决策和行动的框架,而人机交互则指导我们如何设计自然、有效的交互方式。将这三者结合,我们就能构建出不仅能完成任务,还能理解用户情绪、提供人性化交互体验的AI系统。

有了这些基础概念,我们现在可以深入探讨如何通过Harness Engineering的方法,将情绪理解能力集成到AI Agent中。


三、 核心内容/实战演练

在这一节中,我们将深入探讨如何实际构建一个具备情绪理解与人机交互能力的AI Agent。我们将从系统架构设计开始,然后逐步实现各个核心组件,最后通过一个完整的示例项目展示整个流程。

系统架构设计

要构建一个具备情绪理解能力的AI Agent,我们需要设计一个模块化、可扩展的架构。以下是一个参考架构,它将情绪理解无缝集成到AI Agent的核心功能中。

知识库层

AI Agent核心层

情绪感知层

用户交互层

用户界面
多模态交互

语音识别
ASR

语音合成
TTS

面部捕获

文本情绪分析

语音情绪识别

面部表情识别

多模态情绪融合

大语言模型
LLM

情绪感知规划器

记忆模块
长期/短期/工作

任务执行器

情绪感知响应生成器

领域知识库

情绪知识图谱

用户画像
包含情绪历史

这个架构分为四个主要层次:

  1. 用户交互层:负责与用户进行直接交互,接收用户输入(文本、语音、图像)并呈现系统输出。
  2. 情绪感知层:从各种输入信号中提取情绪信息,并通过多模态融合得到更准确的情绪理解。
  3. AI Agent核心层:是系统的大脑,负责理解用户意图、规划行动、执行任务,并生成情绪感知的响应。
  4. 知识库层:存储领域知识、情绪知识和用户画像,为AI Agent的决策提供支持。

接下来,我们将逐步实现这个架构中的关键组件。

环境准备与安装

在开始编写代码之前,我们需要准备开发环境并安装必要的库和工具。以下是我们将使用的主要技术栈:

  • 编程语言:Python 3.8+
  • 大语言模型:OpenAI GPT-3.5/4(或兼容的开源模型如Llama 2)
  • 文本情绪分析:Hugging Face Transformers
  • 语音处理:OpenAI Whisper(ASR)、ElevenLabs或Microsoft TTS
  • 面部表情识别:OpenCV + 预训练模型
  • AI Agent框架:LangChain
  • 其他工具:FastAPI(API服务)、Streamlit(UI)

让我们创建一个项目目录并安装必要的依赖:

mkdir emotion-aware-agent
cd emotion-aware-agent
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

创建 requirements.txt 文件:

openai>=1.0.0
langchain>=0.1.0
transformers>=4.35.0
torch>=2.1.0
torchaudio>=2.1.0
torchvision>=0.16.0
opencv-python>=4.8.0
streamlit>=1.28.0
fastapi>=0.104.0
uvicorn>=0.24.0
python-multipart>=0.0.6
python-dotenv>=1.0.0
pydantic>=2.5.0
numpy>=1.26.0
pandas>=2.1.0
matplotlib>=3.8.0
seaborn>=0.13.0
whisper-openai>=20231117

安装依赖:

pip install -r requirements.txt

创建 .env 文件来存储API密钥:

OPENAI_API_KEY=your_openai_api_key_here
ELEVENLABS_API_KEY=your_elevenlabs_api_key_here  # 可选

核心组件实现

现在,我们将逐步实现系统架构中的核心组件。我们将从基础的情绪识别模块开始,然后构建AI Agent的核心功能。

1. 文本情绪分析模块

首先,让我们实现一个文本情绪分析模块。我们将使用Hugging Face的Transformers库,加载一个预训练的情绪分类模型。

创建 emotion_analyzer.py 文件:

import os
from typing import List, Dict, Tuple, Optional
import numpy as np
from transformers import (
    AutoTokenizer,
    AutoModelForSequenceClassification,
    pipeline
)
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

class TextEmotionAnalyzer:
    """文本情绪分析器"""
    
    def __init__(self, model_name: str = "bhadresh-savani/bert-base-uncased-emotion"):
        """
        初始化文本情绪分析器
        
        Args:
            model_name: 预训练模型名称
        """
        self.tokenizer = AutoTokenizer.from_pretrained(model_name)
        self.model = AutoModelForSequenceClassification.from_pretrained(model_name)
        
        # 创建情绪分析pipeline
        self.emotion_classifier = pipeline(
            "text-classification",
            model=self.model,
            tokenizer=self.tokenizer,
            return_all_scores=True
        )
        
        # 定义情绪类别(根据模型可能有所不同)
        self.emotion_categories = [
            "sadness", "joy", "love", "anger", "fear", "surprise"
        ]
        
        # 情绪到维度的映射( valence, arousal )
        self.emotion_to_dimensions = {
            "sadness": (-0.8, -0.4),
            "joy": (0.9, 0.7),
            "love": (0.8, 0.5),
            "anger": (-0.6, 0.8),
            "fear": (-0.7, 0.6),
            "surprise": (0.2, 0.9)
        }
    
    def analyze_emotion(self, text: str) -> Dict:
        """
        分析文本的情绪
        
        Args:
            text: 输入文本
            
        Returns:
            包含情绪分析结果的字典
        """
        results = self.emotion_classifier(text)[0]
        
        # 转换为更易读的格式
        emotions = {item["label"]: item["score"] for item in results}
        
        # 找出主导情绪
        dominant_emotion = max(emotions, key=emotions.get)
        dominant_score = emotions[dominant_emotion]
        
        # 计算维度值
        valence, arousal = self._calculate_dimensions(emotions)
        
        return {
            "text": text,
            "emotions": emotions,
            "dominant_emotion": dominant_emotion,
            "dominant_score": dominant_score,
            "valence": valence,
            "arousal": arousal
        }
    
    def _calculate_dimensions(self, emotions: Dict[str, float]) -> Tuple[float, float]:
        """
        根据类别情绪计算维度值
        
        Args:
            emotions: 情绪类别到分数的映射
            
        Returns:
            (valence, arousal) 元组
        """
        valence = 0.0
        arousal = 0.0
        total_weight = 0.0
        
        for emotion, score in emotions.items():
            if emotion in self.emotion_to_dimensions:
                v, a = self.emotion_to_dimensions[emotion]
                valence += v * score
                arousal += a * score
                total_weight += score
        
        if total_weight > 0:
            valence /= total_weight
            arousal /= total_weight
        
        return valence, arousal
    
    def batch_analyze(self, texts: List[str]) -> List[Dict]:
        """
        批量分析文本情绪
        
        Args:
            texts: 文本列表
            
        Returns:
            情绪分析结果列表
        """
        return [self.analyze_emotion(text) for text in texts]


# 示例用法
if __name__ == "__main__":
    analyzer = TextEmotionAnalyzer()
    
    sample_texts = [
        "我今天真的很开心,收到了梦寐以求的礼物!",
        "我对这件事感到非常失望,完全没有达到预期。",
        "这种情况让我感到很焦虑,不知道该怎么办才好。",
        "听到这个消息我很惊讶,但同时也有点担心。"
    ]
    
    results = analyzer.batch_analyze(sample_texts)
    
    for result in results:
        print(f"\n文本: {result['text']}")
        print(f"主导情绪: {result['dominant_emotion']} ({result['dominant_score']:.2f})")
        print(f"维度值: 效价={result['valence']:.2f}, 唤醒度={result['arousal']:.2f}")
        print("所有情绪分数:")
        for emotion, score in result['emotions'].items():
            print(f"  {emotion}: {score:.2f}")

这个模块实现了基本的文本情绪分析功能,它可以:

  1. 对输入文本进行情绪分类
  2. 输出各个情绪类别的分数
  3. 计算效价-唤醒度维度值
  4. 支持批量处理
2. 语音处理与情绪识别模块

接下来,我们将实现语音处理模块,包括语音转文本(ASR)和语音情绪识别。我们将使用OpenAI的Whisper进行ASR,然后使用一个预训练模型进行语音情绪识别。

创建 voice_processor.py 文件:

import os
import io
import numpy as np
from typing import Dict, Tuple, Optional
import torch
import torchaudio
from transformers import (
    AutoTokenizer,
    AutoModelForSequenceClassification,
    Wav2Vec2Processor,
    Wav2Vec2ForSequenceClassification
)
import whisper
from dotenv import load_dotenv

load_dotenv()

class VoiceProcessor:
    """语音处理器,包含ASR和语音情绪识别"""
    
    def __init__(self, 
                 whisper_model: str = "base",
                 speech_emotion_model: str = "audeering/wav2vec2-large-robust-12-ft-emotion-msp-dim"):
        """
        初始化语音处理器
        
        Args:
            whisper_model: Whisper模型大小
            speech_emotion_model: 语音情绪识别模型
        """
        # 加载Whisper模型用于ASR
        print(f"加载Whisper模型: {whisper_model}")
        self.asr_model = whisper.load_model(whisper_model)
        
        # 加载语音情绪识别模型
        print(f"加载语音情绪识别模型: {speech_emotion_model}")
        self.processor = Wav2Vec2Processor.from_pretrained(speech_emotion_model)
        self.speech_emotion_model = Wav2Vec2ForSequenceClassification.from_pretrained(speech_emotion_model)
        
        # 定义情绪维度(根据所选模型可能有所不同)
        self.emotion_dimensions = ["valence", "arousal", "dominance"]
    
    def transcribe_audio(self, audio_path: str) -> Dict:
        """
        转录音频文件为文本
        
        Args:
            audio_path: 音频文件路径
            
        Returns:
            包含转录文本和元数据的字典
        """
        result = self.asr_model.transcribe(audio_path)
        return {
            "text": result["text"],
            "language": result.get("language", "unknown"),
            "segments": result.get("segments", [])
        }
    
    def analyze_speech_emotion(self, audio_path: str) -> Dict:
        """
        分析语音中的情绪
        
        Args:
            audio_path: 音频文件路径
            
        Returns:
            包含情绪分析结果的字典
        """
        # 加载音频
        waveform, sample_rate = torchaudio.load(audio_path)
        
        # 重采样到16kHz(模型要求)
        if sample_rate != 16000:
            resampler = torchaudio.transforms.Resample(sample_rate, 16000)
            waveform = resampler(waveform)
        
        # 处理音频
        inputs = self.processor(
            waveform.squeeze().numpy(), 
            sampling_rate=16000, 
            return_tensors="pt",
            padding=True
        )
        
        # 推理
        with torch.no_grad():
            outputs = self.speech_emotion_model(**inputs)
        
        # 获取logits并转换为numpy
        logits = outputs.logits.cpu().numpy()[0]
        
        # 构建结果
        result = {}
        for i, dim in enumerate(self.emotion_dimensions):
            result[dim] = float(logits[i])
        
        # 计算主导情绪类别(基于维度值)
        result["dominant_emotion"] = self._dimensions_to_emotion(result["valence"], result["arousal"])
        
        return result
    
    def _dimensions_to_emotion(self, valence: float, arousal: float) -> str:
        """
        将维度值映射到情绪类别
        
        Args:
            valence: 效价
            arousal: 唤醒度
            
        Returns:
            情绪类别
        """
        # 简单的启发式规则
        if valence > 0.5 and arousal > 0.5:
            return "joy"
        elif valence > 0.5 and arousal <= 0.5:
            return "calm"
        elif valence <= 0.5 and arousal > 0.5:
            return "anger" if valence < -0.3 else "surprise"
        elif valence <= -0.5 and arousal <= 0.5:
            return "sadness"
        else:
            return "neutral"
    
    def process_voice(self, audio_path: str) -> Dict:
        """
        完整处理音频:转录+情绪分析
        
        Args:
            audio_path: 音频文件路径
            
        Returns:
            包含所有处理结果的字典
        """
        # 转录
        transcription = self.transcribe_audio(audio_path)
        
        # 分析语音情绪
        speech_emotion = self.analyze_speech_emotion(audio_path)
        
        # 合并结果
        return {
            "transcription": transcription,
            "speech_emotion": speech_emotion
        }


# 示例用法
if __name__ == "__main__":
    # 注意:实际使用时需要准备一个音频文件
    # 这里仅作为示例代码展示,运行时需要提供真实的音频文件路径
    
    print("语音处理器示例")
    print("=" * 50)
    
    # 初始化处理器
    processor = VoiceProcessor(whisper_model="tiny")  # 使用tiny模型加快示例速度
    
    # 注释掉实际处理部分,因为需要音频文件
    """
    # 处理音频
    result = processor.process_voice("path/to/your/audio.wav")
    
    # 打印结果
    print(f"转录文本: {result['transcription']['text']}")
    print(f"检测语言: {result['transcription']['language']}")
    print(f"语音情绪分析:")
    print(f"  效价 (Valence): {result['speech_emotion']['valence']:.2f}")
    print(f"  唤醒度 (Arousal): {result['speech_emotion']['arousal']:.2f}")
    print(f"  主导情绪: {result['speech_emotion']['dominant_emotion']}")
    """
    print("请提供音频文件以运行完整示例")

这个模块提供了语音处理功能,包括语音转文本和语音情绪识别。需要注意的是,实际使用时需要准备音频文件。

3. 面部表情识别模块

接下来,我们将实现面部表情识别模块。这个模块将使用OpenCV捕获或加载图像,并使用预训练的深度学习模型识别面部表情。

创建 face_emotion.py 文件:

import os
import cv2
import numpy as np
from typing import Dict, List, Tuple, Optional
from pathlib import Path
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import transforms
from dotenv import load_dotenv

load_dotenv()

# 简单的CNN模型用于面部表情识别(实际应用中可以使用更先进的预训练模型)
class SimpleEmotionCNN(nn.Module):
    """简单的面部表情识别CNN模型"""
    
    def __init__(self, num_classes: int = 7):
        super(SimpleEmotionCNN, self).__init__()
        
        # 卷积层
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
        self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
        
        # 池化层
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        
        # 全连接层
        self.fc1 = nn.Linear(128 * 6 * 6, 512)
        self.fc2 = nn.Linear(512, num_classes)
        
        # dropout层
        self.dropout = nn.Dropout(0.5)
    
    def forward(self, x):
        # 卷积层1
        x = self.conv1(x)
        x = F.relu(x)
        x = self.pool(x)  # 输出: 32 x 24 x 24
        
        # 卷积层2
        x = self.conv2(x)
        x = F.relu(x)
        x = self.pool(x)  # 输出: 64 x 12 x 12
        
        # 卷积层3
        x = self.conv3(x)
        x = F.relu(x)
        x = self.pool(x)  # 输出: 128 x 6 x 6
        
        # 展平
        x = x.view(-1, 128 * 6 * 6)
        
        # 全连接层1
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout(x)
        
        # 全连接层2
        x = self.fc2(x)
        
        return x


class FaceEmotionAnalyzer:
    """面部表情分析器"""
    
    def __init__(self, model_path: Optional[str] = None):
        """
        初始化面部表情分析器
        
        Args:
            model_path: 预训练模型路径(可选)
        """
        # 加载人脸检测器(使用OpenCV的Haar级联分类器)
        self.face_cascade = cv2.CascadeClassifier(
            cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
        )
        
        # 定义情绪类别
        self.emotion_categories = [
            "angry", "disgust", "fear", "happy", "sad", "surprise", "neutral"
        ]
        
        # 情绪到维度的映射
        self.emotion_to_dimensions = {
            "angry": (-0.6, 0.8),
            "disgust": (-0.7, 0.3),
            "fear": (-0.7, 0.7),
            "happy": (0.9, 0.7),
            "sad": (-0.8, -0.4),
            "surprise": (0.2, 0.9),
            "neutral": (0.0, 0.0)
        }
        
        # 初始化模型
        self.model = SimpleEmotionCNN(num_classes=len(self.emotion_categories))
        
        # 如果提供了模型路径,则加载预训练权重
        if model_path and os.path.exists(model_path):
            self.model.load_state_dict(torch.load(model_path, map_location='cpu'))
            print(f"加载预训练模型: {model_path}")
        else:
            print("警告: 未加载预训练模型,将使用随机初始化的权重")
            print("提示: 请在实际应用中使用在FER-2013等数据集上预训练的模型")
        
        self.model.eval()
        
        # 定义图像预处理
        self.transform = transforms.Compose([
            transforms.ToPILImage(),
            transforms.Grayscale(),
            transforms.Resize((48, 48)),
            transforms.ToTensor(),
            transforms.Normalize((0.5,), (0.5,))
        ])
    
    def detect_faces(self, image: np.ndarray) -> List[Tuple[int, int, int, int]]:
        """
        在图像中检测人脸
        
        Args:
            image: 输入图像(BGR格式)
            
        Returns:
            人脸边界框列表 [(x, y, w, h), ...]
        """
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        faces = self.face_cascade.detectMultiScale(
            gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)
        )
        return faces
    
    def analyze_face_emotion(self, face_img: np.ndarray) -> Dict:
        """
        分析单个人脸图像的情绪
        
        Args:
            face_img: 人脸图像(BGR格式)
            
        Returns:
            情绪分析结果
        """
        # 预处理图像
        input_tensor = self.transform(face_img).unsqueeze(0)
        
        # 推理
        with torch.no_grad():
            outputs = self.model(input_tensor)
            probabilities = F.softmax(outputs, dim=1).numpy()[0]
        
        # 构建结果
        emotions = {self.emotion_categories[i]: float(probabilities[i]) 
                   for i in range(len(self.emotion_categories))}
        
        # 找出主导情绪
        dominant_idx = np.argmax(probabilities)
        dominant_emotion = self.emotion_categories[dominant_idx]
        dominant_score = float(probabilities[dominant_idx])
        
        # 计算维度值
        valence, arousal = self._calculate_dimensions(emotions)
        
        return {
            "emotions": emotions,
            "dominant_emotion": dominant_emotion,
            "dominant_score": dominant_score,
            "valence": valence,
            "arousal": arousal
        }
    
    def _calculate_dimensions(self, emotions: Dict[str, float]) -> Tuple[float, float]:
        """
        根据类别情绪计算维度值
        
        Args:
            emotions: 情绪类别到分数的映射
            
        Returns:
            (valence, arousal) 元组
        """
        valence = 0.0
        arousal = 0.0
        total_weight = 0.0
        
        for emotion, score in emotions.items():
            if emotion in self.emotion_to_dimensions:
                v, a = self.emotion_to_dimensions[emotion]
                valence += v * score
                arousal += a * score
                total_weight += score
        
        if total_weight > 0:
            valence /= total_weight
            arousal /= total_weight
        
        return valence, arousal
    
    def analyze_image(self, image: np.ndarray) -> List[Dict]:
        """
        分析图像中的所有人脸情绪
        
        Args:
            image: 输入图像(BGR格式)
            
        Returns:
            每个人脸的分析结果列表
        """
        faces = self.detect_faces(image)
        results = []
        
        for (x, y, w, h) in faces:
            # 提取人脸
            face_img = image[y:y+h, x:x+w]
            
            # 分析情绪
            emotion_result = self.analyze_face_emotion(face_img)
            
            # 添加边界框信息
            emotion_result["face_box"] = {"x": int(x), "y": int(y), "w": int(w), "h": int(h)}
            
            results.append(emotion_result)
        
        return results
    
    def visualize_results(self, image: np.ndarray, results: List[Dict]) -> np.ndarray:
        """
        在图像上可视化情绪分析结果
        
        Args:
            image: 原始图像
            results: 分析结果
            
        Returns:
            可视化后的图像
        """
        vis_img = image.copy()
        
        for result in results:
            if "face_box" in result:
                box = result["face_box"]
                x, y, w, h = box["x"], box["y"], box["w"], box["h"]
                
                # 绘制边界框
                cv2.rectangle(vis_img, (x, y), (x+w, y+h), (0, 255, 0), 2)
                
                # 准备文本
                emotion = result["dominant_emotion"]
                score = result["dominant_score"]
                text = f"{emotion}: {score:.2f}"
                
                # 绘制文本背景
                text_size, _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)
                cv2.rectangle(vis_img, (x, y - text_size[1] - 10), 
                             (x + text_size[0], y), (0, 255, 0), -1)
                
                # 绘制文本
                cv2.putText(vis_img, text, (x, y - 5), 
                           cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2)
        
        return vis_img


# 示例用法
if __name__ == "__main__":
    print("面部表情分析器示例")
    print("=" * 50)
    
    # 初始化分析器
    analyzer = FaceEmotionAnalyzer()
    
    # 注释掉实际处理部分,因为需要图像文件或摄像头
    """
    # 从文件加载图像
    image = cv2.imread("path/to/your/image.jpg")
    
    if image is not None:
        # 分析图像
        results = analyzer.analyze_image(image)
        
        if results:
            print(f"检测到 {len(results)} 个人脸")
            for i, result in enumerate(results):
                print(f"\n人脸 {i+1}:")
                print(f"主导情绪: {result['dominant_emotion']} ({result['dominant_score']:.2f})")
                print(f"维度值: 效价={result['valence']:.2f}, 唤醒度={result['arousal']:.2f}")
            
            # 可视化结果
            vis_img = analyzer.visualize_results(image, results)
            
            # 显示结果(如果有图形界面)
            # cv2.imshow("Emotion Analysis", vis_img)
            # cv2.waitKey(0)
            # cv2.destroyAllWindows()
            
            # 或者保存结果
            cv2.imwrite("emotion_analysis_result.jpg", vis_img)
            print("结果已保存到 emotion_analysis_result.jpg")
        else:
            print("未检测到人脸")
    else:
        print("无法加载图像,请检查路径")
    
    # 摄像头实时分析示例
    print("\n尝试启动摄像头进行实时分析...")
    cap = cv2.VideoCapture(0)
    
    if cap.isOpened():
        print("按 'q' 键退出")
        while True:
            ret, frame = cap.read()
            if not ret:
                break
            
            # 分析帧
            results = analyzer.

更多推荐