self-media-james/scripts/render_mermaid.js
邓文兵 76c9a60379 feat(article): 添加 GPT-5.4 深度解析文章及配套图表
- 新增 GPT-5.4 深度解析文章,涵盖六大核心能力详解
- 添加 SVG 格式的 GPT-5.4 能力全景图
- 添加 Mermaid 格式的模型家族关系图
- 添加 GPT-5.4 六大能力思维导图
- 添加 Computer Use 工作流程图
- 添加 OSWorld 桌面操作基准测试图表
- 添加 上下文窗口演进对比图
- 添加 上下文压缩原理图
- 添加 Tool Search 机制对比图
- 添加 可配置推理深度图
- 添加 GDPval 对比图表
- 添加 三方模型对比图
- 添加 API 定价对比图
- 添加 Mermaid 配置文件和样式文件
- 添加模型选择指南 SVG 图片
2026-03-16 16:28:42 +08:00

228 lines
6.9 KiB
JavaScript

/**
* 用 Playwright 渲染 Mermaid .mmd 文件为高质量 PNG
* 用法: node render_mermaid.js <input.mmd> <output.png> [width]
*/
const { chromium } = require('/Users/bing/node_modules/.pnpm/playwright@1.58.2/node_modules/playwright');
const fs = require('fs');
const path = require('path');
const mmdFile = process.argv[2];
const outFile = process.argv[3];
const width = parseInt(process.argv[4] || '2400', 10);
if (!mmdFile || !outFile) {
console.error('Usage: node render_mermaid.js <input.mmd> <output.png> [width]');
process.exit(1);
}
const mmdContent = fs.readFileSync(mmdFile, 'utf-8');
// 检测图表类型
const isMindmap = mmdContent.trim().startsWith('mindmap');
const isXYChart = mmdContent.includes('xychart-beta');
const html = `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<style>
body {
margin: 0;
padding: 40px;
background: #080c18;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
#diagram {
display: inline-block;
}
/* ===== 全局文字 ===== */
.mermaid text, .mermaid tspan, .mermaid span, .mermaid p {
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif !important;
}
/* ===== 流程图节点文字强制白色 ===== */
.mermaid .node .label,
.mermaid .node .label span,
.mermaid .node .label p,
.mermaid .nodeLabel,
.mermaid .edgeLabel span,
.mermaid .edgeLabel p,
.mermaid .cluster-label span,
.mermaid .cluster-label p {
color: #e0f7fa !important;
}
.mermaid .node text, .mermaid .node tspan {
fill: #e0f7fa !important;
}
/* ===== 流程图节点发光 ===== */
.mermaid .node rect, .mermaid .node polygon, .mermaid .node circle {
filter: drop-shadow(0 0 6px rgba(0, 229, 255, 0.4));
rx: 8;
ry: 8;
}
/* ===== 流程图边线 ===== */
.mermaid .edge-pattern-solid, .mermaid .flowchart-link {
stroke: #00b8d4 !important;
stroke-width: 2px !important;
}
.mermaid marker path {
fill: #00e5ff !important;
}
/* ===== Cluster/subgraph ===== */
.mermaid .cluster rect {
stroke: #1a6a8a !important;
stroke-width: 2px !important;
stroke-dasharray: 6 3 !important;
fill: rgba(10, 26, 46, 0.7) !important;
rx: 12 !important;
ry: 12 !important;
}
.mermaid .cluster-label text, .mermaid .cluster-label tspan {
fill: #4dd0e1 !important;
}
.mermaid .cluster-label span, .mermaid .cluster-label p {
color: #4dd0e1 !important;
}
/* ===== Edge labels ===== */
.mermaid .edgeLabel rect {
fill: #0a1628 !important;
opacity: 0.9 !important;
}
.mermaid .edgeLabel text, .mermaid .edgeLabel tspan {
fill: #80deea !important;
}
/* ===== Mindmap 修复黑块 ===== */
.mermaid .mindmap-node rect,
.mermaid .mindmap-node polygon,
.mermaid .mindmap-node circle,
.mermaid .mindmap-node ellipse,
.mermaid .mindmap-node path {
stroke: #00b8d4 !important;
stroke-width: 2px !important;
filter: drop-shadow(0 0 6px rgba(0, 229, 255, 0.35)) !important;
}
.mermaid .mindmap-node text, .mermaid .mindmap-node tspan {
fill: #e0f7fa !important;
}
/* Mindmap 分区颜色 */
.mermaid .section-0 rect, .mermaid .section-0 path { fill: #0d3b66 !important; stroke: #00e5ff !important; }
.mermaid .section-1 rect, .mermaid .section-1 path { fill: #1a3a4a !important; stroke: #26c6da !important; }
.mermaid .section-2 rect, .mermaid .section-2 path { fill: #1b3044 !important; stroke: #4dd0e1 !important; }
.mermaid .section-3 rect, .mermaid .section-3 path { fill: #14293d !important; stroke: #00bcd4 !important; }
.mermaid .section-4 rect, .mermaid .section-4 path { fill: #0f2b3d !important; stroke: #80deea !important; }
.mermaid .section-5 rect, .mermaid .section-5 path { fill: #0d3352 !important; stroke: #4fc3f7 !important; }
.mermaid .section-6 rect, .mermaid .section-6 path { fill: #102a40 !important; stroke: #29b6f6 !important; }
.mermaid .section-7 rect, .mermaid .section-7 path { fill: #0e2d44 !important; stroke: #81d4fa !important; }
/* 根节点 */
.mermaid .mindmap-node:first-of-type circle {
fill: #0d2137 !important;
stroke: #00e5ff !important;
stroke-width: 3px !important;
filter: drop-shadow(0 0 12px rgba(0, 229, 255, 0.6)) !important;
}
/* 黑色回退 */
.mermaid rect[fill="#000"], .mermaid rect[fill="#000000"], .mermaid rect[fill="black"],
.mermaid path[fill="#000"], .mermaid path[fill="#000000"], .mermaid path[fill="black"] {
fill: #0d3b66 !important;
}
</style>
</head>
<body>
<div id="diagram">
<pre class="mermaid">
${mmdContent}
</pre>
</div>
<script>
mermaid.initialize({
startOnLoad: true,
theme: 'base',
themeVariables: {
primaryColor: '#0d2137',
primaryTextColor: '#e0f7fa',
primaryBorderColor: '#00e5ff',
lineColor: '#00b8d4',
secondaryColor: '#1a3a4a',
secondaryTextColor: '#e0f7fa',
secondaryBorderColor: '#00bcd4',
tertiaryColor: '#112240',
tertiaryTextColor: '#e0f7fa',
tertiaryBorderColor: '#26c6da',
noteBkgColor: '#0d2137',
noteTextColor: '#e0f7fa',
noteBorderColor: '#00e5ff',
edgeLabelBackground: '#0a1628',
clusterBkg: '#0a1a2e',
clusterBorder: '#1a5276',
titleColor: '#00e5ff',
background: '#080c18',
mainBkg: '#0d2137',
nodeBorder: '#00e5ff',
nodeTextColor: '#e0f7fa',
fontFamily: 'SF Pro Display, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica Neue, Arial, sans-serif',
fontSize: '16px',
xyChart: {
backgroundColor: '#080c18',
titleColor: '#00e5ff',
xAxisLabelColor: '#e0f7fa',
yAxisLabelColor: '#e0f7fa',
xAxisTitleColor: '#00e5ff',
yAxisTitleColor: '#00e5ff',
xAxisTickColor: '#00b8d4',
yAxisTickColor: '#00b8d4',
xAxisLineColor: '#00b8d4',
yAxisLineColor: '#00b8d4',
plotColorPalette: '#00e5ff,#4dd0e1,#26c6da,#00bcd4,#80deea,#b2ebf2'
}
},
mindmap: { useMaxWidth: false },
flowchart: { useMaxWidth: false, htmlLabels: true }
});
</script>
</body>
</html>`;
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: width, height: 1600 },
deviceScaleFactor: 2
});
await page.setContent(html, { waitUntil: 'networkidle' });
await page.waitForSelector('.mermaid svg', { timeout: 15000 });
await page.waitForTimeout(1000);
const box = await page.locator('#diagram').boundingBox();
if (!box) {
console.error('Failed to locate diagram');
await browser.close();
process.exit(1);
}
const padding = 40;
await page.screenshot({
path: outFile,
clip: {
x: Math.max(0, box.x - padding),
y: Math.max(0, box.y - padding),
width: box.width + padding * 2,
height: box.height + padding * 2
}
});
console.log(`OK: ${outFile} (${Math.round(box.width)}x${Math.round(box.height)})`);
await browser.close();
})();