From 5120afcf009322c51148af7912bbcd396a60bf92 Mon Sep 17 00:00:00 2001 From: tmaog Date: Wed, 30 Apr 2025 11:33:48 +0200 Subject: [PATCH 01/12] feat: creation AI based tool for LP --- src/components/Card/PlanLessonCard.tsx | 106 ++++ src/components/Modals/AIToolModal.tsx | 1 - src/components/Modals/CreateAILPModal.tsx | 595 ++++++++++++++++++ src/components/Modals/CreateFlowModal.tsx | 10 + src/data/api.ts | 5 + .../AIGenerativeTypes/AIGenerativeTypes.ts | 42 ++ 6 files changed, 758 insertions(+), 1 deletion(-) create mode 100644 src/components/Card/PlanLessonCard.tsx create mode 100644 src/components/Modals/CreateAILPModal.tsx diff --git a/src/components/Card/PlanLessonCard.tsx b/src/components/Card/PlanLessonCard.tsx new file mode 100644 index 00000000..61cd0f1b --- /dev/null +++ b/src/components/Card/PlanLessonCard.tsx @@ -0,0 +1,106 @@ +import { + Box, + Card, + CardBody, + CardFooter, + Checkbox, + Image, + Select, + SpaceProps, + Text, +} from '@chakra-ui/react'; +import cardImage from '../../public/test_card.png'; +import { LearningOutcome, PlanLessonNode } from '../../types/polyglotElements'; + +type FlowCardProps = { + planNode: PlanLessonNode; + py?: SpaceProps['py']; + px?: SpaceProps['px']; + id: number; + isSelected: boolean; + setSelectedNode: (id: number) => void; + updateNodeAt: (id: number, updatedNode: PlanLessonNode) => void; +}; + +const PlanLessonCard = ({ + planNode, + px, + py, + id, + setSelectedNode, + isSelected, + updateNodeAt, +}: FlowCardProps) => { + return ( + + + Flow card + + + + Topic: {planNode.topic} + + + Type: {planNode.type} + + + Details: {planNode.details} + + + + Duration: {planNode.duration} min + + + + + + {!id && ( + <> + setSelectedNode(id)} + > + {isSelected ? 'selected' : 'not selected'} + + + )} + + + + ); +}; + +export default PlanLessonCard; diff --git a/src/components/Modals/AIToolModal.tsx b/src/components/Modals/AIToolModal.tsx index 292be289..475cf5a2 100644 --- a/src/components/Modals/AIToolModal.tsx +++ b/src/components/Modals/AIToolModal.tsx @@ -396,7 +396,6 @@ const AIToolModal = ({ setGeneratingLoading(true); setLearningOutcome(choosingLearningOutcome); if (!topicGen) throw ': no topic generated'; - //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa sei arrivato qui: fixa i dati if (eduLevel == undefined || learningOutcome == undefined) throw ': error in eduLevel and learningOutcome'; if (exerciseType != 'ReadMaterialNode') { diff --git a/src/components/Modals/CreateAILPModal.tsx b/src/components/Modals/CreateAILPModal.tsx new file mode 100644 index 00000000..5729f601 --- /dev/null +++ b/src/components/Modals/CreateAILPModal.tsx @@ -0,0 +1,595 @@ +import { + Box, + Button, + Flex, + FormControl, + FormLabel, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalHeader, + ModalOverlay, + NumberDecrementStepper, + NumberIncrementStepper, + NumberInput, + NumberInputField, + NumberInputStepper, + Select, + Text, + Textarea, + useToast, +} from '@chakra-ui/react'; +import { AxiosResponse } from 'axios'; +import { useState } from 'react'; +import { useFormContext } from 'react-hook-form'; +import { API } from '../../data/api'; +import { + AIPlanLessonResponse, + AnalyzedMaterial, + EducationLevel, + LearningOutcome, + PlanLessonNode, + QuestionType, + Topic, +} from '../../types/polyglotElements/AIGenerativeTypes/AIGenerativeTypes'; +import PlanLessonCard from '../Card/PlanLessonCard'; + +export type ModaTemplateProps = { + isOpen: boolean; + onClose: () => void; + exType: string; + action?: (i: boolean) => void; +}; + +function delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function shuffleArray(array: T[]) { + const arr = [...array]; + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr; +} + +const CreateAILPModal = ({ + isOpen, + onClose, + exType, + action, +}: ModaTemplateProps) => { + const [analysedMaterial, setAnalyzedMaterial] = useState(); + const [generatingLoading, setGeneratingLoading] = useState(false); + const [sourceMaterial, setSourceMaterial] = useState(''); + const [context, setContext] = useState(''); + const [AINodes, setAINodes] = useState(); + const [titleGen, setTitle] = useState(''); + const [macroSubjectGen, setMacroSubject] = useState(''); + const [learningOutcome, setLearningOutcome] = useState(); + const [choosingLearningOutcome, setChoosingLearningOutcome] = + useState(); + const [language, setLanguage] = useState(''); + const [duration, setDuration] = useState(0); + const [eduLevel, setEduLevel] = useState(); + const [topicGen, setTopicGen] = useState([ + { topic: 'prova', explanation: '' }, + ]); + const [selectedNodeIds, setSelectedNodeIds] = useState([]); + + const handleToggleNode = (id: number) => { + setSelectedNodeIds((prev) => + prev.includes(id) ? prev.filter((i) => i !== id) : [...prev, id] + ); + }; + + const updateNodeAt = (id: number, updatedNode: PlanLessonNode) => { + if (!AINodes) return; + + const updatedNodes = AINodes.nodes.map((node, index) => + index === id ? updatedNode : node + ); + + setAINodes({ + ...AINodes, + nodes: updatedNodes, + }); + }; + + const [selectedTopic, setSelectedTopic] = useState([]); + let exerciseType: QuestionType | string; + const [ca_n, setCA_N] = useState(1); + const [da_n, setDA_N] = useState(1); + const [eda_n, setEDA_N] = useState(1); + const [screen1, setScreen1] = useState(true); + const [screen2, setScreen2] = useState(false); + const [screen3, setScreen3] = useState(false); + const toast = useToast(); + const { setValue } = useFormContext(); + const word = exType == 'TrueFalseNode' ? 'Statements' : 'Answers'; + switch (exType) { + case 'closeEndedQuestionNode': + exerciseType = QuestionType.ShortAnswerQuestion; + break; + case 'OpenQuestionNode': + exerciseType = QuestionType.OpenQuestion; + break; + case 'TrueFalseNode': + exerciseType = QuestionType.TrueOrFalse; + break; + case 'multipleChoiceQuestionNode': + exerciseType = QuestionType.MultipleChoice; + break; + case 'ReadMaterialNode': + exerciseType = 'ReadMaterial'; + break; + default: + throw 'error in type'; + } + return ( + { + if (action) action(false); + onClose(); + }} + size={'2xl'} + isCentered + > + + + + Do you need help to generate your learning activity? + + +