Skip to content

Commit

Permalink
chore: new page
Browse files Browse the repository at this point in the history
  • Loading branch information
tomwisecodes committed Jan 9, 2025
1 parent 8c1570a commit 812e140
Show file tree
Hide file tree
Showing 9 changed files with 746 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { auth } from "@clerk/nextjs/server";
import { prisma } from "@oakai/db";
import { redirect } from "next/navigation";

import { getChatById } from "@/app/actions";

import ImageTestPage from "./test-page";

export default async function ImageSpikePage({
params,
}: {
params: {
"key-stage-slug": string;
"subject-slug": string;
"lesson-slug": string;
};
}) {
const clerkAuthentication = auth();
const { userId }: { userId: string | null } = clerkAuthentication;

if (!userId) {
redirect("/sign-in?next=/image-test");
}

const keyStageSlug = params["key-stage-slug"];
const subjectSlug = params["subject-slug"];
const lessonId = params["lesson-slug"];

console.log(`Key Stage: ${keyStageSlug}, Subject: ${subjectSlug}`);

const lesson = await prisma.appSession.findFirst({
where: {
id: lessonId,
},
});
const pageData = await getChatById(lessonId);
// @ts-ignore
return <ImageTestPage lesson={lesson} pageData={pageData} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
"use client";

import { useEffect, useState } from "react";

import { chatSchema } from "@oakai/aila/src/protocol/schema";
import type { Prisma } from "@prisma/client";
import { useImageSearch } from "hooks/useImageSearch";
import type { ImageResponse, PageData } from "types/imageTypes";

import LoadingWheel from "@/components/LoadingWheel";
import { trpc } from "@/utils/trpc";

export interface CycleData {
cloudinary: Cloudinary[];
unsplash: Unsplash[];
dale: Dale[];
stable: Stable[];
}

export interface Cloudinary {
id: string;
url: string;
title: string;
alt: string;
license: string;
photographer: string;
appropriatenessScore: number;
appropriatenessReasoning: string;
imagePrompt: string;
}

export interface Unsplash {
id: string;
url: string;
photographer: string;
license: string;
alt: string;
title: string;
appropriatenessScore: number;
appropriatenessReasoning: string;
imagePrompt: string;
}

export interface Dale {
id: string;
url: string;
title: string;
alt: string;
license: string;
photographer: string;
appropriatenessScore: number;
appropriatenessReasoning: string;
imagePrompt: string;
}

export interface Stable {
id: string;
url: string;
title: string;
alt: string;
license: string;
photographer: string;
appropriatenessScore: number;
appropriatenessReasoning: string;
imagePrompt: string;
}

const ImageTestPage = ({
lesson,
pageData,
}: {
pageData: PageData;
lesson: {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
appId: string;
userId: string;
output: Prisma.JsonValue;
} | null;
}) => {
const [seeLessonInfo, setSeeLessonInfo] = useState(false);
if (!lesson) {
return null;
}
const parseOutput = chatSchema.parse(lesson.output);
lesson;
const lessonOutput = parseOutput.lessonPlan;
// @ts-ignore
const { checkForUnderstanding, ...cycle1 } = lessonOutput.cycle1;
// @ts-ignore
const { checkForUnderstanding: checkForUnderstandingCycle2, ...cycle2 } =
lessonOutput.cycle2;
// @ts-ignore
const { checkForUnderstanding: checkForUnderstandingCycle3, ...cycle3 } =
lessonOutput.cycle3;
const cycle1ImagePrompt = cycle1?.explanation?.imagePrompt;
const cycle2ImagePrompt = cycle2?.explanation?.imagePrompt;
const cycle3ImagePrompt = cycle3?.explanation?.imagePrompt;

const {
data: cycle1Images,
isLoading: cycle1Loading,
mutateAsync: cycle1MutateAsync,
} = trpc.imageGen.generateFourImages.useMutation();

const {
data: cycle2Images,
isLoading: cycle2Loading,
mutateAsync: cycle2MutateAsync,
} = trpc.imageGen.generateFourImages.useMutation();

const {
data: cycle3mages,
isLoading: cycle3Loading,
mutateAsync: cycle3MutateAsync,
} = trpc.imageGen.generateFourImages.useMutation();

useEffect(() => {
cycle1MutateAsync({
searchExpression: cycle1ImagePrompt as string,
lessonTitle: pageData.title as string,
subject: pageData.subject as string,
keyStage: pageData.keyStage as string,
lessonPlan: pageData.lessonPlan,
originalPrompt: cycle1ImagePrompt as string,
});
cycle2MutateAsync({
searchExpression: cycle2ImagePrompt as string,
lessonTitle: pageData.title as string,
subject: pageData.subject as string,
keyStage: pageData.keyStage as string,
lessonPlan: pageData.lessonPlan,
originalPrompt: cycle2ImagePrompt as string,
});
cycle3MutateAsync({
searchExpression: cycle3ImagePrompt as string,
lessonTitle: pageData.title as string,
subject: pageData.subject as string,
keyStage: pageData.keyStage as string,
lessonPlan: pageData.lessonPlan,
originalPrompt: cycle3ImagePrompt as string,
});
}, [
cycle1ImagePrompt,
cycle1MutateAsync,
pageData.keyStage,
pageData.lessonPlan,
pageData.subject,
pageData.title,
cycle2ImagePrompt,
cycle2MutateAsync,
cycle3ImagePrompt,
cycle3MutateAsync,
]);

return (
<div className="mx-auto max-w-[1600px] p-19">
<h1 className="mb-11 text-3xl font-bold">{lessonOutput.title}</h1>
<div className="flex flex-row gap-20">
<div className="flex w-[70%] flex-col gap-16 rounded bg-gray-100 p-9">
<div>
{(cycle1Loading || cycle2Loading || cycle3Loading) && (
<p className="font-bold">Loading this might take a few mins</p>
)}
<h2 className="text-2xl font-bold">Cycle 1</h2>
{cycle1Loading ? (
<LoadingWheel />
) : (
// @ts-ignore
<Cycle cycle={cycle1} cycleImages={cycle1Images} />
)}
</div>

<div>
<h2 className="text-2xl font-bold">Cycle 2</h2>
{cycle2Loading ? (
<LoadingWheel />
) : (
// @ts-ignore
<Cycle cycle={cycle2} cycleImages={cycle2Images} />
)}
</div>
<div>
<h2 className="text-2xl font-bold">Cycle 3</h2>
{cycle3Loading ? (
<LoadingWheel />
) : (
// @ts-ignore
<Cycle cycle={cycle3} cycleImages={cycle3mages} />
)}
</div>
</div>
<div className="w-[30%]">
<button
onClick={() => {
setSeeLessonInfo(!seeLessonInfo);
}}
>
{seeLessonInfo ? "Hide Lesson Info" : "See Lesson Info"}
</button>
{seeLessonInfo && (
<pre style={{ whiteSpace: "pre-wrap", wordWrap: "break-word" }}>
{JSON.stringify(lessonOutput, null, 2)}
</pre>
)}
</div>
</div>
</div>
);
};

const Cycle = ({
cycle,
cycleImages,
}: {
cycle: any;
cycleImages?: CycleData | undefined;
}) => {
return (
<>
<div className="flex flex-col gap-8">
<p>{cycle.title}</p>
Spoken explanation:
<br />{" "}
{Array.isArray(cycle.explanation?.spokenExplanation) &&
cycle.explanation?.spokenExplanation?.map((slide) => slide)}
<p>
Accompanying slide details:
<br /> {cycle?.explanation?.accompanyingSlideDetails}
</p>
<p>
Image prompt:
<br /> {cycle?.explanation?.imagePrompt}
</p>
<p>
Slide text:
<br /> {cycle?.explanation?.slideText}
</p>
<p>
Practise:
<br /> {cycle.practice}
</p>
<p>
Feedback:
<br /> {cycle.feedback}
</p>
</div>
<div className="grid grid-cols-4 gap-8">
<div>
<h3>Cloudinary</h3>
{cycleImages?.cloudinary.map((image) => (
<div key={image.id}>
<img src={image.url} alt={image.alt} />
<p>Relevance score judged by ai: {image.appropriatenessScore}</p>
</div>
))}
</div>
<div>
<h3>Unsplash</h3>
{cycleImages?.unsplash.map((image) => (
<div key={image.id}>
<img src={image.url} alt={image.alt} />
<p>Relevance score judged by ai: {image.appropriatenessScore}</p>
</div>
))}
</div>
<div>
<h3>Dale (AI)</h3>
{cycleImages?.dale.map((image) => (
<div key={image.id}>
<img src={image.url} alt={image.alt} />
<p>Relevance score judged by ai: {image.appropriatenessScore}</p>
</div>
))}
</div>
<div>
<h3>Stable (AI)</h3>
{cycleImages?.stable.map((image) => (
<div key={image.id}>
<img src={image.url} alt={image.alt} />
<p>Relevance score judged by ai: {image.appropriatenessScore}</p>
</div>
))}
</div>
</div>
</>
);
};

export default ImageTestPage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use client";

import type { Prisma } from "@prisma/client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { z } from "zod";

const LessonsPage = ({
lessons,
keyStageSlug,
subjectSlug,
}: {
keyStageSlug: string;
subjectSlug: string;
lessons: {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
appId: string;
userId: string;
output: Prisma.JsonValue;
}[];
}) => {
const pathname = usePathname(); // Get the current pathname

// zod parse lessons
const lessonSchema = z
.object({
id: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
deletedAt: z.date().nullable(),
appId: z.string(),
userId: z.string(),
output: z.object({
title: z.string(),
}),
})
.passthrough();

const parsedLessons = lessons.map((lesson) => lessonSchema.parse(lesson));

return (
<div className="mx-auto max-w-[1200px] p-19">
<h1 className="mb-11">
Choose your keystage: {keyStageSlug}, subject: {subjectSlug}
</h1>
<div>
{parsedLessons?.map((lesson) => (
<div key={lesson.id} className="mb-5">
<Link
href={`/image-test/${keyStageSlug}/${subjectSlug}/${lesson.id}`}
className="text-blue hover:underline"
>
{lesson.output.title}
</Link>
</div>
))}
</div>
</div>
);
};

export default LessonsPage;
Loading

0 comments on commit 812e140

Please sign in to comment.