mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-03-23 19:27:51 -04:00
Various improvements: study forms, participant management, PDF generator, robot integration
This commit is contained in:
@@ -35,7 +35,8 @@ async function main() {
|
||||
.values({
|
||||
studyId: study.id,
|
||||
name: "Story: Red Rock",
|
||||
description: "A story about a red rock on Mars with comprehension check and branching.",
|
||||
description:
|
||||
"A story about a red rock on Mars with comprehension check and branching.",
|
||||
version: 1,
|
||||
status: "draft",
|
||||
robotId: robot.id,
|
||||
@@ -53,102 +54,212 @@ async function main() {
|
||||
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();
|
||||
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();
|
||||
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();
|
||||
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();
|
||||
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();
|
||||
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();
|
||||
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 } }
|
||||
{
|
||||
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 } }
|
||||
{
|
||||
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?" } }
|
||||
{
|
||||
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" } }
|
||||
]);
|
||||
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 } }
|
||||
{
|
||||
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 } }
|
||||
{
|
||||
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!");
|
||||
|
||||
@@ -5,21 +5,27 @@ async function migrate() {
|
||||
console.log("Adding identifier column to hs_plugin...");
|
||||
|
||||
try {
|
||||
await db.execute(sql`ALTER TABLE hs_plugin ADD COLUMN identifier varchar(100)`);
|
||||
await db.execute(
|
||||
sql`ALTER TABLE hs_plugin ADD COLUMN identifier varchar(100)`,
|
||||
);
|
||||
console.log("✓ Added identifier column");
|
||||
} catch (e: any) {
|
||||
console.log("Column may already exist:", e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
await db.execute(sql`UPDATE hs_plugin SET identifier = name WHERE identifier IS NULL`);
|
||||
await db.execute(
|
||||
sql`UPDATE hs_plugin SET identifier = name WHERE identifier IS NULL`,
|
||||
);
|
||||
console.log("✓ Copied name to identifier");
|
||||
} catch (e: any) {
|
||||
console.log("Error copying:", e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
await db.execute(sql`ALTER TABLE hs_plugin ADD CONSTRAINT hs_plugin_identifier_unique UNIQUE (identifier)`);
|
||||
await db.execute(
|
||||
sql`ALTER TABLE hs_plugin ADD CONSTRAINT hs_plugin_identifier_unique UNIQUE (identifier)`,
|
||||
);
|
||||
console.log("✓ Added unique constraint");
|
||||
} catch (e: any) {
|
||||
console.log("Constraint may already exist:", e.message);
|
||||
|
||||
Reference in New Issue
Block a user