114 lines
4.3 KiB
JavaScript
114 lines
4.3 KiB
JavaScript
#!/usr/bin/env node
|
||
// scripts/_rebuild-avatars.mjs(临时脚本,_ 前缀不入镜像)
|
||
// 从 DrawLogo 的 10 种风格头像中各取前 10 个,重构追光AI 用户头像库
|
||
// - 10 风格 × 10 个 = 100 个 SVG → public/avatars/
|
||
// - 重写 public/avatars/manifest.json
|
||
// - 重写 src/lib/avatar-library.ts(AVATAR_LIBRARY)
|
||
// 用法: node scripts/_rebuild-avatars.mjs
|
||
import { readFileSync, writeFileSync, copyFileSync, existsSync } from "fs";
|
||
import { resolve, dirname } from "path";
|
||
import { fileURLToPath } from "url";
|
||
|
||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||
const ZG_ROOT = resolve(__dirname, "..");
|
||
const DRAW_SRC = resolve("D:/SGP_KF/DrawLogo/output/agent-avatars-png/avatars");
|
||
const AVATAR_DIR = resolve(ZG_ROOT, "public/avatars");
|
||
const MANIFEST_PATH = resolve(AVATAR_DIR, "manifest.json");
|
||
const LIB_TS_PATH = resolve(ZG_ROOT, "src/lib/avatar-library.ts");
|
||
|
||
// 12 种风格(rings/shapes 渲染杂乱已移除,新增 open-peeps/lorelei/big-smile/croodles)
|
||
const STYLES = [
|
||
{ id: "bottts", name: "科技机器人" },
|
||
{ id: "bottts-neutral", name: "极简机器人" },
|
||
{ id: "micah", name: "米迦人物" },
|
||
{ id: "pixel-art", name: "像素风" },
|
||
{ id: "fun-emoji", name: "趣味表情" },
|
||
{ id: "avataaars", name: "阿凡达" },
|
||
{ id: "notionists", name: "Notion 风" },
|
||
{ id: "adventurer", name: "冒险家" },
|
||
{ id: "open-peeps", name: "简笔人物" },
|
||
{ id: "lorelei", name: "人物插画" },
|
||
{ id: "big-smile", name: "笑脸人物" },
|
||
{ id: "croodles", name: "涂鸦人物" },
|
||
];
|
||
const PER_STYLE = 10; // 每种风格 10 个
|
||
|
||
// 读取 DrawLogo meta.json 获取每种风格渐变颜色
|
||
const metaColors = {};
|
||
try {
|
||
const meta = JSON.parse(readFileSync(resolve(DRAW_SRC, "meta.json"), "utf8"));
|
||
for (const s of meta.styles || []) metaColors[s.id] = [s.c1, s.c2];
|
||
} catch {
|
||
console.log("⚠️ 未读到 meta.json,颜色使用默认值");
|
||
}
|
||
|
||
const avatars = [];
|
||
for (const st of STYLES) {
|
||
for (let i = 1; i <= PER_STYLE; i++) {
|
||
const n = String(i).padStart(3, "0");
|
||
const srcFile = resolve(DRAW_SRC, st.id, `${st.id}-${n}.svg`);
|
||
if (!existsSync(srcFile)) {
|
||
console.log(`❌ 缺少源文件: ${srcFile}`);
|
||
process.exit(1);
|
||
}
|
||
const id = `${st.id}_${n}`;
|
||
const destFile = resolve(AVATAR_DIR, `${id}.svg`);
|
||
copyFileSync(srcFile, destFile);
|
||
// Next.js image-optimizer 按 magic bytes 识别类型,SVG 必须以 <?xml 开头才被识别为有效图片
|
||
// (否则 /_next/image 返回 400,页面图片空白)
|
||
const raw = readFileSync(destFile, "utf8").replace(/^\uFEFF/, "");
|
||
if (!raw.trimStart().startsWith("<?xml")) {
|
||
writeFileSync(destFile, `<?xml version="1.0" encoding="UTF-8"?>\n${raw}`);
|
||
}
|
||
avatars.push({
|
||
id,
|
||
theme: st.id,
|
||
url: `/avatars/${id}.svg`,
|
||
colors: metaColors[st.id] || ["#334155", "#64748b"],
|
||
shape: "circle",
|
||
});
|
||
}
|
||
}
|
||
|
||
if (avatars.length !== STYLES.length * PER_STYLE) {
|
||
console.log(`❌ 期望 ${STYLES.length * PER_STYLE} 个,实际 ${avatars.length} 个`);
|
||
process.exit(1);
|
||
}
|
||
|
||
// —— manifest.json ——
|
||
const manifest = {
|
||
generatedAt: new Date().toISOString(),
|
||
total: avatars.length,
|
||
categories: {},
|
||
themes: {},
|
||
avatars,
|
||
};
|
||
for (const st of STYLES) {
|
||
const count = avatars.filter((a) => a.theme === st.id).length;
|
||
manifest.categories[st.id] = count;
|
||
manifest.themes[st.id] = count;
|
||
}
|
||
writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2), "utf8");
|
||
|
||
// —— src/lib/avatar-library.ts ——
|
||
const idSet = avatars.map((a) => `"${a.id}"`);
|
||
const libLines = [
|
||
"// 头像库100个头像ID列表",
|
||
"// 由 scripts/_rebuild-avatars.mjs 生成(DrawLogo 10 风格 × 10)",
|
||
`// 自动生成时间: ${new Date().toISOString().slice(0, 10)}`,
|
||
"",
|
||
"export const AVATAR_LIBRARY = [",
|
||
];
|
||
for (const st of STYLES) {
|
||
const group = idSet.filter((id) => id.startsWith(`"${st.id}_`));
|
||
libLines.push(` // === ${st.name} (${group.length}) ===`);
|
||
libLines.push(` ${group.join(",")},`);
|
||
}
|
||
libLines.push("];");
|
||
writeFileSync(LIB_TS_PATH, libLines.join("\n"), "utf8");
|
||
|
||
console.log(`✅ 完成: ${avatars.length} 个头像 → public/avatars/`);
|
||
console.log(` 清单: public/avatars/manifest.json`);
|
||
console.log(` 库表: src/lib/avatar-library.ts`);
|
||
for (const st of STYLES) console.log(` ${st.id}(${st.name}): ${manifest.categories[st.id]} 个`);
|