179 lines
5.1 KiB
Python
179 lines
5.1 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Update meta.json and topics/index.json after adding questions.
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
python3 update_meta.py <topics_dir> <group> <subtopic> <question_type>
|
||
|
|
|
||
|
|
- Reads the question file at topics/{group}/{subtopic}/{type}.json
|
||
|
|
- Updates/creates topics/{group}/{subtopic}/meta.json
|
||
|
|
- Updates/creates topics/index.json with subtopic stats
|
||
|
|
|
||
|
|
meta.json format:
|
||
|
|
{
|
||
|
|
"slug": "gc-jvm",
|
||
|
|
"name": "...",
|
||
|
|
"description": "...",
|
||
|
|
"tags": [...],
|
||
|
|
"difficulty_range": [1, 5],
|
||
|
|
"schema_version": "1.0.0",
|
||
|
|
"question_files": ["fill_blank", "single_choice"],
|
||
|
|
"stats": { "total": 20, "by_type": { "fill_blank": 10, "single_choice": 10 } }
|
||
|
|
}
|
||
|
|
|
||
|
|
index.json format:
|
||
|
|
{
|
||
|
|
"version": "1.0.0",
|
||
|
|
"updated": "...",
|
||
|
|
"topics": [
|
||
|
|
{
|
||
|
|
"slug": "qunar-ai-fullstack",
|
||
|
|
"name": "...",
|
||
|
|
"subtopics": [
|
||
|
|
{ "slug": "gc-jvm", "path": "topics/qunar-ai-fullstack/gc-jvm", "stats": {...} }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
Exit codes: 0 = success, 1 = error, 2 = usage error.
|
||
|
|
"""
|
||
|
|
import json
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
from datetime import date
|
||
|
|
|
||
|
|
|
||
|
|
def load_json(path: Path) -> dict:
|
||
|
|
if path.exists() and path.stat().st_size > 0:
|
||
|
|
with open(path, encoding="utf-8") as f:
|
||
|
|
return json.load(f)
|
||
|
|
return {}
|
||
|
|
|
||
|
|
|
||
|
|
def save_json(path: Path, data: dict):
|
||
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||
|
|
with open(path, "w", encoding="utf-8") as f:
|
||
|
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
||
|
|
f.write("\n")
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
if len(sys.argv) != 5:
|
||
|
|
print(f"Usage: {sys.argv[0]} <topics_dir> <group> <subtopic> <question_type>",
|
||
|
|
file=sys.stderr)
|
||
|
|
sys.exit(2)
|
||
|
|
|
||
|
|
topics_dir = Path(sys.argv[1])
|
||
|
|
group = sys.argv[2]
|
||
|
|
subtopic = sys.argv[3]
|
||
|
|
q_type = sys.argv[4]
|
||
|
|
|
||
|
|
subtopic_dir = topics_dir / group / subtopic
|
||
|
|
question_file = subtopic_dir / f"{q_type}.json"
|
||
|
|
meta_file = subtopic_dir / "meta.json"
|
||
|
|
index_file = topics_dir / "index.json"
|
||
|
|
|
||
|
|
if not question_file.exists():
|
||
|
|
print(f"❌ Question file not found: {question_file}", file=sys.stderr)
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
# Load question file
|
||
|
|
q_data = load_json(question_file)
|
||
|
|
questions = q_data.get("questions", [])
|
||
|
|
count = len(questions)
|
||
|
|
|
||
|
|
# Compute difficulty stats
|
||
|
|
difficulties = [q.get("difficulty", 3) for q in questions]
|
||
|
|
diff_range = [min(difficulties), max(difficulties)] if difficulties else [1, 5]
|
||
|
|
|
||
|
|
# Compute tag union
|
||
|
|
all_tags = sorted(set(
|
||
|
|
tag for q in questions for tag in q.get("tags", [])
|
||
|
|
))
|
||
|
|
|
||
|
|
# --- Update meta.json ---
|
||
|
|
meta = load_json(meta_file)
|
||
|
|
meta["slug"] = meta.get("slug", subtopic)
|
||
|
|
meta["name"] = meta.get("name", subtopic.replace("-", " ").title())
|
||
|
|
meta.setdefault("description", "")
|
||
|
|
meta["tags"] = all_tags
|
||
|
|
meta["difficulty_range"] = diff_range
|
||
|
|
meta["schema_version"] = "1.0.0"
|
||
|
|
meta["updated"] = date.today().isoformat()
|
||
|
|
|
||
|
|
# question_files is an array of type names
|
||
|
|
if "question_files" not in meta:
|
||
|
|
meta["question_files"] = []
|
||
|
|
if q_type not in meta["question_files"]:
|
||
|
|
meta["question_files"].append(q_type)
|
||
|
|
|
||
|
|
# stats has total and by_type
|
||
|
|
if "stats" not in meta:
|
||
|
|
meta["stats"] = {"total": 0, "by_type": {}}
|
||
|
|
meta["stats"]["by_type"][q_type] = count
|
||
|
|
meta["stats"]["total"] = sum(meta["stats"]["by_type"].values())
|
||
|
|
|
||
|
|
save_json(meta_file, meta)
|
||
|
|
|
||
|
|
# --- Update index.json ---
|
||
|
|
index = load_json(index_file)
|
||
|
|
index.setdefault("version", "1.0.0")
|
||
|
|
index["updated"] = date.today().isoformat()
|
||
|
|
index.setdefault("topics", [])
|
||
|
|
|
||
|
|
# Find or create the group topic entry
|
||
|
|
group_entry = None
|
||
|
|
for t in index["topics"]:
|
||
|
|
if t.get("slug") == group:
|
||
|
|
group_entry = t
|
||
|
|
break
|
||
|
|
|
||
|
|
if group_entry is None:
|
||
|
|
group_entry = {
|
||
|
|
"slug": group,
|
||
|
|
"name": meta.get("name", group.replace("-", " ").title()),
|
||
|
|
"description": meta.get("description", ""),
|
||
|
|
"subtopics": [],
|
||
|
|
}
|
||
|
|
index["topics"].append(group_entry)
|
||
|
|
|
||
|
|
group_entry.setdefault("subtopics", [])
|
||
|
|
|
||
|
|
# Find or create the subtopic entry
|
||
|
|
sub_entry = None
|
||
|
|
for s in group_entry["subtopics"]:
|
||
|
|
if s.get("slug") == subtopic:
|
||
|
|
sub_entry = s
|
||
|
|
break
|
||
|
|
|
||
|
|
if sub_entry is None:
|
||
|
|
sub_entry = {
|
||
|
|
"slug": subtopic,
|
||
|
|
"name": meta.get("name", subtopic.replace("-", " ").title()),
|
||
|
|
"description": meta.get("description", ""),
|
||
|
|
"path": f"topics/{group}/{subtopic}",
|
||
|
|
"stats": {"total": 0, "by_type": {}},
|
||
|
|
}
|
||
|
|
group_entry["subtopics"].append(sub_entry)
|
||
|
|
|
||
|
|
sub_entry["stats"]["by_type"][q_type] = count
|
||
|
|
sub_entry["stats"]["total"] = sum(sub_entry["stats"]["by_type"].values())
|
||
|
|
|
||
|
|
save_json(index_file, index)
|
||
|
|
|
||
|
|
# Output summary
|
||
|
|
result = {
|
||
|
|
"subtopic": subtopic,
|
||
|
|
"question_type": q_type,
|
||
|
|
"count": count,
|
||
|
|
"total": meta["stats"]["total"],
|
||
|
|
"meta_file": str(meta_file),
|
||
|
|
"index_file": str(index_file),
|
||
|
|
}
|
||
|
|
print(json.dumps(result, ensure_ascii=False))
|
||
|
|
sys.exit(0)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|