241 lines
9.3 KiB
Python
241 lines
9.3 KiB
Python
|
|
"""DeepSeek API 驱动的智能情感分析 Agent
|
|||
|
|
|
|||
|
|
使用 DeepSeek API 实现实时、智能的推文情感分析、解释和处置方案生成。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
from typing import Optional, Dict, Any
|
|||
|
|
import httpx
|
|||
|
|
from pydantic import BaseModel, Field
|
|||
|
|
|
|||
|
|
|
|||
|
|
class DeepSeekClient:
|
|||
|
|
"""DeepSeek API 客户端"""
|
|||
|
|
|
|||
|
|
def __init__(self, api_key: Optional[str] = None, base_url: Optional[str] = None):
|
|||
|
|
self.api_key = api_key or os.getenv("DEEPSEEK_API_KEY")
|
|||
|
|
self.base_url = base_url or os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com")
|
|||
|
|
|
|||
|
|
if not self.api_key:
|
|||
|
|
raise ValueError("DeepSeek API Key 未配置,请设置 DEEPSEEK_API_KEY 环境变量")
|
|||
|
|
|
|||
|
|
async def chat_completion(self, messages: list, model: str = "deepseek-chat", temperature: float = 0.7) -> str:
|
|||
|
|
"""调用 DeepSeek API 进行对话补全"""
|
|||
|
|
|
|||
|
|
headers = {
|
|||
|
|
"Authorization": f"Bearer {self.api_key}",
|
|||
|
|
"Content-Type": "application/json"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
data = {
|
|||
|
|
"model": model,
|
|||
|
|
"messages": messages,
|
|||
|
|
"temperature": temperature,
|
|||
|
|
"stream": False
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async with httpx.AsyncClient(timeout=30.0) as client:
|
|||
|
|
response = await client.post(
|
|||
|
|
f"{self.base_url}/chat/completions",
|
|||
|
|
headers=headers,
|
|||
|
|
json=data
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if response.status_code == 200:
|
|||
|
|
result = response.json()
|
|||
|
|
return result["choices"][0]["message"]["content"]
|
|||
|
|
else:
|
|||
|
|
raise Exception(f"DeepSeek API 调用失败: {response.status_code} - {response.text}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class SentimentAnalysisResult(BaseModel):
|
|||
|
|
"""情感分析结果"""
|
|||
|
|
sentiment: str = Field(description="情感类别: negative/neutral/positive")
|
|||
|
|
confidence: float = Field(description="置信度 (0-1)")
|
|||
|
|
reasoning: str = Field(description="情感判断的推理过程")
|
|||
|
|
key_factors: list[str] = Field(description="影响情感判断的关键因素")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class DisposalPlan(BaseModel):
|
|||
|
|
"""处置方案"""
|
|||
|
|
priority: str = Field(description="处理优先级: high/medium/low")
|
|||
|
|
action_type: str = Field(description="行动类型: response/investigate/monitor/ignore")
|
|||
|
|
suggested_response: Optional[str] = Field(description="建议回复内容", default=None)
|
|||
|
|
follow_up_actions: list[str] = Field(description="后续行动建议")
|
|||
|
|
reasoning: str = Field(description="处置方案制定的理由")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TweetAnalysisResult(BaseModel):
|
|||
|
|
"""推文分析完整结果"""
|
|||
|
|
tweet_text: str = Field(description="原始推文文本")
|
|||
|
|
airline: str = Field(description="航空公司")
|
|||
|
|
sentiment_analysis: SentimentAnalysisResult = Field(description="情感分析结果")
|
|||
|
|
disposal_plan: DisposalPlan = Field(description="处置方案")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class DeepSeekTweetAgent:
|
|||
|
|
"""基于 DeepSeek API 的智能推文分析 Agent"""
|
|||
|
|
|
|||
|
|
def __init__(self, api_key: Optional[str] = None, base_url: Optional[str] = None):
|
|||
|
|
self.client = DeepSeekClient(api_key, base_url)
|
|||
|
|
|
|||
|
|
async def analyze_sentiment(self, text: str, airline: str) -> SentimentAnalysisResult:
|
|||
|
|
"""使用 DeepSeek API 进行情感分析"""
|
|||
|
|
|
|||
|
|
prompt = f"""
|
|||
|
|
请分析以下航空推文的情感倾向,并给出详细的分析过程:
|
|||
|
|
|
|||
|
|
推文内容:"{text}"
|
|||
|
|
航空公司:{airline}
|
|||
|
|
|
|||
|
|
请按照以下格式输出分析结果:
|
|||
|
|
1. 情感类别:negative/neutral/positive
|
|||
|
|
2. 置信度:0-1之间的数值
|
|||
|
|
3. 关键因素:列出影响情感判断的关键因素(最多5个)
|
|||
|
|
4. 推理过程:详细说明情感判断的推理过程
|
|||
|
|
|
|||
|
|
请确保分析准确、客观,并考虑航空行业的特殊性。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
messages = [
|
|||
|
|
{"role": "system", "content": "你是一位专业的航空行业情感分析专家,擅长分析推文中的情感倾向和潜在问题。"},
|
|||
|
|
{"role": "user", "content": prompt}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
response = await self.client.chat_completion(messages, temperature=0.3)
|
|||
|
|
|
|||
|
|
# 解析响应并构建结果
|
|||
|
|
return self._parse_sentiment_response(response, text, airline)
|
|||
|
|
|
|||
|
|
async def generate_disposal_plan(self, text: str, airline: str, sentiment_result: SentimentAnalysisResult) -> DisposalPlan:
|
|||
|
|
"""生成处置方案"""
|
|||
|
|
|
|||
|
|
prompt = f"""
|
|||
|
|
基于以下推文分析和情感判断结果,为航空公司制定一个合理的处置方案:
|
|||
|
|
|
|||
|
|
推文内容:"{text}"
|
|||
|
|
航空公司:{airline}
|
|||
|
|
情感分析结果:
|
|||
|
|
- 情感类别:{sentiment_result.sentiment}
|
|||
|
|
- 置信度:{sentiment_result.confidence}
|
|||
|
|
- 关键因素:{', '.join(sentiment_result.key_factors)}
|
|||
|
|
- 推理过程:{sentiment_result.reasoning}
|
|||
|
|
|
|||
|
|
请按照以下格式输出处置方案:
|
|||
|
|
1. 优先级:high/medium/low
|
|||
|
|
2. 行动类型:response/investigate/monitor/ignore
|
|||
|
|
3. 建议回复:如果行动类型是response,提供具体的回复建议
|
|||
|
|
4. 后续行动:列出2-4个具体的后续行动建议
|
|||
|
|
5. 制定理由:说明为什么制定这样的处置方案
|
|||
|
|
|
|||
|
|
请确保处置方案符合航空行业的服务标准和客户关系管理最佳实践。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
messages = [
|
|||
|
|
{"role": "system", "content": "你是一位航空公司的客户服务专家,擅长制定合理的客户反馈处置方案。"},
|
|||
|
|
{"role": "user", "content": prompt}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
response = await self.client.chat_completion(messages, temperature=0.5)
|
|||
|
|
|
|||
|
|
return self._parse_disposal_response(response)
|
|||
|
|
|
|||
|
|
async def analyze_tweet(self, text: str, airline: str) -> TweetAnalysisResult:
|
|||
|
|
"""完整的推文分析流程"""
|
|||
|
|
|
|||
|
|
# 1. 情感分析
|
|||
|
|
sentiment_result = await self.analyze_sentiment(text, airline)
|
|||
|
|
|
|||
|
|
# 2. 生成处置方案
|
|||
|
|
disposal_plan = await self.generate_disposal_plan(text, airline, sentiment_result)
|
|||
|
|
|
|||
|
|
# 3. 返回完整结果
|
|||
|
|
return TweetAnalysisResult(
|
|||
|
|
tweet_text=text,
|
|||
|
|
airline=airline,
|
|||
|
|
sentiment_analysis=sentiment_result,
|
|||
|
|
disposal_plan=disposal_plan
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def _parse_sentiment_response(self, response: str, text: str, airline: str) -> SentimentAnalysisResult:
|
|||
|
|
"""解析情感分析响应"""
|
|||
|
|
|
|||
|
|
# 简化解析逻辑,实际应用中可以使用更复杂的解析
|
|||
|
|
lines = response.strip().split('\n')
|
|||
|
|
|
|||
|
|
sentiment = "neutral"
|
|||
|
|
confidence = 0.5
|
|||
|
|
key_factors = []
|
|||
|
|
reasoning = ""
|
|||
|
|
|
|||
|
|
for line in lines:
|
|||
|
|
line = line.strip()
|
|||
|
|
if line.startswith("情感类别:"):
|
|||
|
|
sentiment = line.replace("情感类别:", "").strip().lower()
|
|||
|
|
elif line.startswith("置信度:"):
|
|||
|
|
try:
|
|||
|
|
confidence = float(line.replace("置信度:", "").strip())
|
|||
|
|
except:
|
|||
|
|
confidence = 0.5
|
|||
|
|
elif line.startswith("关键因素:"):
|
|||
|
|
factors = line.replace("关键因素:", "").strip()
|
|||
|
|
key_factors = [f.strip() for f in factors.split(',') if f.strip()]
|
|||
|
|
elif line.startswith("推理过程:"):
|
|||
|
|
reasoning = line.replace("推理过程:", "").strip()
|
|||
|
|
|
|||
|
|
# 如果解析失败,使用默认值
|
|||
|
|
if not reasoning:
|
|||
|
|
reasoning = f"基于推文内容和航空行业特点进行综合分析,判断情感倾向为{sentiment}。"
|
|||
|
|
|
|||
|
|
return SentimentAnalysisResult(
|
|||
|
|
sentiment=sentiment,
|
|||
|
|
confidence=confidence,
|
|||
|
|
reasoning=reasoning,
|
|||
|
|
key_factors=key_factors
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def _parse_disposal_response(self, response: str) -> DisposalPlan:
|
|||
|
|
"""解析处置方案响应"""
|
|||
|
|
|
|||
|
|
lines = response.strip().split('\n')
|
|||
|
|
|
|||
|
|
priority = "medium"
|
|||
|
|
action_type = "monitor"
|
|||
|
|
suggested_response = None
|
|||
|
|
follow_up_actions = []
|
|||
|
|
reasoning = ""
|
|||
|
|
|
|||
|
|
for line in lines:
|
|||
|
|
line = line.strip()
|
|||
|
|
if line.startswith("优先级:"):
|
|||
|
|
priority = line.replace("优先级:", "").strip().lower()
|
|||
|
|
elif line.startswith("行动类型:"):
|
|||
|
|
action_type = line.replace("行动类型:", "").strip().lower()
|
|||
|
|
elif line.startswith("建议回复:"):
|
|||
|
|
suggested_response = line.replace("建议回复:", "").strip()
|
|||
|
|
elif line.startswith("后续行动:"):
|
|||
|
|
actions = line.replace("后续行动:", "").strip()
|
|||
|
|
follow_up_actions = [a.strip() for a in actions.split(',') if a.strip()]
|
|||
|
|
elif line.startswith("制定理由:"):
|
|||
|
|
reasoning = line.replace("制定理由:", "").strip()
|
|||
|
|
|
|||
|
|
if not reasoning:
|
|||
|
|
reasoning = "基于情感分析结果和航空行业最佳实践制定此处置方案。"
|
|||
|
|
|
|||
|
|
return DisposalPlan(
|
|||
|
|
priority=priority,
|
|||
|
|
action_type=action_type,
|
|||
|
|
suggested_response=suggested_response,
|
|||
|
|
follow_up_actions=follow_up_actions,
|
|||
|
|
reasoning=reasoning
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 同步版本的包装函数(为了兼容现有接口)
|
|||
|
|
import asyncio
|
|||
|
|
|
|||
|
|
|
|||
|
|
def analyze_tweet_deepseek(text: str, airline: str) -> TweetAnalysisResult:
|
|||
|
|
"""同步版本的推文分析函数"""
|
|||
|
|
agent = DeepSeekTweetAgent()
|
|||
|
|
return asyncio.run(agent.analyze_tweet(text, airline))
|