forked from Ikalus1988/MisakaNet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmisakanet-index.py
More file actions
115 lines (94 loc) · 3.68 KB
/
Copy pathmisakanet-index.py
File metadata and controls
115 lines (94 loc) · 3.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python3
"""
misakanet-index.py — 御坂网络知识索引生成器
从 lessons/ 目录读取所有 lesson 文件,提取 frontmatter + 摘要,
生成 lessons.json 供 CDN 分发。
用法:
python3 misakanet-index.py # 输出到 stdout
python3 misakanet-index.py --output lessons.json # 写入文件
发布:
GitHub Actions 或 cron 定时运行,将 lessons.json 推送到 CDN。
也可直接用 raw.githubusercontent.com 从 GitHub 读取。
"""
import json
import os
import re
import sys
from pathlib import Path
def parse_frontmatter(text: str) -> dict | None:
"""解析 --- 包裹的 JSON frontmatter(支持空行)"""
m = re.match(r"^---[ \t]*\n(.*?)\n[ \t]*---", text, re.DOTALL)
if m:
try:
return json.loads(m.group(1))
except json.JSONDecodeError:
return None
return None
def extract_summary(content: str, max_length: int = 160) -> str:
"""从内容中提取第一段有效文本作为摘要"""
lines = content.split("\n")
for line in lines:
stripped = line.strip()
if not stripped:
continue
if stripped.startswith("---") or stripped.startswith("{"):
continue
if stripped.startswith("#") or stripped.startswith("##"):
continue
if len(stripped) > max_length:
return stripped[:max_length] + "…"
return stripped
return ""
def build_index(lessons_dir: str | Path) -> list[dict]:
"""扫描 lessons/ 目录,构建知识索引"""
lessons_dir = Path(lessons_dir)
if not lessons_dir.exists():
print(f"[warn] {lessons_dir} 不存在,返回空索引", file=sys.stderr)
return []
index = []
for f in sorted(lessons_dir.glob("*.md")):
if f.name == "index.md" or f.name.startswith("."):
continue
content = f.read_text(encoding="utf-8")
fm = parse_frontmatter(content)
entry = {
"id": f.stem,
"title": fm.get("title", f.stem) if fm else f.stem,
"domain": fm.get("domain", "uncategorized") if fm else "uncategorized",
"tags": fm.get("tags", []) if fm else [],
"summary": extract_summary(content),
"url": f"lessons/{f.name}",
"created": fm.get("created", "") if fm else "",
"updated": fm.get("updated", "") if fm else "",
# 置信度衰减:环境变化后旧知识可能失效
"validity_period_days": fm.get("validity_period_days", 365) if fm else 365,
# 本 lesson 适用的环境版本(如 python=3.12, ubuntu=24.04)
"environment_version": fm.get("environment_version", "") if fm else "",
# 置信度 0-1:基于验证次数/用户反馈自动调整
"confidence": fm.get("confidence", 0.5) if fm else 0.5,
"status": fm.get("status", "active") if fm else "active",
}
index.append(entry)
return index
def main():
import argparse
parser = argparse.ArgumentParser(description="御坂网络知识索引生成器")
parser.add_argument(
"--lessons-dir",
default="lessons",
help="lessons 目录路径 (默认: lessons)",
)
parser.add_argument(
"--output", "-o",
help="输出文件路径(默认输出到 stdout)",
)
args = parser.parse_args()
index = build_index(args.lessons_dir)
output = json.dumps(index, ensure_ascii=False, indent=2)
if args.output:
Path(args.output).write_text(output, encoding="utf-8")
print(f"已写入 {args.output}: {len(index)} 条知识", file=sys.stderr)
else:
print(output)
if __name__ == "__main__":
main()