mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-03-23 19:27:51 -04:00
275 lines
7.1 KiB
TypeScript
275 lines
7.1 KiB
TypeScript
import { drizzle } from "drizzle-orm/postgres-js";
|
|
import postgres from "postgres";
|
|
import * as schema from "../../src/server/db/schema";
|
|
import { sql } from "drizzle-orm";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
|
// Database connection
|
|
const connectionString = process.env.DATABASE_URL!;
|
|
const connection = postgres(connectionString);
|
|
const db = drizzle(connection, { schema });
|
|
|
|
async function main() {
|
|
console.log("🌱 Seeding 'Story: Red Rock' experiment...");
|
|
|
|
try {
|
|
// 1. Find Admin User & Study
|
|
const user = await db.query.users.findFirst({
|
|
where: (users, { eq }) => eq(users.email, "sean@soconnor.dev"),
|
|
});
|
|
if (!user) throw new Error("Admin user 'sean@soconnor.dev' not found.");
|
|
|
|
const study = await db.query.studies.findFirst({
|
|
where: (studies, { eq }) => eq(studies.name, "Comparative WoZ Study"),
|
|
});
|
|
if (!study) throw new Error("Study 'Comparative WoZ Study' not found.");
|
|
|
|
const robot = await db.query.robots.findFirst({
|
|
where: (robots, { eq }) => eq(robots.name, "NAO6"),
|
|
});
|
|
if (!robot) throw new Error("Robot 'NAO6' not found.");
|
|
|
|
// 2. Create Experiment
|
|
const [experiment] = await db
|
|
.insert(schema.experiments)
|
|
.values({
|
|
studyId: study.id,
|
|
name: "Story: Red Rock",
|
|
description:
|
|
"A story about a red rock on Mars with comprehension check and branching.",
|
|
version: 1,
|
|
status: "draft",
|
|
robotId: robot.id,
|
|
createdBy: user.id,
|
|
})
|
|
.returning();
|
|
|
|
if (!experiment) throw new Error("Failed to create experiment");
|
|
console.log(`✅ Created Experiment: ${experiment.id}`);
|
|
|
|
// 3. Create Steps (in reverse for ID references if needed, but we'll use uuid placeholders)
|
|
const conclusionId = uuidv4();
|
|
const branchAId = uuidv4();
|
|
const branchBId = uuidv4();
|
|
const checkId = uuidv4();
|
|
|
|
// Step 1: The Hook
|
|
const [step1] = await db
|
|
.insert(schema.steps)
|
|
.values({
|
|
experimentId: experiment.id,
|
|
name: "The Hook",
|
|
type: "wizard",
|
|
orderIndex: 0,
|
|
})
|
|
.returning();
|
|
|
|
// Step 2: The Narrative
|
|
const [step2] = await db
|
|
.insert(schema.steps)
|
|
.values({
|
|
experimentId: experiment.id,
|
|
name: "The Narrative",
|
|
type: "wizard",
|
|
orderIndex: 1,
|
|
})
|
|
.returning();
|
|
|
|
// Step 3: Comprehension Check (Conditional)
|
|
const [step3] = await db
|
|
.insert(schema.steps)
|
|
.values({
|
|
id: checkId,
|
|
experimentId: experiment.id,
|
|
name: "Comprehension Check",
|
|
type: "conditional",
|
|
orderIndex: 2,
|
|
conditions: {
|
|
variable: "last_wizard_response",
|
|
options: [
|
|
{
|
|
label: "Answer: Red (Correct)",
|
|
value: "Red",
|
|
variant: "default",
|
|
nextStepId: branchAId,
|
|
},
|
|
{
|
|
label: "Answer: Other (Incorrect)",
|
|
value: "Incorrect",
|
|
variant: "destructive",
|
|
nextStepId: branchBId,
|
|
},
|
|
],
|
|
},
|
|
})
|
|
.returning();
|
|
|
|
// Step 4: Branch A (Correct)
|
|
const [step4] = await db
|
|
.insert(schema.steps)
|
|
.values({
|
|
id: branchAId,
|
|
experimentId: experiment.id,
|
|
name: "Branch A: Correct Response",
|
|
type: "wizard",
|
|
orderIndex: 3,
|
|
conditions: { nextStepId: conclusionId }, // SKIP BRANCH B
|
|
})
|
|
.returning();
|
|
|
|
// Step 5: Branch B (Incorrect)
|
|
const [step5] = await db
|
|
.insert(schema.steps)
|
|
.values({
|
|
id: branchBId,
|
|
experimentId: experiment.id,
|
|
name: "Branch B: Incorrect Response",
|
|
type: "wizard",
|
|
orderIndex: 4,
|
|
conditions: { nextStepId: conclusionId },
|
|
})
|
|
.returning();
|
|
|
|
// Step 6: Conclusion
|
|
const [step6] = await db
|
|
.insert(schema.steps)
|
|
.values({
|
|
id: conclusionId,
|
|
experimentId: experiment.id,
|
|
name: "Conclusion",
|
|
type: "wizard",
|
|
orderIndex: 5,
|
|
})
|
|
.returning();
|
|
|
|
// 4. Create Actions
|
|
|
|
// The Hook
|
|
await db.insert(schema.actions).values([
|
|
{
|
|
stepId: step1!.id,
|
|
name: "Say Hello",
|
|
type: "nao6-ros2.say_text",
|
|
orderIndex: 0,
|
|
parameters: { text: "Hello! Are you ready for a story?" },
|
|
},
|
|
{
|
|
stepId: step1!.id,
|
|
name: "Wave",
|
|
type: "nao6-ros2.move_arm",
|
|
orderIndex: 1,
|
|
parameters: { arm: "right", shoulder_pitch: 0.5 },
|
|
},
|
|
]);
|
|
|
|
// The Narrative
|
|
await db.insert(schema.actions).values([
|
|
{
|
|
stepId: step2!.id,
|
|
name: "The Story",
|
|
type: "nao6-ros2.say_text",
|
|
orderIndex: 0,
|
|
parameters: {
|
|
text: "Once, a traveler went to Mars. He found a bright red rock that glowed.",
|
|
},
|
|
},
|
|
{
|
|
stepId: step2!.id,
|
|
name: "Look Left",
|
|
type: "nao6-ros2.turn_head",
|
|
orderIndex: 1,
|
|
parameters: { yaw: 0.5, speed: 0.3 },
|
|
},
|
|
{
|
|
stepId: step2!.id,
|
|
name: "Look Right",
|
|
type: "nao6-ros2.turn_head",
|
|
orderIndex: 2,
|
|
parameters: { yaw: -0.5, speed: 0.3 },
|
|
},
|
|
]);
|
|
|
|
// Comprehension Check
|
|
await db.insert(schema.actions).values([
|
|
{
|
|
stepId: step3!.id,
|
|
name: "Ask Color",
|
|
type: "nao6-ros2.say_text",
|
|
orderIndex: 0,
|
|
parameters: { text: "What color was the rock I found on Mars?" },
|
|
},
|
|
{
|
|
stepId: step3!.id,
|
|
name: "Wait for Color",
|
|
type: "wizard_wait_for_response",
|
|
orderIndex: 1,
|
|
parameters: {
|
|
options: ["Red", "Blue", "Green", "Incorrect"],
|
|
prompt_text: "What color did the participant say?",
|
|
},
|
|
},
|
|
]);
|
|
|
|
// Branch A (Using say_with_emotion)
|
|
await db
|
|
.insert(schema.actions)
|
|
.values([
|
|
{
|
|
stepId: step4!.id,
|
|
name: "Happy Response",
|
|
type: "nao6-ros2.say_with_emotion",
|
|
orderIndex: 0,
|
|
parameters: {
|
|
text: "Exacty! It was a glowing red rock.",
|
|
emotion: "happy",
|
|
},
|
|
},
|
|
]);
|
|
|
|
// Branch B
|
|
await db.insert(schema.actions).values([
|
|
{
|
|
stepId: step5!.id,
|
|
name: "Correct them",
|
|
type: "nao6-ros2.say_text",
|
|
orderIndex: 0,
|
|
parameters: { text: "Actually, it was red." },
|
|
},
|
|
{
|
|
stepId: step5!.id,
|
|
name: "Shake Head",
|
|
type: "nao6-ros2.turn_head",
|
|
orderIndex: 1,
|
|
parameters: { yaw: 0.3, speed: 0.5 },
|
|
},
|
|
]);
|
|
|
|
// Conclusion
|
|
await db.insert(schema.actions).values([
|
|
{
|
|
stepId: step6!.id,
|
|
name: "Final Goodbye",
|
|
type: "nao6-ros2.say_text",
|
|
orderIndex: 0,
|
|
parameters: { text: "That is all for today. Goodbye!" },
|
|
},
|
|
{
|
|
stepId: step6!.id,
|
|
name: "Rest",
|
|
type: "nao6-ros2.move_arm",
|
|
orderIndex: 1,
|
|
parameters: { shoulder_pitch: 1.5 },
|
|
},
|
|
]);
|
|
|
|
console.log("✅ Seed completed successfully!");
|
|
} catch (err) {
|
|
console.error("❌ Seed failed:", err);
|
|
process.exit(1);
|
|
} finally {
|
|
await connection.end();
|
|
}
|
|
}
|
|
|
|
main();
|