mirror of
https://gitee.com/houhuan/TrendRadar.git
synced 2025-12-21 14:27:15 +08:00
chore: 更新文档和 AI 对话效果图
- 更新至 mcp-v1.0.1 - 更新 AI 对话效果图 - 完善相关文档
This commit is contained in:
parent
b27f402f71
commit
6749f4e569
@ -109,6 +109,16 @@ cd 你的项目名
|
|||||||
帮我爬取最新的新闻
|
帮我爬取最新的新闻
|
||||||
```
|
```
|
||||||
|
|
||||||
|
或者尝试其他测试命令:
|
||||||
|
|
||||||
|
```
|
||||||
|
搜索最近3天关于"人工智能"的新闻
|
||||||
|
查找2025年1月的"特斯拉"相关报道
|
||||||
|
分析"iPhone"的热度趋势
|
||||||
|
```
|
||||||
|
|
||||||
|
**提示**:当你说"最近3天"时,AI会自动计算日期范围并搜索。
|
||||||
|
|
||||||
### 2. 成功标志
|
### 2. 成功标志
|
||||||
|
|
||||||
如果配置成功,AI 会:
|
如果配置成功,AI 会:
|
||||||
|
|||||||
@ -9,12 +9,14 @@
|
|||||||
| 默认设置 | 说明 | 如何调整 |
|
| 默认设置 | 说明 | 如何调整 |
|
||||||
| -------------- | --------------------------------------- | ------------------------------------- |
|
| -------------- | --------------------------------------- | ------------------------------------- |
|
||||||
| **限制条数** | 默认返回 50 条新闻 | 对话中说"返回前 10 条"或"给我 100 条" |
|
| **限制条数** | 默认返回 50 条新闻 | 对话中说"返回前 10 条"或"给我 100 条" |
|
||||||
| **时间范围** | 默认查询今天的数据 | 说"查询昨天"或"最近一周" |
|
| **时间范围** | 默认查询今天的数据 | 说"查询昨天"、"最近一周"或"1月1日到7日" |
|
||||||
| **URL 链接** | 默认不返回链接(节省约 160 tokens/条) | 说"需要链接"或"包含 URL" |
|
| **URL 链接** | 默认不返回链接(节省约 160 tokens/条) | 说"需要链接"或"包含 URL" |
|
||||||
| **关键词列表** | 默认不使用 frequency_words.txt 过滤新闻 | 只有调用"趋势话题"工具时才使用 |
|
| **关键词列表** | 默认不使用 frequency_words.txt 过滤新闻 | 只有调用"趋势话题"工具时才使用 |
|
||||||
|
|
||||||
**⚠️ 重要:** AI 模型的选择直接影响工具调用效果,AI 越智能,调用越准确。当你解除上面的限制,比如从今天的查询,放宽到一周的查询,首先你要在本地有一周的数据,其次,token 消耗量可能会倍增(为什么说可能,比如我查询 分析'苹果'最近一周的热度趋势,如果一周中没多少苹果的新闻,那么 token消耗量可能反而很少)
|
**⚠️ 重要:** AI 模型的选择直接影响工具调用效果,AI 越智能,调用越准确。当你解除上面的限制,比如从今天的查询,放宽到一周的查询,首先你要在本地有一周的数据,其次,token 消耗量可能会倍增(为什么说可能,比如我查询 分析'苹果'最近一周的热度趋势,如果一周中没多少苹果的新闻,那么 token消耗量可能反而很少)
|
||||||
|
|
||||||
|
**💡 提示:** 当你说"最近7天"时,AI会自动计算对应的日期范围(如 2025-10-18 至 2025-10-25)并传递给工具。
|
||||||
|
|
||||||
|
|
||||||
## 💰 AI 模型
|
## 💰 AI 模型
|
||||||
|
|
||||||
@ -148,6 +150,8 @@
|
|||||||
- "搜索包含'人工智能'的新闻"
|
- "搜索包含'人工智能'的新闻"
|
||||||
- "查找关于'特斯拉降价'的报道"
|
- "查找关于'特斯拉降价'的报道"
|
||||||
- "搜索马斯克相关的新闻,返回前 20 条"
|
- "搜索马斯克相关的新闻,返回前 20 条"
|
||||||
|
- "查找最近7天关于'iPhone 16'的新闻"
|
||||||
|
- "查找2025年1月1日到7日'特斯拉'的相关新闻"
|
||||||
- "查找'iPhone 16 发布'这条新闻的链接"
|
- "查找'iPhone 16 发布'这条新闻的链接"
|
||||||
|
|
||||||
**调用的工具:** `search_news`
|
**调用的工具:** `search_news`
|
||||||
@ -155,7 +159,8 @@
|
|||||||
**工具返回行为:**
|
**工具返回行为:**
|
||||||
|
|
||||||
- 使用关键词模式搜索
|
- 使用关键词模式搜索
|
||||||
- 搜索今天的数据
|
- 默认搜索今天的数据
|
||||||
|
- AI会自动将"最近7天"、"上周"等相对时间转换为具体日期范围
|
||||||
- MCP 工具会返回最多 50 条结果给 AI
|
- MCP 工具会返回最多 50 条结果给 AI
|
||||||
- 不包含 URL 链接
|
- 不包含 URL 链接
|
||||||
|
|
||||||
@ -166,11 +171,23 @@
|
|||||||
|
|
||||||
**可以调整:**
|
**可以调整:**
|
||||||
|
|
||||||
- 指定时间范围:如"搜索最近一周的"
|
- 指定时间范围:
|
||||||
|
- 相对方式:"搜索最近一周的"(AI 自动计算日期)
|
||||||
|
- 绝对日期:"搜索2025年1月1日到7日的"
|
||||||
- 指定平台:如"只搜索知乎"
|
- 指定平台:如"只搜索知乎"
|
||||||
- 调整排序:如"按权重排序"
|
- 调整排序:如"按权重排序"
|
||||||
- 包含链接:如"需要链接"
|
- 包含链接:如"需要链接"
|
||||||
|
|
||||||
|
**示例对话:**
|
||||||
|
|
||||||
|
```
|
||||||
|
用户:搜索最近7天关于"人工智能突破"的新闻
|
||||||
|
AI:(自动计算:date_range={"start": "2025-10-18", "end": "2025-10-25"})
|
||||||
|
|
||||||
|
用户:查找2025年1月的"特斯拉"报道
|
||||||
|
AI:(date_range={"start": "2025-01-01", "end": "2025-01-31"})
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Q5: 如何查找历史相关新闻?
|
### Q5: 如何查找历史相关新闻?
|
||||||
@ -208,13 +225,15 @@
|
|||||||
- "看看'特斯拉'话题是昙花一现还是持续热点"
|
- "看看'特斯拉'话题是昙花一现还是持续热点"
|
||||||
- "检测今天有哪些突然爆火的话题"
|
- "检测今天有哪些突然爆火的话题"
|
||||||
- "预测接下来可能的热点话题"
|
- "预测接下来可能的热点话题"
|
||||||
|
- "分析'比特币'在2024年12月的生命周期"
|
||||||
|
|
||||||
**调用的工具:** `analyze_topic_trend`
|
**调用的工具:** `analyze_topic_trend`
|
||||||
|
|
||||||
**工具返回行为:**
|
**工具返回行为:**
|
||||||
|
|
||||||
- 热度趋势模式
|
- 支持多种分析模式:热度趋势、生命周期、异常检测、预测
|
||||||
- 分析最近 7 天数据
|
- AI会自动将"最近一周"等相对时间转换为具体日期范围
|
||||||
|
- 默认分析最近7天数据
|
||||||
- 按天粒度统计
|
- 按天粒度统计
|
||||||
|
|
||||||
**AI 展示行为:**
|
**AI 展示行为:**
|
||||||
@ -222,6 +241,16 @@
|
|||||||
- 通常会展示趋势分析结果和图表
|
- 通常会展示趋势分析结果和图表
|
||||||
- AI 可能会总结关键发现
|
- AI 可能会总结关键发现
|
||||||
|
|
||||||
|
**示例对话:**
|
||||||
|
|
||||||
|
```
|
||||||
|
用户:分析'人工智能'最近一周的生命周期
|
||||||
|
AI:(自动计算:date_range={"start": "2025-10-18", "end": "2025-10-25"})
|
||||||
|
|
||||||
|
用户:看看'比特币'在2024年12月是昙花一现还是持续热点
|
||||||
|
AI:(date_range={"start": "2024-12-01", "end": "2024-12-31"})
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 数据洞察
|
## 数据洞察
|
||||||
|
|||||||
BIN
_image/ai.png
Normal file
BIN
_image/ai.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 400 KiB |
@ -155,11 +155,10 @@ async def get_news_by_date(
|
|||||||
async def analyze_topic_trend(
|
async def analyze_topic_trend(
|
||||||
topic: str,
|
topic: str,
|
||||||
analysis_type: str = "trend",
|
analysis_type: str = "trend",
|
||||||
time_range: str = "7d",
|
date_range: Optional[Dict[str, str]] = None,
|
||||||
granularity: str = "day",
|
granularity: str = "day",
|
||||||
threshold: float = 3.0,
|
threshold: float = 3.0,
|
||||||
time_window: int = 24,
|
time_window: int = 24,
|
||||||
lookback_days: int = 7,
|
|
||||||
lookahead_hours: int = 6,
|
lookahead_hours: int = 6,
|
||||||
confidence_threshold: float = 0.7
|
confidence_threshold: float = 0.7
|
||||||
) -> str:
|
) -> str:
|
||||||
@ -173,20 +172,27 @@ async def analyze_topic_trend(
|
|||||||
- "lifecycle": 生命周期分析(从出现到消失的完整周期)
|
- "lifecycle": 生命周期分析(从出现到消失的完整周期)
|
||||||
- "viral": 异常热度检测(识别突然爆火的话题)
|
- "viral": 异常热度检测(识别突然爆火的话题)
|
||||||
- "predict": 话题预测(预测未来可能的热点)
|
- "predict": 话题预测(预测未来可能的热点)
|
||||||
time_range: 时间范围(trend模式),默认"7d"(7d/24h/1w/1m/2m)
|
date_range: 日期范围(trend和lifecycle模式),可选
|
||||||
|
- **格式**: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
||||||
|
- **示例**: {"start": "2025-10-18", "end": "2025-10-25"}
|
||||||
|
- **说明**: AI需要根据用户的自然语言(如"最近7天")自动计算日期范围
|
||||||
|
- **默认**: 不指定时默认分析最近7天
|
||||||
granularity: 时间粒度(trend模式),默认"day"(仅支持 day,因为底层数据按天聚合)
|
granularity: 时间粒度(trend模式),默认"day"(仅支持 day,因为底层数据按天聚合)
|
||||||
threshold: 热度突增倍数阈值(viral模式),默认3.0
|
threshold: 热度突增倍数阈值(viral模式),默认3.0
|
||||||
time_window: 检测时间窗口小时数(viral模式),默认24
|
time_window: 检测时间窗口小时数(viral模式),默认24
|
||||||
lookback_days: 回溯天数(lifecycle模式),默认7
|
|
||||||
lookahead_hours: 预测未来小时数(predict模式),默认6
|
lookahead_hours: 预测未来小时数(predict模式),默认6
|
||||||
confidence_threshold: 置信度阈值(predict模式),默认0.7
|
confidence_threshold: 置信度阈值(predict模式),默认0.7
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
JSON格式的趋势分析结果
|
JSON格式的趋势分析结果
|
||||||
|
|
||||||
|
**AI使用说明:**
|
||||||
|
当用户使用相对时间表达时(如"最近7天"、"过去一周"、"上个月"),
|
||||||
|
AI需要自动计算对应的日期范围并传递给 date_range 参数。
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
- analyze_topic_trend(topic="人工智能", analysis_type="trend", time_range="7d")
|
- analyze_topic_trend(topic="人工智能", analysis_type="trend", date_range={"start": "2025-10-18", "end": "2025-10-25"})
|
||||||
- analyze_topic_trend(topic="特斯拉", analysis_type="lifecycle", lookback_days=7)
|
- analyze_topic_trend(topic="特斯拉", analysis_type="lifecycle", date_range={"start": "2025-10-18", "end": "2025-10-25"})
|
||||||
- analyze_topic_trend(topic="比特币", analysis_type="viral", threshold=3.0)
|
- analyze_topic_trend(topic="比特币", analysis_type="viral", threshold=3.0)
|
||||||
- analyze_topic_trend(topic="ChatGPT", analysis_type="predict", lookahead_hours=6)
|
- analyze_topic_trend(topic="ChatGPT", analysis_type="predict", lookahead_hours=6)
|
||||||
"""
|
"""
|
||||||
@ -194,11 +200,10 @@ async def analyze_topic_trend(
|
|||||||
result = tools['analytics'].analyze_topic_trend_unified(
|
result = tools['analytics'].analyze_topic_trend_unified(
|
||||||
topic=topic,
|
topic=topic,
|
||||||
analysis_type=analysis_type,
|
analysis_type=analysis_type,
|
||||||
time_range=time_range,
|
date_range=date_range,
|
||||||
granularity=granularity,
|
granularity=granularity,
|
||||||
threshold=threshold,
|
threshold=threshold,
|
||||||
time_window=time_window,
|
time_window=time_window,
|
||||||
lookback_days=lookback_days,
|
|
||||||
lookahead_hours=lookahead_hours,
|
lookahead_hours=lookahead_hours,
|
||||||
confidence_threshold=confidence_threshold
|
confidence_threshold=confidence_threshold
|
||||||
)
|
)
|
||||||
@ -222,7 +227,10 @@ async def analyze_data_insights(
|
|||||||
- "platform_activity": 平台活跃度统计(统计各平台发布频率和活跃时间)
|
- "platform_activity": 平台活跃度统计(统计各平台发布频率和活跃时间)
|
||||||
- "keyword_cooccur": 关键词共现分析(分析关键词同时出现的模式)
|
- "keyword_cooccur": 关键词共现分析(分析关键词同时出现的模式)
|
||||||
topic: 话题关键词(可选,platform_compare模式适用)
|
topic: 话题关键词(可选,platform_compare模式适用)
|
||||||
date_range: 日期范围,格式: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
date_range: **【对象类型】** 日期范围(可选)
|
||||||
|
- **格式**: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
||||||
|
- **示例**: {"start": "2025-01-01", "end": "2025-01-07"}
|
||||||
|
- **重要**: 必须是对象格式,不能传递整数
|
||||||
min_frequency: 最小共现频次(keyword_cooccur模式),默认3
|
min_frequency: 最小共现频次(keyword_cooccur模式),默认3
|
||||||
top_n: 返回TOP N结果(keyword_cooccur模式),默认20
|
top_n: 返回TOP N结果(keyword_cooccur模式),默认20
|
||||||
|
|
||||||
@ -231,7 +239,7 @@ async def analyze_data_insights(
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
- analyze_data_insights(insight_type="platform_compare", topic="人工智能")
|
- analyze_data_insights(insight_type="platform_compare", topic="人工智能")
|
||||||
- analyze_data_insights(insight_type="platform_activity", date_range={...})
|
- analyze_data_insights(insight_type="platform_activity", date_range={"start": "2025-01-01", "end": "2025-01-07"})
|
||||||
- analyze_data_insights(insight_type="keyword_cooccur", min_frequency=5, top_n=15)
|
- analyze_data_insights(insight_type="keyword_cooccur", min_frequency=5, top_n=15)
|
||||||
"""
|
"""
|
||||||
tools = _get_tools()
|
tools = _get_tools()
|
||||||
@ -258,12 +266,15 @@ async def analyze_sentiment(
|
|||||||
分析新闻的情感倾向和热度趋势
|
分析新闻的情感倾向和热度趋势
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
keywords: 关键词列表,如 ["AI", "人工智能"]
|
topic: 话题关键词(可选)
|
||||||
date_range: 日期范围(天数),如 7 表示最近7天,默认3天
|
|
||||||
platforms: 平台ID列表,如 ['zhihu', 'weibo', 'douyin']
|
platforms: 平台ID列表,如 ['zhihu', 'weibo', 'douyin']
|
||||||
- 不指定时:使用 config.yaml 中配置的所有平台
|
- 不指定时:使用 config.yaml 中配置的所有平台
|
||||||
- 支持的平台来自 config/config.yaml 的 platforms 配置
|
- 支持的平台来自 config/config.yaml 的 platforms 配置
|
||||||
- 每个平台都有对应的name字段(如"知乎"、"微博"),方便AI识别
|
- 每个平台都有对应的name字段(如"知乎"、"微博"),方便AI识别
|
||||||
|
date_range: **【对象类型】** 日期范围(可选)
|
||||||
|
- **格式**: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
||||||
|
- **示例**: {"start": "2025-01-01", "end": "2025-01-07"}
|
||||||
|
- **重要**: 必须是对象格式,不能传递整数
|
||||||
limit: 返回新闻数量,默认50,最大100
|
limit: 返回新闻数量,默认50,最大100
|
||||||
注意:本工具会对新闻标题进行去重(同一标题在不同平台只保留一次),
|
注意:本工具会对新闻标题进行去重(同一标题在不同平台只保留一次),
|
||||||
因此实际返回数量可能少于请求的 limit 值
|
因此实际返回数量可能少于请求的 limit 值
|
||||||
@ -301,7 +312,7 @@ async def find_similar_news(
|
|||||||
查找与指定新闻标题相似的其他新闻
|
查找与指定新闻标题相似的其他新闻
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
title: 新闻标题(完整或部分)
|
reference_title: 新闻标题(完整或部分)
|
||||||
threshold: 相似度阈值,0-1之间,默认0.6
|
threshold: 相似度阈值,0-1之间,默认0.6
|
||||||
注意:阈值越高匹配越严格,返回结果越少
|
注意:阈值越高匹配越严格,返回结果越少
|
||||||
limit: 返回条数限制,默认50,最大100
|
limit: 返回条数限制,默认50,最大100
|
||||||
@ -336,7 +347,10 @@ async def generate_summary_report(
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
report_type: 报告类型(daily/weekly)
|
report_type: 报告类型(daily/weekly)
|
||||||
date_range: 自定义日期范围(可选)
|
date_range: **【对象类型】** 自定义日期范围(可选)
|
||||||
|
- **格式**: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
||||||
|
- **示例**: {"start": "2025-01-01", "end": "2025-01-07"}
|
||||||
|
- **重要**: 必须是对象格式,不能传递整数
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
JSON格式的摘要报告,包含Markdown格式内容
|
JSON格式的摘要报告,包含Markdown格式内容
|
||||||
@ -371,15 +385,24 @@ async def search_news(
|
|||||||
- "keyword": 精确关键词匹配(默认,适合搜索特定话题)
|
- "keyword": 精确关键词匹配(默认,适合搜索特定话题)
|
||||||
- "fuzzy": 模糊内容匹配(适合搜索内容片段,会过滤相似度低于阈值的结果)
|
- "fuzzy": 模糊内容匹配(适合搜索内容片段,会过滤相似度低于阈值的结果)
|
||||||
- "entity": 实体名称搜索(适合搜索人物/地点/机构)
|
- "entity": 实体名称搜索(适合搜索人物/地点/机构)
|
||||||
threshold: 相似度阈值(仅fuzzy模式有效),0-1之间,默认0.6
|
date_range: 日期范围(可选)
|
||||||
注意:阈值越高匹配越严格,返回结果越少
|
- **格式**: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
||||||
|
- **示例**: {"start": "2025-01-01", "end": "2025-01-07"}
|
||||||
|
- **说明**: AI需要根据用户的自然语言(如"最近7天")自动计算日期范围
|
||||||
|
- **默认**: 不指定时默认查询今天的新闻
|
||||||
|
- **注意**: start和end可以相同(表示单日查询)
|
||||||
platforms: 平台ID列表,如 ['zhihu', 'weibo', 'douyin']
|
platforms: 平台ID列表,如 ['zhihu', 'weibo', 'douyin']
|
||||||
- 不指定时:使用 config.yaml 中配置的所有平台
|
- 不指定时:使用 config.yaml 中配置的所有平台
|
||||||
- 支持的平台来自 config/config.yaml 的 platforms 配置
|
- 支持的平台来自 config/config.yaml 的 platforms 配置
|
||||||
- 每个平台都有对应的name字段(如"知乎"、"微博"),方便AI识别
|
- 每个平台都有对应的name字段(如"知乎"、"微博"),方便AI识别
|
||||||
lookback_days: 回溯天数,默认7天,最大30天
|
|
||||||
limit: 返回条数限制,默认50,最大1000
|
limit: 返回条数限制,默认50,最大1000
|
||||||
注意:实际返回数量取决于搜索匹配结果(特别是 fuzzy 模式下会过滤低相似度结果)
|
注意:实际返回数量取决于搜索匹配结果(特别是 fuzzy 模式下会过滤低相似度结果)
|
||||||
|
sort_by: 排序方式,可选值:
|
||||||
|
- "relevance": 按相关度排序(默认)
|
||||||
|
- "weight": 按新闻权重排序
|
||||||
|
- "date": 按日期排序
|
||||||
|
threshold: 相似度阈值(仅fuzzy模式有效),0-1之间,默认0.6
|
||||||
|
注意:阈值越高匹配越严格,返回结果越少
|
||||||
include_url: 是否包含URL链接,默认False(节省token)
|
include_url: 是否包含URL链接,默认False(节省token)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -389,6 +412,19 @@ async def search_news(
|
|||||||
- 本工具返回完整的搜索结果列表
|
- 本工具返回完整的搜索结果列表
|
||||||
- **默认展示方式**:展示全部返回的新闻,无需总结或筛选
|
- **默认展示方式**:展示全部返回的新闻,无需总结或筛选
|
||||||
- 仅在用户明确要求"总结"或"挑重点"时才进行筛选
|
- 仅在用户明确要求"总结"或"挑重点"时才进行筛选
|
||||||
|
|
||||||
|
**AI使用说明:**
|
||||||
|
当用户使用相对时间表达时(如"最近7天"、"过去一周"、"最近半个月"),
|
||||||
|
AI需要自动计算对应的日期范围。计算规则:
|
||||||
|
- "最近7天" → {"start": "今天-6天", "end": "今天"}
|
||||||
|
- "过去一周" → {"start": "今天-6天", "end": "今天"}
|
||||||
|
- "最近30天" → {"start": "今天-29天", "end": "今天"}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- 今天的新闻: search_news(query="人工智能")
|
||||||
|
- 最近7天: search_news(query="人工智能", date_range={"start": "2025-10-18", "end": "2025-10-25"})
|
||||||
|
- 精确日期: search_news(query="人工智能", date_range={"start": "2025-01-01", "end": "2025-01-07"})
|
||||||
|
- 模糊搜索: search_news(query="特斯拉降价", search_mode="fuzzy", threshold=0.4)
|
||||||
"""
|
"""
|
||||||
tools = _get_tools()
|
tools = _get_tools()
|
||||||
result = tools['search'].search_news_unified(
|
result = tools['search'].search_news_unified(
|
||||||
@ -407,7 +443,7 @@ async def search_news(
|
|||||||
@mcp.tool
|
@mcp.tool
|
||||||
async def search_related_news_history(
|
async def search_related_news_history(
|
||||||
reference_text: str,
|
reference_text: str,
|
||||||
time_range: str = "yesterday",
|
time_preset: str = "yesterday",
|
||||||
threshold: float = 0.4,
|
threshold: float = 0.4,
|
||||||
limit: int = 50,
|
limit: int = 50,
|
||||||
include_url: bool = False
|
include_url: bool = False
|
||||||
@ -416,12 +452,15 @@ async def search_related_news_history(
|
|||||||
基于种子新闻,在历史数据中搜索相关新闻
|
基于种子新闻,在历史数据中搜索相关新闻
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
seed_news_title: 种子新闻标题(完整或部分)
|
reference_text: 参考新闻标题(完整或部分)
|
||||||
lookback_days: 向前查找的天数范围,默认7天,最大30天
|
time_preset: 时间范围预设值,可选:
|
||||||
|
- "yesterday": 昨天
|
||||||
|
- "last_week": 上周 (7天)
|
||||||
|
- "last_month": 上个月 (30天)
|
||||||
|
- "custom": 自定义日期范围(需要提供 start_date 和 end_date)
|
||||||
threshold: 相关性阈值,0-1之间,默认0.4
|
threshold: 相关性阈值,0-1之间,默认0.4
|
||||||
注意:综合相似度计算(70%关键词重合 + 30%文本相似度)
|
注意:综合相似度计算(70%关键词重合 + 30%文本相似度)
|
||||||
阈值越高匹配越严格,返回结果越少
|
阈值越高匹配越严格,返回结果越少
|
||||||
platforms: 平台ID列表。不指定则搜索所有平台
|
|
||||||
limit: 返回条数限制,默认50,最大100
|
limit: 返回条数限制,默认50,最大100
|
||||||
注意:实际返回数量取决于相关性匹配结果,可能少于请求值
|
注意:实际返回数量取决于相关性匹配结果,可能少于请求值
|
||||||
include_url: 是否包含URL链接,默认False(节省token)
|
include_url: 是否包含URL链接,默认False(节省token)
|
||||||
@ -437,7 +476,7 @@ async def search_related_news_history(
|
|||||||
tools = _get_tools()
|
tools = _get_tools()
|
||||||
result = tools['search'].search_related_news_history(
|
result = tools['search'].search_related_news_history(
|
||||||
reference_text=reference_text,
|
reference_text=reference_text,
|
||||||
time_range=time_range,
|
time_preset=time_preset,
|
||||||
threshold=threshold,
|
threshold=threshold,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
include_url=include_url
|
include_url=include_url
|
||||||
|
|||||||
@ -495,6 +495,46 @@ class DataService:
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def get_available_date_range(self) -> Tuple[Optional[datetime], Optional[datetime]]:
|
||||||
|
"""
|
||||||
|
扫描 output 目录,返回实际可用的日期范围
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(最早日期, 最新日期) 元组,如果没有数据则返回 (None, None)
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> service = DataService()
|
||||||
|
>>> earliest, latest = service.get_available_date_range()
|
||||||
|
>>> print(f"可用日期范围:{earliest} 至 {latest}")
|
||||||
|
"""
|
||||||
|
output_dir = self.parser.project_root / "output"
|
||||||
|
|
||||||
|
if not output_dir.exists():
|
||||||
|
return (None, None)
|
||||||
|
|
||||||
|
available_dates = []
|
||||||
|
|
||||||
|
# 遍历日期文件夹
|
||||||
|
for date_folder in output_dir.iterdir():
|
||||||
|
if date_folder.is_dir() and not date_folder.name.startswith('.'):
|
||||||
|
# 解析日期(格式: YYYY年MM月DD日)
|
||||||
|
try:
|
||||||
|
date_match = re.match(r'(\d{4})年(\d{2})月(\d{2})日', date_folder.name)
|
||||||
|
if date_match:
|
||||||
|
folder_date = datetime(
|
||||||
|
int(date_match.group(1)),
|
||||||
|
int(date_match.group(2)),
|
||||||
|
int(date_match.group(3))
|
||||||
|
)
|
||||||
|
available_dates.append(folder_date)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not available_dates:
|
||||||
|
return (None, None)
|
||||||
|
|
||||||
|
return (min(available_dates), max(available_dates))
|
||||||
|
|
||||||
def get_system_status(self) -> Dict:
|
def get_system_status(self) -> Dict:
|
||||||
"""
|
"""
|
||||||
获取系统运行状态
|
获取系统运行状态
|
||||||
|
|||||||
@ -157,11 +157,10 @@ class AnalyticsTools:
|
|||||||
self,
|
self,
|
||||||
topic: str,
|
topic: str,
|
||||||
analysis_type: str = "trend",
|
analysis_type: str = "trend",
|
||||||
time_range: str = "7d",
|
date_range: Optional[Dict[str, str]] = None,
|
||||||
granularity: str = "day",
|
granularity: str = "day",
|
||||||
threshold: float = 3.0,
|
threshold: float = 3.0,
|
||||||
time_window: int = 24,
|
time_window: int = 24,
|
||||||
lookback_days: int = 7,
|
|
||||||
lookahead_hours: int = 6,
|
lookahead_hours: int = 6,
|
||||||
confidence_threshold: float = 0.7
|
confidence_threshold: float = 0.7
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
@ -175,11 +174,12 @@ class AnalyticsTools:
|
|||||||
- "lifecycle": 生命周期分析(从出现到消失的完整周期)
|
- "lifecycle": 生命周期分析(从出现到消失的完整周期)
|
||||||
- "viral": 异常热度检测(识别突然爆火的话题)
|
- "viral": 异常热度检测(识别突然爆火的话题)
|
||||||
- "predict": 话题预测(预测未来可能的热点)
|
- "predict": 话题预测(预测未来可能的热点)
|
||||||
time_range: 时间范围(trend模式),默认"7d"(7d/24h/1w/1m/2m)
|
date_range: 日期范围(trend和lifecycle模式),可选
|
||||||
|
- **格式**: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
||||||
|
- **默认**: 不指定时默认分析最近7天
|
||||||
granularity: 时间粒度(trend模式),默认"day"(hour/day)
|
granularity: 时间粒度(trend模式),默认"day"(hour/day)
|
||||||
threshold: 热度突增倍数阈值(viral模式),默认3.0
|
threshold: 热度突增倍数阈值(viral模式),默认3.0
|
||||||
time_window: 检测时间窗口小时数(viral模式),默认24
|
time_window: 检测时间窗口小时数(viral模式),默认24
|
||||||
lookback_days: 回溯天数(lifecycle模式),默认7
|
|
||||||
lookahead_hours: 预测未来小时数(predict模式),默认6
|
lookahead_hours: 预测未来小时数(predict模式),默认6
|
||||||
confidence_threshold: 置信度阈值(predict模式),默认0.7
|
confidence_threshold: 置信度阈值(predict模式),默认0.7
|
||||||
|
|
||||||
@ -187,8 +187,8 @@ class AnalyticsTools:
|
|||||||
趋势分析结果字典
|
趋势分析结果字典
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
- analyze_topic_trend_unified(topic="人工智能", analysis_type="trend", time_range="7d")
|
- analyze_topic_trend_unified(topic="人工智能", analysis_type="trend", date_range={"start": "2025-10-18", "end": "2025-10-25"})
|
||||||
- analyze_topic_trend_unified(topic="特斯拉", analysis_type="lifecycle", lookback_days=7)
|
- analyze_topic_trend_unified(topic="特斯拉", analysis_type="lifecycle", date_range={"start": "2025-10-18", "end": "2025-10-25"})
|
||||||
- analyze_topic_trend_unified(topic="比特币", analysis_type="viral", threshold=3.0)
|
- analyze_topic_trend_unified(topic="比特币", analysis_type="viral", threshold=3.0)
|
||||||
- analyze_topic_trend_unified(topic="ChatGPT", analysis_type="predict", lookahead_hours=6)
|
- analyze_topic_trend_unified(topic="ChatGPT", analysis_type="predict", lookahead_hours=6)
|
||||||
"""
|
"""
|
||||||
@ -206,13 +206,13 @@ class AnalyticsTools:
|
|||||||
if analysis_type == "trend":
|
if analysis_type == "trend":
|
||||||
return self.get_topic_trend_analysis(
|
return self.get_topic_trend_analysis(
|
||||||
topic=topic,
|
topic=topic,
|
||||||
time_range=time_range,
|
date_range=date_range,
|
||||||
granularity=granularity
|
granularity=granularity
|
||||||
)
|
)
|
||||||
elif analysis_type == "lifecycle":
|
elif analysis_type == "lifecycle":
|
||||||
return self.analyze_topic_lifecycle(
|
return self.analyze_topic_lifecycle(
|
||||||
topic=topic,
|
topic=topic,
|
||||||
lookback_days=lookback_days
|
date_range=date_range
|
||||||
)
|
)
|
||||||
elif analysis_type == "viral":
|
elif analysis_type == "viral":
|
||||||
# viral模式不需要topic参数,使用通用检测
|
# viral模式不需要topic参数,使用通用检测
|
||||||
@ -244,7 +244,7 @@ class AnalyticsTools:
|
|||||||
def get_topic_trend_analysis(
|
def get_topic_trend_analysis(
|
||||||
self,
|
self,
|
||||||
topic: str,
|
topic: str,
|
||||||
time_range: str = "7d",
|
date_range: Optional[Dict[str, str]] = None,
|
||||||
granularity: str = "day"
|
granularity: str = "day"
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
"""
|
"""
|
||||||
@ -252,7 +252,9 @@ class AnalyticsTools:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
topic: 话题关键词
|
topic: 话题关键词
|
||||||
time_range: 时间范围,格式:7d(7天)、24h(24小时)、1w(1周)、1m(1个月)、2m(2个月)
|
date_range: 日期范围(可选)
|
||||||
|
- **格式**: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
||||||
|
- **默认**: 不指定时默认分析最近7天
|
||||||
granularity: 时间粒度,仅支持 day(天)
|
granularity: 时间粒度,仅支持 day(天)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -264,20 +266,20 @@ class AnalyticsTools:
|
|||||||
- "查看'比特币'过去一周的热度变化"
|
- "查看'比特币'过去一周的热度变化"
|
||||||
- "看看'iPhone'最近7天的趋势如何"
|
- "看看'iPhone'最近7天的趋势如何"
|
||||||
- "分析'特斯拉'最近一个月的热度趋势"
|
- "分析'特斯拉'最近一个月的热度趋势"
|
||||||
- "查看'ChatGPT'过去2个月的趋势变化"
|
- "查看'ChatGPT'2024年12月的趋势变化"
|
||||||
|
|
||||||
代码调用示例:
|
代码调用示例:
|
||||||
>>> tools = AnalyticsTools()
|
>>> tools = AnalyticsTools()
|
||||||
>>> # 分析7天趋势
|
>>> # 分析7天趋势
|
||||||
>>> result = tools.get_topic_trend_analysis(
|
>>> result = tools.get_topic_trend_analysis(
|
||||||
... topic="人工智能",
|
... topic="人工智能",
|
||||||
... time_range="7d",
|
... date_range={"start": "2025-10-18", "end": "2025-10-25"},
|
||||||
... granularity="day"
|
... granularity="day"
|
||||||
... )
|
... )
|
||||||
>>> # 分析1个月趋势
|
>>> # 分析历史月份趋势
|
||||||
>>> result = tools.get_topic_trend_analysis(
|
>>> result = tools.get_topic_trend_analysis(
|
||||||
... topic="特斯拉",
|
... topic="特斯拉",
|
||||||
... time_range="1m",
|
... date_range={"start": "2024-12-01", "end": "2024-12-31"},
|
||||||
... granularity="day"
|
... granularity="day"
|
||||||
... )
|
... )
|
||||||
>>> print(result['trend_data'])
|
>>> print(result['trend_data'])
|
||||||
@ -294,15 +296,21 @@ class AnalyticsTools:
|
|||||||
suggestion="当前仅支持 'day' 粒度,因为底层数据按天聚合"
|
suggestion="当前仅支持 'day' 粒度,因为底层数据按天聚合"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 解析时间范围
|
# 处理日期范围(不指定时默认最近7天)
|
||||||
days = self._parse_time_range(time_range)
|
if date_range:
|
||||||
|
from ..utils.validators import validate_date_range
|
||||||
|
date_range_tuple = validate_date_range(date_range)
|
||||||
|
start_date, end_date = date_range_tuple
|
||||||
|
else:
|
||||||
|
# 默认最近7天
|
||||||
|
end_date = datetime.now()
|
||||||
|
start_date = end_date - timedelta(days=6)
|
||||||
|
|
||||||
# 收集趋势数据
|
# 收集趋势数据
|
||||||
trend_data = []
|
trend_data = []
|
||||||
start_date = datetime.now() - timedelta(days=days)
|
|
||||||
current_date = start_date
|
current_date = start_date
|
||||||
|
|
||||||
while current_date <= datetime.now():
|
while current_date <= end_date:
|
||||||
try:
|
try:
|
||||||
all_titles, _, _ = self.data_service.parser.read_all_titles_for_date(
|
all_titles, _, _ = self.data_service.parser.read_all_titles_for_date(
|
||||||
date=current_date
|
date=current_date
|
||||||
@ -336,6 +344,7 @@ class AnalyticsTools:
|
|||||||
|
|
||||||
# 计算趋势指标
|
# 计算趋势指标
|
||||||
counts = [item["count"] for item in trend_data]
|
counts = [item["count"] for item in trend_data]
|
||||||
|
total_days = (end_date - start_date).days + 1
|
||||||
|
|
||||||
if len(counts) >= 2:
|
if len(counts) >= 2:
|
||||||
# 计算涨跌幅度
|
# 计算涨跌幅度
|
||||||
@ -359,7 +368,11 @@ class AnalyticsTools:
|
|||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"topic": topic,
|
"topic": topic,
|
||||||
"time_range": time_range,
|
"date_range": {
|
||||||
|
"start": start_date.strftime("%Y-%m-%d"),
|
||||||
|
"end": end_date.strftime("%Y-%m-%d"),
|
||||||
|
"total_days": total_days
|
||||||
|
},
|
||||||
"granularity": granularity,
|
"granularity": granularity,
|
||||||
"trend_data": trend_data,
|
"trend_data": trend_data,
|
||||||
"statistics": {
|
"statistics": {
|
||||||
@ -1452,14 +1465,16 @@ class AnalyticsTools:
|
|||||||
def analyze_topic_lifecycle(
|
def analyze_topic_lifecycle(
|
||||||
self,
|
self,
|
||||||
topic: str,
|
topic: str,
|
||||||
lookback_days: int = 7
|
date_range: Optional[Dict[str, str]] = None
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
"""
|
"""
|
||||||
话题生命周期分析 - 追踪话题从出现到消失的完整周期
|
话题生命周期分析 - 追踪话题从出现到消失的完整周期
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
topic: 话题关键词
|
topic: 话题关键词
|
||||||
lookback_days: 回溯天数
|
date_range: 日期范围(可选)
|
||||||
|
- **格式**: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
||||||
|
- **默认**: 不指定时默认分析最近7天
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
话题生命周期分析结果
|
话题生命周期分析结果
|
||||||
@ -1474,21 +1489,28 @@ class AnalyticsTools:
|
|||||||
>>> tools = AnalyticsTools()
|
>>> tools = AnalyticsTools()
|
||||||
>>> result = tools.analyze_topic_lifecycle(
|
>>> result = tools.analyze_topic_lifecycle(
|
||||||
... topic="人工智能",
|
... topic="人工智能",
|
||||||
... lookback_days=7
|
... date_range={"start": "2025-10-18", "end": "2025-10-25"}
|
||||||
... )
|
... )
|
||||||
>>> print(result['lifecycle_stage'])
|
>>> print(result['lifecycle_stage'])
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# 参数验证
|
# 参数验证
|
||||||
topic = validate_keyword(topic)
|
topic = validate_keyword(topic)
|
||||||
lookback_days = validate_limit(lookback_days, default=7, max_limit=30)
|
|
||||||
|
# 处理日期范围(不指定时默认最近7天)
|
||||||
|
if date_range:
|
||||||
|
from ..utils.validators import validate_date_range
|
||||||
|
date_range_tuple = validate_date_range(date_range)
|
||||||
|
start_date, end_date = date_range_tuple
|
||||||
|
else:
|
||||||
|
# 默认最近7天
|
||||||
|
end_date = datetime.now()
|
||||||
|
start_date = end_date - timedelta(days=6)
|
||||||
|
|
||||||
# 收集话题历史数据
|
# 收集话题历史数据
|
||||||
lifecycle_data = []
|
lifecycle_data = []
|
||||||
start_date = datetime.now() - timedelta(days=lookback_days)
|
|
||||||
|
|
||||||
current_date = start_date
|
current_date = start_date
|
||||||
while current_date <= datetime.now():
|
while current_date <= end_date:
|
||||||
try:
|
try:
|
||||||
all_titles, _, _ = self.data_service.parser.read_all_titles_for_date(
|
all_titles, _, _ = self.data_service.parser.read_all_titles_for_date(
|
||||||
date=current_date
|
date=current_date
|
||||||
@ -1514,12 +1536,16 @@ class AnalyticsTools:
|
|||||||
|
|
||||||
current_date += timedelta(days=1)
|
current_date += timedelta(days=1)
|
||||||
|
|
||||||
|
# 计算分析天数
|
||||||
|
total_days = (end_date - start_date).days + 1
|
||||||
|
|
||||||
# 分析生命周期阶段
|
# 分析生命周期阶段
|
||||||
counts = [item["count"] for item in lifecycle_data]
|
counts = [item["count"] for item in lifecycle_data]
|
||||||
|
|
||||||
if not any(counts):
|
if not any(counts):
|
||||||
|
time_desc = f"{start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}"
|
||||||
raise DataNotFoundError(
|
raise DataNotFoundError(
|
||||||
f"在过去 {lookback_days} 天内未找到话题 '{topic}'",
|
f"在 {time_desc} 内未找到话题 '{topic}'",
|
||||||
suggestion="请尝试其他话题或扩大时间范围"
|
suggestion="请尝试其他话题或扩大时间范围"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1554,7 +1580,7 @@ class AnalyticsTools:
|
|||||||
|
|
||||||
if active_days <= 2 and max_count > avg_count * 2:
|
if active_days <= 2 and max_count > avg_count * 2:
|
||||||
topic_type = "昙花一现"
|
topic_type = "昙花一现"
|
||||||
elif active_days >= lookback_days * 0.6:
|
elif active_days >= total_days * 0.6:
|
||||||
topic_type = "持续热点"
|
topic_type = "持续热点"
|
||||||
else:
|
else:
|
||||||
topic_type = "周期性热点"
|
topic_type = "周期性热点"
|
||||||
@ -1562,7 +1588,11 @@ class AnalyticsTools:
|
|||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"topic": topic,
|
"topic": topic,
|
||||||
"lookback_days": lookback_days,
|
"date_range": {
|
||||||
|
"start": start_date.strftime("%Y-%m-%d"),
|
||||||
|
"end": end_date.strftime("%Y-%m-%d"),
|
||||||
|
"total_days": total_days
|
||||||
|
},
|
||||||
"lifecycle_data": lifecycle_data,
|
"lifecycle_data": lifecycle_data,
|
||||||
"analysis": {
|
"analysis": {
|
||||||
"first_appearance": first_appearance,
|
"first_appearance": first_appearance,
|
||||||
@ -1890,29 +1920,6 @@ class AnalyticsTools:
|
|||||||
|
|
||||||
# ==================== 辅助方法 ====================
|
# ==================== 辅助方法 ====================
|
||||||
|
|
||||||
def _parse_time_range(self, time_range: str) -> int:
|
|
||||||
"""解析时间范围字符串为天数"""
|
|
||||||
match = re.match(r'(\d+)([dhwm])', time_range.lower())
|
|
||||||
if not match:
|
|
||||||
raise InvalidParameterError(
|
|
||||||
f"无效的时间范围格式: {time_range}",
|
|
||||||
suggestion="格式示例:7d(7天)、24h(24小时)、1w(1周)、1m(1个月)、2m(2个月)"
|
|
||||||
)
|
|
||||||
|
|
||||||
value = int(match.group(1))
|
|
||||||
unit = match.group(2)
|
|
||||||
|
|
||||||
if unit == 'h':
|
|
||||||
return max(1, value // 24) # 转换为天数
|
|
||||||
elif unit == 'd':
|
|
||||||
return value
|
|
||||||
elif unit == 'w':
|
|
||||||
return value * 7
|
|
||||||
elif unit == 'm':
|
|
||||||
return value * 30 # 1个月按30天计算
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
||||||
def _extract_keywords(self, title: str, min_length: int = 2) -> List[str]:
|
def _extract_keywords(self, title: str, min_length: int = 2) -> List[str]:
|
||||||
"""
|
"""
|
||||||
从标题中提取关键词(简单实现)
|
从标题中提取关键词(简单实现)
|
||||||
|
|||||||
@ -55,8 +55,11 @@ class SearchTools:
|
|||||||
- "keyword": 精确关键词匹配(默认)
|
- "keyword": 精确关键词匹配(默认)
|
||||||
- "fuzzy": 模糊内容匹配(使用相似度算法)
|
- "fuzzy": 模糊内容匹配(使用相似度算法)
|
||||||
- "entity": 实体名称搜索(自动按权重排序)
|
- "entity": 实体名称搜索(自动按权重排序)
|
||||||
date_range: 日期范围,格式: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
date_range: 日期范围(可选)
|
||||||
不指定则默认查询今天
|
- **格式**: {"start": "YYYY-MM-DD", "end": "YYYY-MM-DD"}
|
||||||
|
- **示例**: {"start": "2025-01-01", "end": "2025-01-07"}
|
||||||
|
- **默认**: 不指定时默认查询今天
|
||||||
|
- **注意**: start和end可以相同(表示单日查询)
|
||||||
platforms: 平台过滤列表,如 ['zhihu', 'weibo']
|
platforms: 平台过滤列表,如 ['zhihu', 'weibo']
|
||||||
limit: 返回条数限制,默认50
|
limit: 返回条数限制,默认50
|
||||||
sort_by: 排序方式,可选值:
|
sort_by: 排序方式,可选值:
|
||||||
@ -73,7 +76,7 @@ class SearchTools:
|
|||||||
- search_news_unified(query="人工智能", search_mode="keyword")
|
- search_news_unified(query="人工智能", search_mode="keyword")
|
||||||
- search_news_unified(query="特斯拉降价", search_mode="fuzzy", threshold=0.4)
|
- search_news_unified(query="特斯拉降价", search_mode="fuzzy", threshold=0.4)
|
||||||
- search_news_unified(query="马斯克", search_mode="entity", limit=20)
|
- search_news_unified(query="马斯克", search_mode="entity", limit=20)
|
||||||
- search_news_unified(query="iPhone 16发布", search_mode="keyword")
|
- search_news_unified(query="iPhone 16", date_range={"start": "2025-01-01", "end": "2025-01-07"})
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# 参数验证
|
# 参数验证
|
||||||
@ -100,8 +103,22 @@ class SearchTools:
|
|||||||
date_range_tuple = validate_date_range(date_range)
|
date_range_tuple = validate_date_range(date_range)
|
||||||
start_date, end_date = date_range_tuple
|
start_date, end_date = date_range_tuple
|
||||||
else:
|
else:
|
||||||
# 默认今天
|
# 不指定日期时,使用最新可用数据日期(而非 datetime.now())
|
||||||
start_date = end_date = datetime.now()
|
earliest, latest = self.data_service.get_available_date_range()
|
||||||
|
|
||||||
|
if latest is None:
|
||||||
|
# 没有任何可用数据
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": {
|
||||||
|
"code": "NO_DATA_AVAILABLE",
|
||||||
|
"message": "output 目录下没有可用的新闻数据",
|
||||||
|
"suggestion": "请先运行爬虫生成数据,或检查 output 目录"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 使用最新可用日期
|
||||||
|
start_date = end_date = latest
|
||||||
|
|
||||||
# 收集所有匹配的新闻
|
# 收集所有匹配的新闻
|
||||||
all_matches = []
|
all_matches = []
|
||||||
@ -137,16 +154,34 @@ class SearchTools:
|
|||||||
current_date += timedelta(days=1)
|
current_date += timedelta(days=1)
|
||||||
|
|
||||||
if not all_matches:
|
if not all_matches:
|
||||||
time_desc = "今天" if start_date == end_date else f"{start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}"
|
# 获取可用日期范围用于错误提示
|
||||||
return {
|
earliest, latest = self.data_service.get_available_date_range()
|
||||||
|
|
||||||
|
# 判断时间范围描述
|
||||||
|
if start_date.date() == datetime.now().date() and start_date == end_date:
|
||||||
|
time_desc = "今天"
|
||||||
|
elif start_date == end_date:
|
||||||
|
time_desc = start_date.strftime("%Y-%m-%d")
|
||||||
|
else:
|
||||||
|
time_desc = f"{start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}"
|
||||||
|
|
||||||
|
# 构建错误消息
|
||||||
|
if earliest and latest:
|
||||||
|
available_desc = f"{earliest.strftime('%Y-%m-%d')} 至 {latest.strftime('%Y-%m-%d')}"
|
||||||
|
message = f"未找到匹配的新闻(查询范围: {time_desc},可用数据: {available_desc})"
|
||||||
|
else:
|
||||||
|
message = f"未找到匹配的新闻({time_desc})"
|
||||||
|
|
||||||
|
result = {
|
||||||
"success": True,
|
"success": True,
|
||||||
"results": [],
|
"results": [],
|
||||||
"total": 0,
|
"total": 0,
|
||||||
"query": query,
|
"query": query,
|
||||||
"search_mode": search_mode,
|
"search_mode": search_mode,
|
||||||
"time_range": time_desc,
|
"time_range": time_desc,
|
||||||
"message": f"未找到匹配的新闻({time_desc})"
|
"message": message
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
# 统一排序逻辑
|
# 统一排序逻辑
|
||||||
if sort_by == "relevance":
|
if sort_by == "relevance":
|
||||||
@ -160,8 +195,10 @@ class SearchTools:
|
|||||||
# 限制返回数量
|
# 限制返回数量
|
||||||
results = all_matches[:limit]
|
results = all_matches[:limit]
|
||||||
|
|
||||||
# 构建时间范围描述
|
# 构建时间范围描述(正确判断是否为今天)
|
||||||
if start_date == end_date:
|
if start_date.date() == datetime.now().date() and start_date == end_date:
|
||||||
|
time_range_desc = "今天"
|
||||||
|
elif start_date == end_date:
|
||||||
time_range_desc = start_date.strftime("%Y-%m-%d")
|
time_range_desc = start_date.strftime("%Y-%m-%d")
|
||||||
else:
|
else:
|
||||||
time_range_desc = f"{start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}"
|
time_range_desc = f"{start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}"
|
||||||
@ -457,7 +494,7 @@ class SearchTools:
|
|||||||
def search_related_news_history(
|
def search_related_news_history(
|
||||||
self,
|
self,
|
||||||
reference_text: str,
|
reference_text: str,
|
||||||
time_range: str = "yesterday",
|
time_preset: str = "yesterday",
|
||||||
start_date: Optional[datetime] = None,
|
start_date: Optional[datetime] = None,
|
||||||
end_date: Optional[datetime] = None,
|
end_date: Optional[datetime] = None,
|
||||||
threshold: float = 0.4,
|
threshold: float = 0.4,
|
||||||
@ -469,13 +506,13 @@ class SearchTools:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
reference_text: 参考新闻标题或内容
|
reference_text: 参考新闻标题或内容
|
||||||
time_range: 时间范围预设值,可选:
|
time_preset: 时间范围预设值,可选:
|
||||||
- "yesterday": 昨天
|
- "yesterday": 昨天
|
||||||
- "last_week": 上周 (7天)
|
- "last_week": 上周 (7天)
|
||||||
- "last_month": 上个月 (30天)
|
- "last_month": 上个月 (30天)
|
||||||
- "custom": 自定义日期范围(需要提供 start_date 和 end_date)
|
- "custom": 自定义日期范围(需要提供 start_date 和 end_date)
|
||||||
start_date: 自定义开始日期(仅当 time_range="custom" 时有效)
|
start_date: 自定义开始日期(仅当 time_preset="custom" 时有效)
|
||||||
end_date: 自定义结束日期(仅当 time_range="custom" 时有效)
|
end_date: 自定义结束日期(仅当 time_preset="custom" 时有效)
|
||||||
threshold: 相似度阈值 (0-1之间),默认0.4
|
threshold: 相似度阈值 (0-1之间),默认0.4
|
||||||
limit: 返回条数限制,默认50
|
limit: 返回条数限制,默认50
|
||||||
include_url: 是否包含URL链接,默认False(节省token)
|
include_url: 是否包含URL链接,默认False(节省token)
|
||||||
@ -487,7 +524,7 @@ class SearchTools:
|
|||||||
>>> tools = SearchTools()
|
>>> tools = SearchTools()
|
||||||
>>> result = tools.search_related_news_history(
|
>>> result = tools.search_related_news_history(
|
||||||
... reference_text="人工智能技术突破",
|
... reference_text="人工智能技术突破",
|
||||||
... time_range="last_week",
|
... time_preset="last_week",
|
||||||
... threshold=0.4,
|
... threshold=0.4,
|
||||||
... limit=50
|
... limit=50
|
||||||
... )
|
... )
|
||||||
@ -503,16 +540,16 @@ class SearchTools:
|
|||||||
# 确定查询日期范围
|
# 确定查询日期范围
|
||||||
today = datetime.now()
|
today = datetime.now()
|
||||||
|
|
||||||
if time_range == "yesterday":
|
if time_preset == "yesterday":
|
||||||
search_start = today - timedelta(days=1)
|
search_start = today - timedelta(days=1)
|
||||||
search_end = today - timedelta(days=1)
|
search_end = today - timedelta(days=1)
|
||||||
elif time_range == "last_week":
|
elif time_preset == "last_week":
|
||||||
search_start = today - timedelta(days=7)
|
search_start = today - timedelta(days=7)
|
||||||
search_end = today - timedelta(days=1)
|
search_end = today - timedelta(days=1)
|
||||||
elif time_range == "last_month":
|
elif time_preset == "last_month":
|
||||||
search_start = today - timedelta(days=30)
|
search_start = today - timedelta(days=30)
|
||||||
search_end = today - timedelta(days=1)
|
search_end = today - timedelta(days=1)
|
||||||
elif time_range == "custom":
|
elif time_preset == "custom":
|
||||||
if not start_date or not end_date:
|
if not start_date or not end_date:
|
||||||
raise InvalidParameterError(
|
raise InvalidParameterError(
|
||||||
"自定义时间范围需要提供 start_date 和 end_date",
|
"自定义时间范围需要提供 start_date 和 end_date",
|
||||||
@ -522,7 +559,7 @@ class SearchTools:
|
|||||||
search_end = end_date
|
search_end = end_date
|
||||||
else:
|
else:
|
||||||
raise InvalidParameterError(
|
raise InvalidParameterError(
|
||||||
f"不支持的时间范围: {time_range}",
|
f"不支持的时间范围: {time_preset}",
|
||||||
suggestion="请使用 'yesterday', 'last_week', 'last_month' 或 'custom'"
|
suggestion="请使用 'yesterday', 'last_week', 'last_month' 或 'custom'"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -600,7 +637,7 @@ class SearchTools:
|
|||||||
"results": [],
|
"results": [],
|
||||||
"total": 0,
|
"total": 0,
|
||||||
"query": reference_text,
|
"query": reference_text,
|
||||||
"time_range": time_range,
|
"time_preset": time_preset,
|
||||||
"date_range": {
|
"date_range": {
|
||||||
"start": search_start.strftime("%Y-%m-%d"),
|
"start": search_start.strftime("%Y-%m-%d"),
|
||||||
"end": search_end.strftime("%Y-%m-%d")
|
"end": search_end.strftime("%Y-%m-%d")
|
||||||
@ -627,7 +664,7 @@ class SearchTools:
|
|||||||
"threshold": threshold,
|
"threshold": threshold,
|
||||||
"reference_text": reference_text,
|
"reference_text": reference_text,
|
||||||
"reference_keywords": reference_keywords,
|
"reference_keywords": reference_keywords,
|
||||||
"time_range": time_range,
|
"time_preset": time_preset,
|
||||||
"date_range": {
|
"date_range": {
|
||||||
"start": search_start.strftime("%Y-%m-%d"),
|
"start": search_start.strftime("%Y-%m-%d"),
|
||||||
"end": search_end.strftime("%Y-%m-%d")
|
"end": search_end.strftime("%Y-%m-%d")
|
||||||
|
|||||||
@ -179,6 +179,33 @@ def validate_date_range(date_range: Optional[dict]) -> Optional[tuple]:
|
|||||||
suggestion=f"start: {start_str}, end: {end_str}"
|
suggestion=f"start: {start_str}, end: {end_str}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 检查日期是否在未来
|
||||||
|
today = datetime.now().date()
|
||||||
|
if start_date.date() > today or end_date.date() > today:
|
||||||
|
# 获取可用日期范围提示
|
||||||
|
try:
|
||||||
|
from ..services.data_service import DataService
|
||||||
|
data_service = DataService()
|
||||||
|
earliest, latest = data_service.get_available_date_range()
|
||||||
|
|
||||||
|
if earliest and latest:
|
||||||
|
available_range = f"{earliest.strftime('%Y-%m-%d')} 至 {latest.strftime('%Y-%m-%d')}"
|
||||||
|
else:
|
||||||
|
available_range = "无可用数据"
|
||||||
|
except Exception:
|
||||||
|
available_range = "未知(请检查 output 目录)"
|
||||||
|
|
||||||
|
future_dates = []
|
||||||
|
if start_date.date() > today:
|
||||||
|
future_dates.append(start_str)
|
||||||
|
if end_date.date() > today and end_str != start_str:
|
||||||
|
future_dates.append(end_str)
|
||||||
|
|
||||||
|
raise InvalidParameterError(
|
||||||
|
f"不允许查询未来日期: {', '.join(future_dates)}(当前日期: {today.strftime('%Y-%m-%d')})",
|
||||||
|
suggestion=f"当前可用数据范围: {available_range}"
|
||||||
|
)
|
||||||
|
|
||||||
return (start_date, end_date)
|
return (start_date, end_date)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "trendradar-mcp"
|
name = "trendradar-mcp"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
description = "TrendRadar MCP Server - 新闻热点聚合工具"
|
description = "TrendRadar MCP Server - 新闻热点聚合工具"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"requests>=2.32.5",
|
"requests>=2.32.5,<3.0.0",
|
||||||
"pytz>=2025.2",
|
"pytz>=2025.2,<2026.0",
|
||||||
"PyYAML>=6.0.3",
|
"PyYAML>=6.0.3,<7.0.0",
|
||||||
"fastmcp>=2.12.0",
|
"fastmcp>=2.12.0,<2.14.0",
|
||||||
"websockets>=13.0,<14.0",
|
"websockets>=13.0,<14.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
21
readme.md
21
readme.md
@ -13,7 +13,8 @@
|
|||||||
[](https://github.com/sansan0/TrendRadar/stargazers)
|
[](https://github.com/sansan0/TrendRadar/stargazers)
|
||||||
[](https://github.com/sansan0/TrendRadar/network/members)
|
[](https://github.com/sansan0/TrendRadar/network/members)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://github.com/sansan0/TrendRadar)
|
[](https://github.com/sansan0/TrendRadar)
|
||||||
|
[](https://github.com/sansan0/TrendRadar)
|
||||||
|
|
||||||
[](https://work.weixin.qq.com/)
|
[](https://work.weixin.qq.com/)
|
||||||
[](https://telegram.org/)
|
[](https://telegram.org/)
|
||||||
@ -505,11 +506,22 @@ GitHub 一键 Fork 即可使用,无需编程基础。
|
|||||||
- **大版本升级**:从 v1.x 升级到 v2.y, 建议删除现有 fork 后重新 fork,这样更省力且避免配置冲突
|
- **大版本升级**:从 v1.x 升级到 v2.y, 建议删除现有 fork 后重新 fork,这样更省力且避免配置冲突
|
||||||
|
|
||||||
|
|
||||||
|
### 2025/10/26 - mcp-v1.0.1
|
||||||
|
|
||||||
|
**MCP 模块更新:**
|
||||||
|
- 修复日期查询参数传递错误
|
||||||
|
- 统一所有工具的时间参数格式
|
||||||
|
|
||||||
|
|
||||||
### 2025/10/23 - v3.0.3
|
### 2025/10/23 - v3.0.3
|
||||||
|
|
||||||
- 扩大 ntfy 错误信息显示范围
|
- 扩大 ntfy 错误信息显示范围
|
||||||
|
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>👉 历史更新</strong></summary>
|
||||||
|
|
||||||
|
|
||||||
### 2025/10/21 - v3.0.2
|
### 2025/10/21 - v3.0.2
|
||||||
|
|
||||||
- 修复 ntfy 推送编码问题
|
- 修复 ntfy 推送编码问题
|
||||||
@ -535,9 +547,6 @@ GitHub 一键 Fork 即可使用,无需编程基础。
|
|||||||
- 可选择性使用,无需升级现有部署
|
- 可选择性使用,无需升级现有部署
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><strong>👉 历史更新</strong></summary>
|
|
||||||
|
|
||||||
### 2025/10/15 - v2.4.4
|
### 2025/10/15 - v2.4.4
|
||||||
|
|
||||||
- **更新内容**:
|
- **更新内容**:
|
||||||
@ -1318,6 +1327,10 @@ Cherry Studio 提供 GUI 配置界面,可快速部署。
|
|||||||
"看看'iPhone'话题是昙花一现还是持续热点"
|
"看看'iPhone'话题是昙花一现还是持续热点"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**效果图**:
|
||||||
|
|
||||||
|
<img src="/_image/ai.png" alt="mcp 使用效果图">
|
||||||
|
|
||||||
**详细教程**:[README-MCP-FAQ.md](README-MCP-FAQ.md)
|
**详细教程**:[README-MCP-FAQ.md](README-MCP-FAQ.md)
|
||||||
|
|
||||||
> 如果有部署问题,请带上截图反馈,后续我会根据反馈出个**图文教程**,争取编程零基础、文科生都能配置,届时会更新到我的公众号上
|
> 如果有部署问题,请带上截图反馈,后续我会根据反馈出个**图文教程**,争取编程零基础、文科生都能配置,届时会更新到我的公众号上
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
requests>=2.32.5
|
requests>=2.32.5,<3.0.0
|
||||||
pytz>=2025.2
|
pytz>=2025.2,<2026.0
|
||||||
PyYAML>=6.0.3
|
PyYAML>=6.0.3,<7.0.0
|
||||||
fastmcp>=2.12.0
|
fastmcp>=2.12.0,<2.14.0
|
||||||
websockets>=13.0,<14.0
|
websockets>=13.0,<14.0
|
||||||
Loading…
Reference in New Issue
Block a user