gts-x / scripts /seed.ts
JAMES HAN
GTS-X: Full HITL editor + QC + file converter for HuggingFace Spaces
c273232
Raw
History Blame Contribute Delete
7.94 kB
/**
* 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);
});