86 lines
3.4 KiB
JavaScript
86 lines
3.4 KiB
JavaScript
#!/usr/bin/env node
|
||
// scripts/bot-avatar-generate.mjs
|
||
// 数字人头像批量预生成 + 落盘 + 回写 User.avatarUrl
|
||
//
|
||
// 用法:
|
||
// node scripts/bot-avatar-generate.mjs # 生成所有 bot 头像
|
||
// node scripts/bot-avatar-generate.mjs --bot=laochen # 只生成单个 bot
|
||
// node scripts/bot-avatar-generate.mjs --force # 强制重新生成(已存在也覆盖)
|
||
// node scripts/bot-avatar-generate.mjs --use-lunaris-only # 只用 Lunaris,不生成 SVG(当前 Lunaris 全是 default,不推荐)
|
||
// node scripts/bot-avatar-generate.mjs --no-update-db # 只落盘,不写 User.avatarUrl
|
||
// node scripts/bot-avatar-generate.mjs --dry-run # 试运行,不落盘不写库
|
||
|
||
import { disconnect, generateForAll } from "./lib/bot-avatar-generator.mjs";
|
||
|
||
function parseArgs() {
|
||
const args = process.argv.slice(2);
|
||
const out = { force: false, useLunarisOnly: false, updateDb: true, dryRun: false, bot: null, delay: 200 };
|
||
for (const a of args) {
|
||
if (a === "--force") out.force = true;
|
||
else if (a === "--use-lunaris-only") out.useLunarisOnly = true;
|
||
else if (a === "--no-update-db") out.updateDb = false;
|
||
else if (a === "--dry-run") out.dryRun = true;
|
||
else if (a.startsWith("--bot=")) out.bot = a.slice(6);
|
||
else if (a.startsWith("--delay=")) out.delay = parseInt(a.slice(8), 10);
|
||
else if (a === "--help" || a === "-h") {
|
||
console.log("用法: node scripts/bot-avatar-generate.mjs [选项]");
|
||
console.log(" --bot=<key> 只生成指定 bot");
|
||
console.log(" --force 覆盖已存在的头像");
|
||
console.log(" --use-lunaris-only 禁用 SVG 兜底(当前不推荐)");
|
||
console.log(" --no-update-db 只落盘不写 User.avatarUrl");
|
||
console.log(" --dry-run 试运行,不落盘不写库");
|
||
console.log(" --delay=<ms> bot 间隔延迟(默认 200ms)");
|
||
process.exit(0);
|
||
}
|
||
}
|
||
return out;
|
||
}
|
||
|
||
function ts() {
|
||
return new Date().toISOString().replace("T", " ").slice(0, 19);
|
||
}
|
||
|
||
async function main() {
|
||
const args = parseArgs();
|
||
console.log(`${ts()} 数字人头像批量预生成开始`);
|
||
console.log(
|
||
` bot=${args.bot || "all"} force=${args.force} lunarisOnly=${args.useLunarisOnly} updateDb=${args.updateDb} dryRun=${args.dryRun} delay=${args.delay}ms`
|
||
);
|
||
|
||
if (!process.env.DATABASE_URL) {
|
||
throw new Error("DATABASE_URL 未配置");
|
||
}
|
||
|
||
const startTime = Date.now();
|
||
const { summary, results } = await generateForAll({
|
||
force: args.force,
|
||
botKey: args.bot,
|
||
useLunarisOnly: args.useLunarisOnly,
|
||
delayMs: args.dryRun ? 0 : args.delay,
|
||
});
|
||
|
||
const duration = Date.now() - startTime;
|
||
console.log("");
|
||
console.log(`${ts()} 完成: total=${summary.total} ok=${summary.ok} failed=${summary.failed} (${duration}ms)`);
|
||
console.log(`${ts()} 落盘位置: public/bot-avatars/{key}.svg + public/bot-avatars/lunaris/{key}.jpg`);
|
||
console.log(`${ts()} 清单: public/bot-avatars/manifest.json`);
|
||
|
||
if (summary.failed > 0) {
|
||
console.log("");
|
||
console.log("失败列表:");
|
||
for (const r of results) {
|
||
if (r.error) console.log(` - ${r.key}: ${r.error}`);
|
||
}
|
||
}
|
||
|
||
await disconnect();
|
||
process.exit(summary.failed > 0 ? 1 : 0);
|
||
}
|
||
|
||
main().catch(async (err) => {
|
||
console.error(`${ts()} ❌ 致命错误: ${err.message}`);
|
||
console.error(err.stack);
|
||
await disconnect().catch(() => {});
|
||
process.exit(1);
|
||
});
|