From 04d899ca89a2826a2842461917243d4c03f438fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com>
Date: Mon, 4 May 2026 22:56:16 +0800
Subject: [PATCH] =?UTF-8?q?feat(=E5=8D=9A=E5=AE=A2):=20=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E5=A4=9A=E7=AF=87=E5=8D=9A=E5=AE=A2=E5=B0=81=E9=9D=A2=E5=9B=BE?=
=?UTF-8?q?=E7=89=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
为博客系统添加了多篇技术文章的封面图片,涵盖Git、Python工具、AI大模型、机器学习等主题。这些封面采用统一的SVG格式设计,包含标题、分类标签和视觉元素,用于提升博客文章的可视化展示效果。
---
.../AI助你轻松上手LaTeX论文写作-cover.svg | 39 ++
.../AI时代的VibeCoding与程序员进化-cover.svg | 47 ++
博客/covers/CLI在AI时代的浴火重生-cover.svg | 45 ++
博客/covers/DeepSeek-V4全面解析-cover.svg | 46 ++
博客/covers/DeepSeek-V4博客大纲-cover.svg | 38 ++
博客/covers/Git内部原理详解-cover.svg | 37 ++
博客/covers/Git团队协作指南-cover.svg | 38 ++
博客/covers/Git团队协作指南大纲-cover.svg | 36 ++
.../covers/Git团队协作指南(精简版)-cover.svg | 37 ++
.../covers/LinearRegression线性回归-cover.svg | 47 ++
博客/covers/OpenClaw介绍-cover.svg | 38 ++
博客/covers/OpenClaw安装教程-cover.svg | 38 ++
博客/covers/SEO分析报告-cover.svg | 39 ++
博客/covers/claude-code-vibe-coding-cover.svg | 53 ++
博客/covers/docker-deployment-guide-cover.svg | 65 +++
博客/covers/uv工具推荐博客-cover.svg | 38 ++
博客/covers/uv工具推荐博客大纲-cover.svg | 37 ++
博客/covers/vision-language-model-cover.svg | 78 +++
博客/covers/从全连接层到卷积-cover.svg | 47 ++
博客/covers/博客爬取报告-cover.svg | 39 ++
博客/covers/大数据技术栈-cover.svg | 39 ++
博客/covers/大模型赋能架构设计-cover.svg | 45 ++
博客/covers/大语言模型算子详解-cover.svg | 46 ++
...习Agent,越学越像在重新理解操作系统-cover.svg | 46 ++
博客/covers/摘要检查报告-cover.svg | 39 ++
博客/covers/文章列表-cover.svg | 40 ++
博客/covers/标签分类审查报告-cover.svg | 39 ++
博客/covers/深度学习完全指南-cover.svg | 47 ++
博客/其他/generate-blog-covers.js | 377 +++++++++++++
博客/其他/generate-blog-covers.ps1 | 494 ++++++++++++++++++
30 files changed, 2094 insertions(+)
create mode 100644 博客/covers/AI助你轻松上手LaTeX论文写作-cover.svg
create mode 100644 博客/covers/AI时代的VibeCoding与程序员进化-cover.svg
create mode 100644 博客/covers/CLI在AI时代的浴火重生-cover.svg
create mode 100644 博客/covers/DeepSeek-V4全面解析-cover.svg
create mode 100644 博客/covers/DeepSeek-V4博客大纲-cover.svg
create mode 100644 博客/covers/Git内部原理详解-cover.svg
create mode 100644 博客/covers/Git团队协作指南-cover.svg
create mode 100644 博客/covers/Git团队协作指南大纲-cover.svg
create mode 100644 博客/covers/Git团队协作指南(精简版)-cover.svg
create mode 100644 博客/covers/LinearRegression线性回归-cover.svg
create mode 100644 博客/covers/OpenClaw介绍-cover.svg
create mode 100644 博客/covers/OpenClaw安装教程-cover.svg
create mode 100644 博客/covers/SEO分析报告-cover.svg
create mode 100644 博客/covers/claude-code-vibe-coding-cover.svg
create mode 100644 博客/covers/docker-deployment-guide-cover.svg
create mode 100644 博客/covers/uv工具推荐博客-cover.svg
create mode 100644 博客/covers/uv工具推荐博客大纲-cover.svg
create mode 100644 博客/covers/vision-language-model-cover.svg
create mode 100644 博客/covers/从全连接层到卷积-cover.svg
create mode 100644 博客/covers/博客爬取报告-cover.svg
create mode 100644 博客/covers/大数据技术栈-cover.svg
create mode 100644 博客/covers/大模型赋能架构设计-cover.svg
create mode 100644 博客/covers/大语言模型算子详解-cover.svg
create mode 100644 博客/covers/学习Agent,越学越像在重新理解操作系统-cover.svg
create mode 100644 博客/covers/摘要检查报告-cover.svg
create mode 100644 博客/covers/文章列表-cover.svg
create mode 100644 博客/covers/标签分类审查报告-cover.svg
create mode 100644 博客/covers/深度学习完全指南-cover.svg
create mode 100644 博客/其他/generate-blog-covers.js
create mode 100644 博客/其他/generate-blog-covers.ps1
diff --git a/博客/covers/AI助你轻松上手LaTeX论文写作-cover.svg b/博客/covers/AI助你轻松上手LaTeX论文写作-cover.svg
new file mode 100644
index 0000000..3bfce87
--- /dev/null
+++ b/博客/covers/AI助你轻松上手LaTeX论文写作-cover.svg
@@ -0,0 +1,39 @@
+
diff --git a/博客/covers/AI时代的VibeCoding与程序员进化-cover.svg b/博客/covers/AI时代的VibeCoding与程序员进化-cover.svg
new file mode 100644
index 0000000..fe92d2a
--- /dev/null
+++ b/博客/covers/AI时代的VibeCoding与程序员进化-cover.svg
@@ -0,0 +1,47 @@
+
diff --git a/博客/covers/CLI在AI时代的浴火重生-cover.svg b/博客/covers/CLI在AI时代的浴火重生-cover.svg
new file mode 100644
index 0000000..4780310
--- /dev/null
+++ b/博客/covers/CLI在AI时代的浴火重生-cover.svg
@@ -0,0 +1,45 @@
+
diff --git a/博客/covers/DeepSeek-V4全面解析-cover.svg b/博客/covers/DeepSeek-V4全面解析-cover.svg
new file mode 100644
index 0000000..5f25e42
--- /dev/null
+++ b/博客/covers/DeepSeek-V4全面解析-cover.svg
@@ -0,0 +1,46 @@
+
diff --git a/博客/covers/DeepSeek-V4博客大纲-cover.svg b/博客/covers/DeepSeek-V4博客大纲-cover.svg
new file mode 100644
index 0000000..364535f
--- /dev/null
+++ b/博客/covers/DeepSeek-V4博客大纲-cover.svg
@@ -0,0 +1,38 @@
+
diff --git a/博客/covers/Git内部原理详解-cover.svg b/博客/covers/Git内部原理详解-cover.svg
new file mode 100644
index 0000000..635bdca
--- /dev/null
+++ b/博客/covers/Git内部原理详解-cover.svg
@@ -0,0 +1,37 @@
+
diff --git a/博客/covers/Git团队协作指南-cover.svg b/博客/covers/Git团队协作指南-cover.svg
new file mode 100644
index 0000000..eda8974
--- /dev/null
+++ b/博客/covers/Git团队协作指南-cover.svg
@@ -0,0 +1,38 @@
+
diff --git a/博客/covers/Git团队协作指南大纲-cover.svg b/博客/covers/Git团队协作指南大纲-cover.svg
new file mode 100644
index 0000000..8e7e823
--- /dev/null
+++ b/博客/covers/Git团队协作指南大纲-cover.svg
@@ -0,0 +1,36 @@
+
diff --git a/博客/covers/Git团队协作指南(精简版)-cover.svg b/博客/covers/Git团队协作指南(精简版)-cover.svg
new file mode 100644
index 0000000..961e6ee
--- /dev/null
+++ b/博客/covers/Git团队协作指南(精简版)-cover.svg
@@ -0,0 +1,37 @@
+
diff --git a/博客/covers/LinearRegression线性回归-cover.svg b/博客/covers/LinearRegression线性回归-cover.svg
new file mode 100644
index 0000000..6219730
--- /dev/null
+++ b/博客/covers/LinearRegression线性回归-cover.svg
@@ -0,0 +1,47 @@
+
diff --git a/博客/covers/OpenClaw介绍-cover.svg b/博客/covers/OpenClaw介绍-cover.svg
new file mode 100644
index 0000000..efbd49f
--- /dev/null
+++ b/博客/covers/OpenClaw介绍-cover.svg
@@ -0,0 +1,38 @@
+
diff --git a/博客/covers/OpenClaw安装教程-cover.svg b/博客/covers/OpenClaw安装教程-cover.svg
new file mode 100644
index 0000000..70f8267
--- /dev/null
+++ b/博客/covers/OpenClaw安装教程-cover.svg
@@ -0,0 +1,38 @@
+
diff --git a/博客/covers/SEO分析报告-cover.svg b/博客/covers/SEO分析报告-cover.svg
new file mode 100644
index 0000000..18d606f
--- /dev/null
+++ b/博客/covers/SEO分析报告-cover.svg
@@ -0,0 +1,39 @@
+
diff --git a/博客/covers/claude-code-vibe-coding-cover.svg b/博客/covers/claude-code-vibe-coding-cover.svg
new file mode 100644
index 0000000..0133fe5
--- /dev/null
+++ b/博客/covers/claude-code-vibe-coding-cover.svg
@@ -0,0 +1,53 @@
+
diff --git a/博客/covers/docker-deployment-guide-cover.svg b/博客/covers/docker-deployment-guide-cover.svg
new file mode 100644
index 0000000..892e7f9
--- /dev/null
+++ b/博客/covers/docker-deployment-guide-cover.svg
@@ -0,0 +1,65 @@
+
diff --git a/博客/covers/uv工具推荐博客-cover.svg b/博客/covers/uv工具推荐博客-cover.svg
new file mode 100644
index 0000000..3c83309
--- /dev/null
+++ b/博客/covers/uv工具推荐博客-cover.svg
@@ -0,0 +1,38 @@
+
diff --git a/博客/covers/uv工具推荐博客大纲-cover.svg b/博客/covers/uv工具推荐博客大纲-cover.svg
new file mode 100644
index 0000000..e2a1424
--- /dev/null
+++ b/博客/covers/uv工具推荐博客大纲-cover.svg
@@ -0,0 +1,37 @@
+
diff --git a/博客/covers/vision-language-model-cover.svg b/博客/covers/vision-language-model-cover.svg
new file mode 100644
index 0000000..90bb6cc
--- /dev/null
+++ b/博客/covers/vision-language-model-cover.svg
@@ -0,0 +1,78 @@
+
diff --git a/博客/covers/从全连接层到卷积-cover.svg b/博客/covers/从全连接层到卷积-cover.svg
new file mode 100644
index 0000000..6c87d6c
--- /dev/null
+++ b/博客/covers/从全连接层到卷积-cover.svg
@@ -0,0 +1,47 @@
+
diff --git a/博客/covers/博客爬取报告-cover.svg b/博客/covers/博客爬取报告-cover.svg
new file mode 100644
index 0000000..dd758d6
--- /dev/null
+++ b/博客/covers/博客爬取报告-cover.svg
@@ -0,0 +1,39 @@
+
diff --git a/博客/covers/大数据技术栈-cover.svg b/博客/covers/大数据技术栈-cover.svg
new file mode 100644
index 0000000..3a84dba
--- /dev/null
+++ b/博客/covers/大数据技术栈-cover.svg
@@ -0,0 +1,39 @@
+
diff --git a/博客/covers/大模型赋能架构设计-cover.svg b/博客/covers/大模型赋能架构设计-cover.svg
new file mode 100644
index 0000000..5f290ce
--- /dev/null
+++ b/博客/covers/大模型赋能架构设计-cover.svg
@@ -0,0 +1,45 @@
+
diff --git a/博客/covers/大语言模型算子详解-cover.svg b/博客/covers/大语言模型算子详解-cover.svg
new file mode 100644
index 0000000..16f9fa3
--- /dev/null
+++ b/博客/covers/大语言模型算子详解-cover.svg
@@ -0,0 +1,46 @@
+
diff --git a/博客/covers/学习Agent,越学越像在重新理解操作系统-cover.svg b/博客/covers/学习Agent,越学越像在重新理解操作系统-cover.svg
new file mode 100644
index 0000000..03725e5
--- /dev/null
+++ b/博客/covers/学习Agent,越学越像在重新理解操作系统-cover.svg
@@ -0,0 +1,46 @@
+
diff --git a/博客/covers/摘要检查报告-cover.svg b/博客/covers/摘要检查报告-cover.svg
new file mode 100644
index 0000000..4dd42a2
--- /dev/null
+++ b/博客/covers/摘要检查报告-cover.svg
@@ -0,0 +1,39 @@
+
diff --git a/博客/covers/文章列表-cover.svg b/博客/covers/文章列表-cover.svg
new file mode 100644
index 0000000..010472e
--- /dev/null
+++ b/博客/covers/文章列表-cover.svg
@@ -0,0 +1,40 @@
+
diff --git a/博客/covers/标签分类审查报告-cover.svg b/博客/covers/标签分类审查报告-cover.svg
new file mode 100644
index 0000000..6d6c4d2
--- /dev/null
+++ b/博客/covers/标签分类审查报告-cover.svg
@@ -0,0 +1,39 @@
+
diff --git a/博客/covers/深度学习完全指南-cover.svg b/博客/covers/深度学习完全指南-cover.svg
new file mode 100644
index 0000000..d27f228
--- /dev/null
+++ b/博客/covers/深度学习完全指南-cover.svg
@@ -0,0 +1,47 @@
+
diff --git a/博客/其他/generate-blog-covers.js b/博客/其他/generate-blog-covers.js
new file mode 100644
index 0000000..ea486ae
--- /dev/null
+++ b/博客/其他/generate-blog-covers.js
@@ -0,0 +1,377 @@
+const fs = require("node:fs");
+const path = require("node:path");
+
+const blogRoot = "d:\\Code\\Obsidian\\博客";
+const coverDir = path.join(blogRoot, "covers");
+
+fs.mkdirSync(coverDir, { recursive: true });
+
+const existingCoverMap = new Map([
+ [
+ path.join(blogRoot, "AI与大模型", "深入解析 Claude Code:Vibe Coding 时代的 AI 编程利器.md"),
+ "claude-code-vibe-coding-cover.svg",
+ ],
+ [path.join(blogRoot, "编程与工具", "Docker部署完全指南.md"), "docker-deployment-guide-cover.svg"],
+ [path.join(blogRoot, "机器学习", "视觉语言模型技术综述.md"), "vision-language-model-cover.svg"],
+]);
+
+function escapeXml(text) {
+ return String(text ?? "")
+ .replaceAll("&", "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">")
+ .replaceAll('"', """);
+}
+
+function walkMarkdownFiles(dir) {
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
+ const files = [];
+ for (const entry of entries) {
+ const fullPath = path.join(dir, entry.name);
+ if (entry.isDirectory()) {
+ if (entry.name === "covers") continue;
+ files.push(...walkMarkdownFiles(fullPath));
+ continue;
+ }
+ if (entry.isFile() && entry.name.endsWith(".md")) {
+ files.push(fullPath);
+ }
+ }
+ return files.sort((a, b) => a.localeCompare(b, "zh-CN"));
+}
+
+function getArticleTitle(filePath) {
+ const raw = fs.readFileSync(filePath, "utf8");
+ const titleMatch = raw.match(/^title:\s*(.+)$/m);
+ if (titleMatch) {
+ return titleMatch[1].trim().replace(/^['"]|['"]$/g, "");
+ }
+ const h1Match = raw.match(/^#\s+(.+)$/m);
+ if (h1Match) {
+ return h1Match[1].trim();
+ }
+ return path.basename(filePath, ".md");
+}
+
+function getCategory(filePath) {
+ return path.basename(path.dirname(filePath));
+}
+
+function getSafeCoverName(filePath) {
+ if (existingCoverMap.has(filePath)) {
+ return existingCoverMap.get(filePath);
+ }
+ const baseName = path.basename(filePath, ".md");
+ const safeName = baseName.replace(/[<>:"/\\|?*]/g, "-").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
+ return `${safeName}-cover.svg`;
+}
+
+function splitTitle(title) {
+ const clean = title.trim();
+ if (clean.length <= 14) return [clean];
+ if (clean.length <= 28) return [clean.slice(0, Math.ceil(clean.length / 2)), clean.slice(Math.ceil(clean.length / 2))];
+ const first = clean.slice(0, 12);
+ const second = clean.slice(12, 24);
+ const third = clean.slice(24);
+ return [first, second, third].filter(Boolean);
+}
+
+function getTheme(category, title) {
+ const theme = {
+ key: "default",
+ label: "博客封面",
+ subtitle: "知识沉淀 / 主题文章",
+ bg1: "#0B1020",
+ bg2: "#172554",
+ bg3: "#0F766E",
+ accent1: "#67E8F9",
+ accent2: "#A78BFA",
+ accent3: "#F472B6",
+ panel: "rgba(7,12,28,0.70)",
+ tags: ["博客", "封面", "文章"],
+ };
+
+ const categoryThemes = {
+ "AI与大模型": {
+ key: "ai",
+ label: "AI 与大模型",
+ subtitle: "模型能力 / Agent / 智能协作",
+ bg1: "#0B1020",
+ bg2: "#1E1B4B",
+ bg3: "#0F766E",
+ accent1: "#67E8F9",
+ accent2: "#A855F7",
+ accent3: "#22D3EE",
+ tags: ["AI", "模型", "智能"],
+ },
+ "机器学习": {
+ key: "ml",
+ label: "机器学习",
+ subtitle: "算法原理 / 神经网络 / 模型理解",
+ bg1: "#0B1020",
+ bg2: "#172554",
+ bg3: "#4C1D95",
+ accent1: "#67E8F9",
+ accent2: "#C084FC",
+ accent3: "#F472B6",
+ tags: ["学习", "网络", "模型"],
+ },
+ "编程与工具": {
+ key: "tools",
+ label: "编程与工具",
+ subtitle: "工程实践 / 工具链 / 效率提升",
+ bg1: "#071A33",
+ bg2: "#0F3D74",
+ bg3: "#0B7285",
+ accent1: "#7DD3FC",
+ accent2: "#FDBA74",
+ accent3: "#60A5FA",
+ tags: ["工具", "工程", "实践"],
+ },
+ "数据分析与报告": {
+ key: "report",
+ label: "数据分析与报告",
+ subtitle: "指标洞察 / 数据审查 / 结果汇总",
+ bg1: "#111827",
+ bg2: "#1F2937",
+ bg3: "#0F766E",
+ accent1: "#34D399",
+ accent2: "#2DD4BF",
+ accent3: "#A7F3D0",
+ tags: ["数据", "分析", "报告"],
+ },
+ "学术与效率": {
+ key: "academic",
+ label: "学术与效率",
+ subtitle: "论文写作 / 知识表达 / 工具方法",
+ bg1: "#1F172A",
+ bg2: "#312E81",
+ bg3: "#0F766E",
+ accent1: "#C4B5FD",
+ accent2: "#93C5FD",
+ accent3: "#A7F3D0",
+ tags: ["学术", "写作", "效率"],
+ },
+ 其他: {
+ key: "outline",
+ label: "内容策划",
+ subtitle: "选题梳理 / 结构设计 / 创作准备",
+ bg1: "#0F172A",
+ bg2: "#1E293B",
+ bg3: "#334155",
+ accent1: "#93C5FD",
+ accent2: "#C4B5FD",
+ accent3: "#F9A8D4",
+ tags: ["策划", "结构", "草稿"],
+ },
+ };
+
+ Object.assign(theme, categoryThemes[category] || {});
+
+ const keywordRules = [
+ [/Claude|Vibe|CLI|Agent/i, { subtitle: "AI 编程 / Agentic CLI / 智能协作", tags: ["Agent", "CLI", "AI"] }],
+ [/DeepSeek|大模型/, { subtitle: "模型解析 / 趋势洞察 / 架构思考", tags: ["模型", "解析", "趋势"] }],
+ [/Docker|部署/, { subtitle: "容器部署 / 服务编排 / 工程实战", tags: ["部署", "容器", "实战"] }],
+ [/Git/, { subtitle: "版本控制 / 团队协作 / 工作流", tags: ["Git", "协作", "工作流"] }],
+ [/OpenClaw/, { subtitle: "AI 编程助手 / 安装配置 / 使用实践", tags: ["AI 工具", "安装", "指南"] }],
+ [/\buv\b|uv工具/, { subtitle: "Python 工具链 / 依赖管理 / 开发效率", tags: ["Python", "uv", "效率"] }],
+ [/SEO|爬取|摘要|标签|文章列表|技术栈/, { subtitle: "数据整理 / 指标审查 / 结果报告", tags: ["数据", "报告", "审查"] }],
+ [/LaTeX|论文/, { subtitle: "论文写作 / 排版工具 / 学术效率", tags: ["论文", "LaTeX", "效率"] }],
+ [/LinearRegression|线性回归/, { subtitle: "监督学习 / 回归模型 / 入门理解", tags: ["回归", "基础", "算法"] }],
+ [/卷积|全连接层/, { subtitle: "神经网络 / 表征学习 / 结构演进", tags: ["卷积", "神经网络", "视觉"] }],
+ [/深度学习/, { subtitle: "模型体系 / 核心概念 / 系统学习", tags: ["深度学习", "模型", "指南"] }],
+ [/视觉语言模型/, { subtitle: "多模态 AI / 视觉理解 / 语言推理", tags: ["VLM", "多模态", "推理"] }],
+ [/大纲/, { subtitle: "内容策划 / 结构拆解 / 写作准备", tags: ["大纲", "结构", "规划"] }],
+ ];
+
+ for (const [regex, patch] of keywordRules) {
+ if (regex.test(title)) {
+ Object.assign(theme, patch);
+ break;
+ }
+ }
+
+ return theme;
+}
+
+function getGraphicMarkup(theme) {
+ const { key, accent1, accent2, accent3 } = theme;
+ if (key === "ai") {
+ return `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ }
+ if (key === "ml") {
+ return `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ }
+ if (key === "tools") {
+ return `
+
+
+
+
+
+
+
+
+
+ `;
+ }
+ if (key === "report") {
+ return `
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ }
+ if (key === "academic") {
+ return `
+
+
+
+
+
+
+
+ ∫
+ LaTeX
+ Σ x² + y²
+ `;
+ }
+ return `
+
+
+
+
+
+
+
+
+ `;
+}
+
+function buildTitleMarkup(title) {
+ const lines = splitTitle(title);
+ const fontSize = lines.length === 1 ? 48 : lines.length === 2 ? 44 : 36;
+ const lineHeight = lines.length === 3 ? 48 : 56;
+ const startY = lines.length === 1 ? 250 : lines.length === 2 ? 224 : 196;
+ return lines
+ .map((line, index) => {
+ const y = startY + index * lineHeight;
+ return ` ${escapeXml(line)}`;
+ })
+ .join("\n");
+}
+
+function buildTagMarkup(tags) {
+ const fills = ["rgba(103,232,249,0.12)", "rgba(168,85,247,0.12)", "rgba(244,114,182,0.12)"];
+ const strokes = ["rgba(103,232,249,0.30)", "rgba(196,181,253,0.30)", "rgba(251,207,232,0.26)"];
+ const textColors = ["#BAE6FD", "#DDD6FE", "#FBCFE8"];
+ let x = 112;
+ return tags.slice(0, 3).map((tag, index) => {
+ const width = Math.max(118, 54 + tag.length * 22);
+ const rect = ` `;
+ const text = ` ${escapeXml(tag)}`;
+ x += width + 18;
+ return `${rect}\n${text}`;
+ }).join("\n");
+}
+
+function buildSvg(title, theme) {
+ return `
+`;
+}
+
+const articles = walkMarkdownFiles(blogRoot);
+const created = [];
+const skipped = [];
+
+for (const articlePath of articles) {
+ if (existingCoverMap.has(articlePath)) {
+ skipped.push(`${articlePath} => ${existingCoverMap.get(articlePath)}`);
+ continue;
+ }
+
+ const title = getArticleTitle(articlePath);
+ const category = getCategory(articlePath);
+ const theme = getTheme(category, title);
+ const coverName = getSafeCoverName(articlePath);
+ const coverPath = path.join(coverDir, coverName);
+
+ if (fs.existsSync(coverPath)) {
+ skipped.push(`${articlePath} => ${coverName}`);
+ continue;
+ }
+
+ fs.writeFileSync(coverPath, buildSvg(title, theme), "utf8");
+ created.push(coverPath);
+}
+
+console.log(`Created: ${created.length}`);
+for (const file of created) console.log(file);
+console.log(`Skipped: ${skipped.length}`);
+for (const file of skipped) console.log(file);
diff --git a/博客/其他/generate-blog-covers.ps1 b/博客/其他/generate-blog-covers.ps1
new file mode 100644
index 0000000..40442b1
--- /dev/null
+++ b/博客/其他/generate-blog-covers.ps1
@@ -0,0 +1,494 @@
+# 批量为博客文章生成 SVG 封面图。
+Set-StrictMode -Version Latest
+$ErrorActionPreference = "Stop"
+
+$blogRoot = "d:\Code\Obsidian\博客"
+$coverDir = Join-Path $blogRoot "covers"
+
+New-Item -ItemType Directory -Force -Path $coverDir | Out-Null
+
+# 已人工调整过的样例封面,后续批量任务中不覆盖。
+$existingCoverMap = @{
+ "d:\Code\Obsidian\博客\AI与大模型\深入解析 Claude Code:Vibe Coding 时代的 AI 编程利器.md" = "claude-code-vibe-coding-cover.svg"
+ "d:\Code\Obsidian\博客\编程与工具\Docker部署完全指南.md" = "docker-deployment-guide-cover.svg"
+ "d:\Code\Obsidian\博客\机器学习\视觉语言模型技术综述.md" = "vision-language-model-cover.svg"
+}
+
+function Escape-Xml {
+ param([string]$Text)
+
+ if ([string]::IsNullOrEmpty($Text)) {
+ return ""
+ }
+
+ return $Text.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace('"', """)
+}
+
+function Get-ArticleTitle {
+ param([string]$Path)
+
+ $raw = Get-Content -LiteralPath $Path -Raw -Encoding UTF8
+
+ if ($raw -match "(?m)^title:\s*(.+)$") {
+ return $matches[1].Trim().Trim("'").Trim('"')
+ }
+
+ if ($raw -match "(?m)^#\s+(.+)$") {
+ return $matches[1].Trim()
+ }
+
+ return [System.IO.Path]::GetFileNameWithoutExtension($Path)
+}
+
+function Get-CategoryName {
+ param([string]$Path)
+
+ return Split-Path (Split-Path $Path -Parent) -Leaf
+}
+
+function Get-SafeCoverName {
+ param([string]$ArticlePath)
+
+ if ($existingCoverMap.ContainsKey($ArticlePath)) {
+ return $existingCoverMap[$ArticlePath]
+ }
+
+ $baseName = [System.IO.Path]::GetFileNameWithoutExtension($ArticlePath)
+ $safeName = ($baseName -replace '[<>:"/\\|?*]', "-") -replace "\s+", "-"
+ $safeName = $safeName.Trim("-")
+ return "$safeName-cover.svg"
+}
+
+function Split-TextLines {
+ param(
+ [string]$Text,
+ [int]$MaxCharsPerLine
+ )
+
+ $clean = $Text.Trim()
+ if ([string]::IsNullOrWhiteSpace($clean)) {
+ return @("")
+ }
+
+ $lines = New-Object System.Collections.Generic.List[string]
+ $remaining = $clean
+
+ while ($remaining.Length -gt $MaxCharsPerLine) {
+ $cutIndex = $MaxCharsPerLine
+ $spaceIndex = $remaining.LastIndexOf(" ", [Math]::Min($MaxCharsPerLine, $remaining.Length - 1))
+ if ($spaceIndex -gt 6) {
+ $cutIndex = $spaceIndex
+ }
+
+ $lines.Add($remaining.Substring(0, $cutIndex).Trim())
+ $remaining = $remaining.Substring($cutIndex).Trim()
+ }
+
+ if ($remaining.Length -gt 0) {
+ $lines.Add($remaining)
+ }
+
+ if ($lines.Count -gt 3) {
+ $merged = @($lines[0], $lines[1], (($lines | Select-Object -Skip 2) -join " "))
+ return $merged
+ }
+
+ return $lines.ToArray()
+}
+
+function Get-ThemeInfo {
+ param(
+ [string]$Category,
+ [string]$Title
+ )
+
+ $theme = [ordered]@{
+ Key = "default"
+ Label = "博客封面"
+ Subtitle = "知识沉淀 / 主题文章"
+ Bg1 = "#0B1020"
+ Bg2 = "#172554"
+ Bg3 = "#0F766E"
+ Accent1 = "#67E8F9"
+ Accent2 = "#A78BFA"
+ Accent3 = "#F472B6"
+ Panel = "rgba(7,12,28,0.70)"
+ Tags = @("博客", "封面", "文章")
+ }
+
+ switch ($Category) {
+ "AI与大模型" {
+ $theme.Key = "ai"
+ $theme.Label = "AI 与大模型"
+ $theme.Subtitle = "模型能力 / Agent / 智能协作"
+ $theme.Bg1 = "#0B1020"
+ $theme.Bg2 = "#1E1B4B"
+ $theme.Bg3 = "#0F766E"
+ $theme.Accent1 = "#67E8F9"
+ $theme.Accent2 = "#A855F7"
+ $theme.Accent3 = "#22D3EE"
+ $theme.Tags = @("AI", "模型", "智能")
+ }
+ "机器学习" {
+ $theme.Key = "ml"
+ $theme.Label = "机器学习"
+ $theme.Subtitle = "算法原理 / 神经网络 / 模型理解"
+ $theme.Bg1 = "#0B1020"
+ $theme.Bg2 = "#172554"
+ $theme.Bg3 = "#4C1D95"
+ $theme.Accent1 = "#67E8F9"
+ $theme.Accent2 = "#C084FC"
+ $theme.Accent3 = "#F472B6"
+ $theme.Tags = @("学习", "网络", "模型")
+ }
+ "编程与工具" {
+ $theme.Key = "tools"
+ $theme.Label = "编程与工具"
+ $theme.Subtitle = "工程实践 / 工具链 / 效率提升"
+ $theme.Bg1 = "#071A33"
+ $theme.Bg2 = "#0F3D74"
+ $theme.Bg3 = "#0B7285"
+ $theme.Accent1 = "#7DD3FC"
+ $theme.Accent2 = "#FDBA74"
+ $theme.Accent3 = "#60A5FA"
+ $theme.Tags = @("工具", "工程", "实践")
+ }
+ "数据分析与报告" {
+ $theme.Key = "report"
+ $theme.Label = "数据分析与报告"
+ $theme.Subtitle = "指标洞察 / 数据审查 / 结果汇总"
+ $theme.Bg1 = "#111827"
+ $theme.Bg2 = "#1F2937"
+ $theme.Bg3 = "#0F766E"
+ $theme.Accent1 = "#34D399"
+ $theme.Accent2 = "#2DD4BF"
+ $theme.Accent3 = "#A7F3D0"
+ $theme.Tags = @("数据", "分析", "报告")
+ }
+ "学术与效率" {
+ $theme.Key = "academic"
+ $theme.Label = "学术与效率"
+ $theme.Subtitle = "论文写作 / 知识表达 / 工具方法"
+ $theme.Bg1 = "#1F172A"
+ $theme.Bg2 = "#312E81"
+ $theme.Bg3 = "#0F766E"
+ $theme.Accent1 = "#C4B5FD"
+ $theme.Accent2 = "#93C5FD"
+ $theme.Accent3 = "#A7F3D0"
+ $theme.Tags = @("学术", "写作", "效率")
+ }
+ "其他" {
+ $theme.Key = "outline"
+ $theme.Label = "内容策划"
+ $theme.Subtitle = "选题梳理 / 结构设计 / 创作准备"
+ $theme.Bg1 = "#0F172A"
+ $theme.Bg2 = "#1E293B"
+ $theme.Bg3 = "#334155"
+ $theme.Accent1 = "#93C5FD"
+ $theme.Accent2 = "#C4B5FD"
+ $theme.Accent3 = "#F9A8D4"
+ $theme.Tags = @("策划", "结构", "草稿")
+ }
+ }
+
+ switch -Regex ($Title) {
+ "Claude|Vibe|CLI|Agent" {
+ $theme.Subtitle = "AI 编程 / Agentic CLI / 智能协作"
+ $theme.Tags = @("Agent", "CLI", "AI")
+ break
+ }
+ "DeepSeek|大模型" {
+ $theme.Subtitle = "模型解析 / 趋势洞察 / 架构思考"
+ $theme.Tags = @("模型", "解析", "趋势")
+ break
+ }
+ "Docker|部署" {
+ $theme.Subtitle = "容器部署 / 服务编排 / 工程实战"
+ $theme.Tags = @("部署", "容器", "实战")
+ break
+ }
+ "Git" {
+ $theme.Subtitle = "版本控制 / 团队协作 / 工作流"
+ $theme.Tags = @("Git", "协作", "工作流")
+ break
+ }
+ "OpenClaw" {
+ $theme.Subtitle = "AI 编程助手 / 安装配置 / 使用实践"
+ $theme.Tags = @("AI 工具", "安装", "指南")
+ break
+ }
+ "uv" {
+ $theme.Subtitle = "Python 工具链 / 依赖管理 / 开发效率"
+ $theme.Tags = @("Python", "uv", "效率")
+ break
+ }
+ "SEO|爬取|摘要|标签|文章列表|技术栈" {
+ $theme.Subtitle = "数据整理 / 指标审查 / 结果报告"
+ $theme.Tags = @("数据", "报告", "审查")
+ break
+ }
+ "LaTeX|论文" {
+ $theme.Subtitle = "论文写作 / 排版工具 / 学术效率"
+ $theme.Tags = @("论文", "LaTeX", "效率")
+ break
+ }
+ "LinearRegression|线性回归" {
+ $theme.Subtitle = "监督学习 / 回归模型 / 入门理解"
+ $theme.Tags = @("回归", "基础", "算法")
+ break
+ }
+ "卷积|全连接层" {
+ $theme.Subtitle = "神经网络 / 表征学习 / 结构演进"
+ $theme.Tags = @("卷积", "神经网络", "视觉")
+ break
+ }
+ "深度学习" {
+ $theme.Subtitle = "模型体系 / 核心概念 / 系统学习"
+ $theme.Tags = @("深度学习", "模型", "指南")
+ break
+ }
+ "视觉语言模型" {
+ $theme.Subtitle = "多模态 AI / 视觉理解 / 语言推理"
+ $theme.Tags = @("VLM", "多模态", "推理")
+ break
+ }
+ "大纲" {
+ $theme.Subtitle = "内容策划 / 结构拆解 / 写作准备"
+ $theme.Tags = @("大纲", "结构", "规划")
+ break
+ }
+ }
+
+ return $theme
+}
+
+function Get-GraphicMarkup {
+ param($Theme)
+
+ switch ($Theme.Key) {
+ "ai" {
+ return @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"@
+ }
+ "ml" {
+ return @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"@
+ }
+ "tools" {
+ return @"
+
+
+
+
+
+
+
+
+
+
+"@
+ }
+ "report" {
+ return @"
+
+
+
+
+
+
+
+
+
+
+
+
+"@
+ }
+ "academic" {
+ return @"
+
+
+
+
+
+
+
+ ∫
+ LaTeX
+ Σ x² + y²
+
+"@
+ }
+ default {
+ return @"
+
+
+
+
+
+
+
+
+
+"@
+ }
+ }
+}
+
+function New-TitleMarkup {
+ param([string]$Title)
+
+ $maxChars = if ($Title.Length -gt 28) { 14 } elseif ($Title.Length -gt 20) { 16 } else { 20 }
+ $lines = Split-TextLines -Text $Title -MaxCharsPerLine $maxChars
+ $fontSize = switch ($lines.Count) {
+ 1 { 48 }
+ 2 { if (($lines | Measure-Object -Maximum Length).Maximum -gt 18) { 42 } else { 46 } }
+ default { 36 }
+ }
+
+ $lineHeight = if ($lines.Count -ge 3) { 48 } else { 56 }
+ $startY = switch ($lines.Count) {
+ 1 { 250 }
+ 2 { 226 }
+ default { 198 }
+ }
+
+ $markup = New-Object System.Collections.Generic.List[string]
+ for ($i = 0; $i -lt $lines.Count; $i++) {
+ $y = $startY + ($i * $lineHeight)
+ $markup.Add(" $([string](Escape-Xml $lines[$i]))")
+ }
+
+ return ($markup -join "`n")
+}
+
+function New-TagMarkup {
+ param([string[]]$Tags)
+
+ $x = 112
+ $y = 376
+ $items = New-Object System.Collections.Generic.List[string]
+ $fills = @("rgba(103,232,249,0.12)", "rgba(168,85,247,0.12)", "rgba(244,114,182,0.12)")
+ $strokes = @("rgba(103,232,249,0.30)", "rgba(196,181,253,0.30)", "rgba(251,207,232,0.26)")
+ $texts = @("#BAE6FD", "#DDD6FE", "#FBCFE8")
+
+ for ($i = 0; $i -lt [Math]::Min(3, $Tags.Count); $i++) {
+ $tag = $Tags[$i]
+ $width = [Math]::Max(118, 54 + ($tag.Length * 22))
+ $items.Add(" ")
+ $items.Add(" $([string](Escape-Xml $tag))")
+ $x += $width + 18
+ }
+
+ return ($items -join "`n")
+}
+
+function New-CoverSvg {
+ param(
+ [string]$Title,
+ [hashtable]$Theme
+ )
+
+ $label = Escape-Xml $Theme.Label
+ $subtitle = Escape-Xml $Theme.Subtitle
+ $titleMarkup = New-TitleMarkup -Title $Title
+ $tagMarkup = New-TagMarkup -Tags $Theme.Tags
+ $graphicMarkup = Get-GraphicMarkup -Theme $Theme
+
+ return @"
+
+"@
+}
+
+$articles = Get-ChildItem -LiteralPath $blogRoot -Recurse -File -Filter "*.md" |
+ Where-Object { $_.FullName -notlike "*\covers\*" } |
+ Sort-Object FullName
+
+$created = New-Object System.Collections.Generic.List[string]
+$skipped = New-Object System.Collections.Generic.List[string]
+
+foreach ($article in $articles) {
+ $articlePath = $article.FullName
+ if ($existingCoverMap.ContainsKey($articlePath)) {
+ $skipped.Add("$articlePath => $($existingCoverMap[$articlePath])")
+ continue
+ }
+
+ $title = Get-ArticleTitle -Path $articlePath
+ $category = Get-CategoryName -Path $articlePath
+ $theme = Get-ThemeInfo -Category $category -Title $title
+ $coverName = Get-SafeCoverName -ArticlePath $articlePath
+ $coverPath = Join-Path $coverDir $coverName
+
+ if (Test-Path -LiteralPath $coverPath) {
+ $skipped.Add("$articlePath => $(Split-Path $coverPath -Leaf)")
+ continue
+ }
+
+ $svg = New-CoverSvg -Title $title -Theme $theme
+ Set-Content -LiteralPath $coverPath -Value $svg -Encoding UTF8
+ $created.Add($coverPath)
+}
+
+Write-Output "Created: $($created.Count)"
+$created | ForEach-Object { Write-Output $_ }
+Write-Output "Skipped: $($skipped.Count)"
+$skipped | ForEach-Object { Write-Output $_ }