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 @@ + + + + + + + + + + + + + + 学术与效率 + 告别Word!AI时代让你的 + LaTeX论文写作效率翻倍 + 论文写作 / 排版工具 / 学术效率 + + 论文 + + LaTeX + + 效率 + + + + + + + + + + + + + LaTeX + Σ x² + y² + + 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 @@ + + + + + + + + + + + + + + AI 与大模型 + AI时代的Vibe Co + ding:程序员不会被取 + 代,但需要进化 + AI 编程 / Agentic CLI / 智能协作 + + Agent + + CLI + + AI + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + AI 与大模型 + CLI在AI时代的浴火重生 + AI 编程 / Agentic CLI / 智能协作 + + Agent + + CLI + + AI + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + AI 与大模型 + DeepSeek + -V4全面解析 + 模型解析 / 趋势洞察 / 架构思考 + + 模型 + + 解析 + + 趋势 + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 内容策划 + 《DeepSeek V4 + 全面解析:开源模型的又 + 一次突破》 + 模型解析 / 趋势洞察 / 架构思考 + + 模型 + + 解析 + + 趋势 + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 编程与工具 + Git内部原理详解 + 版本控制 / 团队协作 / 工作流 + + Git + + 协作 + + 工作流 + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 编程与工具 + Git团队协作指 + 南:从入门到精通 + 版本控制 / 团队协作 / 工作流 + + Git + + 协作 + + 工作流 + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 内容策划 + Git团队协作指南大纲 + 版本控制 / 团队协作 / 工作流 + + Git + + 协作 + + 工作流 + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 编程与工具 + Git团队协作指南(精简版) + 版本控制 / 团队协作 / 工作流 + + Git + + 协作 + + 工作流 + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 机器学习 + Linear Regr + ession 线性回归 + 监督学习 / 回归模型 / 入门理解 + + 回归 + + 基础 + + 算法 + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 编程与工具 + OpenClaw 开 + 源智能体框架全面介绍 + AI 编程助手 / 安装配置 / 使用实践 + + AI 工具 + + 安装 + + 指南 + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 编程与工具 + OpenClaw Wi + ndows 安装教程 + AI 编程助手 / 安装配置 / 使用实践 + + AI 工具 + + 安装 + + 指南 + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 数据分析与报告 + SEO分析报告 + 数据整理 / 指标审查 / 结果报告 + + 数据 + + 报告 + + 审查 + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AI 编程 / Agentic CLI / Vibe Coding + 深入解析 Claude Code + Vibe Coding 时代的 AI 编程利器 + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Container / Compose / Deploy + Docker 部署完全指南 + 从入门到实战 + + + + + + 环境准备 + Compose + 实战部署 + + + + + 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 @@ + + + + + + + + + + + + + + 编程与工具 + 极速 Python 包管 + 理神器:uv 体验报告 + Python 工具链 / 依赖管理 / 开发效率 + + Python + + uv + + 效率 + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 内容策划 + 《极速 Python 包管 + 理神器:uv 体验报告》 + Python 工具链 / 依赖管理 / 开发效率 + + Python + + uv + + 效率 + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IMG + VLM + TXT + + + + + + + + + + + + + Multimodal AI / Vision / Language + 视觉语言模型技术综述 + 图像理解与大语言模型的融合之路 + + + + + + 视觉编码器 + 跨模态对齐 + 生成推理 + + + + + 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 @@ + + + + + + + + + + + + + + AI 与大模型 + 博客爬取报告 + 数据整理 / 指标审查 / 结果报告 + + 数据 + + 报告 + + 审查 + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + AI 与大模型 + 大语言模型算子详解: + 学术版 + 白话版 + 模型能力 / Agent / 智能协作 + + AI + + 模型 + + 智能 + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + AI 与大模型 + 学习 Agent,越学 + 越像在重新理解操作系统 + AI 编程 / Agentic CLI / 智能协作 + + Agent + + CLI + + AI + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + 数据分析与报告 + Serendipi + ty 博客文章列表 + 数据整理 / 指标审查 / 结果报告 + + 数据 + + 报告 + + 审查 + + + + + + + + + + + + + + + + + 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 ` + + + + + + + + + + + + + ${escapeXml(theme.label)} +${buildTitleMarkup(title)} + ${escapeXml(theme.subtitle)} +${buildTagMarkup(theme.tags)} + + + +${getGraphicMarkup(theme)} + +`; +} + +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 @" + + + + + + + + + + + + + + $label +$titleMarkup + $subtitle +$tagMarkup + + + +$graphicMarkup + +"@ +} + +$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 $_ }