#!/usr/bin/env python3 """Generate a Less and Cosmos double-sided employee business card.""" from __future__ import annotations import argparse import html import json import re from pathlib import Path SKILL_DIR = Path(__file__).resolve().parent.parent ASSETS_DIR = SKILL_DIR / "assets" def clean(value: str, field: str) -> str: value = " ".join(value.strip().split()) if not value: raise ValueError(f"{field} must not be empty") return value def normalize_phone(value: str) -> str: value = clean(value, "phone") value = re.sub(r"\s+", " ", value) if value.startswith("+86"): return value if value.startswith("86 "): return "+" + value return "+86 " + value def split_title(value: str) -> tuple[str, str]: parts = re.split(r"\s*[//]\s*", value, maxsplit=1) if len(parts) == 1: return parts[0], "" return parts[0], parts[1] def render_template(template: str, values: dict[str, str]) -> str: for key, value in values.items(): template = template.replace("{{" + key + "}}", html.escape(value)) unresolved = sorted(set(re.findall(r"\{\{([A-Z_]+)\}\}", template))) if unresolved: raise ValueError("Unresolved template fields: " + ", ".join(unresolved)) return template def build_preview(name: str) -> str: safe_name = html.escape(name) return f""" {safe_name} · 纯粹星辰名片

{safe_name} · 纯粹星辰

\"名片正面\"
Front
\"名片背面\"
Back
""" def main() -> None: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--name", required=True, help="Chinese name") parser.add_argument("--title", required=True, help="Role, e.g. 联合创始人 / CMO") parser.add_argument("--email", required=True) parser.add_argument("--phone", required=True) parser.add_argument("--output-dir", required=True, type=Path) args = parser.parse_args() name = clean(args.name, "name") title = clean(args.title, "title") title_zh, title_en = split_title(title) email = clean(args.email, "email") if "@" not in email or email.startswith("@") or email.endswith("@"): raise ValueError("email does not look valid") phone = normalize_phone(args.phone) data = { "name": name, "title": title, "email": email, "phone": phone, "company": "杭州纯粹星辰人工智能科技有限公司", "address": "浙江省杭州市西湖区转塘街道云腾丝路中心5号楼商业208室", "website": "lessncosmos.com", "slogan": "构建能够持续学习与进化的企业级人工智能系统。", } args.output_dir.mkdir(parents=True, exist_ok=True) (args.output_dir / "front.svg").write_text( (ASSETS_DIR / "common-front.svg").read_text(encoding="utf-8"), encoding="utf-8" ) template = (ASSETS_DIR / "back-template.svg").read_text(encoding="utf-8") replacements = {key.upper(): value for key, value in data.items()} replacements.update({"TITLE_ZH": title_zh, "TITLE_EN": title_en}) (args.output_dir / "back.svg").write_text( render_template(template, replacements), encoding="utf-8" ) (args.output_dir / "preview.html").write_text(build_preview(name), encoding="utf-8") (args.output_dir / "card-data.json").write_text( json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8" ) print(f"Created business card in {args.output_dir.resolve()}") if __name__ == "__main__": main()