seed.ts
2,532 bytes
| 1 | /* eslint-disable no-console */ |
|---|---|
| 2 | /** |
| 3 | * Seed the public demo debates from hand-authored, realistic fixtures. |
| 4 | * |
| 5 | * The fixtures are written by hand (see src/lib/demo-fixtures*) so each model |
| 6 | * gives a genuinely different answer and the synthesis is a real verdict. They |
| 7 | * are persisted through the *real* write path (createDebate -> persistEvent -> |
| 8 | * finalizeDebate), so the seeded rows are identical to what a live debate |
| 9 | * produces and the demo replays through the exact same UI. Idempotent: existing |
| 10 | * demo debates are cleared first. Requires DATABASE_URL (loaded from .env below). |
| 11 | */ |
| 12 | import { readFileSync } from 'node:fs'; |
| 13 | import { resolve } from 'node:path'; |
| 14 | |
| 15 | // Next loads .env automatically; a standalone tsx run does not. |
| 16 | try { |
| 17 | const file = readFileSync(resolve(process.cwd(), '.env'), 'utf8'); |
| 18 | for (const raw of file.split('\n')) { |
| 19 | const line = raw.trim(); |
| 20 | if (!line || line.startsWith('#')) continue; |
| 21 | const eq = line.indexOf('='); |
| 22 | if (eq === -1) continue; |
| 23 | const key = line.slice(0, eq).trim(); |
| 24 | let val = line.slice(eq + 1).trim(); |
| 25 | if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) { |
| 26 | val = val.slice(1, -1); |
| 27 | } |
| 28 | if (!(key in process.env)) process.env[key] = val; |
| 29 | } |
| 30 | } catch { |
| 31 | /* rely on ambient environment */ |
| 32 | } |
| 33 | |
| 34 | async function main() { |
| 35 | const { buildDebateResult, resultToStageEvents, FIXTURES } = await import('@/lib/demo-fixtures'); |
| 36 | const { PROMPT_VERSION } = await import('@/core/prompts'); |
| 37 | const { prisma } = await import('@/db/client'); |
| 38 | const repo = await import('@/db/repositories'); |
| 39 | |
| 40 | console.log('Clearing existing demo debates...'); |
| 41 | await prisma.debate.deleteMany({ where: { isDemo: true } }); |
| 42 | |
| 43 | for (const spec of FIXTURES) { |
| 44 | const result = buildDebateResult(spec); |
| 45 | const debateId = await repo.createDebate({ |
| 46 | userId: null, |
| 47 | config: result.config, |
| 48 | participants: result.participants, |
| 49 | promptVersion: PROMPT_VERSION, |
| 50 | isDemo: true, |
| 51 | }); |
| 52 | for (const event of resultToStageEvents(result)) { |
| 53 | await repo.persistEvent(debateId, event); |
| 54 | } |
| 55 | await repo.finalizeDebate(debateId, result); |
| 56 | await repo.ensureShareToken(debateId); |
| 57 | console.log( |
| 58 | ` ok ${spec.question.slice(0, 58)}... ${result.rounds.length} rounds, $${result.totals.costUsd.toFixed(4)}`, |
| 59 | ); |
| 60 | } |
| 61 | |
| 62 | await prisma.$disconnect(); |
| 63 | console.log(`\nSeeded ${FIXTURES.length} demo debates.`); |
| 64 | } |
| 65 | |
| 66 | main().catch(async (err) => { |
| 67 | console.error('Seed failed:', err); |
| 68 | process.exit(1); |
| 69 | }); |
| 70 | |