自动同步: 2026-03-14 02:10
This commit is contained in:
@@ -1,94 +1,207 @@
|
||||
---
|
||||
name: kb-deep-analyzer
|
||||
description: AI深度分析 - 使用 AI 对内容进行深度分析和摘要
|
||||
---
|
||||
|
||||
# KB Deep Analyzer Skill
|
||||
|
||||
**kb-deep-analyzer** - AI-powered deep content analysis.
|
||||
**kb-deep-analyzer** - AI 深度内容分析工具。
|
||||
|
||||
## Features
|
||||
## 什么时候使用
|
||||
|
||||
- Multi-type analysis (tutorial, documentation, news)
|
||||
- Template-based output
|
||||
- Quality scoring
|
||||
- Automatic tagging
|
||||
- **多格式元数据支持**: 支持扁平结构 `{"title":"xxx"}` 和嵌套结构 `{"data":{"metadata":{...}}}`
|
||||
- kb-workflow 步骤 5:对视频字幕或文章内容进行深度分析
|
||||
- 需要生成摘要、主题、见解等
|
||||
|
||||
## Commands
|
||||
## 功能
|
||||
|
||||
- 多类型分析:视频(video)、文章(article)
|
||||
- 模板化输出
|
||||
- 质量评分
|
||||
- 自动标签
|
||||
- 多格式元数据支持
|
||||
|
||||
## 环境变量(必需)
|
||||
|
||||
| 变量名 | 说明 | 示例 |
|
||||
|--------|------|------|
|
||||
| `AI_API_KEY` | AI API 密钥 | `your-api-key` |
|
||||
| `AI_PROVIDER` | AI 提供商 | `zhipu` / `openai` / `minimax` |
|
||||
| `AI_MODEL` | 模型名称 | `glm-5` / `gpt-4` |
|
||||
| `AI_BASE_URL` | API 端点 | `https://open.bigmodel.cn/api/coding/paas/v4` |
|
||||
|
||||
## 命令
|
||||
|
||||
```bash
|
||||
# 分析内容(推荐:使用 -u 参数强制无缓冲输出)
|
||||
AI_API_KEY="your-api-key" AI_PROVIDER="zhipu" AI_MODEL="glm-4.7" \
|
||||
python3 -u deep_analyzer.py --metadata meta.json --content content.json --output analysis.md
|
||||
# 分析视频
|
||||
AI_API_KEY="xxx" AI_PROVIDER="zhipu" AI_MODEL="glm-5" \
|
||||
python3 -u deep_analyzer.py \
|
||||
--metadata meta.json \
|
||||
--content content.json \
|
||||
--output analysis.md \
|
||||
--type video \
|
||||
--provider zhipu --model glm-5
|
||||
|
||||
# 指定类型
|
||||
python deep_analyzer.py --metadata meta.json --content content.json --type tutorial --output tutorial.md
|
||||
|
||||
# 指定 AI 提供商
|
||||
python deep_analyzer.py -m meta.json -c content.json -o out.md --provider zhipu --model glm-4
|
||||
# 分析文章
|
||||
AI_API_KEY="xxx" AI_PROVIDER="zhipu" AI_MODEL="glm-5" \
|
||||
python3 -u deep_analyzer.py \
|
||||
--metadata meta.json \
|
||||
--content content.txt \
|
||||
--output analysis.md \
|
||||
--type article \
|
||||
--provider zhipu --model glm-5
|
||||
```
|
||||
|
||||
## 环境变量配置
|
||||
## 参数说明
|
||||
|
||||
**必须设置以下环境变量**:
|
||||
| 参数 | 说明 | 必需 |
|
||||
|------|------|------|
|
||||
| `--metadata` | 元数据 JSON 文件路径 | 是 |
|
||||
| `--content` | 内容文件路径(JSON/TXT) | 是 |
|
||||
| `--output` | 输出 Markdown 文件路径 | 是 |
|
||||
| `--type` | 内容类型(video/article) | 是 |
|
||||
| `--provider` | AI 提供商 | 否(默认从环境变量) |
|
||||
| `--model` | 模型名称 | 否(默认从环境变量) |
|
||||
|
||||
```bash
|
||||
export AI_API_KEY="your-api-key"
|
||||
export AI_PROVIDER="zhipu" # 或 openai, minimax
|
||||
export AI_MODEL="glm-5" # 模型名称
|
||||
export AI_BASE_URL="https://..." # 可选,自定义 API 地址
|
||||
```
|
||||
## 输出格式 Schema
|
||||
|
||||
### 重要提示
|
||||
### 必需字段
|
||||
|
||||
**必须使用 `-u` 参数运行 Python**,确保输出实时显示在终端:
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `success` | boolean | 是否分析成功 |
|
||||
|
||||
```bash
|
||||
python3 -u deep_analyzer.py ...
|
||||
```
|
||||
### 成功时字段
|
||||
|
||||
如果不使用 `-u` 参数,Python 的 stdout 缓冲会导致输出延迟或看不到进度。
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `output_file` | string | 输出文件路径 |
|
||||
| `model` | string | 使用的模型 |
|
||||
| `provider` | string | 使用的提供商 |
|
||||
|
||||
## 执行方式选择
|
||||
### 失败时字段
|
||||
|
||||
### 方式1: 并发执行(推荐,默认)
|
||||
- 使用 `batch_size=3`(默认)
|
||||
- 6个分片约 100 秒完成
|
||||
- 适合快速分析
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `error` | string | 错误信息 |
|
||||
| `message` | string | 详细说明 |
|
||||
|
||||
```bash
|
||||
python3 -u deep_analyzer.py --metadata meta.json --content content.json -o out.md
|
||||
```
|
||||
|
||||
### 方式2: 顺序执行
|
||||
- 使用 `batch_size=1`
|
||||
- 6个分片约 735 秒完成
|
||||
- 适合调试和问题排查
|
||||
|
||||
```bash
|
||||
# 在代码中设置 batch_size=1
|
||||
# analyzer.analyze(metadata, content, "video", batch_size=1)
|
||||
```
|
||||
|
||||
## Metadata Format
|
||||
|
||||
支持两种元数据格式:
|
||||
## 成功示例
|
||||
|
||||
```json
|
||||
// 格式1: 扁平结构
|
||||
{
|
||||
"title": "视频标题",
|
||||
"author": "作者名",
|
||||
"duration": 619,
|
||||
"bvid": "BVxxx"
|
||||
}
|
||||
|
||||
// 格式2: 嵌套结构(kb-bilibili-metadata 输出)
|
||||
{
|
||||
"data": {
|
||||
"metadata": {
|
||||
"title": "视频标题",
|
||||
"author": "作者名",
|
||||
"duration": "10:19"
|
||||
}
|
||||
}
|
||||
"success": true,
|
||||
"output_file": "analyzed/bilibili_BV1xx411c7mD.md",
|
||||
"model": "glm-5",
|
||||
"provider": "zhipu"
|
||||
}
|
||||
```
|
||||
|
||||
会自动转换为扁平格式进行分析。
|
||||
## 错误示例
|
||||
|
||||
### API 调用失败
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "AI API 调用失败: rate limit exceeded",
|
||||
"message": "深度分析失败,整个流程终止"
|
||||
}
|
||||
```
|
||||
|
||||
### 环境变量未设置
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "AI_API_KEY 环境变量未设置",
|
||||
"suggestion": "请配置 AI_API_KEY 环境变量"
|
||||
}
|
||||
```
|
||||
|
||||
### 内容文件不存在
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "内容文件不存在",
|
||||
"content_file": "content/missing.json"
|
||||
}
|
||||
```
|
||||
|
||||
## 输出格式(Markdown)
|
||||
|
||||
### 视频分析输出
|
||||
|
||||
```markdown
|
||||
# 视频标题
|
||||
|
||||
## 摘要
|
||||
[200-300字的核心内容摘要]
|
||||
|
||||
## 主要主题
|
||||
- 主题1
|
||||
- 主题2
|
||||
- 主题3
|
||||
|
||||
## 关键见解
|
||||
- 见解1
|
||||
- 见解2
|
||||
|
||||
## 时间轴
|
||||
- 00:00 - 02:30: 第一部分
|
||||
- 02:30 - 05:00: 第二部分
|
||||
...
|
||||
|
||||
## 标签
|
||||
#标签1 #标签2 #标签3
|
||||
```
|
||||
|
||||
### 文章分析输出
|
||||
|
||||
```markdown
|
||||
# 文章标题
|
||||
|
||||
## 摘要
|
||||
[300字以内的核心观点]
|
||||
|
||||
## 主要主题
|
||||
- 主题1
|
||||
- 主题2
|
||||
|
||||
## 完整原文
|
||||
[原始文章内容]
|
||||
```
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
cp -r kb-deep-analyzer/ ~/.openclaw/skills/
|
||||
pip install httpx
|
||||
```
|
||||
|
||||
## 在 kb-workflow 中的使用
|
||||
|
||||
```bash
|
||||
# 步骤 5:深度分析
|
||||
# ⚠️ 必须成功,否则整个流程失败
|
||||
|
||||
AI_API_KEY="$AI_API_KEY" AI_PROVIDER="zhipu" AI_MODEL="glm-5" \
|
||||
python3 -u ~/.openclaw/skills/kb-deep-analyzer/deep_analyzer.py \
|
||||
--metadata "metadata/bilibili_BV1xx411c7mD.meta.json" \
|
||||
--content "content/bilibili_BV1xx411c7mD.json" \
|
||||
--output "analyzed/bilibili_BV1xx411c7mD.md" \
|
||||
--type video \
|
||||
--provider zhipu --model glm-5
|
||||
|
||||
# 检查结果:
|
||||
# - success=true → 进入步骤 6(归档)
|
||||
# - success=false → 整个流程终止,报告错误
|
||||
```
|
||||
|
||||
## ⚠️ 重要提示
|
||||
|
||||
1. **必须使用 `-u` 参数**:确保 Python 输出实时显示
|
||||
2. **深度分析不可跳过**:这是必须成功的步骤
|
||||
3. **失败即终止**:如果返回 `success: false`,整个流程必须停止
|
||||
4. **禁止降级**:不能使用预设模板或简单摘要"假装成功"
|
||||
5. **并发执行**:默认使用 batch_size=3 并发处理
|
||||
|
||||
@@ -29,6 +29,7 @@ class AnalysisResult:
|
||||
key_insights: List[str] = field(default_factory=list)
|
||||
recommended_tags: List[str] = field(default_factory=list)
|
||||
full_analysis: str = ""
|
||||
original_text: str = "" # 文章类型的原文内容
|
||||
|
||||
|
||||
# ============== AI 客户端 ==============
|
||||
@@ -129,8 +130,14 @@ class DeepAnalyzer:
|
||||
def __init__(self, ai_client: SimpleAIClient = None):
|
||||
self.ai_client = ai_client or SimpleAIClient()
|
||||
|
||||
def analyze(self, metadata: Dict[str, Any], content: Dict[str, Any]) -> AnalysisResult:
|
||||
"""一次性调用 AI 生成完整分析报告"""
|
||||
def analyze(self, metadata: Dict[str, Any], content: Dict[str, Any], content_type: str = "video") -> AnalysisResult:
|
||||
"""一次性调用 AI 生成完整分析报告
|
||||
|
||||
Args:
|
||||
metadata: 元数据字典
|
||||
content: 内容字典
|
||||
content_type: 内容类型,"video" 或 "article"
|
||||
"""
|
||||
|
||||
# 标准化元数据
|
||||
metadata = self._normalize_metadata(metadata)
|
||||
@@ -141,18 +148,15 @@ class DeepAnalyzer:
|
||||
pubtime = metadata.get('pubtime', '')
|
||||
url = metadata.get('url', '')
|
||||
bvid = metadata.get('bvid', '')
|
||||
platform = metadata.get('platform', 'bilibili')
|
||||
|
||||
# 获取内容 - 支持多种字段名
|
||||
text = content.get('text', '') or content.get('subtitle', '') or content.get('subtitles', '') or content.get('description', '')
|
||||
|
||||
print(f"[DeepAnalyzer] 开始分析: {title}")
|
||||
print(f"[DeepAnalyzer] 时长: {duration}秒, 内容长度: {len(text)} 字符")
|
||||
print(f"[DeepAnalyzer] 类型: {content_type}, 内容长度: {len(text)} 字符")
|
||||
|
||||
# 计算分片数(按10分钟分片)
|
||||
num_chunks = max(1, (duration + 599) // 600) # 向上取整到10分钟
|
||||
print(f"[DeepAnalyzer] 将分 {num_chunks} 段分析")
|
||||
|
||||
# 构建 prompt
|
||||
# 构建 prompt(根据类型选择不同模板)
|
||||
prompt = self._build_prompt(
|
||||
title=title,
|
||||
duration=duration,
|
||||
@@ -161,8 +165,9 @@ class DeepAnalyzer:
|
||||
pubtime=pubtime,
|
||||
url=url,
|
||||
bvid=bvid,
|
||||
platform=platform,
|
||||
text=text,
|
||||
num_chunks=num_chunks
|
||||
content_type=content_type
|
||||
)
|
||||
|
||||
# 调用 AI
|
||||
@@ -173,13 +178,29 @@ class DeepAnalyzer:
|
||||
raise
|
||||
|
||||
# 解析结果
|
||||
result = self._parse_analysis(full_analysis, text, duration)
|
||||
result = self._parse_analysis(full_analysis, text, duration, content_type)
|
||||
|
||||
# 文章类型:追加原文
|
||||
if content_type == "article":
|
||||
result.original_text = text
|
||||
|
||||
return result
|
||||
|
||||
def _build_prompt(self, title: str, duration: int, duration_str: str, author: str,
|
||||
pubtime: str, url: str, bvid: str, text: str, num_chunks: int) -> str:
|
||||
"""构建分析 prompt"""
|
||||
pubtime: str, url: str, bvid: str, platform: str, text: str,
|
||||
content_type: str = "video") -> str:
|
||||
"""构建分析 prompt,根据内容类型选择不同模板"""
|
||||
if content_type == "article":
|
||||
return self._build_article_prompt(title, author, pubtime, url, platform, text)
|
||||
else:
|
||||
return self._build_video_prompt(title, duration, duration_str, author, pubtime, url, bvid, platform, text)
|
||||
|
||||
def _build_video_prompt(self, title: str, duration: int, duration_str: str, author: str,
|
||||
pubtime: str, url: str, bvid: str, platform: str, text: str) -> str:
|
||||
"""构建视频分析 prompt"""
|
||||
|
||||
# 计算分片数(按10分钟分片)
|
||||
num_chunks = max(1, (duration + 599) // 600)
|
||||
|
||||
# 截取适当长度的文本(20-30K 字符)
|
||||
max_chars = 30000
|
||||
@@ -195,7 +216,7 @@ class DeepAnalyzer:
|
||||
作者:{author}
|
||||
时长:{duration_str}({duration}秒)
|
||||
发布日期:{pubtime}
|
||||
平台:bilibili
|
||||
平台:{platform}
|
||||
URL:{url}
|
||||
|
||||
【内容】(完整字幕)
|
||||
@@ -240,7 +261,56 @@ URL:{url}
|
||||
|
||||
return prompt
|
||||
|
||||
def _parse_analysis(self, analysis_text: str, original_text: str, duration: int) -> AnalysisResult:
|
||||
def _build_article_prompt(self, title: str, author: str, pubtime: str,
|
||||
url: str, platform: str, text: str) -> str:
|
||||
"""构建文章分析 prompt"""
|
||||
|
||||
# 文章保留完整内容(不截断,因为需要追加原文)
|
||||
# 但 prompt 中只取前 20000 字符供 AI 分析
|
||||
max_chars = 20000
|
||||
if len(text) > max_chars:
|
||||
text_sample = text[:max_chars] + "\n\n[...内容过长已截断,但原文会完整保留...]"
|
||||
else:
|
||||
text_sample = text
|
||||
|
||||
prompt = f"""你是一个专业的文章内容分析师。请根据以下信息生成摘要:
|
||||
|
||||
【文章信息】
|
||||
标题:{title}
|
||||
作者:{author}
|
||||
发布日期:{pubtime}
|
||||
平台:{platform}
|
||||
URL:{url}
|
||||
|
||||
【内容】
|
||||
{text_sample}
|
||||
|
||||
【输出要求】必须使用以下格式:
|
||||
|
||||
## 摘要
|
||||
[300字以内的摘要,描述文章的核心观点和主要内容]
|
||||
|
||||
## 主要主题
|
||||
[从内容中提取不超过5个主题,每个不超过10字]
|
||||
- 主题1
|
||||
- 主题2
|
||||
...
|
||||
|
||||
## 标签
|
||||
[从内容中提取3-5个精炼标签,每个不超过10字]
|
||||
- 标签1
|
||||
- 标签2
|
||||
...
|
||||
|
||||
【重要】
|
||||
1. 摘要应精炼概括文章核心观点,让读者快速了解文章主旨
|
||||
2. 不要输出时间轴
|
||||
3. 不要输出关键见解(除非是特别重要的观点)"""
|
||||
|
||||
return prompt
|
||||
|
||||
def _parse_analysis(self, analysis_text: str, original_text: str, duration: int,
|
||||
content_type: str = "video") -> AnalysisResult:
|
||||
"""解析 AI 返回的分析结果"""
|
||||
result = AnalysisResult()
|
||||
result.full_analysis = analysis_text
|
||||
@@ -363,7 +433,7 @@ def load_json(file_path: str) -> Dict:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def generate_frontmatter(metadata: Dict, result: AnalysisResult) -> str:
|
||||
def generate_frontmatter(metadata: Dict, result: AnalysisResult, content_type: str = "video") -> str:
|
||||
"""生成 Markdown frontmatter"""
|
||||
# 提取标签
|
||||
tags = result.recommended_tags or []
|
||||
@@ -378,11 +448,16 @@ def generate_frontmatter(metadata: Dict, result: AnalysisResult) -> str:
|
||||
fm = ["---",
|
||||
f"title: \"{metadata.get('title', '未命名')}\"",
|
||||
f"date: {date_str}",
|
||||
f"duration: {metadata.get('duration_str', metadata.get('duration', 0))}",
|
||||
f"author: {metadata.get('author', '未知')}",
|
||||
f"bvid: {metadata.get('bvid', '')}",
|
||||
f"platform: {metadata.get('platform', 'bilibili')}"]
|
||||
|
||||
# 视频类型添加 duration 和 bvid
|
||||
if content_type == "video":
|
||||
fm.insert(3, f"duration: {metadata.get('duration_str', metadata.get('duration', 0))}")
|
||||
bvid = metadata.get('bvid', '')
|
||||
if bvid:
|
||||
fm.insert(5, f"bvid: {bvid}")
|
||||
|
||||
# 添加 URL
|
||||
url = metadata.get('url', '')
|
||||
if url:
|
||||
@@ -454,7 +529,7 @@ def main():
|
||||
|
||||
# 执行分析
|
||||
print(f"[Main] 开始分析...")
|
||||
result = analyzer.analyze(metadata, content)
|
||||
result = analyzer.analyze(metadata, content, args.type)
|
||||
|
||||
# 使用 AI 生成的原始内容(保留 Markdown 格式)
|
||||
full_analysis = result.full_analysis
|
||||
@@ -464,6 +539,10 @@ def main():
|
||||
full_analysis = re.sub(r'(## ?)?标签\n[\s\S]*?(?=\n## ?|\n时间轴|---|\Z)', '', full_analysis)
|
||||
# 清理多余的空行
|
||||
full_analysis = re.sub(r'\n{3,}', '\n\n', full_analysis)
|
||||
|
||||
# 文章类型:追加原文
|
||||
if args.type == "article" and result.original_text:
|
||||
full_analysis = full_analysis.rstrip() + "\n\n## 原文\n\n" + result.original_text
|
||||
|
||||
# 写入输出
|
||||
os.makedirs(os.path.dirname(os.path.abspath(args.output)), exist_ok=True)
|
||||
@@ -471,7 +550,7 @@ def main():
|
||||
with open(args.output, 'w', encoding='utf-8') as f:
|
||||
# 添加 frontmatter
|
||||
if not args.no_frontmatter:
|
||||
fm = generate_frontmatter(metadata, result)
|
||||
fm = generate_frontmatter(metadata, result, args.type)
|
||||
f.write(fm + "\n\n")
|
||||
|
||||
# 写入分析内容
|
||||
|
||||
Reference in New Issue
Block a user