a6f05ab2d5
- Phase 0: AGENTS.md cleanup (dedup quotes, renumber sections, merge qmd) - Phase 1: typed relations (manage-relations.py, graph-search.py, check-staleness.py, detect-conflicts.py) - Phase 2: frontmatter validator, weekly lint, knowledge promotion, git hooks - Fix .gitignore to track tools/ and .githooks/ - Fix git remote URL (remove plaintext token) - New wiki pages: 504 pages, 34 raw sources
193 lines
6.6 KiB
Python
193 lines
6.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
import sys
|
|
import io
|
|
import re
|
|
import datetime
|
|
from pathlib import Path
|
|
from typing import Dict, List, Set, Tuple
|
|
from collections import defaultdict
|
|
|
|
if sys.platform == "win32":
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
|
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
|
|
|
|
|
|
class WikilinkManager:
|
|
def __init__(self, project_root: Path):
|
|
self.project_root = project_root
|
|
self.knowledge_cards_dir = project_root / "知识卡片"
|
|
self.institution_dir = project_root / "机构档案"
|
|
self.weekly_reports_dir = project_root / "每周报告"
|
|
self.deep_reports_dir = project_root / "深度研究报告"
|
|
self.wikilinks: Dict[str, Set[str]] = defaultdict(set)
|
|
|
|
def extract_title_from_file(self, file_path: Path) -> str:
|
|
try:
|
|
content = file_path.read_text(encoding="utf-8")
|
|
fm_match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
|
|
if fm_match:
|
|
for line in fm_match.group(1).split("\n"):
|
|
if line.startswith("title:"):
|
|
return line.replace("title:", "").strip().strip('"')
|
|
first_heading = re.search(r"^#\s+(.+)$", content, re.MULTILINE)
|
|
if first_heading:
|
|
return first_heading.group(1).strip()
|
|
except:
|
|
pass
|
|
return file_path.stem
|
|
|
|
def build_relationship_map(self) -> Dict[str, List[str]]:
|
|
relationships = {
|
|
"LLM教育应用": ["智能辅导系统", "自适应学习系统", "个性化学习系统"],
|
|
"智能辅导系统": ["自适应学习系统", "CMU LearnLab", "Khanmigo"],
|
|
"自适应学习系统": ["智能辅导系统", "个性化学习系统", "自适应学习环境"],
|
|
"个性化学习系统": ["自适应学习系统", "自适应学习环境"],
|
|
"智能评测技术": ["教育大数据分析", "教育机器人应用"],
|
|
"教育大数据分析": ["智能评测技术", "教育机器人应用"],
|
|
"教育机器人应用": ["智能评测技术", "教育大数据分析"],
|
|
"自适应学习环境": ["自适应学习系统", "个性化学习系统"],
|
|
"RCT研究与Cohen's d指标": ["哈佛CS50课程模式", "哈佛教务长框架"],
|
|
"哈佛CS50课程模式": ["MIT RAISE框架", "斯坦福AI Accelerator", "牛津AIEOU"],
|
|
"哈佛教务长框架": ["斯坦福AI Accelerator", "牛津AIEOU", "CMU LearnLab"],
|
|
"MIT RAISE框架": ["斯坦福AI Accelerator", "Khanmigo"],
|
|
"斯坦福AI Accelerator": ["牛津AIEOU", "CMU LearnLab", "Khanmigo"],
|
|
"牛津AIEOU": ["CMU LearnLab", "以人为本AI教育观"],
|
|
"CMU LearnLab": ["Khanmigo", "智能辅导系统"],
|
|
"Khanmigo": ["斯坦福AI Accelerator", "智能辅导系统"],
|
|
"以人为本AI教育观": ["高等教、AI全球图景"],
|
|
"高等教育AI全球图景": ["以人为本AI教育观", "哈佛CS50课程模式"],
|
|
}
|
|
return relationships
|
|
|
|
def add_wikilinks_to_file(
|
|
self, file_path: Path, related_concepts: List[str]
|
|
) -> bool:
|
|
try:
|
|
content = file_path.read_text(encoding="utf-8")
|
|
|
|
if "## 相关概念" in content or "## 相关链接" in content:
|
|
print(f" ⏭️ Skipping (already has related section): {file_path.name}")
|
|
return False
|
|
|
|
section = f"""
|
|
|
|
---
|
|
|
|
## 相关概念
|
|
|
|
- [[{"|".join(related_concepts)}]]
|
|
|
|
"""
|
|
|
|
if content.rstrip().endswith("---"):
|
|
content = content.rstrip() + section
|
|
else:
|
|
content = content.rstrip() + section
|
|
|
|
file_path.write_text(content, encoding="utf-8")
|
|
print(f" ✅ Added related concepts to: {file_path.name}")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f" ❌ Error adding wikilinks to {file_path.name}: {e}")
|
|
return False
|
|
|
|
def process_knowledge_cards(self):
|
|
relationships = self.build_relationship_map()
|
|
|
|
if not self.knowledge_cards_dir.exists():
|
|
print(f"⚠️ Knowledge cards directory not found")
|
|
return
|
|
|
|
card_files = list(self.knowledge_cards_dir.glob("*.md"))
|
|
print(f"\nProcessing {len(card_files)} knowledge cards...")
|
|
|
|
updated_count = 0
|
|
for card_file in card_files:
|
|
card_name = card_file.stem.replace("-知识卡片", "")
|
|
|
|
related = relationships.get(card_name, [])
|
|
if related:
|
|
result = self.add_wikilinks_to_file(card_file, related)
|
|
if result:
|
|
updated_count += 1
|
|
|
|
return updated_count
|
|
|
|
def generate_cross_reference_report(self) -> str:
|
|
relationships = self.build_relationship_map()
|
|
|
|
report = f"""# 跨文档引用增强报告
|
|
|
|
## 基本信息
|
|
|
|
- **生成时间**: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
|
|
- **涉及知识卡片**: {len(relationships)} 个
|
|
|
|
## 关系映射
|
|
|
|
| 概念 | 相关概念 |
|
|
|------|----------|
|
|
"""
|
|
|
|
for concept, related in sorted(relationships.items()):
|
|
report += f"| {concept} | {', '.join(related)} |\n"
|
|
|
|
report += f"""
|
|
|
|
## 更新统计
|
|
|
|
- **已更新文件**: 在知识卡片末尾添加了"相关概念"章节
|
|
- **链接格式**: 使用Obsidian wikilink格式 `[[概念名]]`
|
|
- **关系类型**: 学科关联、技术关联、应用关联
|
|
|
|
## 下一步建议
|
|
|
|
1. 在机构档案中添加相关知识卡片链接
|
|
2. 在周报和深度报告中添加更多内部引用
|
|
3. 定期检查和更新跨文档引用
|
|
4. 考虑建立双向链接(反向引用)
|
|
|
|
---
|
|
|
|
*报告生成时间: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}*
|
|
"""
|
|
|
|
return report
|
|
|
|
|
|
def main():
|
|
print("=" * 60)
|
|
print("Cross-Document References Enhancement Tool")
|
|
print("=" * 60)
|
|
print(f"Execution time: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
print()
|
|
|
|
project_dir = Path(__file__).parent.parent
|
|
manager = WikilinkManager(project_dir)
|
|
|
|
updated = manager.process_knowledge_cards()
|
|
|
|
report = manager.generate_cross_reference_report()
|
|
report_path = (
|
|
project_dir
|
|
/ "outputs"
|
|
/ f"cross_reference_enhancement_{datetime.date.today()}.md"
|
|
)
|
|
report_path.parent.mkdir(parents=True, exist_ok=True)
|
|
with open(report_path, "w", encoding="utf-8") as f:
|
|
f.write(report)
|
|
|
|
print()
|
|
print("=" * 60)
|
|
print("Enhancement Complete")
|
|
print("=" * 60)
|
|
print(f"Files updated: {updated}")
|
|
print(f"Report saved to: {report_path.name}")
|
|
print("=" * 60)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|