493 lines
18 KiB
Python
493 lines
18 KiB
Python
|
|
"""优化版 DeepSeek API 驱动的智能情感分析 Agent"""
|
|||
|
|
|
|||
|
|
import asyncio
|
|||
|
|
import json
|
|||
|
|
import re
|
|||
|
|
from typing import Optional, Dict, Any
|
|||
|
|
from functools import lru_cache
|
|||
|
|
import httpx
|
|||
|
|
from pydantic import BaseModel, Field
|
|||
|
|
|
|||
|
|
from src.config import Config
|
|||
|
|
|
|||
|
|
|
|||
|
|
class APIError(Exception):
|
|||
|
|
"""API 错误异常类"""
|
|||
|
|
def __init__(self, message: str, status_code: Optional[int] = None):
|
|||
|
|
self.message = message
|
|||
|
|
self.status_code = status_code
|
|||
|
|
super().__init__(self.message)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class DeepSeekClient:
|
|||
|
|
"""优化版 DeepSeek API 客户端"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
api_key = Config.get_api_key()
|
|||
|
|
if not api_key:
|
|||
|
|
raise ValueError("DeepSeek API Key 未配置")
|
|||
|
|
|
|||
|
|
self.api_key = api_key
|
|||
|
|
self.base_url = Config.get_base_url()
|
|||
|
|
self.model = Config.DEEPSEEK_MODEL
|
|||
|
|
|
|||
|
|
async def chat_completion_with_retry(
|
|||
|
|
self,
|
|||
|
|
messages: list,
|
|||
|
|
temperature: float = 0.3,
|
|||
|
|
max_tokens: int = 500
|
|||
|
|
) -> str:
|
|||
|
|
"""带重试机制的 API 调用"""
|
|||
|
|
|
|||
|
|
headers = {
|
|||
|
|
"Authorization": f"Bearer {self.api_key}",
|
|||
|
|
"Content-Type": "application/json"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
data = {
|
|||
|
|
"model": self.model,
|
|||
|
|
"messages": messages,
|
|||
|
|
"temperature": temperature,
|
|||
|
|
"max_tokens": max_tokens,
|
|||
|
|
"stream": False
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
last_error = None
|
|||
|
|
|
|||
|
|
for attempt in range(Config.MAX_RETRY_ATTEMPTS):
|
|||
|
|
try:
|
|||
|
|
async with httpx.AsyncClient(timeout=Config.REQUEST_TIMEOUT) 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"]
|
|||
|
|
elif response.status_code == 401:
|
|||
|
|
raise APIError("API 密钥无效", response.status_code)
|
|||
|
|
elif response.status_code == 429:
|
|||
|
|
# 限流,等待后重试
|
|||
|
|
wait_time = 2 ** attempt # 指数退避
|
|||
|
|
await asyncio.sleep(wait_time)
|
|||
|
|
continue
|
|||
|
|
else:
|
|||
|
|
raise APIError(f"API 调用失败: {response.status_code}", response.status_code)
|
|||
|
|
|
|||
|
|
except (httpx.ConnectError, httpx.TimeoutException) as e:
|
|||
|
|
last_error = e
|
|||
|
|
if attempt < Config.MAX_RETRY_ATTEMPTS - 1:
|
|||
|
|
await asyncio.sleep(1) # 等待1秒后重试
|
|||
|
|
continue
|
|||
|
|
else:
|
|||
|
|
raise APIError(f"网络连接失败: {str(e)}")
|
|||
|
|
except Exception as e:
|
|||
|
|
last_error = e
|
|||
|
|
if attempt < Config.MAX_RETRY_ATTEMPTS - 1:
|
|||
|
|
await asyncio.sleep(1)
|
|||
|
|
continue
|
|||
|
|
else:
|
|||
|
|
raise APIError(f"API 调用异常: {str(e)}")
|
|||
|
|
|
|||
|
|
raise last_error or APIError("未知错误")
|
|||
|
|
|
|||
|
|
|
|||
|
|
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="影响情感判断的关键因素")
|
|||
|
|
intensity: str = Field(description="情感强度: mild/moderate/strong")
|
|||
|
|
|
|||
|
|
|
|||
|
|
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="处置方案制定的理由")
|
|||
|
|
urgency_level: str = Field(description="紧急程度: immediate/soon/normal")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TweetAnalysisResult(BaseModel):
|
|||
|
|
"""推文分析完整结果"""
|
|||
|
|
tweet_text: str = Field(description="原始推文文本")
|
|||
|
|
airline: str = Field(description="航空公司")
|
|||
|
|
sentiment_analysis: SentimentAnalysisResult = Field(description="情感分析结果")
|
|||
|
|
disposal_plan: DisposalPlan = Field(description="处置方案")
|
|||
|
|
processing_time: float = Field(description="处理耗时(秒)")
|
|||
|
|
api_used: bool = Field(description="是否使用了 API")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ResponseParser:
|
|||
|
|
"""API 响应解析器"""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def parse_sentiment_response(response: str) -> Dict[str, Any]:
|
|||
|
|
"""解析情感分析响应"""
|
|||
|
|
|
|||
|
|
# 使用正则表达式进行更精确的解析
|
|||
|
|
patterns = {
|
|||
|
|
"sentiment": r"情感类别[::]\s*(negative|neutral|positive)",
|
|||
|
|
"confidence": r"置信度[::]\s*([0-9]*\.?[0-9]+)",
|
|||
|
|
"intensity": r"情感强度[::]\s*(mild|moderate|strong)",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result = {}
|
|||
|
|
|
|||
|
|
for key, pattern in patterns.items():
|
|||
|
|
match = re.search(pattern, response, re.IGNORECASE)
|
|||
|
|
if match:
|
|||
|
|
result[key] = match.group(1).lower() if key != "confidence" else float(match.group(1))
|
|||
|
|
|
|||
|
|
# 解析关键因素
|
|||
|
|
factors_match = re.search(r"关键因素[::]([^\n]*)(?:\n|$)", response)
|
|||
|
|
if factors_match:
|
|||
|
|
factors_text = factors_match.group(1).strip()
|
|||
|
|
result["key_factors"] = [f.strip() for f in factors_text.split(",") if f.strip()]
|
|||
|
|
else:
|
|||
|
|
result["key_factors"] = []
|
|||
|
|
|
|||
|
|
# 提取推理过程
|
|||
|
|
reasoning_match = re.search(r"推理过程[::]([^\n]*)(?:\n|$)", response)
|
|||
|
|
if reasoning_match:
|
|||
|
|
result["reasoning"] = reasoning_match.group(1).strip()
|
|||
|
|
else:
|
|||
|
|
# 如果找不到,使用默认推理
|
|||
|
|
result["reasoning"] = "基于推文内容和航空行业特点进行综合分析"
|
|||
|
|
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def parse_disposal_response(response: str) -> Dict[str, Any]:
|
|||
|
|
"""解析处置方案响应"""
|
|||
|
|
|
|||
|
|
patterns = {
|
|||
|
|
"priority": r"优先级[::]\s*(high|medium|low)",
|
|||
|
|
"action_type": r"行动类型[::]\s*(response|investigate|monitor|ignore)",
|
|||
|
|
"urgency_level": r"紧急程度[::]\s*(immediate|soon|normal)",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result = {}
|
|||
|
|
|
|||
|
|
for key, pattern in patterns.items():
|
|||
|
|
match = re.search(pattern, response, re.IGNORECASE)
|
|||
|
|
if match:
|
|||
|
|
result[key] = match.group(1).lower()
|
|||
|
|
|
|||
|
|
# 解析建议回复
|
|||
|
|
response_match = re.search(r"建议回复[::]([^\n]*)(?:\n|$)", response)
|
|||
|
|
if response_match:
|
|||
|
|
result["suggested_response"] = response_match.group(1).strip()
|
|||
|
|
|
|||
|
|
# 解析后续行动
|
|||
|
|
actions_match = re.search(r"后续行动[::]([^\n]*)(?:\n|$)", response)
|
|||
|
|
if actions_match:
|
|||
|
|
actions_text = actions_match.group(1).strip()
|
|||
|
|
result["follow_up_actions"] = [a.strip() for a in actions_text.split(",") if a.strip()]
|
|||
|
|
else:
|
|||
|
|
result["follow_up_actions"] = []
|
|||
|
|
|
|||
|
|
# 解析制定理由
|
|||
|
|
reasoning_match = re.search(r"制定理由[::]([^\n]*)(?:\n|$)", response)
|
|||
|
|
if reasoning_match:
|
|||
|
|
result["reasoning"] = reasoning_match.group(1).strip()
|
|||
|
|
else:
|
|||
|
|
result["reasoning"] = "基于情感分析结果制定"
|
|||
|
|
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
|
|||
|
|
class OptimizedDeepSeekTweetAgent:
|
|||
|
|
"""优化版 DeepSeek 推文分析 Agent"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self.client = DeepSeekClient()
|
|||
|
|
self.parser = ResponseParser()
|
|||
|
|
|
|||
|
|
async def analyze_sentiment(self, text: str, airline: str) -> SentimentAnalysisResult:
|
|||
|
|
"""优化版情感分析"""
|
|||
|
|
|
|||
|
|
prompt = f"""
|
|||
|
|
你是一位专业的航空行业情感分析专家。请分析以下推文的情感倾向:
|
|||
|
|
|
|||
|
|
推文内容:"{text}"
|
|||
|
|
航空公司:{airline}
|
|||
|
|
|
|||
|
|
请严格按照以下JSON格式输出分析结果:
|
|||
|
|
{{
|
|||
|
|
"sentiment": "negative/neutral/positive",
|
|||
|
|
"confidence": 0.0-1.0之间的数值,
|
|||
|
|
"intensity": "mild/moderate/strong",
|
|||
|
|
"key_factors": ["因素1", "因素2", "因素3"],
|
|||
|
|
"reasoning": "详细的情感判断推理过程"
|
|||
|
|
}}
|
|||
|
|
|
|||
|
|
分析要求:
|
|||
|
|
1. 情感判断要准确反映推文的真实情感
|
|||
|
|
2. 置信度要基于推文的明确程度和情感强度
|
|||
|
|
3. 关键因素要具体、相关
|
|||
|
|
4. 推理过程要详细、有逻辑
|
|||
|
|
|
|||
|
|
请只输出JSON格式的结果,不要有其他内容。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
messages = [
|
|||
|
|
{
|
|||
|
|
"role": "system",
|
|||
|
|
"content": "你是一位专业的航空行业情感分析专家,擅长准确识别推文中的情感倾向。"
|
|||
|
|
},
|
|||
|
|
{"role": "user", "content": prompt}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
response = await self.client.chat_completion_with_retry(messages, temperature=0.1)
|
|||
|
|
|
|||
|
|
# 清理响应文本,移除可能的标记和空白
|
|||
|
|
cleaned_response = response.strip()
|
|||
|
|
|
|||
|
|
# 尝试解析JSON响应
|
|||
|
|
try:
|
|||
|
|
# 尝试提取JSON部分(如果响应包含其他文本)
|
|||
|
|
json_match = re.search(r'\{[^}]+\}', cleaned_response)
|
|||
|
|
if json_match:
|
|||
|
|
json_text = json_match.group(0)
|
|||
|
|
result_data = json.loads(json_text)
|
|||
|
|
else:
|
|||
|
|
result_data = json.loads(cleaned_response)
|
|||
|
|
|
|||
|
|
# 验证必需字段
|
|||
|
|
required_fields = ["sentiment", "confidence", "intensity"]
|
|||
|
|
for field in required_fields:
|
|||
|
|
if field not in result_data:
|
|||
|
|
raise ValueError(f"缺少必需字段: {field}")
|
|||
|
|
|
|||
|
|
return SentimentAnalysisResult(**result_data)
|
|||
|
|
|
|||
|
|
except (json.JSONDecodeError, ValueError) as json_error:
|
|||
|
|
# JSON解析失败,使用正则解析
|
|||
|
|
print(f"JSON解析失败,使用正则解析: {json_error}")
|
|||
|
|
parsed_data = self.parser.parse_sentiment_response(response)
|
|||
|
|
|
|||
|
|
# 确保必需字段有默认值
|
|||
|
|
default_values = {
|
|||
|
|
"sentiment": "neutral",
|
|||
|
|
"confidence": 0.5,
|
|||
|
|
"intensity": "moderate"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for field, default_value in default_values.items():
|
|||
|
|
if field not in parsed_data or not parsed_data[field]:
|
|||
|
|
parsed_data[field] = default_value
|
|||
|
|
|
|||
|
|
return SentimentAnalysisResult(**parsed_data)
|
|||
|
|
|
|||
|
|
except APIError as e:
|
|||
|
|
# API调用失败,返回默认结果
|
|||
|
|
print(f"API调用失败: {e.message}")
|
|||
|
|
return SentimentAnalysisResult(
|
|||
|
|
sentiment="neutral",
|
|||
|
|
confidence=0.5,
|
|||
|
|
intensity="moderate",
|
|||
|
|
key_factors=["API调用失败,使用默认分析"],
|
|||
|
|
reasoning=f"API调用失败: {e.message}"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def generate_disposal_plan(
|
|||
|
|
self,
|
|||
|
|
text: str,
|
|||
|
|
airline: str,
|
|||
|
|
sentiment_result: SentimentAnalysisResult
|
|||
|
|
) -> DisposalPlan:
|
|||
|
|
"""生成优化版处置方案"""
|
|||
|
|
|
|||
|
|
prompt = f"""
|
|||
|
|
基于以下推文分析和情感判断结果,为航空公司制定一个合理的处置方案:
|
|||
|
|
|
|||
|
|
推文内容:"{text}"
|
|||
|
|
航空公司:{airline}
|
|||
|
|
情感分析结果:
|
|||
|
|
- 情感类别:{sentiment_result.sentiment}
|
|||
|
|
- 置信度:{sentiment_result.confidence:.1%}
|
|||
|
|
- 情感强度:{sentiment_result.intensity}
|
|||
|
|
- 关键因素:{', '.join(sentiment_result.key_factors)}
|
|||
|
|
|
|||
|
|
请严格按照以下JSON格式输出处置方案:
|
|||
|
|
{{
|
|||
|
|
"priority": "high/medium/low",
|
|||
|
|
"action_type": "response/investigate/monitor/ignore",
|
|||
|
|
"suggested_response": "具体的回复建议(如适用)",
|
|||
|
|
"follow_up_actions": ["行动1", "行动2"],
|
|||
|
|
"reasoning": "制定此方案的理由",
|
|||
|
|
"urgency_level": "immediate/soon/normal"
|
|||
|
|
}}
|
|||
|
|
|
|||
|
|
要求:
|
|||
|
|
1. 优先级要基于情感强度和置信度
|
|||
|
|
2. 行动类型要符合航空行业最佳实践
|
|||
|
|
3. 建议回复要专业、有同理心
|
|||
|
|
4. 后续行动要具体、可执行
|
|||
|
|
|
|||
|
|
请只输出JSON格式的结果。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
messages = [
|
|||
|
|
{
|
|||
|
|
"role": "system",
|
|||
|
|
"content": "你是一位航空公司的客户服务专家,擅长制定合理的客户反馈处置方案。"
|
|||
|
|
},
|
|||
|
|
{"role": "user", "content": prompt}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
response = await self.client.chat_completion_with_retry(messages, temperature=0.3)
|
|||
|
|
|
|||
|
|
# 清理响应文本
|
|||
|
|
cleaned_response = response.strip()
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 尝试提取JSON部分
|
|||
|
|
json_match = re.search(r'\{[^}]+\}', cleaned_response)
|
|||
|
|
if json_match:
|
|||
|
|
json_text = json_match.group(0)
|
|||
|
|
result_data = json.loads(json_text)
|
|||
|
|
else:
|
|||
|
|
result_data = json.loads(cleaned_response)
|
|||
|
|
|
|||
|
|
# 验证必需字段
|
|||
|
|
required_fields = ["priority", "action_type", "reasoning"]
|
|||
|
|
for field in required_fields:
|
|||
|
|
if field not in result_data:
|
|||
|
|
raise ValueError(f"缺少必需字段: {field}")
|
|||
|
|
|
|||
|
|
return DisposalPlan(**result_data)
|
|||
|
|
|
|||
|
|
except (json.JSONDecodeError, ValueError) as json_error:
|
|||
|
|
# JSON解析失败,使用正则解析
|
|||
|
|
print(f"处置方案JSON解析失败,使用正则解析: {json_error}")
|
|||
|
|
parsed_data = self.parser.parse_disposal_response(response)
|
|||
|
|
|
|||
|
|
# 确保必需字段有默认值
|
|||
|
|
default_values = {
|
|||
|
|
"priority": "medium",
|
|||
|
|
"action_type": "monitor",
|
|||
|
|
"reasoning": "基于情感分析结果制定",
|
|||
|
|
"follow_up_actions": [],
|
|||
|
|
"urgency_level": "normal"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for field, default_value in default_values.items():
|
|||
|
|
if field not in parsed_data or not parsed_data[field]:
|
|||
|
|
parsed_data[field] = default_value
|
|||
|
|
|
|||
|
|
return DisposalPlan(**parsed_data)
|
|||
|
|
|
|||
|
|
except APIError as e:
|
|||
|
|
# API调用失败,返回默认处置方案
|
|||
|
|
print(f"处置方案API调用失败: {e.message}")
|
|||
|
|
return self._generate_default_disposal_plan(sentiment_result)
|
|||
|
|
|
|||
|
|
def _generate_default_disposal_plan(self, sentiment_result: SentimentAnalysisResult) -> DisposalPlan:
|
|||
|
|
"""生成默认处置方案"""
|
|||
|
|
|
|||
|
|
if sentiment_result.sentiment == "negative":
|
|||
|
|
return DisposalPlan(
|
|||
|
|
priority="medium",
|
|||
|
|
action_type="investigate",
|
|||
|
|
suggested_response=None,
|
|||
|
|
follow_up_actions=["进一步核实情况", "根据核实结果决定行动"],
|
|||
|
|
reasoning="负面情感需要进一步调查",
|
|||
|
|
urgency_level="soon"
|
|||
|
|
)
|
|||
|
|
elif sentiment_result.sentiment == "positive":
|
|||
|
|
return DisposalPlan(
|
|||
|
|
priority="low",
|
|||
|
|
action_type="monitor",
|
|||
|
|
suggested_response=None,
|
|||
|
|
follow_up_actions=["持续关注用户动态"],
|
|||
|
|
reasoning="正面情感保持关注即可",
|
|||
|
|
urgency_level="normal"
|
|||
|
|
)
|
|||
|
|
else:
|
|||
|
|
return DisposalPlan(
|
|||
|
|
priority="low",
|
|||
|
|
action_type="monitor",
|
|||
|
|
suggested_response=None,
|
|||
|
|
follow_up_actions=["常规关注"],
|
|||
|
|
reasoning="中性情感常规处理",
|
|||
|
|
urgency_level="normal"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def analyze_tweet(self, text: str, airline: str) -> TweetAnalysisResult:
|
|||
|
|
"""完整的推文分析流程"""
|
|||
|
|
import time
|
|||
|
|
start_time = time.time()
|
|||
|
|
|
|||
|
|
# 1. 情感分析
|
|||
|
|
sentiment_result = await self.analyze_sentiment(text, airline)
|
|||
|
|
|
|||
|
|
# 2. 生成处置方案
|
|||
|
|
disposal_plan = await self.generate_disposal_plan(text, airline, sentiment_result)
|
|||
|
|
|
|||
|
|
# 3. 计算处理时间
|
|||
|
|
processing_time = time.time() - start_time
|
|||
|
|
|
|||
|
|
# 返回完整结果
|
|||
|
|
return TweetAnalysisResult(
|
|||
|
|
tweet_text=text,
|
|||
|
|
airline=airline,
|
|||
|
|
sentiment_analysis=sentiment_result,
|
|||
|
|
disposal_plan=disposal_plan,
|
|||
|
|
processing_time=processing_time,
|
|||
|
|
api_used=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 同步版本的包装函数
|
|||
|
|
async def analyze_tweet_async(text: str, airline: str) -> TweetAnalysisResult:
|
|||
|
|
"""异步版本的推文分析"""
|
|||
|
|
agent = OptimizedDeepSeekTweetAgent()
|
|||
|
|
return await agent.analyze_tweet(text, airline)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def analyze_tweet_sync(text: str, airline: str) -> TweetAnalysisResult:
|
|||
|
|
"""同步版本的推文分析函数"""
|
|||
|
|
return asyncio.run(analyze_tweet_async(text, airline))
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 终极版本 - 完全不需要航空公司参数
|
|||
|
|
async def analyze_tweet_ultimate_async(text: str) -> TweetAnalysisResult:
|
|||
|
|
"""终极版本异步推文分析 - 无需航空公司参数"""
|
|||
|
|
agent = OptimizedDeepSeekTweetAgent()
|
|||
|
|
|
|||
|
|
# 自动检测航空公司或使用通用标识
|
|||
|
|
airline = "通用航空公司"
|
|||
|
|
|
|||
|
|
# 简单的航空公司检测逻辑
|
|||
|
|
airline_keywords = {
|
|||
|
|
"united": "United Airlines",
|
|||
|
|
"delta": "Delta Air Lines",
|
|||
|
|
"american": "American Airlines",
|
|||
|
|
"southwest": "Southwest Airlines",
|
|||
|
|
"jetblue": "JetBlue Airways",
|
|||
|
|
"air china": "中国国际航空",
|
|||
|
|
"china eastern": "中国东方航空",
|
|||
|
|
"china southern": "中国南方航空"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
text_lower = text.lower()
|
|||
|
|
for keyword, airline_name in airline_keywords.items():
|
|||
|
|
if keyword in text_lower:
|
|||
|
|
airline = airline_name
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
return await agent.analyze_tweet(text, airline)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def analyze_tweet_sync_ultimate(text: str) -> TweetAnalysisResult:
|
|||
|
|
"""终极版本同步推文分析 - 完全无需航空公司参数"""
|
|||
|
|
return asyncio.run(analyze_tweet_ultimate_async(text))
|