#!/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()