Files
drawlogo/scripts/gen-300-bot-png.js

75 lines
3.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 🤖 300 个 bottts 机器人 → 白底方形 PNG(1024×1024)
* 与 preview-300.html 的 seed 序列一一对应(共享 bot-common 逻辑,过滤负面表情),
* 白底 + bottts 居中放大,Chrome headless 并发截图。
*
* 用法:node scripts/gen-300-bot-png.js
*/
'use strict';
const fs = require('fs');
const path = require('path');
const vm = require('vm');
const { spawn } = require('child_process');
const { generateSeeds } = require('./bot-common');
const ROOT = path.resolve(__dirname, '..');
const OUT_DIR = path.join(ROOT, 'output', 'agent-avatars-png', 'bot-png');
const TMP_DIR = path.join(ROOT, 'output', '.tmp-bot');
const CHROME = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
const SIZE = 1024;
const COUNT = 300;
// —— 1. 加载 bottts ——
global.window = global;
vm.runInThisContext(fs.readFileSync(path.join(ROOT, 'js', 'data', 'sources', 'dicebear-bottts.js'), 'utf8'), { filename: 'dicebear-bottts.js' });
vm.runInThisContext(fs.readFileSync(path.join(ROOT, 'js', 'core', 'dicebear.js'), 'utf8'), { filename: 'dicebear.js' });
// —— 2. 生成 300 个 seed(与预览页一致)——
const cards = generateSeeds(seed => HGB_Dicebear.renderAvatar('bottts', seed), COUNT);
// —— 3. 生成 HTML(白底 + bottts 居中,SVG 放大到 880)——
fs.mkdirSync(TMP_DIR, { recursive: true });
const htmlFiles = [];
for (let i = 0; i < cards.length; i++) {
const { svg } = cards[i];
const html = `<!DOCTYPE html><html><head><meta charset="utf-8">
<style>html,body{margin:0;padding:0;width:${SIZE}px;height:${SIZE}px;overflow:hidden;background:#ffffff}
.wrap{width:${SIZE}px;height:${SIZE}px;display:flex;align-items:center;justify-content:center}</style>
</head><body><div class="wrap">${svg.replace('<svg ', '<svg width="880" height="880" ')}</div></body></html>`;
const f = path.join(TMP_DIR, `a${i + 1}.html`);
fs.writeFileSync(f, html, 'utf8');
htmlFiles.push(f);
}
// —— 4. 并发截图(8 进程)——
function shot(file, out) {
return new Promise((res) => {
const p = spawn(CHROME, [
'--headless=new', '--disable-gpu', '--hide-scrollbars',
'--force-device-scale-factor=1',
'--window-size=' + SIZE + ',' + SIZE, '--virtual-time-budget=800',
'--screenshot=' + out,
'file:///' + file.replace(/\\/g, '/')
], { stdio: 'ignore' });
p.on('close', () => res());
p.on('error', () => res());
});
}
(async () => {
fs.mkdirSync(OUT_DIR, { recursive: true });
const jobs = htmlFiles.map((f, i) => ({
f, out: path.join(OUT_DIR, 'agent-' + String(i + 1).padStart(2, '0') + '.png')
}));
let done = 0, t0 = Date.now();
const CONC = 8;
for (let s = 0; s < jobs.length; s += CONC) {
const batch = jobs.slice(s, s + CONC);
await Promise.all(batch.map(j => shot(j.f, j.out)));
done += batch.length;
console.log(`⏳ ${done}/${jobs.length} ${((Date.now() - t0) / 1000).toFixed(1)}s`);
}
fs.rmSync(TMP_DIR, { recursive: true, force: true });
console.log('🎉 完成 → output/agent-avatars-png/bot-png/ (' + jobs.length + ' 张,白底 1024×1024)');
})();