Files
teamai-global/skills/daily-hot-news/sentiment_monitor.py
T

285 lines
9.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
舆情监控 - Sentiment Monitoring Module
功能:
- 直接用全量数据做关键词过滤
- 监控特定关键词的舆情
"""
from typing import List, Dict, Optional, Any
from dataclasses import dataclass, field
from enum import Enum
from datetime import datetime
import asyncio
class SentimentType(Enum):
"""舆情类型"""
ALL = "all" # 全部
POSITIVE = "positive" # 正面
NEGATIVE = "negative" # 负面
NEUTRAL = "neutral" # 中性
@dataclass
class SentimentConfig:
"""舆情监控配置"""
keywords: List[str] = field(default_factory=list) # 监控关键词
sentiment_type: SentimentType = SentimentType.ALL # 舆情类型
items_per_platform: int = 10 # 每个平台获取的条目数
total_items: int = 50 # 总条目数限制
include_platforms: List[str] = None # 包含的平台
exclude_platforms: List[str] = None # 排除的平台
class SentimentMonitor:
"""舆情监控类"""
def __init__(self, api_client=None, formatter=None):
"""
初始化舆情监控
Args:
api_client: API客户端实例(可选)
formatter: 格式化器实例(可选)
"""
self.api_client = api_client
self.formatter = formatter
self.all_platforms = self._get_default_platforms()
def _get_default_platforms(self) -> List[str]:
"""获取默认的全部平台列表"""
return [
"weibo", "zhihu", "douban-group", "douban-movie",
"ithome", "36kr", "sspai", "csdn", "juejin",
"genshin", "miyoushe", "bilibili", "hupu",
"sina-news", "netease-news", "qq-news",
"sina-money", "eastmoney", "xueqiu",
"autohome", "懂车帝", "mafengwo", "ctrip",
"dianping", "xiaohongshu", "weibo"
]
async def fetch_all_hot_data(self, limit_per_platform: int = 10) -> List[Dict[str, Any]]:
"""
一次性获取全部平台的热榜数据
Args:
limit_per_platform: 每个平台获取的条目数
Returns:
全部平台的热榜数据列表
"""
all_items = []
if self.api_client:
for platform in self.all_platforms:
try:
items = await self.api_client.get_hot榜单(platform, limit=limit_per_platform)
if items:
for item in items:
item["source_platform"] = platform
all_items.extend(items)
except Exception as e:
print(f"Error fetching {platform}: {e}")
continue
return all_items
async def monitor_keywords(self, keywords: List[str], config: Optional[SentimentConfig] = None) -> Dict[str, Any]:
"""
监控关键词舆情(新版:先全部获取,再关键词过滤)
Args:
keywords: 关键词列表
config: 配置对象(可选)
Returns:
舆情监控数据
"""
if config is None:
config = SentimentConfig(keywords=keywords)
# 步骤1:全部获取
all_items = await self.fetch_all_hot_data(limit_per_platform=config.items_per_platform)
# 步骤2:关键词过滤
filtered_items = self._filter_by_keywords(all_items, config.keywords)
# 平台过滤
if config.include_platforms:
filtered_items = [item for item in filtered_items if item.get("source_platform") in config.include_platforms]
if config.exclude_platforms:
filtered_items = [item for item in filtered_items if item.get("source_platform") not in config.exclude_platforms]
# 限制总数
filtered_items = filtered_items[:config.total_items]
return {
"keywords": config.keywords,
"total_items": len(filtered_items),
"items": filtered_items
}
def _filter_by_keywords(self, items: List[Dict], keywords: List[str]) -> List[Dict]:
"""
按关键词过滤
Args:
items: 条目列表
keywords: 关键词列表
Returns:
过滤后的条目列表
"""
if not keywords:
return items
filtered = []
for item in items:
title = item.get("title", "").lower()
desc = item.get("description", "").lower()
# 检查是否匹配任何关键词
matches = False
for kw in keywords:
if kw.lower() in title or kw.lower() in desc:
matches = True
break
if matches:
filtered.append(item)
# 按热度排序
filtered.sort(key=lambda x: x.get("hot", 0) or x.get("score", 0), reverse=True)
return filtered
def format_monitoring_response(self, monitor_data: Dict[str, Any]) -> str:
"""
格式化监控响应
Args:
monitor_data: 监控数据
Returns:
格式化的响应文本
"""
items = monitor_data.get("items", [])
keywords = monitor_data.get("keywords", [])
if not items:
return f"❌ 暂无关于「{', '.join(keywords)}」的舆情数据"
response = f"🔍 **舆情监控 - {', '.join(keywords)}**\n"
response += f"共 {monitor_data['total_items']} 条相关内容\n"
response += "-" * 40 + "\n\n"
for i, item in enumerate(items, 1):
title = item.get("title", "无标题")
hot = item.get("hot", item.get("score", ""))
platform = item.get("source_platform", "")
response += f"{i}. {title}\n"
if hot:
response += f" 🔥 热度: {hot}"
if platform:
response += f" | 📱 {platform}"
response += "\n\n"
return response
def parse_keywords_from_input(self, user_input: str) -> List[str]:
"""
从用户输入解析关键词
Args:
user_input: 用户输入
Returns:
关键词列表
"""
user_input = user_input.strip()
# 常用监控关键词
common_keywords = [
"AI", "人工智能", "ChatGPT", "大模型",
"特斯拉", "比亚迪", "新能源汽车",
"华为", "iPhone", "小米",
"直播", "电商", "网红",
"房价", "股票", "基金",
"高考", "考研", "留学"
]
matched_keywords = []
for kw in common_keywords:
if kw.lower() in user_input.lower():
matched_keywords.append(kw)
# 如果没有匹配到常用关键词,尝试提取用户输入的词
if not matched_keywords:
# 按逗号、空格等分隔
import re
words = re.split(r'[,,\s]+', user_input)
matched_keywords = [w for w in words if w.strip()]
return matched_keywords
async def process_user_request(self, user_input: str) -> Dict[str, Any]:
"""
处理用户请求
Args:
user_input: 用户输入
Returns:
处理结果
"""
# 解析关键词
keywords = self.parse_keywords_from_input(user_input)
if not keywords:
# 返回引导信息
return {
"action": "ask_keywords",
"message": "🔍 **舆情监控**\n\n"
"请输入您想监控的关键词,例如:\n"
"• AI、人工智能、ChatGPT\n"
"• 特斯拉、比亚迪、新能源汽车\n"
"• 华为、iPhone、小米\n"
"• 直播、电商、网红\n"
"• 房价、股票、基金\n\n"
"💡 您可以直接输入任意关键词进行监控"
}
# 获取监控数据
monitor_data = await self.monitor_keywords(keywords)
# 格式化响应
response_text = self.format_monitoring_response(monitor_data)
return {
"action": "show_monitoring",
"data": monitor_data,
"message": response_text
}
# 便捷函数
async def create_sentiment_monitor(api_client=None, formatter=None) -> SentimentMonitor:
"""创建舆情监控实例"""
return SentimentMonitor(api_client=api_client, formatter=formatter)
if __name__ == "__main__":
# 测试代码
async def test():
monitor = await create_sentiment_monitor()
print("测试舆情监控...")
result = await monitor.process_user_request("监控AI和特斯拉")
print(result["message"])
asyncio.run(test())