import { Module } from "."; export type Exam = ReadingExam | ListeningExam | WritingExam | SpeakingExam | LevelExam; export type Variant = "full" | "partial"; export type InstructorGender = "male" | "female" | "varied"; export type Difficulty = "easy" | "medium" | "hard"; interface ExamBase { id: string; module: Module; minTimer: number; isDiagnostic: boolean; variant?: Variant; difficulty?: Difficulty; createdBy?: string; // option as it has been added later createdAt?: string; // option as it has been added later } export interface ReadingExam extends ExamBase { module: "reading"; parts: ReadingPart[]; type: "academic" | "general"; } export interface ReadingPart { text: { title: string; content: string; }; exercises: Exercise[]; } export interface LevelExam extends ExamBase { module: "level"; parts: LevelPart[]; } export interface LevelPart { context?: string; exercises: Exercise[]; } export interface ListeningExam extends ExamBase { parts: ListeningPart[]; module: "listening"; } export interface ListeningPart { audio: { source: string; repeatableTimes: number; // *The amount of times the user is allowed to repeat the audio, 0 for unlimited }; exercises: Exercise[]; } export interface UserSolution { id?: string; solutions: any[]; module?: Module; exam?: string; type: string; score: { correct: number; total: number; missing: number; }; exercise: string; isDisabled?: boolean; } export interface WritingExam extends ExamBase { module: "writing"; exercises: WritingExercise[]; } interface WordCounter { type: "min" | "max"; limit: number; } export interface SpeakingExam extends ExamBase { module: "speaking"; exercises: (SpeakingExercise | InteractiveSpeakingExercise)[]; instructorGender: InstructorGender; } export type Exercise = | FillBlanksExercise | TrueFalseExercise | MatchSentencesExercise | MultipleChoiceExercise | WriteBlanksExercise | WritingExercise | SpeakingExercise | InteractiveSpeakingExercise; export interface Evaluation { comment: string; overall: number; task_response: {[key: string]: number | {grade: number; comment: string}}; misspelled_pairs?: {correction: string | null; misspelled: string}[]; } type InteractivePerfectAnswerKey = `perfect_answer_${number}`; type InteractiveTranscriptKey = `transcript_${number}`; type InteractiveFixedTextKey = `fixed_text_${number}`; type InteractivePerfectAnswerType = { [key in InteractivePerfectAnswerKey]: { answer: string } }; type InteractiveTranscriptType = { [key in InteractiveTranscriptKey]?: string }; type InteractiveFixedTextType = { [key in InteractiveFixedTextKey]?: string }; interface InteractiveSpeakingEvaluation extends Evaluation, InteractivePerfectAnswerType, InteractiveTranscriptType, InteractiveFixedTextType {} interface SpeakingEvaluation extends CommonEvaluation { perfect_answer_1?: string; transcript_1?: string; fixed_text_1?: string; } interface CommonEvaluation extends Evaluation { perfect_answer?: string; fixed_text?: string; } export interface WritingExercise { id: string; type: "writing"; prefix: string; //* The information about the task, like the amount of time they should spend on it suffix: string; prompt: string; //* The context given to the user containing what they should write about wordCounter: WordCounter; //* The minimum or maximum amount of words that should be written attachment?: { url: string; description: string; }; //* The url for an image to work as an attachment to show the user userSolutions: { id: string; solution: string; evaluation?: WritingEvaluation; }[]; topic?: string; } export interface AIDetectionAttributes { predicted_class: "ai" | "mixed" | "human"; confidence_category: "high" | "medium" | "low"; class_probabilities: { ai: number; human: number; mixed: number; }; sentences: { sentence: string; highlight_sentence_for_ai: boolean; }[]; } export interface WritingEvaluation extends CommonEvaluation { ai_detection?: AIDetectionAttributes; } export interface SpeakingExercise { id: string; type: "speaking"; title: string; text: string; prompts: string[]; suffix?: string; video_url: string; userSolutions: { id: string; solution: string; evaluation?: SpeakingEvaluation; }[]; topic?: string; } export interface InteractiveSpeakingExercise { id: string; type: "interactiveSpeaking"; title: string; first_title?: string; second_title?: string; text: string; prompts: {text: string; video_url: string}[]; userSolutions: { id: string; solution: {questionIndex: number; question: string; answer: string}[]; evaluation?: InteractiveSpeakingEvaluation; }[]; topic?: string; first_topic?: string; second_topic?: string; variant?: "initial" | "final"; } export interface FillBlanksExercise { prompt: string; // *EXAMPLE: "Complete the summary below. Click a blank to select the corresponding word for it." type: "fillBlanks"; id: string; words: (string | {letter: string; word: string})[]; // *EXAMPLE: ["preserve", "unaware"] text: string; // *EXAMPLE: "They tried to {{1}} burning" allowRepetition: boolean; solutions: { id: string; // *EXAMPLE: "1" solution: string; // *EXAMPLE: "preserve" }[]; userSolutions: { id: string; // *EXAMPLE: "1" solution: string; // *EXAMPLE: "preserve" }[]; } export interface TrueFalseExercise { type: "trueFalse"; id: string; prompt: string; // *EXAMPLE: "Select the appropriate option." questions: TrueFalseQuestion[]; userSolutions: {id: string; solution: "true" | "false" | "not_given"}[]; } export interface TrueFalseQuestion { id: string; // *EXAMPLE: "1" prompt: string; // *EXAMPLE: "What does her briefcase look like?" solution: "true" | "false" | "not_given"; // *EXAMPLE: "True" } export interface WriteBlanksExercise { prompt: string; // *EXAMPLE: "Complete the notes below by writing NO MORE THAN THREE WORDS in the spaces provided." maxWords: number; // *EXAMPLE: 3 - The maximum amount of words allowed per blank, 0 for unlimited type: "writeBlanks"; id: string; text: string; // *EXAMPLE: "The Government plans to give ${{14}}" solutions: { id: string; // *EXAMPLE: "14" solution: string[]; // *EXAMPLE: ["Prescott"] - All possible solutions (case sensitive) }[]; userSolutions: { id: string; solution: string; }[]; } export interface MatchSentencesExercise { type: "matchSentences"; id: string; prompt: string; userSolutions: {question: string; option: string}[]; sentences: MatchSentenceExerciseSentence[]; allowRepetition: boolean; options: MatchSentenceExerciseOption[]; } export interface MatchSentenceExerciseSentence { id: string; sentence: string; solution: string; color: string; } export interface MatchSentenceExerciseOption { id: string; sentence: string; } export interface MultipleChoiceExercise { type: "multipleChoice"; id: string; prompt: string; // *EXAMPLE: "Select the appropriate option." questions: MultipleChoiceQuestion[]; userSolutions: {question: string; option: string}[]; } export interface MultipleChoiceQuestion { variant: "image" | "text"; id: string; // *EXAMPLE: "1" prompt: string; // *EXAMPLE: "What does her briefcase look like?" solution: string; // *EXAMPLE: "A" options: { id: string; // *EXAMPLE: "A" src?: string; // *EXAMPLE: "https://i.imgur.com/rEbrSqA.png" (only used if the variant is "image") text?: string; // *EXAMPLE: "wallet, pens and novel" (only used if the variant is "text") }[]; }