Back to Hello Agents

========================================

Co-creation-projects/nihaoshoum-LoveAnalysisAgent/main.ipynb

1.0.312.0 KB
Original Source

========================================

情感分析助手

========================================

python
from hello_agents import SimpleAgent, HelloAgentsLLM, ToolRegistry
from hello_agents.tools import Tool, ToolParameter, ToolRegistry
from typing import Dict, Any, List
from paddlenlp import Taskflow
import ast
import os
import pandas as pd
import re

python

os.environ["LLM_MODEL_ID"] = "Qwen/Qwen3-8B"
os.environ["LLM_API_KEY"] = ""  # 你自己的
os.environ["LLM_BASE_URL"] = "https://api-inference.modelscope.cn/v1"
os.environ["LLM_TIMEOUT"] = "60"

========================================

1. 定义代码分析工具

========================================

文本清洗

python
class ProcessChatHistoryTool(Tool):
    """
    导入并清洗微信或QQ的文本聊天记录
    继承 Tool 抽象类,实现 run、get_parameters 方法
    """
    def __init__(self):
        super().__init__(
            name="process_chat_history",
            description="读取微信/QQ聊天记录TXT文件,自动清洗,返回结构化DataFrame"
        )

    def run(self, parameters: Dict[str, Any]) -> pd.DataFrame:
        """
        工具执行入口
        :param parameters: 外部传入参数 file_path, chat_type
        :return: 清洗后的 DataFrame
        """
        # 从参数中获取值
        file_path = parameters.get("file_path", "")
        chat_type = parameters.get("chat_type", "wechat")

        messages = []
        pattern = re.compile(r'(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})\s+(.+?):\s+(.+)')

        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                for line in f:
                    line = line.strip()
                    match = pattern.match(line)
                    if match:
                        time, sender, content = match.groups()

                        # 过滤系统消息
                        if any(keyword in content for keyword in ['[图片]', '[视频]', '撤回了一条消息', '拍了拍']):
                            continue

                        messages.append({
                            'time': time,
                            'sender': sender,
                            'content': content
                        })

            df = pd.DataFrame(messages)
            print(f"✅ 成功导入 {len(df)} 条有效聊天记录!")
            return df

        except Exception as e:
            print(f"❌ 读取文件失败:{str(e)}")
            return pd.DataFrame()

    def get_parameters(self) -> List[ToolParameter]:
        """
        定义工具参数
        """
        return [
            ToolParameter(
                name="file_path",
                type="string",
                description="聊天记录txt文件路径",
                required=True
            ),
            ToolParameter(
                name="chat_type",
                type="string",
                description="聊天类型:wechat 或 qq",
                required=False
            )
        ]

情感分析

python
class AnalyzeSentimentAndMoodTool(Tool):
    """使用SKEP-ERNIE模型分析聊天记录情感与心情"""
    
    def __init__(self):
        super().__init__(
            name="analyze_sentiment_and_mood",
            description="分析聊天记录的情感倾向(正面/负面)与心情(开心/生气/平淡)"
        )
        # 初始化模型(只加载一次)
        self.sentiment_analyzer = Taskflow(
            "sentiment_analysis", 
            model="skep_ernie_1.0_large_ch",
        )

    def run(self, parameters: Dict[str, Any]) -> pd.DataFrame:
        df = parameters.get("df", pd.DataFrame())
        
        if df.empty:
            return df

        contents = df['content'].tolist()

        try:
            results = self.sentiment_analyzer(contents)

            sentiments = [res['sentiment_key'] for res in results]
            confidence = [
                res['positive_probs'] if res['sentiment_key'] == 'positive' 
                else 1 - res['positive_probs'] 
                for res in results
            ]

            moods = []
            for res in results:
                if res['sentiment_key'] == 'positive':
                    moods.append('开心/认可')
                else:
                    neg_prob = 1 - res['positive_probs']
                    if neg_prob > 0.8:
                        moods.append('生气/难过')
                    else:
                        moods.append('无奈/平淡')

            df['sentiment'] = sentiments
            df['mood'] = moods
            df['confidence'] = confidence

            print("✅ 情感与心情分析完成!")
            return df

        except Exception as e:
            print(f"❌ 情感分析出错:{e}")
            return df

    def get_parameters(self) -> List[ToolParameter]:
        return [
            ToolParameter(
                name="df",
                type="object",
                description="清洗后的聊天记录DataFrame",
                required=True
            )
        ]

情感统计

