|
@@ -3,6 +3,7 @@
|
|
|
"""
|
|
"""
|
|
|
|
|
|
|
|
from typing import List, Dict, Any, Optional
|
|
from typing import List, Dict, Any, Optional
|
|
|
|
|
+from datetime import datetime, timedelta
|
|
|
from agent.tools import tool, ToolResult, ToolContext
|
|
from agent.tools import tool, ToolResult, ToolContext
|
|
|
|
|
|
|
|
|
|
|
|
@@ -10,51 +11,63 @@ from agent.tools import tool, ToolResult, ToolContext
|
|
|
async def douyin_search(
|
|
async def douyin_search(
|
|
|
keywords: str,
|
|
keywords: str,
|
|
|
max_results: int = 20,
|
|
max_results: int = 20,
|
|
|
- min_views: Optional[int] = None,
|
|
|
|
|
min_likes: Optional[int] = None,
|
|
min_likes: Optional[int] = None,
|
|
|
ctx: Optional[ToolContext] = None,
|
|
ctx: Optional[ToolContext] = None,
|
|
|
) -> ToolResult:
|
|
) -> ToolResult:
|
|
|
"""
|
|
"""
|
|
|
通过关键词搜索抖音视频内容
|
|
通过关键词搜索抖音视频内容
|
|
|
|
|
|
|
|
|
|
+ ⚠️ 注意:当前返回的是模拟数据,仅用于测试和演示
|
|
|
|
|
+ 实际使用时需要对接真实的抖音API
|
|
|
|
|
+
|
|
|
Args:
|
|
Args:
|
|
|
keywords: 搜索关键词
|
|
keywords: 搜索关键词
|
|
|
max_results: 最大结果数,默认20
|
|
max_results: 最大结果数,默认20
|
|
|
- min_views: 最小播放量筛选
|
|
|
|
|
min_likes: 最小点赞数筛选
|
|
min_likes: 最小点赞数筛选
|
|
|
ctx: 工具上下文
|
|
ctx: 工具上下文
|
|
|
|
|
|
|
|
Returns:
|
|
Returns:
|
|
|
- ToolResult: 包含搜索到的视频列表
|
|
|
|
|
|
|
+ ToolResult: 包含搜索到的视频列表(模拟数据)
|
|
|
"""
|
|
"""
|
|
|
# TODO: 实际实现需要调用抖音API或爬虫服务
|
|
# TODO: 实际实现需要调用抖音API或爬虫服务
|
|
|
# 这里返回模拟数据
|
|
# 这里返回模拟数据
|
|
|
|
|
|
|
|
- results = await _mock_douyin_search(keywords, max_results, min_views, min_likes)
|
|
|
|
|
|
|
+ results = await _mock_douyin_search(keywords, max_results, min_likes)
|
|
|
|
|
|
|
|
- summary = f"搜索关键词「{keywords}」,找到 {len(results)} 条视频"
|
|
|
|
|
- if min_views:
|
|
|
|
|
- summary += f"(播放量 ≥ {min_views})"
|
|
|
|
|
|
|
+ summary = f"⚠️ [模拟数据] 搜索关键词「{keywords}」,找到 {len(results)} 条视频"
|
|
|
if min_likes:
|
|
if min_likes:
|
|
|
summary += f"(点赞数 ≥ {min_likes})"
|
|
summary += f"(点赞数 ≥ {min_likes})"
|
|
|
|
|
+ summary += "\n\n⚠️ 注意:以下是模拟数据,仅用于测试。实际使用需对接真实抖音API。"
|
|
|
|
|
|
|
|
# 构建详细输出
|
|
# 构建详细输出
|
|
|
output_lines = [summary, ""]
|
|
output_lines = [summary, ""]
|
|
|
for i, item in enumerate(results[:5], 1): # 只显示前5条
|
|
for i, item in enumerate(results[:5], 1): # 只显示前5条
|
|
|
|
|
+ days_ago = item.get('days_since_publish', 0)
|
|
|
|
|
+ time_desc = f"{days_ago}天前" if days_ago > 0 else "今天"
|
|
|
|
|
+
|
|
|
output_lines.append(f"{i}. {item['title']}")
|
|
output_lines.append(f"{i}. {item['title']}")
|
|
|
output_lines.append(f" 作者: {item['author_name']} (ID: {item['author_id']})")
|
|
output_lines.append(f" 作者: {item['author_name']} (ID: {item['author_id']})")
|
|
|
- output_lines.append(f" 数据: 播放 {item['play_count']:,} | 点赞 {item['like_count']:,} | 分享 {item['share_count']:,}")
|
|
|
|
|
|
|
+ output_lines.append(f" 发布: {time_desc}")
|
|
|
|
|
+ output_lines.append(f" 数据: 点赞 {item['like_count']:,} | 评论 {item['comment_count']:,} | 分享 {item['share_count']:,}")
|
|
|
|
|
+
|
|
|
|
|
+ # 计算互动比例
|
|
|
|
|
+ like_count = item['like_count']
|
|
|
|
|
+ comment_ratio = (item['comment_count'] / like_count * 100) if like_count > 0 else 0
|
|
|
|
|
+ share_ratio = (item['share_count'] / like_count * 100) if like_count > 0 else 0
|
|
|
|
|
+ output_lines.append(f" 互动: 评论率 {comment_ratio:.1f}% | 分享率 {share_ratio:.1f}%")
|
|
|
output_lines.append("")
|
|
output_lines.append("")
|
|
|
|
|
|
|
|
if len(results) > 5:
|
|
if len(results) > 5:
|
|
|
output_lines.append(f"... 还有 {len(results) - 5} 条结果")
|
|
output_lines.append(f"... 还有 {len(results) - 5} 条结果")
|
|
|
|
|
|
|
|
return ToolResult(
|
|
return ToolResult(
|
|
|
- title=f"抖音搜索: {keywords}",
|
|
|
|
|
|
|
+ title=f"[模拟数据] 抖音搜索: {keywords}",
|
|
|
output="\n".join(output_lines),
|
|
output="\n".join(output_lines),
|
|
|
metadata={
|
|
metadata={
|
|
|
"total": len(results),
|
|
"total": len(results),
|
|
|
"items": results,
|
|
"items": results,
|
|
|
|
|
+ "is_mock_data": True,
|
|
|
|
|
+ "warning": "这是模拟数据,实际使用需对接真实API",
|
|
|
},
|
|
},
|
|
|
)
|
|
)
|
|
|
|
|
|
|
@@ -62,23 +75,25 @@ async def douyin_search(
|
|
|
async def _mock_douyin_search(
|
|
async def _mock_douyin_search(
|
|
|
keywords: str,
|
|
keywords: str,
|
|
|
max_results: int,
|
|
max_results: int,
|
|
|
- min_views: Optional[int],
|
|
|
|
|
min_likes: Optional[int],
|
|
min_likes: Optional[int],
|
|
|
) -> List[Dict[str, Any]]:
|
|
) -> List[Dict[str, Any]]:
|
|
|
"""模拟抖音搜索(实际应调用真实API)"""
|
|
"""模拟抖音搜索(实际应调用真实API)"""
|
|
|
|
|
|
|
|
- # 模拟数据
|
|
|
|
|
|
|
+ now = datetime.now()
|
|
|
|
|
+
|
|
|
|
|
+ # 模拟数据(包含不同时效性的内容)
|
|
|
mock_data = [
|
|
mock_data = [
|
|
|
{
|
|
{
|
|
|
"video_id": "7234567890123456789",
|
|
"video_id": "7234567890123456789",
|
|
|
"title": f"感人至深!{keywords}相关视频1",
|
|
"title": f"感人至深!{keywords}相关视频1",
|
|
|
"author_id": "user_001",
|
|
"author_id": "user_001",
|
|
|
"author_name": "感动中国",
|
|
"author_name": "感动中国",
|
|
|
- "play_count": 150000,
|
|
|
|
|
"like_count": 8000,
|
|
"like_count": 8000,
|
|
|
"comment_count": 1200,
|
|
"comment_count": 1200,
|
|
|
"share_count": 500,
|
|
"share_count": 500,
|
|
|
- "create_time": "2024-03-01 10:00:00",
|
|
|
|
|
|
|
+ "collect_count": 1500,
|
|
|
|
|
+ "create_time": (now - timedelta(days=3)).strftime("%Y-%m-%d %H:%M:%S"),
|
|
|
|
|
+ "days_since_publish": 3,
|
|
|
"video_url": "https://www.douyin.com/video/7234567890123456789",
|
|
"video_url": "https://www.douyin.com/video/7234567890123456789",
|
|
|
"cover_url": "https://example.com/cover1.jpg",
|
|
"cover_url": "https://example.com/cover1.jpg",
|
|
|
},
|
|
},
|
|
@@ -87,11 +102,12 @@ async def _mock_douyin_search(
|
|
|
"title": f"{keywords}经典片段合集",
|
|
"title": f"{keywords}经典片段合集",
|
|
|
"author_id": "user_002",
|
|
"author_id": "user_002",
|
|
|
"author_name": "历史回忆",
|
|
"author_name": "历史回忆",
|
|
|
- "play_count": 280000,
|
|
|
|
|
"like_count": 15000,
|
|
"like_count": 15000,
|
|
|
"comment_count": 2300,
|
|
"comment_count": 2300,
|
|
|
"share_count": 1200,
|
|
"share_count": 1200,
|
|
|
- "create_time": "2024-03-02 14:30:00",
|
|
|
|
|
|
|
+ "collect_count": 3000,
|
|
|
|
|
+ "create_time": (now - timedelta(days=15)).strftime("%Y-%m-%d %H:%M:%S"),
|
|
|
|
|
+ "days_since_publish": 15,
|
|
|
"video_url": "https://www.douyin.com/video/7234567890123456790",
|
|
"video_url": "https://www.douyin.com/video/7234567890123456790",
|
|
|
"cover_url": "https://example.com/cover2.jpg",
|
|
"cover_url": "https://example.com/cover2.jpg",
|
|
|
},
|
|
},
|
|
@@ -100,21 +116,48 @@ async def _mock_douyin_search(
|
|
|
"title": f"真实{keywords}故事",
|
|
"title": f"真实{keywords}故事",
|
|
|
"author_id": "user_001",
|
|
"author_id": "user_001",
|
|
|
"author_name": "感动中国",
|
|
"author_name": "感动中国",
|
|
|
- "play_count": 95000,
|
|
|
|
|
"like_count": 5200,
|
|
"like_count": 5200,
|
|
|
"comment_count": 800,
|
|
"comment_count": 800,
|
|
|
"share_count": 350,
|
|
"share_count": 350,
|
|
|
- "create_time": "2024-03-03 09:15:00",
|
|
|
|
|
|
|
+ "collect_count": 1000,
|
|
|
|
|
+ "create_time": (now - timedelta(days=45)).strftime("%Y-%m-%d %H:%M:%S"),
|
|
|
|
|
+ "days_since_publish": 45,
|
|
|
"video_url": "https://www.douyin.com/video/7234567890123456791",
|
|
"video_url": "https://www.douyin.com/video/7234567890123456791",
|
|
|
"cover_url": "https://example.com/cover3.jpg",
|
|
"cover_url": "https://example.com/cover3.jpg",
|
|
|
},
|
|
},
|
|
|
|
|
+ {
|
|
|
|
|
+ "video_id": "7234567890123456792",
|
|
|
|
|
+ "title": f"最新{keywords}短片",
|
|
|
|
|
+ "author_id": "user_003",
|
|
|
|
|
+ "author_name": "时代记忆",
|
|
|
|
|
+ "like_count": 3500,
|
|
|
|
|
+ "comment_count": 450,
|
|
|
|
|
+ "share_count": 200,
|
|
|
|
|
+ "collect_count": 800,
|
|
|
|
|
+ "create_time": (now - timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S"),
|
|
|
|
|
+ "days_since_publish": 1,
|
|
|
|
|
+ "video_url": "https://www.douyin.com/video/7234567890123456792",
|
|
|
|
|
+ "cover_url": "https://example.com/cover4.jpg",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "video_id": "7234567890123456793",
|
|
|
|
|
+ "title": f"{keywords}珍贵影像",
|
|
|
|
|
+ "author_id": "user_002",
|
|
|
|
|
+ "author_name": "历史回忆",
|
|
|
|
|
+ "like_count": 2800,
|
|
|
|
|
+ "comment_count": 350,
|
|
|
|
|
+ "share_count": 150,
|
|
|
|
|
+ "collect_count": 600,
|
|
|
|
|
+ "create_time": (now - timedelta(days=120)).strftime("%Y-%m-%d %H:%M:%S"),
|
|
|
|
|
+ "days_since_publish": 120,
|
|
|
|
|
+ "video_url": "https://www.douyin.com/video/7234567890123456793",
|
|
|
|
|
+ "cover_url": "https://example.com/cover5.jpg",
|
|
|
|
|
+ },
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
# 应用筛选条件
|
|
# 应用筛选条件
|
|
|
filtered = []
|
|
filtered = []
|
|
|
for item in mock_data:
|
|
for item in mock_data:
|
|
|
- if min_views and item["play_count"] < min_views:
|
|
|
|
|
- continue
|
|
|
|
|
if min_likes and item["like_count"] < min_likes:
|
|
if min_likes and item["like_count"] < min_likes:
|
|
|
continue
|
|
continue
|
|
|
filtered.append(item)
|
|
filtered.append(item)
|