Claude Skill

ks-ai-feed

快手AI内容日报生成工具。每日自动扫描快手平台AI创作内容,按播放量筛选爆款视频并智能聚类,生成深色主题HTML日报(含封面图、互动数据、视频直链),同步输出AI情报洞察(热度TOP话题、起量信号、核心达人、推荐调查方向)。当用户需要AI快手日报、快手爆款、AI快手热点、快手AI内容、快手AI视频、快手情报时使用。触发词:AI快手日报、快手爆款、快手AI热点、快手情报、快手AI视频。

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download redfox-data-redfox-community-skills_ks-ai-feed-5e7b435.zip · 40 KB
Part of redfox-data/redfox-community — 66 skills

Install

skills CLI npx skills add https://github.com/redfox-data/redfox-community/tree/main/skills/ks-ai-feed
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install redfox-data-redfox-community@llmmart
Git git clone https://github.com/redfox-data/redfox-community.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole redfox-data/redfox-community collection as a plugin from our marketplace. Git is the plain clone.

README

AI快手信息源 / ks-ai-feed


简介

每日自动扫描快手平台AI创作内容,按播放量筛选爆款视频并智能聚类,交付深色主题可视化日报,同步输出AI情报洞察——热度TOP话题、新兴起量信号、核心达人分析与推荐调查方向。

核心价值

  • 精准发现爆款:按播放量与互动数据自动扫描快手AI热门视频,告别逐条翻找。
  • 智能话题聚类:自动识别内容方向并按分类汇总,每日热点分布一目了然。
  • 多维情报洞察:同步输出热度TOP话题、起量信号、达人分析与推荐调查方向,深度把握流量趋势。
  • 可视化日报交付:深色主题页面含封面图、互动数据与视频直链,支持浏览器直接浏览与跳转。
  • 一键订阅追踪:开启每日自动产出,持续追踪快手AI内容动态不遗漏。

适用对象

  • 📊 内容运营 / 自媒体 — 每日掌握快手AI赛道热点,快速获取选题灵感。
  • 🏢 MCN / 品牌方 — 追踪AI内容趋势,识别潜力达人与起量信号。
  • 🔍 行业研究者 — 获取结构化情报,了解快手AI内容生态与流量格局。

功能特性

核心功能

  • 爆款内容发现:按播放量与互动数据筛选快手AI热门视频,精准定位当日高热度内容。
  • 智能话题聚类:自动识别视频内容的话题方向,按分类汇总数量与占比。
  • AI情报洞察:基于智能情报调查员方法论,生成热度TOP话题、新兴起量信号、核心达人、推荐调查方向与跨平台对比建议。
  • 可视化日报:深色主题页面含视频封面图、播放/点赞/评论等互动数据、视频直链,可直接浏览。
  • 一键订阅:支持每日自动产出日报,持续追踪无需手动重复操作。
  • 封面图稳定展示:内置防盗链代理与图片格式自动转换,确保封面图正常加载。

