feat: 首次推送到Gitea - 完整项目代码 + 安全加固 + 知识库

This commit is contained in:
ZhuiGuangAI Dev
2026-10-02 18:52:49 +08:00
parent b44601bb66
commit 8205ae709c
1185 changed files with 49841 additions and 12802 deletions
+113
View File
@@ -0,0 +1,113 @@
#!/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]} 个`);