Spaces:
Sleeping
Sleeping
| /** | |
| * Seed script for GTS-X local development | |
| * Run with: npx tsx scripts/seed.ts | |
| */ | |
| import pg from "pg"; | |
| import { drizzle } from "drizzle-orm/node-postgres"; | |
| import * as schema from "../src/schema/schema"; | |
| const DATABASE_URL = | |
| process.env.DATABASE_URL || | |
| "postgresql://cpx_user:cpx_password@localhost:5432/cpx_studio"; | |
| async function seed() { | |
| const pool = new pg.Pool({ connectionString: DATABASE_URL }); | |
| const db = drizzle(pool, { schema }); | |
| console.log("Seeding GTS-X development data...\n"); | |
| // 1. Create resources | |
| console.log("Creating resources..."); | |
| const [resource1] = await db | |
| .insert(schema.resources) | |
| .values({ | |
| name: "Alice Kim", | |
| email: "alice.kim@iyuno.com", | |
| atlasResourceId: "atlas-r-001", | |
| branchId: "seoul", | |
| }) | |
| .onConflictDoNothing() | |
| .returning(); | |
| const [resource2] = await db | |
| .insert(schema.resources) | |
| .values({ | |
| name: "Bob Tanaka", | |
| email: "bob.tanaka@iyuno.com", | |
| atlasResourceId: "atlas-r-002", | |
| branchId: "tokyo", | |
| }) | |
| .onConflictDoNothing() | |
| .returning(); | |
| const [resource3] = await db | |
| .insert(schema.resources) | |
| .values({ | |
| name: "Clara Nowak", | |
| email: "clara.nowak@iyuno.com", | |
| atlasResourceId: "atlas-r-003", | |
| branchId: "warsaw", | |
| }) | |
| .onConflictDoNothing() | |
| .returning(); | |
| if (!resource1 || !resource2 || !resource3) { | |
| console.log( | |
| " Resources already exist (skipping). Drop tables first to re-seed." | |
| ); | |
| await pool.end(); | |
| return; | |
| } | |
| console.log(` Created: ${resource1.name}, ${resource2.name}, ${resource3.name}`); | |
| // 2. Create skill sets | |
| console.log("Creating skill sets..."); | |
| await db.insert(schema.resourceSkillSets).values([ | |
| { | |
| resourceId: resource1.id, | |
| platform: "GTS_X", | |
| grade: "senior", | |
| sourceLanguageId: "en", | |
| targetLanguageId: "ko", | |
| }, | |
| { | |
| resourceId: resource2.id, | |
| platform: "GTS_X", | |
| grade: "mid", | |
| sourceLanguageId: "en", | |
| targetLanguageId: "ja", | |
| }, | |
| { | |
| resourceId: resource3.id, | |
| platform: "GTS_X", | |
| grade: "senior", | |
| sourceLanguageId: "en", | |
| targetLanguageId: "pl", | |
| }, | |
| ]); | |
| // 3. Create sample jobs | |
| console.log("Creating sample jobs..."); | |
| // Sample GTSDocument for testing | |
| const sampleDocument = { | |
| info: { | |
| title: "Sample Episode S01E01", | |
| episode: "S01E01", | |
| fps: 23.976, | |
| }, | |
| tracks: [ | |
| { | |
| language: "en", | |
| subtitles: [ | |
| { | |
| tcIn: "00:00:05:00", | |
| tcOut: "00:00:08:00", | |
| text: "Welcome to the show.", | |
| speaker: "NARRATOR", | |
| }, | |
| { | |
| tcIn: "00:00:10:00", | |
| tcOut: "00:00:13:00", | |
| text: "It's a beautiful day outside.", | |
| speaker: "CHARACTER_A", | |
| }, | |
| { | |
| tcIn: "00:00:14:00", | |
| tcOut: "00:00:17:00", | |
| text: "I couldn't agree more.\nLet's go for a walk.", | |
| speaker: "CHARACTER_B", | |
| }, | |
| { | |
| tcIn: "00:00:20:00", | |
| tcOut: "00:00:23:00", | |
| text: "The park should be lovely this time of year.", | |
| speaker: "CHARACTER_A", | |
| }, | |
| { | |
| tcIn: "00:00:25:00", | |
| tcOut: "00:00:28:00", | |
| text: "βͺ Background music plays βͺ", | |
| speaker: "", | |
| }, | |
| ], | |
| }, | |
| ], | |
| }; | |
| const [job1] = await db | |
| .insert(schema.jobs) | |
| .values({ | |
| arcJobId: "arc-job-001", | |
| orderId: "ORD-2026-001", | |
| sourceLanguage: "en", | |
| targetLanguage: "ko", | |
| clientId: "netflix", | |
| status: "pending", | |
| initialDocument: sampleDocument, | |
| currentDocument: sampleDocument, | |
| metadata: { clientProfile: "netflix-standard", maxCPL: 42 }, | |
| }) | |
| .returning(); | |
| const [job2] = await db | |
| .insert(schema.jobs) | |
| .values({ | |
| arcJobId: "arc-job-002", | |
| orderId: "ORD-2026-002", | |
| sourceLanguage: "en", | |
| targetLanguage: "ja", | |
| clientId: "disney", | |
| status: "assigned", | |
| initialDocument: sampleDocument, | |
| currentDocument: sampleDocument, | |
| metadata: { clientProfile: "disney-plus", maxCPL: 40 }, | |
| }) | |
| .returning(); | |
| const [job3] = await db | |
| .insert(schema.jobs) | |
| .values({ | |
| arcJobId: "arc-job-003", | |
| orderId: "ORD-2026-003", | |
| sourceLanguage: "en", | |
| targetLanguage: "pl", | |
| clientId: "hbo", | |
| status: "in_progress", | |
| initialDocument: sampleDocument, | |
| currentDocument: sampleDocument, | |
| }) | |
| .returning(); | |
| const [job4] = await db | |
| .insert(schema.jobs) | |
| .values({ | |
| arcJobId: "arc-job-004", | |
| orderId: "ORD-2026-004", | |
| sourceLanguage: "en", | |
| targetLanguage: "ko", | |
| clientId: "netflix", | |
| status: "completed", | |
| initialDocument: sampleDocument, | |
| currentDocument: sampleDocument, | |
| }) | |
| .returning(); | |
| console.log(` Created ${4} sample jobs`); | |
| // 4. Create assignments for assigned/in_progress jobs | |
| console.log("Creating assignments..."); | |
| await db.insert(schema.jobAssignments).values([ | |
| { | |
| jobId: job2.id, | |
| resourceId: resource2.id, | |
| assignmentType: "manual", | |
| acceptanceStatus: "accepted", | |
| startedAt: new Date(), | |
| deadline: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), | |
| }, | |
| { | |
| jobId: job3.id, | |
| resourceId: resource3.id, | |
| assignmentType: "manual", | |
| acceptanceStatus: "accepted", | |
| startedAt: new Date(), | |
| }, | |
| { | |
| jobId: job4.id, | |
| resourceId: resource1.id, | |
| assignmentType: "auto", | |
| acceptanceStatus: "accepted", | |
| startedAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), | |
| completedAt: new Date(), | |
| }, | |
| ]); | |
| // 5. Create sample diffs for the completed job | |
| console.log("Creating sample edit diffs..."); | |
| await db.insert(schema.editDiffs).values([ | |
| { | |
| jobId: job4.id, | |
| subtitleIndex: 1, | |
| field: "text", | |
| oldValue: "It's a beautiful day outside.", | |
| newValue: "λ°μ μ λ§ μλ¦λ€μ΄ λ μ΄μμ.", | |
| rationale: "LSX translation was too literal β adjusted to natural Korean phrasing", | |
| changeCategory: "translation_fix", | |
| }, | |
| { | |
| jobId: job4.id, | |
| subtitleIndex: 2, | |
| field: "tc_out", | |
| oldValue: "00:00:17:00", | |
| newValue: "00:00:16:12", | |
| rationale: "Subtitle was overlapping with next cue by 1 frame β shortened to fix gap", | |
| changeCategory: "timing_fix", | |
| }, | |
| { | |
| jobId: job4.id, | |
| subtitleIndex: 3, | |
| field: "text", | |
| oldValue: "The park should be lovely this time of year.", | |
| newValue: "μ΄λ§λ 곡μμ΄ μ’μ κ±°μμ.", | |
| rationale: "CPL exceeded 42 chars β shortened translation while preserving meaning", | |
| changeCategory: "cpl_fix", | |
| }, | |
| ]); | |
| // 6. Create sample feedback analysis for the completed job | |
| console.log("Creating sample feedback analysis..."); | |
| await db.insert(schema.feedbackAnalyses).values([ | |
| { | |
| jobId: job4.id, | |
| errorType: "cicd_needed", | |
| confidenceScore: 0.87, | |
| description: | |
| "Editor shortened subtitle 3 due to CPL violation (42 char limit). LSX should have enforced Netflix Korean CPL during translation.", | |
| affectedInput: "lsx_prompt", | |
| reviewStatus: "pending", | |
| }, | |
| { | |
| jobId: job4.id, | |
| errorType: "style_preference", | |
| confidenceScore: 0.65, | |
| description: | |
| "Editor rephrased subtitle 1 for more natural Korean. This is a style improvement, not an error in LSX output.", | |
| reviewStatus: "pending", | |
| }, | |
| ]); | |
| console.log("\nSeed complete!"); | |
| console.log(" 3 resources"); | |
| console.log(" 4 jobs (pending, assigned, in_progress, completed)"); | |
| console.log(" 3 assignments"); | |
| console.log(" 3 edit diffs"); | |
| console.log(" 2 feedback analyses"); | |
| await pool.end(); | |
| } | |
| seed().catch((err) => { | |
| console.error("Seed failed:", err); | |
| process.exit(1); | |
| }); | |