scripts/generate_note.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Obsidian笔记生成脚本 - 正确处理frontmatter格式
"""
import sys
import os
import argparse
import logging
from datetime import datetime
from pathlib import Path
logger = logging.getLogger(__name__)
def get_vault_path(cli_vault=None):
"""从CLI参数或环境变量获取vault路径"""
if cli_vault:
return cli_vault
env_path = os.environ.get('OBSIDIAN_VAULT_PATH')
if env_path:
return env_path
logger.error("未指定 vault 路径。请通过 --vault 参数或 OBSIDIAN_VAULT_PATH 环境变量设置。")
sys.exit(1)
def generate_note_content(paper_id, title, authors, domain, date):
"""生成笔记的 Markdown 内容"""
domain_tags = {
"大模型": ["大模型", "LLM"],
"多模态技术": ["多模态", "Vision-Language"],
"智能体": ["智能体", "Agent"],
}
tags = ["论文笔记"] + domain_tags.get(domain, [domain])
tags_yaml = "\n".join(f' - {tag}' for tag in tags)
return f'''---
date: "{date}"
paper_id: "{paper_id}"
title: "{title}"
authors: "{authors}"
domain: "{domain}"
tags:
{tags_yaml}
quality_score: "[SCORE]/10"
related_papers: []
created: "{date}"
updated: "{date}"
status: analyzed
---
# {title}
## 核心信息
- **论文ID**:{paper_id}
- **作者**:{authors}
- **机构**:[从作者推断或查看论文]
- **发布时间**:{date}
- **会议/期刊**:[从categories推断]
- **链接**:[arXiv](https://arxiv.org/abs/{paper_id}) | [PDF](https://arxiv.org/pdf/{paper_id})
- **引用**:[如果可获取]
## 研究问题
[问题描述中文翻译和解释]
## 方法概述
### 核心方法
1. [方法1]
- [详细描述]
- [关键步骤]
- [创新点]
### 方法架构
[架构描述和图片引用]
### 关键创新
1. [创新点1] - [为什么重要]
2. [创新点2] - [为什么重要]
3. [创新点3] - [为什么重要]
## 实验结果
### 数据集
- [数据集1]:[规模、特点]
- [数据集2]:[规模、特点]
### 实验设置
- **基线方法**:[列出对比方法]
- **评估指标**:[列出指标]
- **实验环境**:[硬件、超参数]
### 主要结果
[实验结果表格和关键发现]
## 深度分析
### 研究价值
- **理论贡献**:[理论上的贡献]
- **实际应用**:[实际应用价值]
- **领域影响**:[对研究领域的潜在影响]
### 优势
- [优势1]
- [优势2]
- [优势3]
### 局限性
- [局限1]
- [局限2]
- [局限3]
### 适用场景
- [适用场景1]
- [适用场景2]
## 与相关论文对比
### [[相关论文1]] - [对比关系]
- **差异**:[本文方法的不同之处]
- **改进**:[相比的改进点]
- **性能对比**:[如果可用]
### [[相关论文2]] - [对比关系]
[类似格式]
### [[相关论文3]] - [对比关系]
[类似格式]
## 技术路线定位
本文属于[技术路线],主要关注[具体子方向]。
## 未来工作建议
1. [作者建议1]
2. [作者建议2]
3. [基于分析的延伸建议]
## 我的综合评价
### 价值评分
- **总体评分**:[X.X/10]
- **分项评分**:
- 创新性:[X/10]
- 技术质量:[X/10]
- 实验充分性:[X/10]
- 写作质量:[X/10]
- 实用性:[X/10]
### 突出亮点
- [亮点1]
- [亮点2]
- [亮点3]
### 重点关注
- [需要特别关注的方面]
### 可借鉴点
- [可以学习借鉴的技术]
- [可以应用的方法]
- [有启发性的思路]
### 批判性思考
- [潜在问题]
- [可改进之处]
- [质疑点]
## 我的笔记
[用户阅读后手动补充的内容]
## 相关论文
- [[相关论文1]] - [对比关系]
- [[相关论文2]] - [对比关系]
- [[相关论文3]] - [对比关系]
## 外部资源
- [论文链接]
- [代码链接(如果有)]
- [项目主页(如果有)]
- [相关资源]
'''
def main():
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
datefmt='%H:%M:%S',
stream=sys.stderr,
)
parser = argparse.ArgumentParser(description='生成论文分析笔记')
parser.add_argument('--paper-id', type=str, default='[PAPER_ID]', help='论文 arXiv ID')
parser.add_argument('--title', type=str, default='[论文标题]', help='论文标题')
parser.add_argument('--authors', type=str, default='[Authors]', help='论文作者')
parser.add_argument('--domain', type=str, default='其他', help='论文领域')
parser.add_argument('--vault', type=str, default=None, help='Obsidian vault 路径')
args = parser.parse_args()
vault_root = get_vault_path(args.vault)
papers_dir = os.path.join(vault_root, "20_Research", "Papers")
date = datetime.now().strftime("%Y-%m-%d")
paper_title_safe = args.title
for ch in ' /\\:*?"<>|':
paper_title_safe = paper_title_safe.replace(ch, "_")
note_dir = os.path.join(papers_dir, args.domain)
os.makedirs(note_dir, exist_ok=True)
note_path = os.path.join(note_dir, f"{paper_title_safe}.md")
content = generate_note_content(args.paper_id, args.title, args.authors, args.domain, date)
with open(note_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f"笔记已生成: {note_path}")
print(f"请手动编辑笔记内容,替换占位符为实际分析结果")
if __name__ == '__main__':
main()
scripts/update_graph.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
更新知识图谱脚本
"""
import json
import os
import sys
import argparse
import logging
from datetime import datetime
logger = logging.getLogger(__name__)
def get_vault_path(cli_vault=None):
"""从CLI参数或环境变量获取vault路径"""
if cli_vault:
return cli_vault
env_path = os.environ.get('OBSIDIAN_VAULT_PATH')
if env_path:
return env_path
logger.error("未指定 vault 路径。请通过 --vault 参数或 OBSIDIAN_VAULT_PATH 环境变量设置。")
sys.exit(1)
def main():
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
datefmt='%H:%M:%S',
stream=sys.stderr,
)
parser = argparse.ArgumentParser(description='更新知识图谱')
parser.add_argument('--paper-id', type=str, required=True, help='论文 arXiv ID')
parser.add_argument('--title', type=str, required=True, help='论文标题')
parser.add_argument('--domain', type=str, required=True, help='论文领域')
parser.add_argument('--score', type=float, default=0.0, help='质量评分')
parser.add_argument('--related', type=str, nargs='*', default=[], help='相关论文ID列表')
parser.add_argument('--vault', type=str, default=None, help='Obsidian vault 路径')
args = parser.parse_args()
vault_root = get_vault_path(args.vault)
date = datetime.now().strftime("%Y-%m-%d")
graph_dir = os.path.join(vault_root, "20_Research", "PaperGraph")
os.makedirs(graph_dir, exist_ok=True)
graph_path = os.path.join(graph_dir, "graph_data.json")
try:
with open(graph_path, 'r', encoding='utf-8') as f:
graph = json.load(f)
except FileNotFoundError:
graph = {
"nodes": [],
"edges": [],
"last_updated": date
}
paper_node = {
"id": args.paper_id,
"title": args.title,
"year": int(date[:4]),
"domain": args.domain,
"quality_score": args.score,
"tags": ["论文笔记", args.domain],
"analyzed": True
}
existing_nodes = {node["id"]: i for i, node in enumerate(graph["nodes"])}
if args.paper_id in existing_nodes:
graph["nodes"][existing_nodes[args.paper_id]].update(paper_node)
else:
graph["nodes"].append(paper_node)
if args.related:
existing_edges = {(edge["source"], edge["target"]) for edge in graph["edges"]}
for related_id in args.related:
if related_id and (args.paper_id, related_id) not in existing_edges:
graph["edges"].append({
"source": args.paper_id,
"target": related_id,
"type": "related",
"weight": 0.7
})
graph["last_updated"] = date
with open(graph_path, 'w', encoding='utf-8') as f:
json.dump(graph, f, ensure_ascii=False, indent=2)
print(f"图谱已更新: {graph_path}")
print(f"节点数: {len(graph['nodes'])}")
print(f"边数: {len(graph['edges'])}")
if __name__ == '__main__':
main()
SKILL.md
---
id: paper-analyzer
name: paper-analyzer
version: 1.0.0
description: |-
Deep analysis of a single paper — generate structured notes with figures, evaluation, and knowledge graph updates
stages: ["survey", "publication"]
tools: ["read_file", "search_project", "write_file", "run_terminal"]
summary: |-
Deep analysis of a single paper — generate structured notes with figures, evaluation, and knowledge graph updates
primaryIntent: research
intents: ["research"]
capabilities: ["evaluation-benchmarking"]
domains: ["cs-ai"]
keywords: ["paper-analyzer", "paper analysis", "evaluation-benchmarking", "cs-ai", "paper", "analyzer", "deep", "analysis", "single", "generate", "structured", "notes"]
source: builtin
status: verified
upstream:
repo: dr-claw
path: skills/paper-analyzer
revision: 8322dc4ef575affaa374aa7922c0a0971c6db7d7
resourceFlags:
hasReferences: false
hasScripts: true
hasTemplates: false
hasAssets: false
referenceCount: 0
scriptCount: 2
templateCount: 0
assetCount: 0
optionalScripts: true
---
# paper-analyzer
## Canonical Summary
Deep analysis of a single paper — generate structured notes with figures, evaluation, and knowledge graph updates
## Trigger Rules
Use this skill when the user request matches its research workflow scope. Prefer the bundled resources instead of recreating templates or reference material. Keep outputs traceable to project files, citations, scripts, or upstream evidence.
## Resource Use Rules
- Treat `scripts/` as optional helpers. Run them only when their dependencies are available, keep outputs in the project workspace, and explain a manual fallback if execution is blocked.
## Execution Contract
- Resolve every relative path from this skill directory first.
- Prefer inspection before mutation when invoking bundled scripts.
- If a required runtime, CLI, credential, or API is unavailable, explain the blocker and continue with the best manual fallback instead of silently skipping the step.
- Do not write generated artifacts back into the skill directory; save them inside the active project workspace.
## Upstream Instructions
You are the Paper Analyzer for Dr. Claw.
# Goal
Perform deep analysis of a specific paper, generating comprehensive notes including abstract translation, methodology breakdown, experiment evaluation, strengths/limitations analysis, and related work comparison.
# Workflow
## Step 1: Identify Paper
Accept input: arXiv ID (e.g., "2402.12345"), full ID ("arXiv:2402.12345"), paper title, or file path.
## Step 2: Fetch Paper Content
```bash
curl -L "https://arxiv.org/pdf/[PAPER_ID]" -o /tmp/paper_analysis/[PAPER_ID].pdf
curl -L "https://arxiv.org/e-print/[PAPER_ID]" -o /tmp/paper_analysis/[PAPER_ID].tar.gz
curl -s "https://arxiv.org/abs/[PAPER_ID]" > /tmp/paper_analysis/arxiv_page.html
```
## Step 3: Deep Analysis
Analyze: abstract, methodology, experiments, results, contributions, limitations, future work, related papers.
## Step 4: Generate Note
```bash
python scripts/generate_note.py --paper-id "$PAPER_ID" --title "$TITLE" --authors "$AUTHORS" --domain "$DOMAIN"
```
## Step 5: Update Knowledge Graph
```bash
python scripts/update_graph.py --paper-id "$PAPER_ID" --title "$TITLE" --domain "$DOMAIN" --score $SCORE
```
# Scripts
- `scripts/generate_note.py` — Generate structured note template
- `scripts/update_graph.py` — Update paper relationship graph
# Note Structure
The generated note includes: core info, abstract (EN/CN), research background, method overview with architecture figures, experiment results with tables, deep analysis, related paper comparison, tech roadmap positioning, future work, and comprehensive evaluation (0-10 scoring).
# Dependencies
- Python 3.8+, PyYAML, requests
- Network access (arXiv)
---
> Based on [evil-read-arxiv](https://github.com/evil-read-arxiv) — an automated paper reading workflow. MIT License.