mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-03-23 19:27:51 -04:00
255 lines
7.6 KiB
TypeScript
255 lines
7.6 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 'Control Flow Demo' 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. Run seed-dev.ts first.",
|
|
);
|
|
|
|
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. Run seed-dev.ts first.",
|
|
);
|
|
|
|
// Find Robot
|
|
const robot = await db.query.robots.findFirst({
|
|
where: (robots, { eq }) => eq(robots.name, "NAO6"),
|
|
});
|
|
if (!robot)
|
|
throw new Error("Robot 'NAO6' not found. Run seed-dev.ts first.");
|
|
|
|
// 2. Create Experiment
|
|
const [experiment] = await db
|
|
.insert(schema.experiments)
|
|
.values({
|
|
studyId: study.id,
|
|
name: "Control Flow Demo",
|
|
description:
|
|
"Demonstration of enhanced control flow actions: Sequence, Parallel, Wait, Loop, Branch.",
|
|
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
|
|
|
|
// Step 1: Sequence & Parallel
|
|
const [step1] = await db
|
|
.insert(schema.steps)
|
|
.values({
|
|
experimentId: experiment.id,
|
|
name: "Complex Action Structures",
|
|
description: "Demonstrating Sequence and Parallel groups",
|
|
type: "robot",
|
|
orderIndex: 0,
|
|
required: true,
|
|
durationEstimate: 30,
|
|
})
|
|
.returning();
|
|
if (!step1) throw new Error("Failed to create step1");
|
|
|
|
// Step 2: Loops & Waits
|
|
const [step2] = await db
|
|
.insert(schema.steps)
|
|
.values({
|
|
experimentId: experiment.id,
|
|
name: "Repetition & Delays",
|
|
description: "Demonstrating Loop and Wait actions",
|
|
type: "robot",
|
|
orderIndex: 1,
|
|
required: true,
|
|
durationEstimate: 45,
|
|
})
|
|
.returning();
|
|
if (!step2) throw new Error("Failed to create step2");
|
|
|
|
// 4. Create Actions
|
|
|
|
// --- Step 1 Actions ---
|
|
|
|
// Action 1: Sequence
|
|
// Note: Nested children are stored in 'children' property of the action object in frontend,
|
|
// but in DB 'parameters' is the JSONB field.
|
|
// However, looking at ActionChip, it expects `action.children`.
|
|
// The `ExperimentAction` type usually has `children` at top level.
|
|
// If the DB doesn't have it, the API must be hydrating it.
|
|
// BUT, for the purpose of this seed which writes to DB directly, I will put it in `parameters.children`
|
|
// and assume the frontend/API handles it or I'm missing a column.
|
|
// Actually, looking at schema again, `actions` table DOES NOT have children.
|
|
// So it MUST be in `parameters` or it's not persisted in this table structure yet (which would be a bug, but I'm seeding what exists).
|
|
// Wait, if I put it in parameters, does the UI read it?
|
|
// `ActionChip` reads `action.children`.
|
|
// I will try to put it in `parameters` and distinct `children` property in the JSON passed to `parameters`?
|
|
// No, `parameters` is jsonb.
|
|
// I will assume for now that the system expects it in parameters if it's not a column, OR it's not fully supported in DB yet.
|
|
// I will stick to what the UI likely consumes. `parameters: { children: [...] }`
|
|
|
|
// Sequence
|
|
await db.insert(schema.actions).values({
|
|
stepId: step1.id,
|
|
name: "Introduction Sequence",
|
|
type: "sequence",
|
|
orderIndex: 0,
|
|
// Embedding children here to demonstrate.
|
|
// Real implementation might vary if keys are strictly checked.
|
|
parameters: {
|
|
children: [
|
|
{
|
|
id: uuidv4(),
|
|
name: "Say Hello",
|
|
type: "nao6-ros2.say_text",
|
|
parameters: { text: "Hello there!" },
|
|
category: "interaction",
|
|
},
|
|
{
|
|
id: uuidv4(),
|
|
name: "Wave Hand",
|
|
type: "nao6-ros2.move_arm",
|
|
parameters: { arm: "right", action: "wave" },
|
|
category: "movement",
|
|
},
|
|
],
|
|
},
|
|
pluginId: "hristudio-core",
|
|
category: "control",
|
|
sourceKind: "core",
|
|
});
|
|
|
|
// Parallel
|
|
await db.insert(schema.actions).values({
|
|
stepId: step1.id,
|
|
name: "Parallel Actions",
|
|
type: "parallel",
|
|
orderIndex: 1,
|
|
parameters: {
|
|
children: [
|
|
{
|
|
id: uuidv4(),
|
|
name: "Say 'Moving'",
|
|
type: "nao6-ros2.say_text",
|
|
parameters: { text: "I am moving and talking." },
|
|
category: "interaction",
|
|
},
|
|
{
|
|
id: uuidv4(),
|
|
name: "Walk Forward",
|
|
type: "nao6-ros2.move_to",
|
|
parameters: { x: 0.5, y: 0 },
|
|
category: "movement",
|
|
},
|
|
],
|
|
},
|
|
pluginId: "hristudio-core",
|
|
category: "control",
|
|
sourceKind: "core",
|
|
});
|
|
|
|
// --- Step 2 Actions ---
|
|
|
|
// Loop
|
|
await db.insert(schema.actions).values({
|
|
stepId: step2.id,
|
|
name: "Repeat Message",
|
|
type: "loop",
|
|
orderIndex: 0,
|
|
parameters: {
|
|
iterations: 3,
|
|
children: [
|
|
{
|
|
id: uuidv4(),
|
|
name: "Say 'Echo'",
|
|
type: "nao6-ros2.say_text",
|
|
parameters: { text: "Echo" },
|
|
category: "interaction",
|
|
},
|
|
],
|
|
},
|
|
pluginId: "hristudio-core",
|
|
category: "control",
|
|
sourceKind: "core",
|
|
});
|
|
|
|
// Wait
|
|
await db.insert(schema.actions).values({
|
|
stepId: step2.id,
|
|
name: "Wait 5 Seconds",
|
|
type: "wait",
|
|
orderIndex: 1,
|
|
parameters: { duration: 5 },
|
|
pluginId: "hristudio-core",
|
|
category: "control",
|
|
sourceKind: "core",
|
|
});
|
|
|
|
// Branch (Controls step routing, not nested actions)
|
|
// Note: Branch configuration is stored in step.trigger.conditions, not action.parameters
|
|
// The branch action itself is just a marker that this step has conditional routing
|
|
await db.insert(schema.actions).values({
|
|
stepId: step2.id,
|
|
name: "Conditional Routing",
|
|
type: "branch",
|
|
orderIndex: 2,
|
|
parameters: {
|
|
// Branch actions don't have nested children
|
|
// Routing is configured at the step level via trigger.conditions
|
|
},
|
|
pluginId: "hristudio-core",
|
|
category: "control",
|
|
sourceKind: "core",
|
|
});
|
|
|
|
// Update step2 to have conditional routing
|
|
await db
|
|
.update(schema.steps)
|
|
.set({
|
|
type: "conditional",
|
|
conditions: {
|
|
options: [
|
|
{
|
|
label: "High Score Path",
|
|
nextStepIndex: 2, // Would go to a hypothetical step 3
|
|
variant: "default",
|
|
},
|
|
{
|
|
label: "Low Score Path",
|
|
nextStepIndex: 0, // Loop back to step 1
|
|
variant: "outline",
|
|
},
|
|
],
|
|
},
|
|
})
|
|
.where(sql`id = ${step2.id}`);
|
|
} catch (err) {
|
|
console.error(err);
|
|
process.exit(1);
|
|
} finally {
|
|
await connection.end();
|
|
}
|
|
}
|
|
|
|
main();
|