#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys import io import re import datetime from pathlib import Path from typing import Dict, List, Optional, Tuple if sys.platform == "win32": sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") def extract_existing_frontmatter(file_path: Path) -> Dict[str, any]: try: content = file_path.read_text(encoding="utf-8") match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL) if match: fm_text = match.group(1) fm = {} for line in fm_text.split("\n"): if ":" in line: key, value = line.split(":", 1) key = key.strip() value = value.strip() if value.startswith("[") or value.startswith("{"): continue elif value.startswith('"') and value.endswith('"'): fm[key] = value.strip('"') elif value: fm[key] = value return fm except Exception as e: print(f"Error reading {file_path.name}: {e}") return {} def get_card_type_from_filename(filename: str) -> Tuple[str, str]: name = Path(filename).stem if "AI教育" in name or "全球图景" in name or "九校" in name: return "concept", "概念" elif any( x in name for x in [ "CMU", "MIT", "斯坦福", "牛津", "哈佛", "AIEOU", "RAISE", "Accelerator", ] ): return "entity", "机构" elif any( x in name for x in ["Victor", "Emma", "Ken", "Rose", "Neil", "Ryan", "Kestin"] ): return "entity", "人物" elif "知识卡片" in name: return "concept", "概念" return "concept", "概念" def update_frontmatter(file_path: Path) -> bool: try: content = file_path.read_text(encoding="utf-8") if not content.startswith("---"): print(f"⚠️ No frontmatter in {file_path.name}") return False fm_match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL) if not fm_match: print(f"⚠️ Cannot parse frontmatter in {file_path.name}") return False fm_text = fm_match.group(1) body = content[fm_match.end() :] existing_fm = {} for line in fm_text.split("\n"): if ":" in line: key, value = line.split(":", 1) existing_fm[key.strip()] = value.strip() card_type, card_category = get_card_type_from_filename(file_path.name) new_fm_lines = [ "---", "categories:", ' - "[[LLM Wiki]]"', ' - "[[知识卡片]]"', "tags:", ] existing_tags = existing_fm.get("tags", "") if existing_tags: if existing_tags.startswith("["): tag_match = re.findall(r"'([^']+)'", existing_tags) for tag in tag_match: new_fm_lines.append(f" - {tag}") else: for tag in existing_tags.split(","): tag = tag.strip() if tag: new_fm_lines.append(f" - {tag}") else: new_fm_lines.append(" - AI教育") new_fm_lines.append(" - 知识卡片") new_fm_lines.extend( [ f"type: {card_type}", f"created: {existing_fm.get('created', datetime.date.today().isoformat())}", ] ) if "updated" in existing_fm: new_fm_lines.append(f"updated: {existing_fm['updated']}") if "source" in existing_fm: new_fm_lines.append(f"source: {existing_fm['source']}") if "title" in existing_fm: new_fm_lines.append(f"title: {existing_fm['title']}") if "review-date" in existing_fm: new_fm_lines.append(f"review-date: {existing_fm['review-date']}") if "review-status" in existing_fm: new_fm_lines.append(f"review-status: {existing_fm['review-status']}") new_fm_lines.append("---") new_content = "\n".join(new_fm_lines) + body file_path.write_text(new_content, encoding="utf-8") print( f"✅ Updated: {file_path.name} (type={card_type}, category={card_category})" ) return True except Exception as e: print(f"❌ Error updating {file_path.name}: {e}") return False def main(): print("=" * 60) print("Knowledge Cards Frontmatter Batch Update Tool") print("=" * 60) print(f"Execution time: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print() cards_dir = Path(__file__).parent.parent / "知识卡片" if not cards_dir.exists(): print(f"❌ Knowledge cards directory not found: {cards_dir}") return card_files = list(cards_dir.glob("*.md")) print(f"Found {len(card_files)} knowledge card files") print() success_count = 0 fail_count = 0 for card_file in card_files: result = update_frontmatter(card_file) if result: success_count += 1 else: fail_count += 1 print() print("=" * 60) print("Update Complete") print("=" * 60) print(f"Total files: {len(card_files)}") print(f"Successfully updated: {success_count}") print(f"Failed: {fail_count}") print("=" * 60) if __name__ == "__main__": main()