vault-video-processor / scripts /seed-test-data.ts
dvijaykrishnan's picture
Deployment fix for HF
ceb943f
Raw
History Blame Contribute Delete
7.54 kB
/**
* Seed script for local testing without real YouTube videos.
* Inserts fake videos, detected objects, and marketplace matches
* tied to your connected YouTube channel.
*
* Usage: npx tsx scripts/seed-test-data.ts
*/
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import * as dotenv from "dotenv";
import * as schema from "../src/lib/db/schema";
const { youtubeVideos, detectedObjects, marketplaceMatches } = schema;
dotenv.config({ path: ".env.local" });
const run = async () => {
const connectionString = process.env.DIRECT_URL;
if (!connectionString) throw new Error("DIRECT_URL not set in .env.local");
const sql = postgres(connectionString, { max: 1 });
const db = drizzle(sql, { schema, casing: "snake_case" });
// 1. Find the connected channel
const channel = await db.query.youtubeChannels.findFirst();
if (!channel) {
console.error("❌ No YouTube channel found. Connect one on the dashboard first.");
await sql.end();
process.exit(1);
}
console.log(`✅ Found channel: ${channel.channelName} (${channel.id})`);
// 2. Insert fake videos
const videos = [
{ videoId: "seed-vid-001", title: "Tech Gadget Unboxing", duration: "PT12M30S", viewCount: 4200 },
{ videoId: "seed-vid-002", title: "Home Office Setup Tour", duration: "PT8M15S", viewCount: 1800 },
{ videoId: "seed-vid-003", title: "Fashion Haul 2024", duration: "PT15M00S", viewCount: 9100 },
{ videoId: "seed-vid-004", title: "Audio Equipment Review", duration: "PT20M45S", viewCount: 3300 },
{ videoId: "seed-vid-005", title: "Living Room Makeover", duration: "PT18M10S", viewCount: 5600 },
];
const insertedVideos = await db
.insert(youtubeVideos)
.values(
videos.map((v) => ({
channelId: channel.id,
videoId: v.videoId,
title: v.title,
description: `Seed data: ${v.title}`,
thumbnailUrl: `https://i.ytimg.com/vi/${v.videoId}/mqdefault.jpg`,
duration: v.duration,
viewCount: v.viewCount,
publishedAt: new Date("2024-11-15T10:00:00Z"),
}))
)
.onConflictDoNothing()
.returning();
console.log(`✅ Inserted ${insertedVideos.length} videos`);
// Re-fetch all seed videos (in case they already existed)
const allVideos = await db.query.youtubeVideos.findMany({
where: (t, { inArray }) => inArray(t.videoId, videos.map((v) => v.videoId)),
});
// 3. Insert detected objects (mix of statuses for testing moderation)
const objects: Array<{
videoId: string;
objectName: string;
category: "Tech" | "Fashion" | "Furniture" | "Audio" | "Other";
moderationStatus: "PENDING" | "APPROVED" | "REJECTED";
confidenceScore: number;
frameTimestamp: number;
}> = [
{ videoId: "seed-vid-001", objectName: "Wireless Headphones", category: "Audio", moderationStatus: "APPROVED", confidenceScore: 0.94, frameTimestamp: 45 },
{ videoId: "seed-vid-001", objectName: "USB-C Hub", category: "Tech", moderationStatus: "APPROVED", confidenceScore: 0.88, frameTimestamp: 120 },
{ videoId: "seed-vid-001", objectName: "Mechanical Keyboard", category: "Tech", moderationStatus: "PENDING", confidenceScore: 0.76, frameTimestamp: 200 },
{ videoId: "seed-vid-002", objectName: "Standing Desk", category: "Furniture", moderationStatus: "APPROVED", confidenceScore: 0.91, frameTimestamp: 30 },
{ videoId: "seed-vid-002", objectName: "Ergonomic Chair", category: "Furniture", moderationStatus: "APPROVED", confidenceScore: 0.89, frameTimestamp: 60 },
{ videoId: "seed-vid-002", objectName: "Monitor Light Bar", category: "Tech", moderationStatus: "REJECTED", confidenceScore: 0.62, frameTimestamp: 90 },
{ videoId: "seed-vid-003", objectName: "Leather Jacket", category: "Fashion", moderationStatus: "APPROVED", confidenceScore: 0.95, frameTimestamp: 15 },
{ videoId: "seed-vid-003", objectName: "Running Shoes", category: "Fashion", moderationStatus: "PENDING", confidenceScore: 0.71, frameTimestamp: 180 },
{ videoId: "seed-vid-004", objectName: "Studio Microphone", category: "Audio", moderationStatus: "APPROVED", confidenceScore: 0.93, frameTimestamp: 55 },
{ videoId: "seed-vid-004", objectName: "Audio Interface", category: "Audio", moderationStatus: "APPROVED", confidenceScore: 0.87, frameTimestamp: 110 },
{ videoId: "seed-vid-005", objectName: "Throw Pillows", category: "Furniture", moderationStatus: "APPROVED", confidenceScore: 0.82, frameTimestamp: 25 },
{ videoId: "seed-vid-005", objectName: "Floor Lamp", category: "Furniture", moderationStatus: "PENDING", confidenceScore: 0.74, frameTimestamp: 95 },
];
const videoMap = new Map(allVideos.map((v) => [v.videoId, v.id]));
const insertedObjects = await db
.insert(detectedObjects)
.values(
objects.map((o) => ({
videoId: videoMap.get(o.videoId)!,
objectName: o.objectName,
category: o.category,
confidenceScore: o.confidenceScore,
frameTimestamp: o.frameTimestamp,
status: "approved" as const,
moderationStatus: o.moderationStatus,
detectionMetadata: { source: "seed", model: "test" },
}))
)
.onConflictDoNothing()
.returning();
console.log(`✅ Inserted ${insertedObjects.length} detected objects`);
// Re-fetch approved objects for marketplace match seeding
const approvedObjects = await db.query.detectedObjects.findMany({
where: (t, { and, eq: eq_ }) =>
and(eq_(t.moderationStatus, "APPROVED")),
});
// 4. Insert marketplace matches for approved objects
const matchTemplates: Array<{
marketplace: "amazon" | "ebay" | "etsy";
productName: string;
price: number;
}> = [
{ marketplace: "amazon", productName: "Sony WH-1000XM5 Headphones", price: 349.99 },
{ marketplace: "amazon", productName: "Anker USB-C 7-in-1 Hub", price: 39.99 },
{ marketplace: "amazon", productName: "FlexiSpot E7 Standing Desk", price: 449.0 },
{ marketplace: "amazon", productName: "Herman Miller Aeron Chair", price: 1199.0 },
{ marketplace: "amazon", productName: "Shure SM7B Microphone", price: 249.0 },
{ marketplace: "ebay", productName: "Audio-Technica AT2020 Mic", price: 89.99 },
{ marketplace: "ebay", productName: "Focusrite Solo Audio Interface", price: 119.99 },
{ marketplace: "etsy", productName: "Handmade Leather Jacket", price: 289.0 },
{ marketplace: "amazon", productName: "IKEA Lack Floor Lamp", price: 24.99 },
];
let matchCount = 0;
for (let i = 0; i < approvedObjects.length && i < matchTemplates.length; i++) {
const obj = approvedObjects[i];
const tmpl = matchTemplates[i];
const inserted = await db
.insert(marketplaceMatches)
.values({
objectId: obj.id,
marketplace: tmpl.marketplace,
productId: `seed-prod-${String(i + 1).padStart(3, "0")}`,
productName: tmpl.productName,
price: tmpl.price,
availabilityStatus: "IN_STOCK",
affiliateUrl: `https://www.amazon.com/dp/seed-${i + 1}`,
})
.onConflictDoNothing()
.returning();
matchCount += inserted.length;
}
console.log(`✅ Inserted ${matchCount} marketplace matches`);
console.log("\n🎉 Seed complete. Test pages to try:");
console.log(` • Dashboard: http://localhost:3000/dashboard`);
console.log(` • Public Vault: http://localhost:3000/vault/${channel.creatorSlug}`);
await sql.end();
};
run().catch((err) => {
console.error("❌ Seed failed:", err);
process.exit(1);
});