密钥获取与安全说明

  • 本技能需要使用环境变量:REDFOX_API_KEY。
  • REDFOX_API_KEY 由 红狐 hub(https://redfox.hk)提供。
  • 请前往 红狐 hub 注册账号,获取 REDFOX_API_KEY。
  • 配置设备环境变量 REDFOX_API_KEY 后使用本技能。
  • 在提供密钥前,请先确认密钥来源、可用范围、有效期及是否支持重置/撤销。
  • 禁止在代码、提示词、日志或输出文件中硬编码/明文暴露密钥。

使用指南

直接用自然语言描述需求即可,无需记忆命令。

常用说法速查

意图 示例话术 效果
今日日报 「帮我生成今天的快手AI爆款日报」 扫描当日热门内容,输出可视化日报与情报洞察
指定方向 「看看快手AI绘画和AI教程方向最近什么火」 按你关注的关键词聚焦匹配内容
历史回顾 「查看6月10号的快手AI日报」 回溯指定日期的爆款内容与趋势
开启订阅 「帮我开启快手AI日报每日订阅」 每日自动产出一份日报,持续追踪

输出示例

日报完成后你将收到:

  • 分类概览表:按话题聚类展示各分类的视频数量、占比与头部亮点,快速掌握当日风向。
  • AI情报洞察报告:含新兴起量信号(提前捕捉潜力话题)、核心达人(高产+高互动作者)、推荐调查方向(场景+搜索关键词)与跨平台对比建议。
  • 可视化日报页面:深色主题,含封面图、完整互动数据与视频直链,支持浏览器直接浏览。
  • 终端结构化输出:同步以表格形式在对话中展示分类视频与情报摘要。

使用场景

场景 角色 示例问法 收益
每日热点追踪 内容运营 「今天的快手AI日报出来了吗」 快速了解当日AI赛道热门内容与话题分布
选题灵感获取 自媒体博主 「快手最近有哪些AI爆款视频值得参考」 发现热门选题方向与内容创作规律
达人发现 MCN / 品牌方 「最近快手AI领域有哪些活跃达人」 识别高互动创作者,辅助合作决策
趋势预判 行业分析师 「本周快手AI内容有什么新趋势」 捕捉流量风口,提前布局内容方向

重要数据说明

  • 更新时间:每日 15:00 更新前一天的数据。
  • 可查询范围:仅可查询已更新数据的日期(昨天及之前),当天数据通常不可用。
  • 数据不可用时:若目标日期数据尚未更新,系统将自动提示并询问是否查询最新可用日期。

Skill manifest

AI快手信息源

📝 简介

每日自动扫描快手平台AI创作内容,按播放量筛选爆款视频、智能聚类生成深色主题HTML日报,同步输出基于智能情报调查员方法论的AI情报洞察。

✨ 功能特性

功能模块 能力描述 核心价值
爆款发现 按播放量筛选快手AI热门视频 精准定位高热度内容
智能聚类 从内容中自动识别话题方向 每日热点一目了然
AI情报洞察 热度TOP话题、起量信号、达人分析、推荐调查方向 深度洞察流量趋势
可视化日报 深色HTML日报,含封面图、互动数据、视频直链 直观浏览与跳转
一键订阅 --subscribe 开启每日自动产出 持续追踪不遗漏
图片兼容 防盗链代理 + HEIF/HEIC 自动转JPG 封面图稳定展示

🔑 鉴权

前往 redfox.hk/login 注册获取 API Token,然后配置:

方式 命令
环境变量(推荐) export REDFOX_API_KEY=ak_你的密钥
命令行参数 --api-key ak_你的密钥
配置文件 echo '{"api_key":"ak_你的密钥"}' > ~/.qoder/apis/redfox.json

🔌 API 接口规范

批量查询接口

接口地址: POST https://redfox.hk/story/api/parseWork/queryKsAiMsgs/batch

请求头:

X-API-Key: ak_你的API密钥
Content-Type: application/json

请求体:

{
  "keywords": ["AI", "人工智能", "大模型", "GPT", "Agent", "AI绘画", "AI教程"],
  "pageNum": 1,
  "pageSize": 200,
  "source": "AI快手信息源-GitHub",
  "startTime": "2026-06-16 00:00:00",  // 可选
  "endTime": "2026-06-16 23:59:59"      // 可选
}

参数说明:

参数 类型 必填 说明
keywords Array ✅ 关键词数组,支持多关键词批量查询
pageNum Number ✅ 页码,从1开始
pageSize Number ✅ 每页条数,默认200
source String ✅ 来源标识
startTime String ❌ 开始时间 YYYY-MM-DD HH:mm:ss
endTime String ❌ 结束时间 YYYY-MM-DD HH:mm:ss

性能优势:

  • ✅ 一次请求传入所有关键词,减少85%+ API调用
  • ✅ 自动去重合并,数据更全面
  • ✅ 超时时间30秒,适配大批量数据

📊 数据更新规则

  • 更新时间:每日 15:00 更新前一天的数据
  • 可查询日期:仅可查询已更新数据的日期(昨天及之前)
  • 数据不可用时:脚本自动判断目标日期是否已有数据,若尚未更新则提示用户并询问是否查询最新可用日期

🔧 使用方式

# 生成今日爆款日报(含情报洞察)
python3 "$SKILL_PATH/assets/daily_report.py"

# 自定义关注方向
python3 "$SKILL_PATH/assets/daily_report.py" --keywords "AI教程,AI绘画,ChatGPT,AI工具"

# 查看历史某天
python3 "$SKILL_PATH/assets/daily_report.py" --date 2026-06-10

# 订阅 / 取消订阅
python3 "$SKILL_PATH/assets/daily_report.py" --subscribe
python3 "$SKILL_PATH/assets/daily_report.py" --unsubscribe

依赖:pip3 install requests

⚠️ Windows 用户注意:命令中的 python3 需替换为 python,pip3 替换为 pip。

生成的 HTML 日报保存在 ~/Downloads/QoderReports/。终端同步输出分类视频表格 + AI情报洞察。

预览服务

  1. 运行 daily_report.py 时加 --no-open 参数
  2. 单独启动预览服务(后台运行):
    python3 "$SKILL_PATH/assets/preview_server.py"
    
  3. 调用 RunPreview,必须使用 HTML 文件直链地址:http://127.0.0.1:8766/{HTML文件名}

⚠️ RunPreview 必须使用 HTML 文件直链地址(如 http://127.0.0.1:8766/AI快手日报_2026-06-16_150715.html),不可使用根路径 http://127.0.0.1:8766,根路径的 302 重定向会导致空白页面。

内置服务同时提供:静态 HTML 文件服务 + /api/search 搜索代理 + /api/img 图片代理(绕过快手防盗链)。

核心参数

参数 说明 默认值
--keywords 关注的话题方向,逗号分隔 AI,人工智能,大模型,GPT,Agent,AI绘画,AI教程
--count 扫描视频数量 200
--date 指定日期,YYYY-MM-DD 或范围 YYYY-MM-DD~YYYY-MM-DD 今天
--output-dir 输出目录 ~/Downloads/QoderReports
--api-key 指定 API Key —
--subscribe 开启每日订阅 —
--unsubscribe 关闭每日订阅 —
--no-open 不自动打开浏览器 —

🧠 AI情报洞察

基于智能情报调查员方法论,在每日快手爆款内容聚类后同步生成:

洞察模块 内容 价值
热度TOP话题 占比、条数、头部视频 快速掌握当日风向
新兴起量信号 低占比高互动的潜力话题 提前捕捉流量风口
核心达人 高产+高互动作者 锁定关键创作者
推荐调查方向 场景+引擎组合+搜索关键词 一键进入深度调查
跨平台对比建议 同步关注其他平台同话题 全网视角消除偏差

详细调查策略见 engine-strategy.md、investigation-modes.md、investigation-templates.md。

📋 固定输出模式

每次运行日报后,终端与对话输出必须遵循以下结构化格式:

## AI快手信息源 · {日期} 日报

**扫描 {N} 条热门视频,聚类 {M} 个分类**

---

### 分类概览

| 分类 | 数量 | 占比 | 亮点 |
|------|------|------|------|
| #{分类名} | {N}条 | {X}% | 头部视频亮点描述 |

---

### AI情报洞察报告

**一、新兴起量信号**

- 🔥 **#{话题}** — 仅{N}条但均互动{X}+,描述

**二、核心达人**

| 达人 | 作品数 | 总赞 | 亮点 |
|------|--------|------|------|
| @{作者} | {N}条 | {X}w | 描述 |

**三、推荐调查方向**

| 话题 | 调查场景 | 推荐引擎 | 搜索关键词 |
|------|---------|---------|-----------|
| #{话题} | {场景} | 引擎组合 | 关键词1 / 关键词2 |

**四、跨平台对比建议**

- **{话题}** — 建议同步关注抖音、B站、小红书同话题热度

---

**日报地址**:{HTML文件绝对路径}

**预览地址**:http://127.0.0.1:8766/{HTML文件名}

以上格式为强制规范,所有字段不可省略。若某模块无数据则标注"暂无"。

必须执行:日报输出完成后,按以下步骤启动预览:

  1. 后台启动预览服务:python3 "$SKILL_PATH/assets/preview_server.py"
  2. 调用 RunPreview,使用 HTML 文件直链地址 http://127.0.0.1:8766/{HTML文件名}(不可用根路径)

其他资源

Files (redfox-community)
  • assets
    • daily_report.py 57.5 KB
      #!/usr/bin/env python3
      """
      AI快手信息源 — 每日热门内容聚类
      ====================================
      每天扫描快手平台 AI 相关热门视频,自动聚类后生成 HTML 日报。
      
      Usage:
          python3 daily_report.py
          python3 daily_report.py --keywords "AI教程,AI绘画,ChatGPT"
          python3 daily_report.py --subscribe
      """
      
      import argparse
      import io
      import json
      import os
      import re
      import subprocess
      import sys
      import time
      
      # Windows GBK 终端兼容:强制 stdout/stderr 使用 UTF-8
      if sys.stdout.encoding and sys.stdout.encoding.lower() not in ('utf-8', 'utf8'):
          sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
      if sys.stderr.encoding and sys.stderr.encoding.lower() not in ('utf-8', 'utf8'):
          sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
      from collections import Counter, defaultdict
      from datetime import datetime, timedelta
      from http.server import HTTPServer, SimpleHTTPRequestHandler
      from pathlib import Path
      from urllib.parse import urlparse, parse_qs, quote
      
      try:
          from urllib.request import Request, urlopen
          HAS_URLLIB = True
      except ImportError:
          HAS_URLLIB = False
      
      try:
          import requests
          HAS_REQUESTS = True
      except ImportError:
          HAS_REQUESTS = False
      
      # ─── 配置 ─────────────────────────────────────────────────────────────────────────
      API_URL = "https://redfox.hk/story/api/parseWork/queryKsAiMsgs/batch"
      CONFIG_DIR = Path.home() / ".qoder" / "apis"
      CONFIG_FILE = CONFIG_DIR / "redfox.json"
      ENV_KEY = "REDFOX_API_KEY"
      SOURCE = "AI快手信息源-GitHub"
      
      DEFAULT_KEYWORDS = ["AI", "人工智能", "大模型", "GPT", "Agent", "AI绘画", "AI教程"]
      DEFAULT_OUTPUT_DIR = Path.home() / "Downloads" / "QoderReports"
      PAGE_SIZE = 200         # 每页获取200条
      
      # 数据更新规则:每日15:00更新前一天的数据
      DATA_UPDATE_HOUR = 15   # 数据更新时间(小时)
      DATA_UPDATE_MINUTE = 0 # 数据更新时间(分钟)
      
      PLIST_LABEL = "com.qoder.ks-ai-feed"
      PLIST_DIR = Path.home() / "Library" / "LaunchAgents"
      
      # ─── 终端颜色 ──────────────────────────────────────────────────────────────────────
      GREEN = "\033[92m"
      YELLOW = "\033[93m"
      RED = "\033[91m"
      CYAN = "\033[96m"
      BOLD = "\033[1m"
      RESET = "\033[0m"
      
      
      def info(msg):
          print(f"{GREEN}[✓]{RESET} {msg}")
      
      
      def warn(msg):
          print(f"{YELLOW}[!]{RESET} {msg}")
      
      
      def error(msg):
          print(f"{RED}[✗]{RESET} {msg}")
      
      
      def step(msg):
          print(f"{CYAN}[→]{RESET} {msg}")
      
      
      # ─── 数据可用性检查 ──────────────────────────────────────────────────────────────
      def get_latest_available_date():
          """根据数据更新规则计算当前可查询的最新日期。
          
          规则:每日15:00更新前一天的数据。
          - 如果当前时间 >= 15:00,则昨天及之前的数据可用,最新可查日期为昨天
          - 如果当前时间 < 15:00,则前天及之前的数据可用,最新可查日期为前天
          """
          now = datetime.now()
          if now.hour >= DATA_UPDATE_HOUR:
              # 今日15:00后,昨天的数据已更新
              latest = now.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=1)
          else:
              # 今日15:00前,昨天的数据尚未更新,最新是前天
              latest = now.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=2)
          return latest.strftime("%Y-%m-%d")
      
      
      def check_date_available(target_date_str):
          """检查目标日期是否已有数据可用。
          
          Returns:
              (is_available, latest_date_str) - 是否可用,最新可查日期
          """
          latest_date_str = get_latest_available_date()
          try:
              target_date = datetime.strptime(target_date_str, "%Y-%m-%d")
              latest_date = datetime.strptime(latest_date_str, "%Y-%m-%d")
          except ValueError:
              return False, latest_date_str
          
          return target_date <= latest_date, latest_date_str
      
      
      def print_data_unavailable_notice(query_date, latest_date):
          """输出数据不可用提示文案(不自动获取数据,需用户确认)"""
          print(f"\n⚠️ **{query_date} 数据尚未更新**\n")
          print(f"数据更新规则:每日15:00更新前一天的数据")
          print(f"当前可查询的最新日期:{latest_date}\n")
          print(f"是否需要查询 {latest_date} 的数据?")
      
      
      # ─── API Key 管理 ──────────────────────────────────────────────────────────────────
      def get_api_key(cli_key=None):
          """Get API key: CLI arg > env var > config file."""
          if cli_key:
              return cli_key
          env_key = os.environ.get(ENV_KEY)
          if env_key:
              return env_key
          if CONFIG_FILE.exists():
              try:
                  data = json.loads(CONFIG_FILE.read_text())
                  key = data.get("api_key")
                  if key:
                      return key
              except (json.JSONDecodeError, OSError):
                  pass
          return ""
      
      
      # ─── 数据获取 ──────────────────────────────────────────────────────────────────────
      def fetch_batch(session, keywords, page_num, start_time=None, end_time=None):
          """批量获取多个关键词的单页视频数据"""
          payload = {
              "keywords": keywords,  # 传入关键词列表
              "pageNum": page_num,
              "pageSize": PAGE_SIZE,
              "source": SOURCE,
          }
          if start_time:
              payload["startTime"] = start_time
          if end_time:
              payload["endTime"] = end_time
          
          try:
              resp = session.post(API_URL, json=payload, timeout=30)  # 批量查询增加超时时间
              result = resp.json()
          except Exception as e:
              warn(f"批量请求失败 (page={page_num}): {e}")
              return []
      
          code = result.get("code")
          if code == 3108:
              warn("限频,等待 5s...")
              time.sleep(5)
              try:
                  resp = session.post(API_URL, json=payload, timeout=30)
                  result = resp.json()
                  code = result.get("code")
              except Exception:
                  return []
      
          if code not in (200, 2000):
              if code in (3106, 3107):
                  error(f"API Key 错误 (code {code}): {result.get('msg', '')}")
              return []
      
          data = result.get("data", {})
          return data.get("list", [])
      
      
      def fetch_articles(session, keywords, target_count, start_time=None, end_time=None):
          """批量分页获取所有关键词的数据,一次请求传入所有关键词"""
          articles = []
          seen_ids = set()
      
          # 一次性传入所有关键词进行批量查询
          page_num = 1
          total_fetched = 0
          
          while True:
              # 批量请求所有关键词
              page_articles = fetch_batch(session, keywords, page_num, start_time=start_time, end_time=end_time)
              
              if not page_articles:
                  if page_num == 1:
                      warn(f"所有关键词均暂无内容(当前仅搜索 AI 相关快手视频,更多内容请访问 redfox.hk)")
                  break
      
              # 统计本次新增数量
              new_count = 0
              for article in page_articles:
                  pid = article.get("photoId", "")
                  if pid and pid not in seen_ids:
                      seen_ids.add(pid)
                      articles.append(article)
                      new_count += 1
              
              total_fetched += new_count
              
              # 输出进度
              if new_count > 0:
                  print(f"  {CYAN}[→]{RESET} 第{page_num}页: 新增{new_count}条, 累计{len(articles)}条")
      
              # 本页无新数据或返回不足一页,说明已到底
              if new_count == 0 or len(page_articles) < PAGE_SIZE:
                  break
      
              # 达到目标数量
              if len(articles) >= target_count:
                  break
      
              page_num += 1
      
              # 安全上限:最多10页(2000条)
              if page_num > 10:
                  break
      
          return articles
      
      
      # ─── 自动聚类 ──────────────────────────────────────────────────────────────────────
      STOP_WORDS = set("的了是在和与及或但对于从到被将把让给用有这那个也都还又不没"
                       "就才能会要可以怎么什么为什么怎样如何哪些多少一个一些这些那些"
                       "已经正在可能应该必须需要通过进行使用利用根据关于对于由于因为所以"
                       "虽然但是然而因此所以如果那么只要只有无论不管即使不仅而且")
      
      # 过于宽泛的标签,聚类时跳过
      GENERIC_TAGS = {"#AI", "#人工智能", "#ai", "AI", "人工智能", "#科技", "#技术",
                      "#人工智能应用", "#智能", "科技", "技术"}
      
      
      def extract_keywords(title):
          """从标题中提取中文关键词片段"""
          if not title:
              return []
          # 移除标点和特殊字符
          cleaned = re.sub(r'[^\u4e00-\u9fff\w]', ' ', title)
          # 提取 2-4 字中文片段
          segments = re.findall(r'[\u4e00-\u9fff]{2,4}', cleaned)
          # 过滤停用词
          keywords = [s for s in segments if not all(c in STOP_WORDS for c in s)]
          return keywords[:5]
      
      
      def get_article_tags(article):
          """提取视频的所有有效标签(去除泛标签),优先 type 再 topic"""
          tags = []
      
          # type 字段通常更细致(如 #AI热点、#AI教程、#AI大模型)
          atype = (article.get("type") or "").strip()
          if atype:
              for t in re.split(r'[,,]+', atype):
                  t = t.strip()
                  if t and t not in GENERIC_TAGS:
                      tags.append(t)
      
          # topic 字段作为补充(跳过泛标签)
          topic = (article.get("topic") or "").strip()
          if topic:
              for t in re.split(r'[,,\s]+', topic):
                  t = t.strip()
                  if t and t not in GENERIC_TAGS and t not in tags:
                      tags.append(t)
      
          return tags
      
      
      def cluster_articles(articles):
          """基于 type + topic 标签自动聚类,确保分类细致且至少 5 个"""
          # 第一步:为每个视频提取标签,按首个有效标签分组
          topic_groups = defaultdict(list)
      
          for article in articles:
              tags = get_article_tags(article)
              if tags:
                  # 使用第一个非泛标签作为主分类
                  topic_groups[tags[0]].append(article)
              else:
                  topic_groups["其他"].append(article)
      
          # 第二步:如果大组过大(>20%文章),尝试拆分
          total = len(articles)
          split_threshold = max(total * 0.2, 25)
          groups_to_split = {}
          for topic, arts in list(topic_groups.items()):
              if len(arts) > split_threshold and topic != "其他":
                  groups_to_split[topic] = arts
      
          for topic, arts in groups_to_split.items():
              del topic_groups[topic]
              # 用视频的第二标签进行二次拆分
              for article in arts:
                  tags = get_article_tags(article)
                  if len(tags) >= 2:
                      topic_groups[tags[1]].append(article)
                  else:
                      topic_groups[topic].append(article)
      
          # 第三步:合并小组(< 3 篇)
          final_groups = {}
          small_articles = []
      
          for topic, arts in topic_groups.items():
              if len(arts) >= 3:
                  final_groups[topic] = arts
              else:
                  small_articles.extend(arts)
      
          # 小组视频尝试用标签匹配到已有大组
          still_orphan = []
          for article in small_articles:
              tags = get_article_tags(article)
              placed = False
              for tag in tags:
                  if tag in final_groups:
                      final_groups[tag].append(article)
                      placed = True
                      break
              if not placed:
                  still_orphan.append(article)
      
          if still_orphan:
              if "其他" in final_groups:
                  final_groups["其他"].extend(still_orphan)
              else:
                  final_groups["其他"] = still_orphan
      
          # 第四步:对过大的组用标题关键词进一步拆分
          MAX_GROUP_SIZE = max(total * 0.3, 40)
          for _ in range(3):  # 最多拆 3 轮
              oversized = [(t, a) for t, a in final_groups.items() if len(a) > MAX_GROUP_SIZE]
              if not oversized:
                  break
              for topic, arts in oversized:
                  # 用标题中的高频关键词拆分
                  kw_counter = Counter()
                  article_kw_map = {}
                  for article in arts:
                      title = article.get("title", "")
                      kws = extract_keywords(title)
                      article_kw_map[id(article)] = kws
                      for kw in kws:
                          kw_counter[kw] += 1
                  # 找出频次够高的关键词作为子分类
                  common_kws = [kw for kw, cnt in kw_counter.most_common(5)
                                if cnt >= 5 and kw not in topic
                                and f"#{kw}" not in GENERIC_TAGS
                                and kw not in ("人工智能", "智能", "模型", "技术", "应用")]
                  if not common_kws:
                      continue
                  # 用第一个高频词拆出子组
                  split_kw = common_kws[0]
                  new_group = []
                  remaining = []
                  for article in arts:
                      kws = article_kw_map.get(id(article), [])
                      if split_kw in kws:
                          new_group.append(article)
                      else:
                          remaining.append(article)
                  if len(new_group) >= 5:
                      final_groups[f"#{split_kw}"] = new_group
                      final_groups[topic] = remaining
      
          # 第五步:确保至少 5 个分类(如果不够,对最大组继续拆分)
          _split_attempts = 0
          while len(final_groups) < 5 and final_groups and _split_attempts < 10:
              _split_attempts += 1
              largest_topic = max(final_groups, key=lambda k: len(final_groups[k]))
              largest_arts = final_groups[largest_topic]
              if len(largest_arts) < 6:
                  break  # 最大组也太小了,无法再拆
      
              # 从最大组中按第二标签拆出子组
              sub_groups = defaultdict(list)
              remain = []
              for article in largest_arts:
                  tags = get_article_tags(article)
                  second_tag = None
                  for t in tags:
                      if t != largest_topic:
                          second_tag = t
                          break
                  if second_tag:
                      sub_groups[second_tag].append(article)
                  else:
                      remain.append(article)
      
              # 找出最大的子组拆出来
              if sub_groups:
                  best_sub = max(sub_groups, key=lambda k: len(sub_groups[k]))
                  # best_sub 不能与 largest_topic 同名,否则死循环
                  if len(sub_groups[best_sub]) >= 3 and best_sub != largest_topic:
                      final_groups[best_sub] = sub_groups[best_sub]
                      # 更新原组
                      new_arts = remain
                      for k, v in sub_groups.items():
                          if k != best_sub:
                              new_arts.extend(v)
                      final_groups[largest_topic] = new_arts
                      continue
              break  # 无法继续拆分
      
          # 第六步:构建输出,按条数降序(过滤空分类)
          clusters = []
          for category, arts in sorted(final_groups.items(), key=lambda x: -len(x[1])):
              if not arts:  # 跳过空分类
                  continue
              # 按阅读量排序取 top 5
              sorted_arts = sorted(arts, key=lambda a: (a.get("readCount") or 0), reverse=True)
              clusters.append({
                  "category": category,
                  "count": len(arts),
                  "articles": sorted_arts[:5],
              })
      
          return clusters
      
      
      # ─── AI 情报洞察分析 ────────────────────────────────────────────────────────────────
      # 情报调查引擎配置(来自智能情报调查员 skill)
      INVESTIGATION_ENGINES = {
          "Baidu": {"url": "https://www.baidu.com/s?wd={keyword}", "region": "cn", "strength": "中文生态覆盖最广"},
          "WeChat": {"url": "https://wx.sogou.com/weixin?type=2&query={keyword}", "region": "cn", "strength": "微信公众号文章"},
          "Toutiao": {"url": "https://so.toutiao.com/search?keyword={keyword}", "region": "cn", "strength": "自媒体/热点追踪"},
          "Google": {"url": "https://www.google.com/search?q={keyword}", "region": "global", "strength": "全球索引最全+高级操作符"},
          "DuckDuckGo": {"url": "https://duckduckgo.com/html/?q={keyword}", "region": "global", "strength": "无追踪+Bangs直达"},
          "Brave": {"url": "https://search.brave.com/search?q={keyword}", "region": "global", "strength": "独立索引+无偏见"},
          "Sogou": {"url": "https://sogou.com/web?query={keyword}", "region": "cn", "strength": "微信+知乎内容"},
          "Bing INT": {"url": "https://cn.bing.com/search?q={keyword}&ensearch=1", "region": "cn", "strength": "中文界面+国际结果"},
      }
      
      # 按调查场景推荐引擎组合
      SCENARIO_ENGINES = {
          "产品竞品分析": ["Baidu", "Google", "WeChat", "DuckDuckGo"],
          "热点事件追踪": ["Baidu", "Toutiao", "Google", "WeChat"],
          "人物背景验证": ["Baidu", "Google", "DuckDuckGo"],
          "用户口碑收集": ["WeChat", "Toutiao", "DuckDuckGo", "Brave"],
          "技术趋势调查": ["DuckDuckGo", "Google", "Brave"],
          "市场数据验证": ["Google", "Baidu", "Bing INT"],
      }
      
      # 信源可信度分级
      CREDIBILITY_LEVELS = {
          "A": "官方/政府/权威媒体",
          "B": "行业媒体/专业平台",
          "C": "社交媒体/自媒体",
          "D": "匿名/未验证来源",
      }
      
      
      def generate_intelligence_briefing(clusters, articles):
          """基于当日聚类结果生成AI情报洞察报告"""
          if not clusters:
              return None
      
          total = len(articles)
      
          # 1. 提取热度TOP话题
          top_topics = []
          for cluster in clusters[:5]:
              top_topics.append({
                  "topic": cluster["category"],
                  "count": cluster["count"],
                  "ratio": round(cluster["count"] / total * 100, 1) if total > 0 else 0,
                  "top_article": cluster["articles"][0] if cluster["articles"] else None,
              })
      
          # 2. 识别新兴起量话题(占比小但互动高)
          emerging_topics = []
          for cluster in clusters:
              if cluster["count"] < total * 0.1 and cluster["articles"]:
                  avg_engagement = sum(
                      (a.get("likeCount") or 0) + (a.get("commentCount") or 0)
                      for a in cluster["articles"]
                  ) / max(len(cluster["articles"]), 1)
                  if avg_engagement > 1000:
                      emerging_topics.append({
                          "topic": cluster["category"],
                          "count": cluster["count"],
                          "avg_engagement": int(avg_engagement),
                      })
      
          # 3. 核心达人分析
          author_counter = Counter()
          author_articles = defaultdict(list)
          for article in articles:
              author = article.get("userName", "未知")
              author_counter[author] += 1
              author_articles[author].append(article)
      
          top_authors = []
          for author, count in author_counter.most_common(5):
              arts = author_articles[author]
              total_likes = sum(a.get("likeCount") or 0 for a in arts)
              reads_with_data = [a["readCount"] for a in arts if a.get("readCount") is not None]
              total_reads = sum(reads_with_data) if reads_with_data else None
              top_authors.append({
                  "name": author,
                  "article_count": count,
                  "total_likes": total_likes,
                  "total_reads": total_reads,
              })
      
          # 4. 为每个TOP话题生成推荐调查方向
          investigation_hints = []
          for topic_info in top_topics[:3]:
              topic_name = topic_info["topic"].lstrip("#")
              hints = []
      
              # 根据话题内容推荐调查场景
              if any(kw in topic_name for kw in ["大模型", "GPT", "ChatGPT", "大模型"]):
                  hints.append({
                      "scenario": "技术趋势调查",
                      "engines": SCENARIO_ENGINES["技术趋势调查"],
                      "keywords": [f"{topic_name} 最新进展", f"{topic_name} 技术对比", f"{topic_name} 开源项目"],
                  })
                  hints.append({
                      "scenario": "产品竞品分析",
                      "engines": SCENARIO_ENGINES["产品竞品分析"],
                      "keywords": [f"{topic_name} 产品对比", f"{topic_name} 用户评价"],
                  })
              elif any(kw in topic_name for kw in ["绘画", "创作", "动画"]):
                  hints.append({
                      "scenario": "用户口碑收集",
                      "engines": SCENARIO_ENGINES["用户口碑收集"],
                      "keywords": [f"{topic_name} 工具测评", f"{topic_name} 教程推荐", f"AI{topic_name} 最新工具"],
                  })
              elif any(kw in topic_name for kw in ["教程", "教学"]):
                  hints.append({
                      "scenario": "技术趋势调查",
                      "engines": SCENARIO_ENGINES["技术趋势调查"],
                      "keywords": [f"AI{topic_name} 学习路线", f"{topic_name} 变现方法"],
                  })
              else:
                  hints.append({
                      "scenario": "热点事件追踪",
                      "engines": SCENARIO_ENGINES["热点事件追踪"],
                      "keywords": [f"{topic_name} 最新动态", f"{topic_name} 行业趋势"],
                  })
      
              investigation_hints.append({
                  "topic": topic_info["topic"],
                  "hints": hints,
              })
      
          # 5. 跨平台对比建议
          cross_platform_tips = []
          for topic_info in top_topics[:3]:
              topic_name = topic_info["topic"].lstrip("#")
              cross_platform_tips.append(
                  f"「{topic_name}」— 建议同步关注抖音、B站、小红书同话题热度,"
                  f"用 Baidu+WeChat+Toutiao 三引擎追踪国内全平台动态"
              )
      
          briefing = {
              "top_topics": top_topics,
              "emerging_topics": emerging_topics,
              "top_authors": top_authors,
              "investigation_hints": investigation_hints,
              "cross_platform_tips": cross_platform_tips,
          }
      
          return briefing
      
      
      def print_intelligence_briefing(briefing):
          """在终端输出情报洞察"""
          if not briefing:
              return
      
          print(f"\n{BOLD}{'='*78}{RESET}")
          print(f"{BOLD}  AI情报洞察 · 深度调查指引{RESET}")
          print(f"{BOLD}{'='*78}{RESET}\n")
      
          # 新兴起量话题
          if briefing["emerging_topics"]:
              print(f"  {CYAN}{BOLD}【新兴起量信号】{RESET}")
              for topic in briefing["emerging_topics"]:
                  print(f"    🔥 {topic['topic']} — 虽仅{topic['count']}条但均互动{topic['avg_engagement']}+,"
                        f"值得深挖")
              print()
      
          # 核心达人
          if briefing["top_authors"]:
              print(f"  {CYAN}{BOLD}【核心达人】{RESET}")
              for author in briefing["top_authors"]:
                  reads_part = f", 总播{format_number(author['total_reads'])}" if author.get('total_reads') else ''
                  print(f"    @{author['name']} — {author['article_count']}条作品, "
                        f"总赞{format_number(author['total_likes'])}{reads_part}")
              print()
      
          # 推荐调查方向
          print(f"  {CYAN}{BOLD}【推荐调查方向】{RESET}")
          for hint_group in briefing["investigation_hints"]:
              print(f"    ▸ {hint_group['topic']}")
              for hint in hint_group["hints"]:
                  engines_str = " + ".join(hint["engines"])
                  print(f"      {hint['scenario']}: {engines_str}")
                  for kw in hint["keywords"][:2]:
                      print(f"        → 搜索: {kw}")
          print()
      
          # 跨平台对比
          if briefing["cross_platform_tips"]:
              print(f"  {CYAN}{BOLD}【跨平台对比建议】{RESET}")
              for tip in briefing["cross_platform_tips"]:
                  print(f"    • {tip}")
          print()
      
      
      
      # ─── HTML 报告生成 ──────────────────────────────────────────────────────────────────
      def compute_stats(articles):
          """计算统计数据"""
          total = len(articles)
          if total == 0:
              return {"total": 0, "avg_reads": None, "top_author": "-", "total_likes": 0}
      
          reads_with_data = [a["readCount"] for a in articles if a.get("readCount") is not None]
          avg_reads = sum(reads_with_data) // len(reads_with_data) if reads_with_data else None
      
          author_counter = Counter(a.get("userName", "未知") for a in articles)
          top_author = author_counter.most_common(1)[0][0] if author_counter else "-"
      
          total_likes = sum(a.get("likeCount") or 0 for a in articles)
      
          return {
              "total": total,
              "avg_reads": avg_reads,
              "top_author": top_author,
              "total_likes": total_likes,
          }
      
      
      def format_number(n):
          """格式化数字: 1234 -> 1.2k"""
          if n is None:
              return "0"
          if n >= 10000:
              return f"{n/10000:.1f}w"
          if n >= 1000:
              return f"{n/1000:.1f}k"
          return str(n)
      
      
      def print_article_table(clusters):
          """在终端打印分类视频表格"""
          print(f"\n{BOLD}{'='*78}{RESET}")
          print(f"{BOLD}  AI快手信息源 · 分类视频一览{RESET}")
          print(f"{BOLD}{'='*78}{RESET}\n")
      
          for i, cluster in enumerate(clusters, 1):
              category = cluster["category"]
              arts = cluster["articles"]
      
              # 分类标题
              print(f"  {CYAN}{BOLD}【{category}】{RESET} "
                    f"共 {len(arts)} 条展示 / {cluster['count']} 条总计")
      
              # 表头
              header = (f"  {'序号':<4}{'标题':<36}{'作者':<14}"
                        f"{'播放':>8}{'点赞':>8}{'评论':>8}")
              print(f"  {YELLOW}{'─'*76}{RESET}")
              print(f"  {YELLOW}{header}{RESET}")
              print(f"  {YELLOW}{'─'*76}{RESET}")
      
              for j, article in enumerate(arts, 1):
                  title = article.get("title", "无标题")
                  author = article.get("userName", "-")
                  reads = format_number(article.get("readCount")) if article.get("readCount") else "-"
                  likes = format_number(article.get("likeCount"))
                  comments = format_number(article.get("commentCount"))
      
                  # 截断过长的标题和作者
                  display_title = title[:34] + ".." if len(title) > 36 else title
                  display_author = author[:12] + ".." if len(author) > 14 else author
      
                  print(f"  {j:<4}{display_title:<36}{display_author:<14}"
                        f"{reads:>8}{likes:>8}{comments:>8}")
      
              print()  # 分类之间空行
      
      
      def generate_category_cards(clusters):
          """生成分类卡片 HTML"""
          cards_html = ""
          for i, cluster in enumerate(clusters, 1):
              articles_html = ""
              for article in cluster["articles"]:
                  title = article.get("title", "无标题")
                  url = article.get("url") or ""
                  if not url or url == "#":
                      photo_id = article.get("photoId", "")
                      if photo_id:
                          url = f"https://www.kuaishou.com/short-video/{photo_id}"
                      else:
                          url = "#"
                  author = article.get("userName", "")
                  cover = article.get("coverUrl") or ""
                  # 不兼容格式转换为 JPG:HEIF/HEIC、快手私有格式 kvif/kpg
                  # URL 可能带 ?tag=... 查询参数,需要在 ? 前匹配后缀,而不是在字符串末尾
                  cover = re.sub(r'\.(heif|heic|kvif|kpg)(?=[?#]|$)', '.jpg', cover, flags=re.IGNORECASE)
                  cover = re.sub(r'/(heif|heic)/', '/jpg/', cover, flags=re.IGNORECASE)
                  likes = format_number(article.get("likeCount"))
                  reads_raw = article.get("readCount")
                  comments = format_number(article.get("commentCount"))
      
                  reads_metric = f'<span class="metric">&#x1f441; {format_number(reads_raw)}</span>' if reads_raw else ''
                  articles_html += f'''
                      <a href="{url}" target="_blank" class="article-item">
                          <div class="article-info">
                              <span class="article-title">{title}</span>
                              <div class="article-meta">
                                  <span class="author">{author}</span>
                                  <span class="metrics">
                                      {reads_metric}
                                      <span class="metric">&#x1f44d; {likes}</span>
                                      <span class="metric">&#x1f4ac; {comments}</span>
                                  </span>
                              </div>
                          </div>
                      </a>'''
      
              cards_html += f'''
              <div class="category-card reveal">
                  <div class="card-header">
                      <span class="card-number">{i:02d}</span>
                      <h3 class="card-category">{cluster["category"]}</h3>
                      <span class="card-count">{cluster["count"]} 条</span>
                  </div>
                  <div class="card-body">{articles_html}
                  </div>
              </div>'''
      
          return cards_html
      
      
      def generate_intelligence_html(briefing):
          """生成情报洞察板块 HTML"""
          if not briefing:
              return ""
      
          # 热度TOP话题
          topics_html = ""
          for i, topic in enumerate(briefing["top_topics"], 1):
              top_art = topic.get("top_article")
              top_title = (top_art.get("title", "-")[:50] if top_art else "-")
              top_reads_raw = top_art.get("readCount") if top_art else None
              top_reads_metric = f'{format_number(top_reads_raw)} 播放' if top_reads_raw else ''
              topics_html += f'''
                      <div class="intel-rank-item">
                          <span class="intel-rank-num">{i}</span>
                          <div class="intel-rank-info">
                              <span class="intel-rank-topic">{topic['topic']}</span>
                              <span class="intel-rank-detail">占比 {topic['ratio']}% · {topic['count']}条 · 头部: {top_title}</span>
                          </div>
                          <span class="intel-rank-metric">{top_reads_metric}</span>
                      </div>'''
      
          # 新兴起量话题
          emerging_html = ""
          for topic in briefing.get("emerging_topics", []):
              emerging_html += f'''
                      <div class="intel-emerging-item">
                          <span class="intel-emerging-badge">起量信号</span>
                          <span class="intel-emerging-topic">{topic['topic']}</span>
                          <span class="intel-emerging-detail">{topic['count']}条 · 均互动{topic['avg_engagement']}+</span>
                      </div>'''
      
          emerging_section = ""
          if emerging_html:
              emerging_section = f'''
              <div class="intel-subsection">
                  <h4 class="intel-subtitle">新兴起量信号</h4>
                  <div class="intel-emerging-list">{emerging_html}
                  </div>
              </div>'''
      
          # 核心达人
          authors_html = ""
          for author in briefing.get("top_authors", []):
              reads_part = f' · 总播{format_number(author["total_reads"])}' if author.get("total_reads") else ''
              authors_html += f'''
                      <div class="intel-author-item">
                          <span class="intel-author-name">@{author['name']}</span>
                          <span class="intel-author-stats">{author['article_count']}条 · 总赞{format_number(author['total_likes'])}{reads_part}</span>
                      </div>'''
      
          authors_section = ""
          if authors_html:
              authors_section = f'''
              <div class="intel-subsection">
                  <h4 class="intel-subtitle">核心达人</h4>
                  <div class="intel-author-list">{authors_html}
                  </div>
              </div>'''
      
          # 推荐调查方向
          hints_html = ""
          for hint_group in briefing.get("investigation_hints", []):
              hint_items = ""
              for hint in hint_group["hints"]:
                  engines_str = " + ".join(hint["engines"])
                  kw_list = " | ".join(hint["keywords"][:2])
                  hint_items += f'''
                          <div class="intel-hint-item">
                              <span class="intel-hint-scenario">{hint['scenario']}</span>
                              <span class="intel-hint-engines">{engines_str}</span>
                              <span class="intel-hint-kw">{kw_list}</span>
                          </div>'''
      
              hints_html += f'''
                      <div class="intel-hint-group">
                          <span class="intel-hint-topic">{hint_group['topic']}</span>
                          <div class="intel-hint-items">{hint_items}
                          </div>
                      </div>'''
      
          # 跨平台对比
          cross_html = ""
          for tip in briefing.get("cross_platform_tips", []):
              cross_html += f'<div class="intel-cross-tip">{tip}</div>'
      
          cross_section = ""
          if cross_html:
              cross_section = f'''
              <div class="intel-subsection">
                  <h4 class="intel-subtitle">跨平台对比建议</h4>
                  <div class="intel-cross-list">{cross_html}
                  </div>
              </div>'''
      
          # 情报调查引擎表
          engine_rows = ""
          for name, info in INVESTIGATION_ENGINES.items():
              engine_rows += f'''
                          <tr>
                              <td class="intel-engine-name">{name}</td>
                              <td class="intel-engine-region">{info['region'].upper()}</td>
                              <td class="intel-engine-strength">{info['strength']}</td>
                          </tr>'''
      
          credibility_rows = ""
          for level, desc in CREDIBILITY_LEVELS.items():
              credibility_rows += f'''
                          <tr>
                              <td class="intel-cred-level">{level}级</td>
                              <td>{desc}</td>
                          </tr>'''
      
          html = f'''
          <div class="intelligence-section reveal">
              <div class="intel-header">
                  <h2 class="intel-title">AI情报洞察</h2>
                  <span class="intel-subtitle-badge">基于智能情报调查员 · 多源交叉验证</span>
              </div>
      
              <div class="intel-body">
                  <div class="intel-subsection">
                      <h4 class="intel-subtitle">热度TOP话题</h4>
                      <div class="intel-rank-list">{topics_html}
                      </div>
                  </div>
      
                  {emerging_section}
      
                  {authors_section}
      
                  <div class="intel-subsection">
                      <h4 class="intel-subtitle">推荐调查方向</h4>
                      <div class="intel-hints">{hints_html}
                      </div>
                  </div>
      
                  {cross_section}
      
                  <div class="intel-subsection">
                      <h4 class="intel-subtitle">调查引擎一览</h4>
                      <div class="intel-engine-table-wrap">
                          <table class="intel-engine-table">
                              <thead><tr><th>引擎</th><th>区域</th><th>优势</th></tr></thead>
                              <tbody>{engine_rows}
                              </tbody>
                          </table>
                      </div>
                      <div class="intel-cred-table-wrap">
                          <table class="intel-cred-table">
                              <thead><tr><th>信源级别</th><th>类型</th></tr></thead>
                              <tbody>{credibility_rows}
                              </tbody>
                          </table>
                      </div>
                  </div>
              </div>
          </div>'''
      
          return html
      
      
      def generate_report(clusters, articles, date_str, api_key=None, briefing=None):
          """生成完整 HTML 报告"""
          stats = compute_stats(articles)
          topic_count = len(clusters)
      
          # 尝试从模板文件读取
          template_path = Path(__file__).parent / "report_template.html"
          if template_path.exists():
              template = template_path.read_text(encoding="utf-8")
          else:
              warn("模板文件未找到,使用内置模板")
              template = get_fallback_template()
      
          # 生成日期显示
          try:
              dt = datetime.strptime(date_str, "%Y-%m-%d")
              weekdays = ["一", "二", "三", "四", "五", "六", "日"]
              date_cn = f"{dt.year}年{dt.month}月{dt.day}日 星期{weekdays[dt.weekday()]}"
          except ValueError:
              date_cn = date_str
      
          category_cards = generate_category_cards(clusters)
          timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
      
          # 生成情报洞察 HTML
          intelligence_html = generate_intelligence_html(briefing) if briefing else ""
      
          html = template
          html = html.replace("{{DATE}}", date_str)
          html = html.replace("{{DATE_CN}}", date_cn)
          html = html.replace("{{TOTAL_COUNT}}", str(stats["total"]))
          html = html.replace("{{TOPIC_COUNT}}", str(topic_count))
          html = html.replace("{{TOP_AUTHOR}}", stats["top_author"])
          html = html.replace("{{AVG_READS}}", format_number(stats["avg_reads"]) if stats["avg_reads"] is not None else "-")
          html = html.replace("{{TOTAL_LIKES}}", format_number(stats["total_likes"]))
          html = html.replace("{{CATEGORY_CARDS}}", category_cards)
          html = html.replace("{{INTELLIGENCE_SECTION}}", intelligence_html)
          html = html.replace("{{TIMESTAMP}}", timestamp)
          html = html.replace("{{API_KEY}}", api_key or "")
          html = html.replace("{{SOURCE}}", SOURCE)
      
          return html
      
      
      def get_fallback_template():
          """内置最小 HTML 模板(当模板文件缺失时使用)"""
          return '''<!DOCTYPE html>
      <html lang="zh-CN">
      <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>AI快手信息源 - {{DATE}}</title>
      <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font-family: -apple-system, sans-serif; background: #1a1a1a; color: #e8e4df; padding: 2rem; }
      .header { text-align: center; padding: 2rem 0; }
      .header h1 { font-size: 2rem; color: #FF4906; }
      .header p { color: #9a9590; margin-top: 0.5rem; }
      .stats { display: flex; justify-content: center; gap: 2rem; padding: 1rem; margin: 1rem 0; }
      .stat-item { text-align: center; }
      .stat-value { font-size: 1.5rem; font-weight: bold; color: #FF4906; }
      .stat-label { font-size: 0.8rem; color: #9a9590; }
      .cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: 1.5rem; max-width: 1200px; margin: 2rem auto; }
      .category-card { background: #2d2d2d; border-radius: 12px; padding: 1.5rem; }
      .card-header { display: flex; align-items: center; gap: 0.8rem; margin-bottom: 1rem; padding-bottom: 0.8rem; border-bottom: 1px solid #3d3d3d; }
      .card-number { font-size: 1.5rem; font-weight: bold; color: #FF4906; }
      .card-category { flex: 1; font-size: 1.1rem; }
      .card-count { color: #9a9590; font-size: 0.9rem; }
      .article-item { padding: 0.6rem 0; border-bottom: 1px solid #3d3d3d; display: block; text-decoration: none; color: inherit; cursor: pointer; }
      .article-item:hover { background: #333; }
      .article-item:hover .article-title { color: #FF4906; }
      .article-item:last-child { border-bottom: none; }
      .article-info { flex: 1; min-width: 0; }
      .article-title { color: #e8e4df; font-size: 0.9rem; line-height: 1.4; display: block; transition: color 0.2s; }
      .article-meta { display: flex; justify-content: space-between; margin-top: 0.3rem; font-size: 0.75rem; color: #9a9590; }
      .metrics { display: flex; gap: 0.8rem; }
      .footer { text-align: center; padding: 2rem; color: #666; font-size: 0.8rem; }
      </style>
      </head>
      <body>
      <div class="header">
          <h1>AI快手信息源</h1>
          <p>{{DATE_CN}} | 共 {{TOTAL_COUNT}} 条热门视频</p>
      </div>
      <div class="stats">
          <div class="stat-item"><div class="stat-value">{{TOPIC_COUNT}}</div><div class="stat-label">分类</div></div>
          <div class="stat-item"><div class="stat-value">{{TOTAL_COUNT}}</div><div class="stat-label">视频</div></div>
          <div class="stat-item"><div class="stat-value">{{AVG_READS}}</div><div class="stat-label">平均播放</div></div>
          <div class="stat-item"><div class="stat-value">{{TOTAL_LIKES}}</div><div class="stat-label">总点赞</div></div>
      </div>
      <div class="cards">{{CATEGORY_CARDS}}</div>
      <div class="footer">Generated at {{TIMESTAMP}} by AI快手信息源 Skill</div>
      </body>
      </html>'''
      
      
      # ─── 订阅机制 ──────────────────────────────────────────────────────────────────────
      def install_subscription():
          """安装定时任务,每天自动生成日报"""
          if sys.platform == "darwin":
              PLIST_DIR.mkdir(parents=True, exist_ok=True)
              plist_path = PLIST_DIR / f"{PLIST_LABEL}.plist"
      
              script_path = os.path.abspath(__file__)
              log_path = str(Path.home() / "Library" / "Logs" / "qoder-ks-ai-hot-articles.log")
      
              # 传递 API Key 环境变量
              env_section = ""
              api_key = os.environ.get(ENV_KEY)
              if api_key:
                  env_section = f"""
              <key>EnvironmentVariables</key>
              <dict>
                  <key>{ENV_KEY}</key>
                  <string>{api_key}</string>
              </dict>"""
      
              plist_content = f'''<?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
      <plist version="1.0">
      <dict>
          <key>Label</key>
          <string>{PLIST_LABEL}</string>
          <key>ProgramArguments</key>
          <array>
              <string>/usr/bin/python3</string>
              <string>{script_path}</string>
              <string>--no-open</string>
          </array>
          <key>StartCalendarInterval</key>
          <dict>
              <key>Hour</key>
              <integer>9</integer>
              <key>Minute</key>
              <integer>0</integer>
          </dict>
          <key>StandardOutPath</key>
          <string>{log_path}</string>
          <key>StandardErrorPath</key>
          <string>{log_path}</string>
          <key>RunAtLoad</key>
          <false/>{env_section}
      </dict>
      </plist>'''
      
              plist_path.write_text(plist_content, encoding="utf-8")
      
              try:
                  subprocess.run(["launchctl", "load", str(plist_path)], check=True, capture_output=True)
                  info("订阅成功! 每天 09:00 自动生成快手爆款日报")
                  info(f"日报目录: ~/Downloads/QoderReports/")
                  info(f"日志: {log_path}")
                  return True
              except subprocess.CalledProcessError as e:
                  error(f"订阅安装失败: {e.stderr.decode()}")
                  return False
          else:
              # Linux / Windows: 使用 crontab
              script_path = os.path.abspath(__file__)
              cron_line = f"0 9 * * * /usr/bin/python3 {script_path} --no-open"
              try:
                  subprocess.run(
                      f'(crontab -l 2>/dev/null; echo "{cron_line}") | crontab -',
                      shell=True, check=True, capture_output=True
                  )
                  info("订阅成功! 每天 09:00 自动生成快手爆款日报 (crontab)")
                  info(f"日报目录: ~/Downloads/QoderReports/")
                  return True
              except subprocess.CalledProcessError:
                  warn("自动配置 crontab 失败,请手动添加:")
                  print(f"  {cron_line}")
                  return False
      
      
      def remove_subscription():
          """卸载定时任务"""
          if sys.platform == "darwin":
              plist_path = PLIST_DIR / f"{PLIST_LABEL}.plist"
              if not plist_path.exists():
                  warn("未找到订阅配置,无需取消")
                  return False
              try:
                  subprocess.run(["launchctl", "unload", str(plist_path)], check=True, capture_output=True)
              except subprocess.CalledProcessError:
                  pass
              plist_path.unlink(missing_ok=True)
              info("已取消订阅,定时任务已移除")
              return True
          else:
              script_path = os.path.abspath(__file__)
              try:
                  subprocess.run(
                      f'crontab -l 2>/dev/null | grep -v "{script_path}" | crontab -',
                      shell=True, check=True, capture_output=True
                  )
                  info("已取消订阅,crontab 任务已移除")
                  return True
              except subprocess.CalledProcessError:
                  warn("自动移除 crontab 失败,请手动执行: crontab -e")
                  return False
      
      
      # ─── API 代理 HTTP 服务 ─────────────────────────────────────────────────────────────
      class ProxyHTTPHandler(SimpleHTTPRequestHandler):
          """静态文件服务 + /api/search 代理到 redfox.hk"""
          api_key = ""  # 将由 start_server 调用旹覆盖
          search_url = API_URL
      
          def do_GET(self):
              parsed = urlparse(self.path)
              if parsed.path == "/api/search":
                  self._handle_search(parsed)
              elif parsed.path == "/api/img":
                  self._handle_img_proxy(parsed)
              else:
                  super().do_GET()
      
          def _handle_img_proxy(self, parsed):
              """代理图片请求,绕过防盗链"""
              params = parse_qs(parsed.query)
              url = params.get("url", [""])[0]
      
              if not url:
                  self.send_error(400, "missing url")
                  return
      
              try:
                  req = Request(url, headers={
                      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
                      "Referer": "https://www.kuaishou.com/",
                  })
                  resp = urlopen(req, timeout=10)
                  content_type = resp.headers.get("Content-Type", "image/jpeg")
                  data = resp.read()
      
                  self.send_response(200)
                  self.send_header("Content-Type", content_type)
                  self.send_header("Access-Control-Allow-Origin", "*")
                  self.send_header("Cache-Control", "public, max-age=86400")
                  self.send_header("Content-Length", str(len(data)))
                  self.end_headers()
                  self.wfile.write(data)
              except Exception as e:
                  self.send_error(502, f"proxy error: {e}")
      
          def _handle_search(self, parsed):
              params = parse_qs(parsed.query)
              keyword = params.get("keyword", [""])[0]
      
              if not keyword:
                  self._send_json({"code": -1, "msg": "missing keyword"})
                  return
      
              payload = {
                  "keyword": keyword,
                  "pageNum": 1,
                  "pageSize": 20,
                  "source": SOURCE,
              }
              try:
                  resp = requests.post(
                      self.search_url,
                      json=payload,
                      headers={
                          "Content-Type": "application/json",
                          "X-API-KEY": self.api_key,
                      },
                      timeout=10,
                  )
                  self._send_json(resp.json())
              except Exception as e:
                  self._send_json({"code": -1, "msg": str(e)})
      
          def _send_json(self, data):
              body = json.dumps(data, ensure_ascii=False).encode("utf-8")
              self.send_response(200)
              self.send_header("Content-Type", "application/json; charset=utf-8")
              self.send_header("Access-Control-Allow-Origin", "*")
              self.send_header("Content-Length", str(len(body)))
              self.end_headers()
              self.wfile.write(body)
      
          def log_message(self, format, *args):
              pass  # 静默日志
      
      
      def start_server(output_dir, api_key, port=8766, latest_filename=None):
          """启动内置 HTTP 服务(静态文件 + API 代理),根路径自动重定向到最新日报"""
          import threading
      
          class _RedirectHandler(ProxyHTTPHandler):
              _latest = latest_filename
      
              def do_GET(self):
                  parsed = urlparse(self.path)
                  if parsed.path in ("/", "") and self._latest:
                      self.send_response(302)
                      self.send_header("Location", f"/{self._latest}")
                      self.end_headers()
                  else:
                      super().do_GET()
      
          _RedirectHandler.api_key = api_key or ""
          os.chdir(str(output_dir))
          server = HTTPServer(("127.0.0.1", port), _RedirectHandler)
          t = threading.Thread(target=server.serve_forever, daemon=False)
          t.start()
          info(f"本地服务已启动: http://127.0.0.1:{port}")
          return server
      
      
      # ─── 主流程 ────────────────────────────────────────────────────────────────────────
      def main():
          parser = argparse.ArgumentParser(
              description="AI快手信息源 — 每日热门内容聚类日报",
              formatter_class=argparse.RawDescriptionHelpFormatter,
              epilog="""
      Examples:
        python3 daily_report.py
        python3 daily_report.py --keywords "AI教程,AI绘画,ChatGPT"
        python3 daily_report.py --subscribe
        python3 daily_report.py --unsubscribe
              """,
          )
          parser.add_argument("--keywords", default=",".join(DEFAULT_KEYWORDS),
                              help="搜索关键词,逗号分隔 (默认: AI,人工智能,大模型,GPT,Agent,AI绘画,AI教程)")
          parser.add_argument("--count", type=int, default=50, help="目标视频数 (默认: 50)")
          parser.add_argument("--date", default=datetime.now().strftime("%Y-%m-%d"),
                              help="指定日期 YYYY-MM-DD 或日期范围 YYYY-MM-DD~YYYY-MM-DD (默认: 今天)")
          parser.add_argument("--output-dir", help=f"输出目录 (默认: ~/Downloads/QoderReports)")
          parser.add_argument("--api-key", help="API Key (不传则读取环境变量或配置文件)")
          parser.add_argument("--subscribe", action="store_true", help="安装每日定时任务 (09:00)")
          parser.add_argument("--unsubscribe", action="store_true", help="卸载定时任务")
          parser.add_argument("--no-open", action="store_true", help="不自动打开浏览器")
      
          args = parser.parse_args()
      
          # ── Banner ──
          banner = f"""{CYAN}{BOLD}
        ╔══════════════════════════════════════╗
        ║     AI快手信息源 · 日报生成          ║
        ║     每日热门内容聚类 · 爆款一网打尽   ║
        ╚══════════════════════════════════════╝{RESET}
      """
          print(banner)
      
          # ── 订阅/取消 ──
          if args.subscribe:
              install_subscription()
              return
      
          if args.unsubscribe:
              remove_subscription()
              return
      
          # ── 检查依赖 ──
          if not HAS_REQUESTS:
              error("缺少 requests 库,请安装: pip3 install requests")
              sys.exit(1)
      
          # ── API Key ──
          api_key = get_api_key(cli_key=args.api_key)
          if not api_key:
              error("未配置 API Key,请通过以下方式之一提供:")
              print(f"  1. 环境变量: export {ENV_KEY}=ak_你的密鑰")
              print(f"  2. 命令行参数: --api-key ak_你的密鑰")
              print(f"  3. 配置文件: echo '{{\"api_key\":\"ak_你的密鑰\"}}' > ~/.qoder/apis/redfox.json")
              sys.exit(1)
          # ── Session ──
          session = requests.Session()
          session.verify = True
          session.headers.update({
              "Content-Type": "application/json",
              "X-API-KEY": api_key,
          })
      
          # ── 日期范围推算 ──
          date_val = args.date
          if "~" in date_val:
              # 日期范围:2026-06-01~2026-06-11
              parts = date_val.split("~", 1)
              start_date = parts[0].strip()
              end_date = parts[1].strip()
          else:
              # 单日
              start_date = end_date = date_val.strip()
      
          try:
              dt_start = datetime.strptime(start_date, "%Y-%m-%d")
              dt_end = datetime.strptime(end_date, "%Y-%m-%d")
          except ValueError:
              error(f"日期格式错误,请使用 YYYY-MM-DD 或 YYYY-MM-DD~YYYY-MM-DD:{date_val}")
              sys.exit(1)
      
          # 开始时间:start_date 的0点(本地时间,字符串格式)
          start_time_str = dt_start.strftime("%Y-%m-%d 00:00:00")
          # 结束时间:end_date 当天23:59:59
          end_time_str = dt_end.strftime("%Y-%m-%d 23:59:59")
      
          # 日报展示日期(单日用单日,范围用范围)
          display_date = date_val if "~" in date_val else start_date
      
          # ── 数据可用性检查 ──
          # 检查结束日期是否已有数据(日期范围时检查结束日期,单日时检查该日期)
          is_available, latest_date = check_date_available(end_date)
          if not is_available:
              print_data_unavailable_notice(end_date, latest_date)
              sys.exit(0)
      
          # ── 获取视频 ──
          keywords = [k.strip() for k in args.keywords.split(",") if k.strip()]
          step(f"扫描热门内容,关键词: {keywords}")
          step(f"目标: {args.count} 条, 日期: {display_date}")
          step(f"时间范围: {start_time_str} ~ {end_time_str} (本地时间)")
          print()
      
          articles = fetch_articles(session, keywords, args.count, start_time=start_time_str, end_time=end_time_str)
      
          if not articles:
              error("未获取到任何视频")
              sys.exit(1)
      
          info(f"扫描完成: {len(articles)} 条热门视频")
      
          # ── 自动聚类 ──
          step("正在自动聚类...")
          clusters = cluster_articles(articles)
          info(f"聚类完成: 发现 {len(clusters)} 个分类")
          for c in clusters[:10]:
              print(f"    {c['category']}: {c['count']} 条")
      
          # ── 终端表格展示 ──
          print_article_table(clusters)
      
          # ── AI情报洞察 ──
          step("正在生成AI情报洞察...")
          briefing = generate_intelligence_briefing(clusters, articles)
          if briefing:
              info(f"情报洞察完成: {len(briefing['investigation_hints'])}个推荐调查方向")
              print_intelligence_briefing(briefing)
      
      
          # ── 生成报告 ──
          step("生成 HTML 日报...")
          html_content = generate_report(clusters, articles, display_date, api_key=api_key, briefing=briefing)
      
          # ── 保存文件 ──
          output_dir = Path(args.output_dir) if args.output_dir else DEFAULT_OUTPUT_DIR
          output_dir.mkdir(parents=True, exist_ok=True)
          ts = datetime.now().strftime("%H%M%S")
          filename = f"AI快手日报_{display_date.replace('~', '_')}_{ts}.html"
          output_path = output_dir / filename
      
          output_path.write_text(html_content, encoding="utf-8")
          info(f"日报已生成: {output_path}")
      
          # ── 始终启动内置预览服务 ──
          server = start_server(output_dir, api_key, latest_filename=filename)
          preview_url = f"http://127.0.0.1:8766/{filename}"
          info(f"预览地址: {preview_url}")
      
          # ── 打开系统浏览器(--no-open 时跳过)──
          if not args.no_open:
              if sys.platform == "darwin":
                  subprocess.run(["open", preview_url], check=False)
              elif sys.platform == "win32":
                  os.startfile(preview_url)
              elif sys.platform == "linux":
                  subprocess.run(["xdg-open", preview_url], check=False)
              info(f"浏览器已打开: {preview_url}")
      
          # ── 结构化摘要(严格对齐SKILL.md固定输出模式) ──
          print(f"\n{GREEN}{BOLD}✓ 完成!{RESET}")
          
          # 标题
          print(f"\n{BOLD}## AI快手信息源 · {display_date} 日报{RESET}")
          print(f"\n**扫描 {len(articles)} 条热门视频,聚类 {len(clusters)} 个分类**")
          print(f"\n---")
          
          # 分类概览表
          total = len(articles)
          print(f"\n{BOLD}### 分类概览{RESET}")
          print(f"\n| 分类 | 数量 | 占比 | 亮点 |")
          print(f"|------|------|------|------|")
          for c in clusters:
              ratio = f"{c['count']/total*100:.1f}%" if total > 0 else "0%"
              # 亮点:头部视频标题截断 + 点赞
              highlight = "暂无"
              if c["articles"]:
                  top = c["articles"][0]
                  title = (top.get("title") or "无标题")[:20]
                  likes = format_number(top.get("likeCount") or 0)
                  highlight = f"{title} {likes}赞"
              print(f"| {c['category']} | {c['count']}条 | {ratio} | {highlight} |")
          
          print(f"\n---")
          
          # AI情报洞察报告
          if briefing:
              print(f"\n{BOLD}### AI情报洞察报告{RESET}")
          
              # 一、新兴起量信号
              print(f"\n**一、新兴起量信号**")
              if briefing["emerging_topics"]:
                  for topic in briefing["emerging_topics"]:
                      print(f"\n- 🔥 **{topic['topic']}** — 仅{topic['count']}条但均互动{topic['avg_engagement']}+,")
              else:
                  print(f"\n暂无")
          
              # 二、核心达人
              print(f"\n**二、核心达人**")
              if briefing["top_authors"]:
                  print(f"\n| 达人 | 作品数 | 总赞 | 亮点 |")
                  print(f"|------|--------|------|------|")
                  for author in briefing["top_authors"][:5]:
                      name = f"@{author['name']}"
                      count = f"{author['article_count']}条"
                      total_likes = format_number(author['total_likes'])
                      highlight = f"总播{format_number(author['total_reads'])}" if author.get('total_reads') else '-'
                      print(f"| {name} | {count} | {total_likes} | {highlight} |")
              else:
                  print(f"\n暂无")
          
              # 三、推荐调查方向
              print(f"\n**三、推荐调查方向**")
              if briefing["investigation_hints"]:
                  print(f"\n| 话题 | 调查场景 | 推荐引擎 | 搜索关键词 |")
                  print(f"|------|---------|---------|-----------|")
                  for hint_group in briefing["investigation_hints"]:
                      topic_name = hint_group['topic']
                      for hint in hint_group["hints"][:2]:  # 每个话题最多展示2个场景
                          engines_str = " + ".join(hint["engines"])
                          keywords_str = " / ".join(hint["keywords"][:2])
                          print(f"| {topic_name} | {hint['scenario']} | {engines_str} | {keywords_str} |")
              else:
                  print(f"\n暂无")
          
              # 四、跨平台对比建议
              print(f"\n**四、跨平台对比建议**")
              if briefing["cross_platform_tips"]:
                  for tip in briefing["cross_platform_tips"]:
                      print(f"\n- {tip}")
              else:
                  print(f"\n暂无")
          
              print(f"\n---")
          
          # 日报地址
          print(f"\n**日报地址**:{output_path}")
          if not args.no_open:
              print(f"  搜索功能: 已就绪(通过内置 API 代理)")
              print(f"  {YELLOW}提示:关闭终端后服务自动停止,HTML 文件可随时离线查阅{RESET}")
      
      
      if __name__ == "__main__":
          main()
      
    • preview_server.py 1.6 KB
      #!/usr/bin/env python3
      """启动带图片代理的本地预览服务,根路径自动重定向到最新快手日报"""
      import sys
      import os
      
      # 将 daily_report 的目录加入路径
      sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
      
      from daily_report import ProxyHTTPHandler, info
      from pathlib import Path
      from http.server import HTTPServer
      
      output_dir = Path.home() / "Downloads" / "QoderReports"
      
      # 动态找最新生成的快手日报文件
      html_files = sorted(output_dir.glob("AI快手日报_*.html"), key=lambda f: f.stat().st_mtime, reverse=True)
      latest = html_files[0].name if html_files else None
      
      
      class RedirectHandler(ProxyHTTPHandler):
          """在 ProxyHTTPHandler 基础上,根路径自动重定向到最新快手日报"""
          latest_file = latest
      
          def do_GET(self):
              from urllib.parse import urlparse
              parsed = urlparse(self.path)
              if parsed.path in ("/", "") and self.latest_file:
                  self.send_response(302)
                  self.send_header("Location", f"/{self.latest_file}")
                  self.end_headers()
              else:
                  super().do_GET()
      
      
      os.chdir(str(output_dir))
      server = HTTPServer(("127.0.0.1", 8766), RedirectHandler)
      
      import threading
      t = threading.Thread(target=server.serve_forever, daemon=False)
      t.start()
      
      info(f"本地服务已启动: http://127.0.0.1:8766")
      if latest:
          print(f"\n预览地址: http://127.0.0.1:8766/{latest}")
      else:
          print("\n未找到快手日报文件")
      print("按 Ctrl+C 退出\n")
      
      try:
          import time
          while True:
              time.sleep(1)
      except KeyboardInterrupt:
          print("\n服务已停止")
      
    • report_template.html 19.8 KB · in bundle
  • references
    • engine-strategy.md 6.9 KB
      # 引擎选择策略详解
      
      ## 一、决策树:如何选择引擎组合
      
      ```
      用户输入调查需求
      │
      ├── 包含中文关键词?
      │   ├── 是 → 必选: Baidu + WeChat + Toutiao
      │   └── 否 → 跳过国内引擎
      │
      ├── 需要国际视角?
      │   ├── 是 → 必选: Google + DuckDuckGo/Brave
      │   └── 否 → 聚焦国内引擎
      │
      ├── 信息敏感/需隐私?
      │   ├── 是 → 优先: DuckDuckGo + Startpage + Qwant
      │   └── 否 → 无特殊要求
      │
      ├── 需要时间线/实时性?
      │   ├── 小时级 → Google(tbs=qdr:h) + Brave
      │   ├── 天级 → Google(tbs=qdr:d) + Baidu
      │   └── 周级 → 全引擎均可
      │
      ├── 需要数据验证?
      │   ├── 是 → WolframAlpha + Google Scholar
      │   └── 否 → 通用引擎
      │
      └── 需要技术深度?
          ├── 是 → DuckDuckGo(!gh !so !npm)
          └── 否 → 通用引擎
      ```
      
      ---
      
      ## 二、四类调查模式的引擎编排
      
      ### 竞品情报调查
      
      | 轮次 | 目的 | 引擎 | 搜索策略 |
      |------|------|------|---------|
      | 第1轮 | 广域扫描 | Baidu, Google, Bing INT | 广泛关键词,建立全景 |
      | 第2轮 | 深度挖掘 | WeChat, Toutiao, DuckDuckGo | 细分关键词,挖掘真实反馈 |
      | 第3轮 | 交叉验证 | Baidu, Google, Brave | 关键数据多源验证 |
      
      **关键词构建模板:**
      - 第1轮:`{竞品名} 产品 功能 定价`
      - 第2轮:`{竞品名} 使用体验 测评 评价` / `site:reddit.com {竞品名} review`
      - 第3轮:`{竞品名} 融资 营收 市场份额`
      
      ### 舆情事件调查
      
      | 轮次 | 目的 | 引擎 | 搜索策略 |
      |------|------|------|---------|
      | 第1轮 | 事件还原 | Baidu, Google(tbs=qdr:d), Toutiao | 时间过滤+热点词 |
      | 第2轮 | 多视角 | WeChat, Sogou, DuckDuckGo | 评论区+论坛+自媒体 |
      | 第3轮 | 时间线 | Google(tbs=qdr:w), Bing INT | 追溯事件发展脉络 |
      
      **关键词构建模板:**
      - 第1轮:`{事件关键词}` (加时间过滤)
      - 第2轮:`{事件关键词} 评论 分析 观点` / `site:reddit.com {事件}`
      - 第3轮:`{事件关键词} 时间线 经过 回顾`
      
      ### 人物背景调查
      
      | 轮次 | 目的 | 引擎 | 搜索策略 |
      |------|------|------|---------|
      | 第1轮 | 基本信息 | Baidu, Google, Bing INT | 姓名+职务+公司 |
      | 第2轮 | 专业验证 | DuckDuckGo(!gh), Google Scholar | 学术/技术成果 |
      | 第3轮 | 信誉排查 | Baidu, Google, WeChat | 争议+诉讼+负面 |
      
      **关键词构建模板:**
      - 第1轮:`{人物名} 简介 背景 职务` / `{人物名} biography`
      - 第2轮:`!gh {人物名}` / `author:"{人物名}"`
      - 第3轮:`{人物名} 争议 诉讼 负面` / `{人物名} controversy`
      
      ### 信息交叉验证
      
      | 轮次 | 目的 | 引擎 | 搜索策略 |
      |------|------|------|---------|
      | 第1轮 | 溯源 | Google(精确匹配), Baidu | 引号包裹+精确搜索 |
      | 第2轮 | 比对 | DuckDuckGo, Brave, Startpage | 同一关键词不同引擎 |
      | 第3轮 | 权威 | WolframAlpha, Google(site:权威站) | 官方信源确认 |
      
      **关键词构建模板:**
      - 第1轮:`"{待验证信息}"`
      - 第2轮:`{待验证信息核心关键词}` (不同引擎)
      - 第3轮:`site:gov.cn {关键词}` / WolframAlpha计算
      
      ---
      
      ## 三、引擎独有能力与场景匹配
      
      | 引擎 | 独有能力 | 最佳调查场景 |
      |------|---------|------------|
      | **Google** | 最全索引+高级操作符+时间过滤+语言筛选 | 所有调查的基础引擎 |
      | **Baidu** | 中文内容最全+知道/贴吧/百科 | 国内舆情+竞品口碑 |
      | **DuckDuckGo** | Bangs直达(!gh !so !w !a)+无追踪 | 技术调查+隐私调查 |
      | **WeChat搜狗** | 微信公众号文章搜索 | 深度分析文章+行业观察 |
      | **Toutiao** | 自媒体+热点追踪+实时性 | 热点事件+舆论走向 |
      | **Brave** | 独立索引+无偏见+Discussions | 无过滤信息+论坛观点 |
      | **Startpage** | Google结果+隐私保护 | 需Google结果但保护隐私 |
      | **WolframAlpha** | 结构化数据+知识计算 | 数据验证+数值型信息 |
      | **Bing INT** | 中文界面+国际搜索结果 | 跨国调查+国际对比 |
      | **Sogou** | 微信+知乎内容 | 中文社区深度内容 |
      
      ---
      
      ## 四、高级搜索策略
      
      ### 4.1 反向搜索法
      
      目的:通过已知信息反推更多细节
      
      ```
      已知:公司名 → 反向搜索
      ├── Google: "site:linkedin.com {公司名}"
      ├── DuckDuckGo: "!gh {公司名}"
      ├── Baidu: "{公司名} 团队 创始人"
      └── Google: "{公司名} filetype:pdf" (查找公开文档)
      ```
      
      ### 4.2 时间轴搜索法
      
      目的:追踪事件/信息随时间的变化
      
      ```
      ├── Google: "{关键词}&tbs=qdr:h" (1小时内)
      ├── Google: "{关键词}&tbs=qdr:d" (24小时内)
      ├── Google: "{关键词}&tbs=qdr:w" (1周内)
      ├── Google: "{关键词}&tbs=qdr:m" (1月内)
      └── 对比不同时间段结果变化
      ```
      
      ### 4.3 地域对比法
      
      目的:对比不同地区的信息差异
      
      ```
      ├── Baidu: "{关键词}" (中国视角)
      ├── Google: "{关键词}&gl=us" (美国视角)
      ├── Google HK: "{关键词}" (香港视角)
      ├── Ecosia: "{关键词}" (欧洲视角)
      └── 对比结果差异,识别信息偏差
      ```
      
      ### 4.4 垂直深耕法
      
      目的:在特定平台深入挖掘
      
      ```
      ├── Google: "site:reddit.com {关键词}" (Reddit社区)
      ├── Google: "site:zhihu.com {关键词}" (知乎)
      ├── Google: "site:github.com {关键词}" (开源项目)
      ├── Google: "site:crunchbase.com {关键词}" (融资数据)
      ├── WeChat: "{关键词}" (公众号深度文章)
      └── Google: "site:bloomberg.com {关键词}" (财经数据)
      ```
      
      ### 4.5 证据链构建法
      
      目的:构建完整证据链确认信息
      
      ```
      信息A(待验证)
      ├── 寻找首发源 → 源头是官方还是转载?
      ├── 确认传播路径 → 哪些媒体引用了?
      ├── 检查是否有反驳 → 搜索"辟谣"+"信息关键词"
      ├── 权威信源验证 → site:gov.cn / site:reuters.com
      └── 数据验证 → WolframAlpha(如适用)
      ```
      
      ---
      
      ## 五、常见调查场景引擎组合速查
      
      | 调查场景 | 推荐引擎组合 | 时间过滤 | 关键操作符 |
      |---------|------------|---------|-----------|
      | 产品竞品分析 | Baidu+Google+WeChat+DuckDuckGo | 近1月 | `site:` `""` |
      | 公司背景调查 | Baidu+Google+Bing INT+WeChat | 无限制 | `site:linkedin.com` |
      | 热点事件追踪 | Baidu+Toutiao+Google+WeChat | 近1天/1周 | `tbs=qdr:d` |
      | 人物背景验证 | Baidu+Google+DuckDuckGo(!gh) | 无限制 | `""` `site:` |
      | 融资数据验证 | Google+Baidu+WolframAlpha+Jisilu | 近1年 | `site:crunchbase.com` |
      | 用户口碑收集 | WeChat+Toutiao+DuckDuckGo+Brave | 近1月 | `site:reddit.com` |
      | 技术栈调查 | DuckDuckGo(!gh !so)+Google | 无限制 | `!gh` `!so` `site:` |
      | 价格/销量调查 | Baidu+Google+DuckDuckGo(!a) | 近1月 | `filetype:pdf` |
      | 学术论文验证 | Google Scholar+Google+DuckDuckGo | 近2年 | `site:arxiv.org` |
      | 法律诉讼排查 | Baidu+Google+Bing INT | 无限制 | `site:court.gov.cn` |
      
    • investigation-modes.md 5.3 KB
      # 调查模式详解
      
      ## 竞品情报调查
      
      分析竞争对手产品、市场策略、用户口碑。
      
      ### 搜索策略编排
      
      **第1轮:广域扫描**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | Baidu | {竞品名} 产品 功能 | 建立全景认知 |
      | Google | {竞品名} product review | 国际化视角 |
      | Bing INT | {竞品名} vs alternatives | 竞品对比 |
      
      **第2轮:深度挖掘**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | WeChat | {竞品名} 分析 测评 | 深度分析文章 |
      | Toutiao | {竞品名} 用户 评价 | 自媒体评价 |
      | DuckDuckGo | {竞品名} site:reddit.com OR site:producthunt.com | 社区真实反馈 |
      
      **第3轮:交叉验证**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | Baidu | {竞品名} 融资 营收 | 国内商业数据 |
      | Google | {竞品名} funding revenue | 国际商业数据 |
      | Brave | {竞品名} market share | 市场份额验证 |
      
      ### 输出模板
      
      | 维度 | 发现 | 来源 | 可信度 |
      |------|------|------|--------|
      | 产品定位 | ... | 多源交叉 | 高/中/低 |
      | 核心功能 | ... | 官方+评测 | 高 |
      | 用户口碑 | ... | 社交+论坛 | 中 |
      | 市场表现 | ... | 公开数据 | 高 |
      | 竞争优势 | ... | 对比分析 | 中 |
      | 潜在风险 | ... | 舆情监测 | 低 |
      
      ---
      
      ## 舆情事件调查
      
      热点事件追踪、舆论走向分析、危机监测。
      
      ### 搜索策略编排
      
      **第1轮:事件还原**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | Baidu | {事件关键词} (tbs=qdr:d) | 国内最新报道 |
      | Google | {事件关键词} (tbs=qdr:d) | 国际最新报道 |
      | Toutiao | {事件关键词} | 热点实时追踪 |
      
      **第2轮:多视角收集**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | WeChat | {事件关键词} 评论 分析 | 公众号深度解读 |
      | Sogou | {事件关键词} 观点 | 知乎等中文社区 |
      | DuckDuckGo | {事件关键词} site:reddit.com | 国际社区讨论 |
      
      **第3轮:时间线重建**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | Google | {事件关键词} (tbs=qdr:w) | 一周内演变 |
      | Bing INT | {事件关键词} timeline | 国际时间线 |
      | Baidu | {事件关键词} 时间线 | 国内时间线 |
      
      ### 输出模板
      
      ```
      📋 舆情调查报告
      
      🕐 时间线
      ├── [时间1] 事件起因 — 来源: xxx
      ├── [时间2] 关键转折 — 来源: xxx
      └── [时间3] 当前状态 — 来源: xxx
      
      📊 舆论分布
      ├── 支持方观点: ... (来源数: N)
      ├── 反对方观点: ... (来源数: N)
      └── 中立/观望: ... (来源数: N)
      
      ⚠️ 待验证信息
      ├── [信息A] — 验证状态: ⚠️ 单一来源
      └── [信息B] — 验证状态: ✅ 多源确认
      
      🔑 关键结论
      ├── 已确认: ...
      ├── 高概率: ...
      └── 待观察: ...
      ```
      
      ---
      
      ## 人物背景调查
      
      商务合作前的背景调查、行业人物了解。
      
      ### 搜索策略编排
      
      **第1轮:基本信息**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | Baidu | {人物名} 简介 背景 | 建立人物画像 |
      | Google | {人物名} biography profile | 国际化视角 |
      | Bing INT | {人物名} company role | 职业信息 |
      
      **第2轮:专业验证**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | Google Scholar | {人物名} | 学术成果验证 |
      | DuckDuckGo | !gh {人物名} | 开源项目/技术能力 |
      | DuckDuckGo | !so {人物名} | 技术社区活跃度 |
      
      **第3轮:信誉排查**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | Baidu | {人物名} 争议 诉讼 | 国内风险信号 |
      | Google | {人物名} controversy lawsuit | 国际风险信号 |
      | WeChat | {人物名} 评价 口碑 | 行业口碑 |
      
      ### 输出模板
      
      | 维度 | 信息 | 来源 | 可信度 |
      |------|------|------|--------|
      | 身份核实 | ... | 官方/社交 | 高 |
      | 职业履历 | ... | LinkedIn/官网 | 高 |
      | 专业成就 | ... | 学术/社区 | 中 |
      | 行业口碑 | ... | 社交媒体 | 中 |
      | 风险信号 | ... | 新闻/法律 | 需验证 |
      
      ---
      
      ## 信息交叉验证
      
      验证某条信息的真实性、对比不同来源的说法。
      
      ### 搜索策略编排
      
      **第1轮:信息溯源**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | Google | "{待验证信息}" (精确匹配) | 找到信息首发源 |
      | Baidu | "{待验证信息}" | 国内信息溯源 |
      
      **第2轮:多源比对**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | DuckDuckGo | {待验证信息} | 无追踪比对 |
      | Brave | {待验证信息} | 独立索引比对 |
      | Startpage | {待验证信息} | Google结果+隐私比对 |
      
      **第3轮:权威验证**
      
      | 引擎 | 搜索词 | 目的 |
      |------|--------|------|
      | Google | site:gov.cn {相关关键词} | 政府权威信源 |
      | Bing INT | site:reuters.com OR site:apnews.com {关键词} | 国际权威信源 |
      | WolframAlpha | {可计算的数据} | 结构化数据验证 |
      
      ### 输出模板
      
      ```
      🔍 信息验证报告
      
      📝 待验证信息:"{原始信息}"
      
      📊 验证结果
      ├── 支持来源数: N个
      │   ├── 来源1: xxx (可信度: 高)
      │   └── 来源2: xxx (可信度: 中)
      ├── 反对来源数: N个
      │   └── 来源3: xxx
      └── 无法确认来源数: N个
      
      ⚖️ 综合判定
      ├── ✅ 已确认: ... (多源一致)
      ├── ⚠️ 待确认: ... (来源矛盾)
      └── ❌ 已否定: ... (权威信源反驳)
      ```
      
    • investigation-templates.md 5.9 KB
      # 调查报告模板集
      
      ## 一、竞品情报调查报告
      
      ```markdown
      # 🔍 竞品情报调查报告
      
      ## 基本信息
      - **调查目标**:{竞品名称}
      - **调查日期**:{日期}
      - **调查模式**:竞品情报调查
      
      ---
      
      ## 1. 产品定位与概述
      
      | 维度 | 内容 | 来源 |
      |------|------|------|
      | 公司名称 | ... | ... |
      | 产品定位 | ... | ... |
      | 目标用户 | ... | ... |
      | 核心价值主张 | ... | ... |
      | 定价策略 | ... | ... |
      
      ## 2. 功能与特性
      
      | 功能 | 描述 | 我们是否有 | 差异分析 |
      |------|------|-----------|---------|
      | 功能A | ... | ✅/❌ | ... |
      | 功能B | ... | ✅/❌ | ... |
      | 功能C | ... | ✅/❌ | ... |
      
      ## 3. 用户口碑分析
      
      ### 正面评价
      - 评价1: "..." — 来源: {平台}
      - 评价2: "..." — 来源: {平台}
      
      ### 负面评价
      - 评价1: "..." — 来源: {平台}
      - 评价2: "..." — 来源: {平台}
      
      ### 口碑总结
      - 正面关键词: {关键词1, 关键词2, 关键词3}
      - 负面关键词: {关键词1, 关键词2, 关键词3}
      
      ## 4. 市场表现
      
      | 指标 | 数据 | 来源 | 可信度 |
      |------|------|------|--------|
      | 融资轮次/金额 | ... | ... | ... |
      | 用户规模 | ... | ... | ... |
      | 市场份额 | ... | ... | ... |
      | 增长趋势 | ... | ... | ... |
      
      ## 5. SWOT分析
      
      | | 正面 | 负面 |
      |---|------|------|
      | **内部** | **优势(S)**: ... | **劣势(W)**: ... |
      | **外部** | **机会(O)**: ... | **威胁(T)**: ... |
      
      ## 6. 关键发现与建议
      
      ### 🔑 关键发现
      1. ...
      2. ...
      3. ...
      
      ### 💡 行动建议
      1. ...
      2. ...
      3. ...
      
      ---
      *数据来源:多搜索引擎交叉调查 | 可信度标注遵循ABCD分级*
      ```
      
      ---
      
      ## 二、舆情事件调查报告
      
      ```markdown
      # 📋 舆情事件调查报告
      
      ## 基本信息
      - **事件主题**:{事件名称}
      - **调查日期**:{日期}
      - **调查模式**:舆情事件调查
      
      ---
      
      ## 1. 事件概况
      
      | 维度 | 内容 |
      |------|------|
      | 事件概述 | ... |
      | 涉及方 | ... |
      | 当前状态 | ... |
      | 舆论热度 | 🔥🔥🔥 (1-5级) |
      
      ## 2. 事件时间线
      
      | 时间 | 事件 | 来源 | 可信度 |
      |------|------|------|--------|
      | {时间1} | {事件1} | {来源1} | {A/B/C/D} |
      | {时间2} | {事件2} | {来源2} | {A/B/C/D} |
      | {时间3} | {事件3} | {来源3} | {A/B/C/D} |
      
      ## 3. 舆论分布
      
      ### 支持方观点
      - 观点1: "..." (来源数: N, 代表平台: ...)
      - 观点2: "..." (来源数: N, 代表平台: ...)
      
      ### 反对方观点
      - 观点1: "..." (来源数: N, 代表平台: ...)
      - 观点2: "..." (来源数: N, 代表平台: ...)
      
      ### 中立/观望
      - 观点1: "..." (来源数: N)
      
      ## 4. 关键信息验证
      
      | 待验证信息 | 验证结果 | 支持来源 | 反对来源 |
      |-----------|---------|---------|---------|
      | {信息1} | ✅已确认/⚠️待确认/❌已否定 | ... | ... |
      | {信息2} | ✅已确认/⚠️待确认/❌已否定 | ... | ... |
      
      ## 5. 舆论走向预判
      
      | 方向 | 概率 | 依据 |
      |------|------|------|
      | 走向A | 高/中/低 | ... |
      | 走向B | 高/中/低 | ... |
      
      ## 6. 风险评估
      
      | 风险项 | 影响级别 | 说明 |
      |--------|---------|------|
      | {风险1} | 🔴高/🟡中/🟢低 | ... |
      | {风险2} | 🔴高/🟡中/🟢低 | ... |
      
      ---
      *数据来源:多搜索引擎交叉调查 | 可信度标注遵循ABCD分级*
      ```
      
      ---
      
      ## 三、人物背景调查报告
      
      ```markdown
      # 👤 人物背景调查报告
      
      ## 基本信息
      - **调查对象**:{人物姓名}
      - **调查日期**:{日期}
      - **调查模式**:人物背景调查
      
      ---
      
      ## 1. 身份信息
      
      | 维度 | 信息 | 来源 | 可信度 |
      |------|------|------|--------|
      | 姓名 | ... | ... | ... |
      | 当前职务 | ... | ... | ... |
      | 所在公司 | ... | ... | ... |
      | 所在地 | ... | ... | ... |
      | 教育背景 | ... | ... | ... |
      
      ## 2. 职业履历
      
      | 时间 | 职位/经历 | 机构 | 来源 |
      |------|---------|------|------|
      | ... | ... | ... | ... |
      | ... | ... | ... | ... |
      
      ## 3. 专业成就
      
      | 成就 | 详情 | 来源 | 可信度 |
      |------|------|------|--------|
      | ... | ... | ... | ... |
      | ... | ... | ... | ... |
      
      ## 4. 行业口碑
      
      | 维度 | 评价 | 来源 |
      |------|------|------|
      | 技术能力 | ... | ... |
      | 管理风格 | ... | ... |
      | 行业影响力 | ... | ... |
      
      ## 5. 风险信号
      
      | 风险项 | 详情 | 来源 | 可信度 |
      |--------|------|------|--------|
      | 争议事件 | ... | ... | ... |
      | 法律诉讼 | ... | ... | ... |
      | 负面报道 | ... | ... | ... |
      
      ⚠️ 注:风险信号需多源确认,单一来源信息标注为"待验证"
      
      ## 6. 综合评估
      
      | 维度 | 评级 | 说明 |
      |------|------|------|
      | 专业能力 | ⭐⭐⭐⭐⭐ | ... |
      | 行业口碑 | ⭐⭐⭐⭐⭐ | ... |
      | 合作风险 | 🟢低/🟡中/🔴高 | ... |
      
      ## 7. 调查结论
      
      ...
      
      ---
      *数据来源:多搜索引擎交叉调查 | 可信度标注遵循ABCD分级*
      ```
      
      ---
      
      ## 四、信息验证报告
      
      ```markdown
      # 🔍 信息验证报告
      
      ## 验证请求
      - **待验证信息**:"{原始信息}"
      - **验证日期**:{日期}
      - **验证模式**:信息交叉验证
      
      ---
      
      ## 验证过程
      
      ### 第1轮:信息溯源
      | 引擎 | 搜索词 | 找到相关结果 | 首发/最早来源 |
      |------|--------|------------|-------------|
      | ... | ... | ✅/❌ | ... |
      | ... | ... | ✅/❌ | ... |
      
      ### 第2轮:多源比对
      | 引擎 | 结果倾向 | 关键发现 |
      |------|---------|---------|
      | Google | 支持/反对/中立 | ... |
      | Baidu | 支持/反对/中立 | ... |
      | DuckDuckGo | 支持/反对/中立 | ... |
      | Brave | 支持/反对/中立 | ... |
      
      ### 第3轮:权威验证
      | 权威来源 | 确认/否定 | 说明 |
      |---------|---------|------|
      | ... | ... | ... |
      
      ---
      
      ## 验证结论
      
      | 项目 | 结果 |
      |------|------|
      | **综合判定** | ✅ 已确认 / ⚠️ 待确认 / ❌ 已否定 |
      | **支持来源数** | N个 |
      | **反对来源数** | N个 |
      | **最高可信度来源** | {来源} (A级) |
      | **信息偏差风险** | 高/中/低 |
      
      ## 偏差分析
      - 不同引擎结果差异:...
      - 可能原因分析:...
      
      ## 建议
      - ...
      
      ---
      *数据来源:多搜索引擎交叉验证 | 可信度标注遵循ABCD分级*
      ```
      
    • investigator-config.json 4.6 KB
      {
        "name": "智能情报调查员",
        "version": "1.1.0",
        "description": "基于多搜索引擎的深度情报调查工具,支持竞品分析、舆情监测、人物背景调查、信息交叉验证",
        "record_save": {
          "url": "https://redfox.hk/story/api/skill/record/save",
          "method": "POST",
          "auth_header": "X-API-Key",
          "auth_note": "apikey必须通过X-API-Key请求头传入,放在Body中会返回code:3106错误",
          "source": "智能情报调查员",
          "source_note": "动态传入当前skill名称,不同skill使用不同source值",
          "credit_note": "需配置用户自有 REDFOX_API_KEY(格式 ak_xxxxxxxx)"
        },
        "modes": [
          {
            "id": "competitive",
            "name": "竞品情报调查",
            "description": "分析竞争对手产品、市场策略、用户口碑",
            "engines": ["Baidu", "Google", "Bing INT", "WeChat", "Toutiao", "DuckDuckGo", "Brave"]
          },
          {
            "id": "sentiment",
            "name": "舆情事件调查",
            "description": "热点事件追踪、舆论走向分析、危机监测",
            "engines": ["Baidu", "Google", "Toutiao", "WeChat", "Sogou", "DuckDuckGo", "Bing INT"]
          },
          {
            "id": "person",
            "name": "人物背景调查",
            "description": "商务合作前的背景调查、行业人物了解",
            "engines": ["Baidu", "Google", "Bing INT", "DuckDuckGo", "WeChat"]
          },
          {
            "id": "verify",
            "name": "信息交叉验证",
            "description": "验证信息真实性、对比不同来源说法",
            "engines": ["Google", "Baidu", "DuckDuckGo", "Brave", "Startpage", "WolframAlpha"]
          }
        ],
        "engines": [
          {"name": "Baidu", "url": "https://www.baidu.com/s?wd={keyword}", "region": "cn", "strength": "中文生态覆盖最广"},
          {"name": "Bing CN", "url": "https://cn.bing.com/search?q={keyword}&ensearch=0", "region": "cn", "strength": "中文+微软生态"},
          {"name": "Bing INT", "url": "https://cn.bing.com/search?q={keyword}&ensearch=1", "region": "cn", "strength": "中文界面+国际结果"},
          {"name": "360", "url": "https://www.so.com/s?q={keyword}", "region": "cn", "strength": "安全类信息"},
          {"name": "Sogou", "url": "https://sogou.com/web?query={keyword}", "region": "cn", "strength": "微信公众号收录"},
          {"name": "WeChat", "url": "https://wx.sogou.com/weixin?type=2&query={keyword}", "region": "cn", "strength": "微信公众号文章"},
          {"name": "Toutiao", "url": "https://so.toutiao.com/search?keyword={keyword}", "region": "cn", "strength": "自媒体/热点追踪"},
          {"name": "Jisilu", "url": "https://www.jisilu.cn/explore/?keyword={keyword}", "region": "cn", "strength": "金融投资数据"},
          {"name": "Google", "url": "https://www.google.com/search?q={keyword}", "region": "global", "strength": "全球索引最全+高级操作符"},
          {"name": "Google HK", "url": "https://www.google.com.hk/search?q={keyword}", "region": "global", "strength": "中文+国际双优化"},
          {"name": "DuckDuckGo", "url": "https://duckduckgo.com/html/?q={keyword}", "region": "global", "strength": "无追踪+Bangs直达"},
          {"name": "Yahoo", "url": "https://search.yahoo.com/search?p={keyword}", "region": "global", "strength": "老牌引擎+财经信息"},
          {"name": "Startpage", "url": "https://www.startpage.com/sp/search?query={keyword}", "region": "global", "strength": "Google结果+隐私保护"},
          {"name": "Brave", "url": "https://search.brave.com/search?q={keyword}", "region": "global", "strength": "独立索引+无偏见"},
          {"name": "Ecosia", "url": "https://www.ecosia.org/search?q={keyword}", "region": "global", "strength": "环保+欧洲视角"},
          {"name": "Qwant", "url": "https://www.qwant.com/?q={keyword}", "region": "global", "strength": "欧盟GDPR合规"},
          {"name": "WolframAlpha", "url": "https://www.wolframalpha.com/input?i={keyword}", "region": "global", "strength": "结构化数据+知识计算"}
        ],
        "time_filters": {
          "google": {
            "past_hour": "tbs=qdr:h",
            "past_day": "tbs=qdr:d",
            "past_week": "tbs=qdr:w",
            "past_month": "tbs=qdr:m",
            "past_year": "tbs=qdr:y",
            "custom": "tbs=cdr:1,cd_min:{start},cd_max:{end}"
          },
          "brave": {
            "past_day": "tf=pd",
            "past_week": "tf=pw",
            "past_month": "tf=pm",
            "past_year": "tf=py"
          },
          "startpage": {
            "past_day": "time=day",
            "past_week": "time=week",
            "past_month": "time=month",
            "past_year": "time=year"
          }
        },
        "credibility_levels": {
          "A": "官方/政府/权威媒体",
          "B": "行业媒体/专业平台",
          "C": "社交媒体/自媒体",
          "D": "匿名/未验证来源"
        }
      }
      
  • README.en.md 5.7 KB
    # AI Kuaishou Feed / ks-ai-feed
    
    ---
    
    ## Overview
    
    Automatically scans Kuaishou's AI content daily, filters viral videos by play count with intelligent clustering, delivers a dark-themed visual daily report, and provides AI intelligence insights — trending topics, emerging growth signals, key creator analysis, and recommended investigation directions.
    
    **Core Value**
    
    - **Precise Viral Discovery**: Automatically scans Kuaishou AI trending videos by play count and engagement — no more manual searching.
    - **Intelligent Topic Clustering**: Automatically identifies content directions and summarizes by category, giving you a clear breakdown of daily hot topics.
    - **Multi-Dimensional Intelligence**: Delivers trending topic rankings, growth signals, creator analysis, and recommended investigation directions for deep traffic trend insights.
    - **Visual Daily Report**: Dark-themed page with cover images, engagement data, and direct video links — ready for browser viewing and navigation.
    - **One-Click Subscription**: Enable daily automatic generation to track Kuaishou AI content trends continuously.
    
    **Who It's For**
    
    - 📊 **Content Operators / Creators** — Stay on top of daily Kuaishou AI trends and quickly get content inspiration.
    - 🏢 **MCNs / Brands** — Track AI content trends, identify rising creators and growth signals.
    - 🔍 **Industry Researchers** — Access structured intelligence on the Kuaishou AI content ecosystem and traffic landscape.
    
    ---
    
    ## Features
    
    ### Core Capabilities
    
    - **Viral Content Discovery**: Filters Kuaishou AI trending videos by play count and engagement, precisely identifying the day's hottest content.
    - **Intelligent Topic Clustering**: Automatically detects topic directions from video content and summarizes counts and proportions by category.
    - **AI Intelligence Insights**: Powered by the Intelligence Investigator methodology, generates trending topic rankings, emerging growth signals, key creators, recommended investigation directions, and cross-platform comparison suggestions.
    - **Visual Daily Report**: Dark-themed page featuring video cover images, views/likes/comments, and direct video links — ready to browse.
    - **One-Click Subscription**: Supports daily automatic report generation for continuous tracking without repeated manual effort.
    - **Reliable Cover Image Display**: Built-in anti-leech proxy and automatic image format conversion ensure cover images load properly.
    
    ---
    
    ## API Key Acquisition & Security
    
    - This skill requires the environment variable: `REDFOX_API_KEY`.
    - `REDFOX_API_KEY` is provided by [RedFoxHub](https://redfox.hk/settings/api-keys?source=github) (`https://redfox.hk`).
    - Please visit [RedFoxHub](https://redfox.hk?source=github) to register and obtain your `REDFOX_API_KEY`.
    - Configure the environment variable `REDFOX_API_KEY` on your device before using this skill.
    - Before providing your key, verify its source, permitted scope, validity period, and whether it supports reset or revocation.
    - Never hardcode or expose your key in plaintext within code, prompts, logs, or output files.
    
    ---
    
    ## Usage Guide
    
    Simply describe your needs in natural language — no commands to memorize.
    
    ### Quick Reference
    
    | Intent | Example Phrase | Result |
    | ------ | -------------- | ------ |
    | Today's Report | "Generate today's Kuaishou AI viral report" | Scans the day's trending content and outputs a visual report with intelligence insights |
    | Specific Direction | "Show me what's trending in Kuaishou AI art and AI tutorials" | Focuses on your specified keywords for targeted content matching |
    | Historical Review | "Pull up the Kuaishou AI report from June 10th" | Retrieves viral content and trends from a specific date |
    | Enable Subscription | "Set up daily Kuaishou AI report subscription for me" | Automatically generates a daily report for continuous tracking |
    
    ### Output Example
    
    Once the report is ready, you'll receive:
    
    - **Category Overview Table**: Topic-clustered display of video counts, proportions, and highlights per category — quickly grasp the day's trends.
    - **AI Intelligence Insights Report**: Includes emerging growth signals (early identification of potential topics), key creators (high-output, high-engagement authors), recommended investigation directions (scenarios + search keywords), and cross-platform comparison suggestions.
    - **Visual Report Page**: Dark-themed, with cover images, full engagement data, and direct video links — ready for browser viewing.
    - **Structured Terminal Output**: Tables displayed in the conversation summarizing categorized videos and intelligence insights.
    
    ---
    
    ## Use Cases
    
    | Scenario | Role | Example Query | Benefit |
    | -------- | ---- | ------------- | ------- |
    | Daily Trend Tracking | Content Operator | "Is today's Kuaishou AI report ready?" | Quickly understand the day's AI trending content and topic distribution |
    | Content Inspiration | Creator | "What AI viral videos on Kuaishou are worth referencing?" | Discover trending content angles and creative patterns |
    | Creator Discovery | MCN / Brand | "Who are the active creators in the Kuaishou AI space recently?" | Identify high-engagement creators to support collaboration decisions |
    | Trend Forecasting | Industry Analyst | "What new trends are emerging in Kuaishou AI content this week?" | Capture traffic opportunities and plan content direction ahead of time |
    
    ---
    
    ## Important Data Notes
    
    - **Update Time**: Data from the previous day is updated daily at 15:00.
    - **Queryable Range**: Only dates with updated data are available (yesterday and earlier); current-day data is typically unavailable.
    - **When Data Is Unavailable**: If the target date's data has not been updated yet, the system will automatically notify you and ask whether to query the latest available date.
    
  • README.md 4.7 KB
    # AI快手信息源 / ks-ai-feed
    
    ---
    
    ## 简介
    
    每日自动扫描快手平台AI创作内容,按播放量筛选爆款视频并智能聚类,交付深色主题可视化日报,同步输出AI情报洞察——热度TOP话题、新兴起量信号、核心达人分析与推荐调查方向。
    
    **核心价值**
    
    - **精准发现爆款**:按播放量与互动数据自动扫描快手AI热门视频,告别逐条翻找。
    - **智能话题聚类**:自动识别内容方向并按分类汇总,每日热点分布一目了然。
    - **多维情报洞察**:同步输出热度TOP话题、起量信号、达人分析与推荐调查方向,深度把握流量趋势。
    - **可视化日报交付**:深色主题页面含封面图、互动数据与视频直链,支持浏览器直接浏览与跳转。
    - **一键订阅追踪**:开启每日自动产出,持续追踪快手AI内容动态不遗漏。
    
    **适用对象**
    
    - 📊 **内容运营 / 自媒体** — 每日掌握快手AI赛道热点,快速获取选题灵感。
    - 🏢 **MCN / 品牌方** — 追踪AI内容趋势,识别潜力达人与起量信号。
    - 🔍 **行业研究者** — 获取结构化情报,了解快手AI内容生态与流量格局。
    
    ---
    
    ## 功能特性
    
    ### 核心功能
    
    - **爆款内容发现**:按播放量与互动数据筛选快手AI热门视频,精准定位当日高热度内容。
    - **智能话题聚类**:自动识别视频内容的话题方向,按分类汇总数量与占比。
    - **AI情报洞察**:基于智能情报调查员方法论,生成热度TOP话题、新兴起量信号、核心达人、推荐调查方向与跨平台对比建议。
    - **可视化日报**:深色主题页面含视频封面图、播放/点赞/评论等互动数据、视频直链,可直接浏览。
    - **一键订阅**:支持每日自动产出日报,持续追踪无需手动重复操作。
    - **封面图稳定展示**:内置防盗链代理与图片格式自动转换,确保封面图正常加载。
    
    ---
    
    ## 密钥获取与安全说明
    
    - 本技能需要使用环境变量:`REDFOX_API_KEY`。
    - `REDFOX_API_KEY` 由 [红狐 hub](https://redfox.hk/settings/api-keys?source=github)(`https://redfox.hk`)提供。
    - 请前往 [红狐 hub](https://redfox.hk?source=github) 注册账号,获取 `REDFOX_API_KEY`。
    - 配置设备环境变量 `REDFOX_API_KEY` 后使用本技能。
    - 在提供密钥前,请先确认密钥来源、可用范围、有效期及是否支持重置/撤销。
    - 禁止在代码、提示词、日志或输出文件中硬编码/明文暴露密钥。
    
    ---
    
    ## 使用指南
    
    直接用自然语言描述需求即可,无需记忆命令。
    
    ### 常用说法速查
    
    | 意图 | 示例话术 | 效果 |
    | ---- | -------- | ---- |
    | 今日日报 | 「帮我生成今天的快手AI爆款日报」 | 扫描当日热门内容,输出可视化日报与情报洞察 |
    | 指定方向 | 「看看快手AI绘画和AI教程方向最近什么火」 | 按你关注的关键词聚焦匹配内容 |
    | 历史回顾 | 「查看6月10号的快手AI日报」 | 回溯指定日期的爆款内容与趋势 |
    | 开启订阅 | 「帮我开启快手AI日报每日订阅」 | 每日自动产出一份日报,持续追踪 |
    
    ### 输出示例
    
    日报完成后你将收到:
    
    - **分类概览表**:按话题聚类展示各分类的视频数量、占比与头部亮点,快速掌握当日风向。
    - **AI情报洞察报告**:含新兴起量信号(提前捕捉潜力话题)、核心达人(高产+高互动作者)、推荐调查方向(场景+搜索关键词)与跨平台对比建议。
    - **可视化日报页面**:深色主题,含封面图、完整互动数据与视频直链,支持浏览器直接浏览。
    - **终端结构化输出**:同步以表格形式在对话中展示分类视频与情报摘要。
    
    ---
    
    ## 使用场景
    
    | 场景 | 角色 | 示例问法 | 收益 |
    | ---- | ---- | -------- | ---- |
    | 每日热点追踪 | 内容运营 | 「今天的快手AI日报出来了吗」 | 快速了解当日AI赛道热门内容与话题分布 |
    | 选题灵感获取 | 自媒体博主 | 「快手最近有哪些AI爆款视频值得参考」 | 发现热门选题方向与内容创作规律 |
    | 达人发现 | MCN / 品牌方 | 「最近快手AI领域有哪些活跃达人」 | 识别高互动创作者,辅助合作决策 |
    | 趋势预判 | 行业分析师 | 「本周快手AI内容有什么新趋势」 | 捕捉流量风口,提前布局内容方向 |
    
    ---
    
    ## 重要数据说明
    
    - **更新时间**:每日 15:00 更新前一天的数据。
    - **可查询范围**:仅可查询已更新数据的日期(昨天及之前),当天数据通常不可用。
    - **数据不可用时**:若目标日期数据尚未更新,系统将自动提示并询问是否查询最新可用日期。
    
  • SKILL.md 7.6 KB
    ---
    name: ks-ai-feed
    description: 快手AI内容日报生成工具。每日自动扫描快手平台AI创作内容,按播放量筛选爆款视频并智能聚类,生成深色主题HTML日报(含封面图、互动数据、视频直链),同步输出AI情报洞察(热度TOP话题、起量信号、核心达人、推荐调查方向)。当用户需要AI快手日报、快手爆款、AI快手热点、快手AI内容、快手AI视频、快手情报时使用。触发词:AI快手日报、快手爆款、快手AI热点、快手情报、快手AI视频。
    ---
    
    # AI快手信息源
    
    ## 📝 简介
    
    每日自动扫描快手平台AI创作内容,按播放量筛选爆款视频、智能聚类生成深色主题HTML日报,同步输出基于智能情报调查员方法论的AI情报洞察。
    
    
    ## ✨ 功能特性
    
    | 功能模块 | 能力描述 | 核心价值 |
    |---------|---------|----------|
    | 爆款发现 | 按播放量筛选快手AI热门视频 | 精准定位高热度内容 |
    | 智能聚类 | 从内容中自动识别话题方向 | 每日热点一目了然 |
    | AI情报洞察 | 热度TOP话题、起量信号、达人分析、推荐调查方向 | 深度洞察流量趋势 |
    | 可视化日报 | 深色HTML日报,含封面图、互动数据、视频直链 | 直观浏览与跳转 |
    | 一键订阅 | `--subscribe` 开启每日自动产出 | 持续追踪不遗漏 |
    | 图片兼容 | 防盗链代理 + HEIF/HEIC 自动转JPG | 封面图稳定展示 |
    
    ## 🔑 鉴权
    
    前往 [redfox.hk/login](https://www.redfox.hk/login) 注册获取 API Token,然后配置:
    
    | 方式 | 命令 |
    |------|------|
    | 环境变量(推荐) | `export REDFOX_API_KEY=ak_你的密钥` |
    | 命令行参数 | `--api-key ak_你的密钥` |
    | 配置文件 | `echo '{"api_key":"ak_你的密钥"}' > ~/.qoder/apis/redfox.json` |
    
    ## 🔌 API 接口规范
    
    ### 批量查询接口
    
    **接口地址**: `POST https://redfox.hk/story/api/parseWork/queryKsAiMsgs/batch`
    
    **请求头**:
    ```
    X-API-Key: ak_你的API密钥
    Content-Type: application/json
    ```
    
    **请求体**:
    ```json
    {
      "keywords": ["AI", "人工智能", "大模型", "GPT", "Agent", "AI绘画", "AI教程"],
      "pageNum": 1,
      "pageSize": 200,
      "source": "AI快手信息源-GitHub",
      "startTime": "2026-06-16 00:00:00",  // 可选
      "endTime": "2026-06-16 23:59:59"      // 可选
    }
    ```
    
    **参数说明**:
    | 参数 | 类型 | 必填 | 说明 |
    |------|------|------|------|
    | `keywords` | Array | ✅ | 关键词数组,支持多关键词批量查询 |
    | `pageNum` | Number | ✅ | 页码,从1开始 |
    | `pageSize` | Number | ✅ | 每页条数,默认200 |
    | `source` | String | ✅ | 来源标识 |
    | `startTime` | String | ❌ | 开始时间 `YYYY-MM-DD HH:mm:ss` |
    | `endTime` | String | ❌ | 结束时间 `YYYY-MM-DD HH:mm:ss` |
    
    **性能优势**:
    - ✅ 一次请求传入所有关键词,减少85%+ API调用
    - ✅ 自动去重合并,数据更全面
    - ✅ 超时时间30秒,适配大批量数据
    
    ## 📊 数据更新规则
    
    - **更新时间**:每日 15:00 更新前一天的数据
    - **可查询日期**:仅可查询已更新数据的日期(昨天及之前)
    - **数据不可用时**:脚本自动判断目标日期是否已有数据,若尚未更新则提示用户并询问是否查询最新可用日期
    
    ## 🔧 使用方式
    
    ```bash
    # 生成今日爆款日报(含情报洞察)
    python3 "$SKILL_PATH/assets/daily_report.py"
    
    # 自定义关注方向
    python3 "$SKILL_PATH/assets/daily_report.py" --keywords "AI教程,AI绘画,ChatGPT,AI工具"
    
    # 查看历史某天
    python3 "$SKILL_PATH/assets/daily_report.py" --date 2026-06-10
    
    # 订阅 / 取消订阅
    python3 "$SKILL_PATH/assets/daily_report.py" --subscribe
    python3 "$SKILL_PATH/assets/daily_report.py" --unsubscribe
    ```
    
    > 依赖:`pip3 install requests`
    
    > ⚠️ **Windows 用户注意**:命令中的 `python3` 需替换为 `python`,`pip3` 替换为 `pip`。
    
    生成的 HTML 日报保存在 `~/Downloads/QoderReports/`。终端同步输出分类视频表格 + AI情报洞察。
    
    ### 预览服务
    
    1. 运行 `daily_report.py` 时加 `--no-open` 参数
    2. **单独启动预览服务**(后台运行):
       ```bash
       python3 "$SKILL_PATH/assets/preview_server.py"
       ```
    3. 调用 RunPreview,**必须使用 HTML 文件直链地址**:`http://127.0.0.1:8766/{HTML文件名}`
    
    > ⚠️ **RunPreview 必须使用 HTML 文件直链地址**(如 `http://127.0.0.1:8766/AI快手日报_2026-06-16_150715.html`),不可使用根路径 `http://127.0.0.1:8766`,根路径的 302 重定向会导致空白页面。
    
    > 内置服务同时提供:静态 HTML 文件服务 + `/api/search` 搜索代理 + `/api/img` 图片代理(绕过快手防盗链)。
    
    ## 核心参数
    
    | 参数 | 说明 | 默认值 |
    |------|------|--------|
    | `--keywords` | 关注的话题方向,逗号分隔 | `AI,人工智能,大模型,GPT,Agent,AI绘画,AI教程` |
    | `--count` | 扫描视频数量 | `200` |
    | `--date` | 指定日期,`YYYY-MM-DD` 或范围 `YYYY-MM-DD~YYYY-MM-DD` | 今天 |
    | `--output-dir` | 输出目录 | `~/Downloads/QoderReports` |
    | `--api-key` | 指定 API Key | — |
    | `--subscribe` | 开启每日订阅 | — |
    | `--unsubscribe` | 关闭每日订阅 | — |
    | `--no-open` | 不自动打开浏览器 | — |
    
    ## 🧠 AI情报洞察
    
    基于智能情报调查员方法论,在每日快手爆款内容聚类后同步生成:
    
    | 洞察模块 | 内容 | 价值 |
    |---------|------|------|
    | 热度TOP话题 | 占比、条数、头部视频 | 快速掌握当日风向 |
    | 新兴起量信号 | 低占比高互动的潜力话题 | 提前捕捉流量风口 |
    | 核心达人 | 高产+高互动作者 | 锁定关键创作者 |
    | 推荐调查方向 | 场景+引擎组合+搜索关键词 | 一键进入深度调查 |
    | 跨平台对比建议 | 同步关注其他平台同话题 | 全网视角消除偏差 |
    
    详细调查策略见 [engine-strategy.md](references/engine-strategy.md)、[investigation-modes.md](references/investigation-modes.md)、[investigation-templates.md](references/investigation-templates.md)。
    
    ## 📋 固定输出模式
    
    每次运行日报后,终端与对话输出**必须**遵循以下结构化格式:
    
    ```markdown
    ## AI快手信息源 · {日期} 日报
    
    **扫描 {N} 条热门视频,聚类 {M} 个分类**
    
    ---
    
    ### 分类概览
    
    | 分类 | 数量 | 占比 | 亮点 |
    |------|------|------|------|
    | #{分类名} | {N}条 | {X}% | 头部视频亮点描述 |
    
    ---
    
    ### AI情报洞察报告
    
    **一、新兴起量信号**
    
    - 🔥 **#{话题}** — 仅{N}条但均互动{X}+,描述
    
    **二、核心达人**
    
    | 达人 | 作品数 | 总赞 | 亮点 |
    |------|--------|------|------|
    | @{作者} | {N}条 | {X}w | 描述 |
    
    **三、推荐调查方向**
    
    | 话题 | 调查场景 | 推荐引擎 | 搜索关键词 |
    |------|---------|---------|-----------|
    | #{话题} | {场景} | 引擎组合 | 关键词1 / 关键词2 |
    
    **四、跨平台对比建议**
    
    - **{话题}** — 建议同步关注抖音、B站、小红书同话题热度
    
    ---
    
    **日报地址**:{HTML文件绝对路径}
    
    **预览地址**:http://127.0.0.1:8766/{HTML文件名}
    ```
    
    > 以上格式为**强制规范**,所有字段不可省略。若某模块无数据则标注"暂无"。
    
    > **必须执行**:日报输出完成后,按以下步骤启动预览:
    > 1. 后台启动预览服务:`python3 "$SKILL_PATH/assets/preview_server.py"`
    > 2. 调用 RunPreview,使用 HTML 文件直链地址 `http://127.0.0.1:8766/{HTML文件名}`(不可用根路径)
    
    ## 其他资源
    
    - [engine-strategy.md](references/engine-strategy.md) — 引擎选择策略、独有能力与高级搜索方法
    - [investigation-modes.md](references/investigation-modes.md) — 四种调查模式的搜索策略编排与输出模板
    - [investigation-templates.md](references/investigation-templates.md) — 调查报告完整模板集
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related