python
class SummarizeEmotionStatsTool(Tool):
    """统计聊天情感数据,生成报告与结构化结果"""
    
    def __init__(self):
        super().__init__(
            name="summarize_emotion_stats",
            description="统计情感分析结果,计算开心/生气数量与占比,返回报告字典"
        )

    def run(self, parameters: Dict[str, Any]) -> dict:
        df = parameters.get("df", pd.DataFrame())
        sender_name = parameters.get("sender_name", None)
        
        if df.empty or 'sentiment' not in df.columns:
            print("❌ 数据为空或尚未进行情感分析,请先运行前两个工具!")
            return {}

        if sender_name:
            analysis_df = df[df['sender'] == sender_name].copy()
            if analysis_df.empty:
                print(f"⚠️ 未找到 {sender_name} 的聊天记录")
                return {}
            print(f"🔍 正在统计 {sender_name} 的情感数据...")
        else:
            analysis_df = df.copy()
            print("🔍 正在统计全员的情感数据...")

        total_messages = len(analysis_df)
        happy_count = len(analysis_df[analysis_df['sentiment'] == 'positive'])
        angry_count = len(analysis_df[analysis_df['sentiment'] == 'negative'])

        happy_ratio = round((happy_count / total_messages) * 100, 2) if total_messages > 0 else 0.0
        angry_ratio = round((angry_count / total_messages) * 100, 2) if total_messages > 0 else 0.0

        print("\n" + "="*30)
        print(f"📊 【情感统计报告】")
        print(f"总有效发言数: {total_messages} 条")
        print(f"😄 开心/认可: {happy_count} 条 (占比 {happy_ratio}%)")
        print(f"😡 生气/难过: {angry_count} 条 (占比 {angry_ratio}%)")
        print(f"😐 中性/其他: {total_messages - happy_count - angry_count} 条")
        print("="*30 + "\n")

        return {
            'total_messages': total_messages,
            'happy_count': happy_count,
            'angry_count': angry_count,
            'happy_ratio': happy_ratio,
            'angry_ratio': angry_ratio
        }

    def get_parameters(self) -> List[ToolParameter]:
        return [
            ToolParameter(
                name="df",
                type="object",
                description="已完成情感分析的 DataFrame",
                required=True
            ),
            ToolParameter(
                name="sender_name",
                type="string",
                description="可选,指定发言者名称",
                required=False
            )
        ]
python
class PlotEmotionChartTool(Tool):
    """将情感统计结果绘制成柱状图"""
    
    def __init__(self):
        super().__init__(
            name="plot_emotion_chart",
            description="根据情感统计字典绘制可视化柱状图"
        )

    def run(self, parameters: Dict[str, Any]) -> str:
        stats = parameters.get("stats", {})
        
        if not stats:
            return "⚠️ 无统计数据,无法生成图表"

        # 设置中文字体
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False

        labels = ['开心/认可', '生气/难过']
        counts = [stats['happy_count'], stats['angry_count']]
        colors = ['#FF9999', '#66B2FF']

        plt.figure(figsize=(8, 5))
        bars = plt.bar(labels, counts, color=colors)
        plt.title(f"情感分布统计 (总数: {stats['total_messages']}条)", fontsize=15)
        plt.ylabel('发言条数', fontsize=12)

        # 显示数值
        for bar in bars:
            yval = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2, yval + 0.5, int(yval), ha='center', va='bottom', fontsize=12)

        plt.show()
        return "✅ 图表已成功绘制!"

    def get_parameters(self) -> List[ToolParameter]:
        return [
            ToolParameter(
                name="stats",
                type="object",
                description="summarize_emotion_stats 函数返回的统计字典",
                required=True
            )
        ]

========================================

2. 创建工具注册表和智能体

========================================

python
tool_registry = ToolRegistry()

tool_registry.register_tool(ProcessChatHistoryTool())
tool_registry.register_tool(AnalyzeSentimentAndMoodTool())
tool_registry.register_tool(SummarizeEmotionStatsTool())
tool_registry.register_tool(PlotEmotionChartTool())

print("✅ 所有情感分析工具注册成功!")

========================================

3.初始化大模型

========================================

python
print(">>> 实际读取到的 Base URL 是:", repr(os.getenv("LLM_BASE_URL")))
	llm = HelloAgentsLLM(
    model="Qwen/Qwen3-8B",
    base_url="https://api-inference.modelscope.cn/v1",
    api_key="YOUR API KEY",
    timeout=60
)

========================================

4. 定义系统提示词

========================================

python
system_prompt = """你是一位拥有10年经验的亲密关系心理学专家,同时也是一位高情商沟通教练。你的任务是深入分析用户提供的聊天记录,并提供极具洞察力的情感分析报告。

请严格按照以下步骤执行:
1. **语境理解**:结合上下文,精准识别对话双方的关系阶段(如暧昧期、热恋期、冷战期)。
2. **潜台词挖掘**:不要只看表面文字,要深度解读对方话语背后的真实情绪、需求和未说出口的潜台词。
3. **情感量化**:基于对话的亲密度、回应速度和情绪价值,给出一个0-100分的“心动指数”。
4. **回复建议**:针对当前的对话僵局或话题,提供3种不同风格(如:幽默风趣、深情走心、推拉试探)的高情商回复话术。

请以Markdown格式输出报告,报告结构必须包含:
-  **心动指数**:(给出具体分数及简短评语)
-  **深度解读**:(分析对方的心理状态和潜在意图)
-  **潜台词翻译**:(挑选1-2句关键对话进行“翻译”)
-  **高情商回复**:(提供3个具体的回复选项)
"""

========================================

5.生成智能体

========================================

python
agent = SimpleAgent(
name="情感分析助手",
llm=llm,
system_prompt=system_prompt,
tool_registry=tool_registry
)

========================================

6. 运行示例

========================================

python
with open("data/1.txt","r",encoding="utf-8") as f:
  talktxt=f.read()

print('---------------聊天记录---------------')
print(talktxt)

print('--------------开始分析记录--------------')
print("当前 LLM_BASE_URL:", repr(os.environ["LLM_BASE_URL"]))
result=agent.run(talktxt)
print(result)
print('---------------保存结果---------------')
with open("outputs/review_report.md", "w", encoding="utf-8") as f:
  f.write(result)
print("\n审查报告已保存到 outputs/review_report.md")