374 lines
9.6 KiB
TypeScript
374 lines
9.6 KiB
TypeScript
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 = BasicDifficulty | CEFRLevels;
|
|
|
|
// Left easy, medium and hard to support older exam versions
|
|
export type BasicDifficulty = "easy" | "medium" | "hard";
|
|
export type CEFRLevels = "A1" | "A2" | "B1" | "B2" | "C1" | "C2";
|
|
export const ACCESSTYPE = ["public", "private", "confidential"] as const;
|
|
export type AccessType = typeof ACCESSTYPE[number];
|
|
|
|
|
|
|
|
export interface ExamBase {
|
|
id: string;
|
|
module: Module;
|
|
minTimer: number;
|
|
isDiagnostic: boolean;
|
|
variant?: Variant;
|
|
difficulty?: Difficulty | Difficulty[];
|
|
owners?: string[];
|
|
entities?: string[]
|
|
shuffle?: boolean;
|
|
createdBy?: string; // option as it has been added later
|
|
createdAt?: string; // option as it has been added later
|
|
access: AccessType;
|
|
label?: string;
|
|
}
|
|
export interface ReadingExam extends ExamBase {
|
|
module: "reading";
|
|
parts: ReadingPart[];
|
|
type: "academic" | "general";
|
|
}
|
|
|
|
export interface Section {
|
|
intro?: string;
|
|
category?: string;
|
|
sectionId?: number;
|
|
}
|
|
|
|
export interface ReadingPart extends Section {
|
|
text: {
|
|
title: string;
|
|
content: string;
|
|
};
|
|
exercises: Exercise[];
|
|
}
|
|
|
|
export interface LevelExam extends ExamBase {
|
|
module: "level";
|
|
parts: LevelPart[];
|
|
}
|
|
|
|
export interface LevelPart extends Section {
|
|
// to support old exams that have reading passage mc on context
|
|
context?: string;
|
|
exercises: Exercise[];
|
|
audio?: {
|
|
source: string;
|
|
repeatableTimes: number; // *The amount of times the user is allowed to repeat the audio, 0 for unlimited
|
|
};
|
|
script?: Script;
|
|
text?: {
|
|
title: string;
|
|
content: string;
|
|
};
|
|
}
|
|
|
|
export interface ListeningExam extends ExamBase {
|
|
parts: ListeningPart[];
|
|
module: "listening";
|
|
instructions?: string;
|
|
}
|
|
|
|
export type Message = { name: string; gender: string; text: string; voice?: string; };
|
|
export type Script = Message[] | string;
|
|
|
|
export interface ListeningPart extends Section {
|
|
audio?: {
|
|
source: string;
|
|
repeatableTimes: number; // *The amount of times the user is allowed to repeat the audio, 0 for unlimited
|
|
};
|
|
script?: Script;
|
|
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;
|
|
shuffleMaps?: ShuffleMap[];
|
|
isPractice?: boolean
|
|
}
|
|
|
|
export interface WritingExam extends ExamBase {
|
|
module: "writing";
|
|
enableNavigation?: boolean;
|
|
exercises: WritingExercise[];
|
|
type?: "academic" | "general";
|
|
}
|
|
|
|
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 extends Section {
|
|
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;
|
|
variant?: string;
|
|
isPractice?: boolean
|
|
difficulty?: Difficulty
|
|
}
|
|
|
|
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 extends Section {
|
|
id: string;
|
|
type: "speaking";
|
|
title: string;
|
|
text: string;
|
|
prompts: string[];
|
|
suffix?: string;
|
|
video_url: string;
|
|
userSolutions: {
|
|
id: string;
|
|
solution: string;
|
|
evaluation?: SpeakingEvaluation;
|
|
}[];
|
|
topic?: string;
|
|
isPractice?: boolean
|
|
difficulty?: Difficulty
|
|
}
|
|
|
|
export interface InteractiveSpeakingExercise extends Section {
|
|
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";
|
|
isPractice?: boolean
|
|
difficulty?: Difficulty
|
|
}
|
|
|
|
export interface FillBlanksMCOption {
|
|
id: string;
|
|
options: {
|
|
A: string;
|
|
B: string;
|
|
C: string;
|
|
D: string;
|
|
};
|
|
}
|
|
|
|
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 } | FillBlanksMCOption)[]; // *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"
|
|
}[];
|
|
variant?: string;
|
|
isPractice?: boolean
|
|
difficulty?: Difficulty
|
|
}
|
|
|
|
export interface TrueFalseExercise {
|
|
type: "trueFalse";
|
|
id: string;
|
|
prompt: string; // *EXAMPLE: "Select the appropriate option."
|
|
questions: TrueFalseQuestion[];
|
|
userSolutions: { id: string; solution: "true" | "false" | "not_given" }[];
|
|
isPractice?: boolean
|
|
difficulty?: Difficulty
|
|
}
|
|
|
|
export interface TrueFalseQuestion {
|
|
id: string; // *EXAMPLE: "1"
|
|
prompt: string; // *EXAMPLE: "What does her briefcase look like?"
|
|
solution: "true" | "false" | "not_given" | undefined; // *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;
|
|
}[];
|
|
variant?: string;
|
|
isPractice?: boolean
|
|
difficulty?: Difficulty
|
|
}
|
|
|
|
export interface MatchSentencesExercise {
|
|
type: "matchSentences";
|
|
id: string;
|
|
prompt: string;
|
|
userSolutions: { question: string; option: string }[];
|
|
sentences: MatchSentenceExerciseSentence[];
|
|
allowRepetition: boolean;
|
|
options: MatchSentenceExerciseOption[];
|
|
variant?: string;
|
|
isPractice?: boolean
|
|
difficulty?: Difficulty
|
|
}
|
|
|
|
export interface MatchSentenceExerciseSentence {
|
|
id: string;
|
|
sentence: string;
|
|
solution: 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 }[];
|
|
mcVariant?: string;
|
|
passage?: {
|
|
title: string;
|
|
content: string;
|
|
}
|
|
isPractice?: boolean
|
|
difficulty?: Difficulty
|
|
}
|
|
|
|
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")
|
|
}[];
|
|
shuffleMap?: Record<string, string>;
|
|
}
|
|
|
|
export interface ShuffleMap {
|
|
questionID: string;
|
|
map: {
|
|
[key: string]: string;
|
|
};
|
|
}
|
|
|
|
export interface Shuffles {
|
|
exerciseID: string;
|
|
shuffles: ShuffleMap[];
|
|
}
|
|
|
|
export type ModuleExam = LevelExam | ReadingExam | ListeningExam | WritingExam | SpeakingExam;
|
|
export type PartExam = ReadingExam | ListeningExam | LevelExam;
|
|
export type ExerciseOnlyExam = SpeakingExam | WritingExam;
|