#!/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= 只生成指定 bot"); console.log(" --force 覆盖已存在的头像"); console.log(" --use-lunaris-only 禁用 SVG 兜底(当前不推荐)"); console.log(" --no-update-db 只落盘不写 User.avatarUrl"); console.log(" --dry-run 试运行,不落盘不写库"); console.log(" --delay= 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); });