/** * 一次性脚本:对所有项目跑 AI 三件套分类(category + bizSystem + projectType), * 同时自动生成新 identifier(airhubs-hw-001 这种)+ 同步更新 mapping。 * * 用法: * bun run scripts/ai-classify-all.ts # 仅处理未完整分类的项目 * bun run scripts/ai-classify-all.ts --force # 强制重跑所有项目(覆盖) */ import dayjs from 'dayjs'; import { eq } from 'drizzle-orm'; import { db } from '../src/db/index'; import { projects } from '../src/db/schema'; import { suggestProjectTag } from '../src/services/roi/ai-tag-suggester'; import { applyAutoIdentifier } from '../src/services/roi/identifier-generator'; const force = process.argv.includes('--force'); const all = await db.select().from(projects); console.log(`Total projects: ${all.length}, force=${force}`); let okCount = 0, skipCount = 0, failCount = 0; const startedAt = Date.now(); for (const p of all) { const label = `${p.planeIdentifier || p.identifier || '?'} (${p.name})`; const alreadyFull = p.category && p.bizSystem && p.projectType; if (!force && alreadyFull) { console.log(` ⊘ SKIP ${label} — fully classified (${p.bizSystem}/${p.projectType}/${p.category})`); skipCount += 1; continue; } try { console.log(` → AI ${label} ...`); const sug = await suggestProjectTag(p.id); const launchedAt = p.launchedAt ?? p.createdAt ?? dayjs().subtract(90, 'day').toDate(); const needsAsset = sug.suggestedCategory === 'moat'; const vAsset = needsAsset ? (p.vAsset ?? 100_000) : (p.vAsset ?? null); // 1. 更新分类字段 await db.update(projects).set({ category: sug.suggestedCategory, launchedAt: launchedAt as any, vAsset: vAsset, updatedAt: new Date(), }).where(eq(projects.id, p.id)); // 2. 自动生成新 identifier + 同步 mapping const newId = await applyAutoIdentifier(p.id, sug.suggestedBizSystem, sug.suggestedProjectType); console.log(` ✓ ${newId} | ${sug.suggestedBizSystem}/${sug.suggestedProjectType}/${sug.suggestedCategory} conf=${sug.confidence}`); console.log(` ↳ ${sug.reasoning.slice(0, 80)}`); okCount += 1; } catch (e) { console.error(` ✗ FAIL ${label}: ${(e as Error).message.slice(0, 200)}`); failCount += 1; } await new Promise(r => setTimeout(r, 1000)); } const elapsed = ((Date.now() - startedAt) / 1000).toFixed(1); console.log(''); console.log(`Done. ok=${okCount} skipped=${skipCount} failed=${failCount} elapsed=${elapsed}s`); process.exit(0);