@thanh01.pmt/interactive-quiz-kit 1.0.66 → 1.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/HEADLESS.md CHANGED
@@ -179,7 +179,7 @@ async function createAIQuestion() {
179
179
  console.log('Generating a Multiple Choice question about the Solar System...');
180
180
  const result = await generateMCQQuestion({
181
181
  topic: 'The Solar System',
182
- difficulty: 'easy',
182
+ difficulty: 'Easy',
183
183
  language: 'English'
184
184
  }, 'YOUR_API_KEY');
185
185
 
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  **Interactive Quiz Kit** is a comprehensive TypeScript library built with React, designed to effortlessly create, manage, play, and distribute interactive quizzes. It provides a robust core logic (`QuizEngine`), reusable React UI components, and support for a wide variety of question types.
7
7
 
8
- The library is architected for easy extension and integration, featuring a powerful authoring tool, AI-powered content generation (using Google's Genkit and Gemini), and SCORM packaging for seamless LMS integration.
8
+ The library is architected for Easy extension and integration, featuring a powerful authoring tool, AI-powered content generation (using Google's Genkit and Gemini), and SCORM packaging for seamless LMS integration.
9
9
 
10
10
  ## ✨ Features
11
11
 
@@ -167,7 +167,7 @@ async function createNewQuestion() {
167
167
  try {
168
168
  const { question } = await generateTrueFalseQuestion({
169
169
  topic: "The history of the internet",
170
- difficulty: "medium"
170
+ difficulty: "Medium"
171
171
  });
172
172
 
173
173
  if (question) {
@@ -1,4 +1,4 @@
1
- import { R as RichContentString, Q as QuestionTypeStrings, s as QuizConfig } from './quiz-config-o4j2dfsu.cjs';
1
+ import { R as RichContentString, Q as QuestionTypeStrings, s as QuizConfig } from './quiz-config-CwaP-pBs.cjs';
2
2
 
3
3
  interface TestCaseResult {
4
4
  testCaseId: string;
@@ -103,7 +103,7 @@ interface Achievement {
103
103
  }
104
104
  type PracticeDifficulty = 'Very Easy' | 'Easy' | 'Medium' | 'Hard' | 'Expert';
105
105
  interface PracticeSuggestionTopic {
106
- loId: string;
106
+ code: string;
107
107
  topicName: string;
108
108
  reason: 'review' | 'explore';
109
109
  suggestedDifficulty?: PracticeDifficulty;
@@ -175,7 +175,7 @@ interface RoadmapItem {
175
175
  topicName: string;
176
176
  reason: string;
177
177
  suggestedDifficulty: PracticeDifficulty;
178
- loId: string;
178
+ code: string;
179
179
  isCompleted: boolean;
180
180
  }
181
181
  interface WeeklyRoadmap {
@@ -1,4 +1,4 @@
1
- import { R as RichContentString, Q as QuestionTypeStrings, s as QuizConfig } from './quiz-config-o4j2dfsu.js';
1
+ import { R as RichContentString, Q as QuestionTypeStrings, s as QuizConfig } from './quiz-config-CwaP-pBs.js';
2
2
 
3
3
  interface TestCaseResult {
4
4
  testCaseId: string;
@@ -103,7 +103,7 @@ interface Achievement {
103
103
  }
104
104
  type PracticeDifficulty = 'Very Easy' | 'Easy' | 'Medium' | 'Hard' | 'Expert';
105
105
  interface PracticeSuggestionTopic {
106
- loId: string;
106
+ code: string;
107
107
  topicName: string;
108
108
  reason: 'review' | 'explore';
109
109
  suggestedDifficulty?: PracticeDifficulty;
@@ -175,7 +175,7 @@ interface RoadmapItem {
175
175
  topicName: string;
176
176
  reason: string;
177
177
  suggestedDifficulty: PracticeDifficulty;
178
- loId: string;
178
+ code: string;
179
179
  isCompleted: boolean;
180
180
  }
181
181
  interface WeeklyRoadmap {
package/dist/ai.cjs CHANGED
@@ -94,12 +94,12 @@ var QuizContextSchema = zod.z.object({
94
94
  originalSubject: zod.z.string().optional(),
95
95
  originalCategory: zod.z.string().optional(),
96
96
  originalTopic: zod.z.string().optional(),
97
- loDescription: zod.z.string().optional().describe("The full description of the learning objective for deep context."),
97
+ description: zod.z.string().optional().describe("The full description of the learning objective for deep context."),
98
98
  gradeBand: zod.z.string().optional()
99
99
  });
100
100
  var BaseQuestionGenerationClientInputSchema = zod.z.object({
101
101
  language: zod.z.string().optional().default("English"),
102
- difficulty: zod.z.enum(["easy", "medium", "hard"]),
102
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]),
103
103
  quizContext: QuizContextSchema.optional(),
104
104
  imageUrl: zod.z.string().url().optional().describe("Optional URL of an image to be used as context.")
105
105
  });
@@ -108,7 +108,7 @@ var BaseQuestionZodSchema = zod.z.object({
108
108
  prompt: zod.z.string().min(1),
109
109
  points: zod.z.number().min(0).optional(),
110
110
  explanation: zod.z.string().optional(),
111
- difficulty: zod.z.enum(["easy", "medium", "hard"]).optional(),
111
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
112
112
  topic: zod.z.string().optional(),
113
113
  category: zod.z.string().optional(),
114
114
  subject: zod.z.string().optional(),
@@ -204,7 +204,7 @@ var AITrueFalseOutputFieldsSchema = zod.z.object({
204
204
  correctAnswer: zod.z.boolean(),
205
205
  explanation: zod.z.string().optional().describe("An explanation of why the statement is true or false, especially important if false."),
206
206
  points: zod.z.number().optional().default(10),
207
- difficulty: zod.z.enum(["easy", "medium", "hard"]).optional(),
207
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
208
208
  topic: zod.z.string().optional(),
209
209
  verifiedCategory: zod.z.string().optional()
210
210
  // Thêm để xác thực
@@ -225,7 +225,7 @@ Previous attempts failed. Ensure the JSON is valid and 'correctAnswer' is a bool
225
225
  const misconceptionGuidance = quizContext?.targetMisconception ? `**Target Misconception:** The statement you create MUST be FALSE and based on this common mistake: "${quizContext.targetMisconception}"` : "";
226
226
  const contextStrings = [
227
227
  `**Required Category:** ${category}`,
228
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
228
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
229
229
  imageContextInstruction,
230
230
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
231
231
  misconceptionGuidance,
@@ -236,7 +236,7 @@ Previous attempts failed. Ensure the JSON is valid and 'correctAnswer' is a bool
236
236
  correctAnswer: true,
237
237
  explanation: "Optional values in Swift represent the presence or absence of a value. To access the value when it exists, you must unwrap it using methods like 'if let', 'guard let', or the force unwrap operator '!'.",
238
238
  points: 10,
239
- difficulty: "easy",
239
+ difficulty: "Easy",
240
240
  topic: "Swift Optionals",
241
241
  verifiedCategory: category
242
242
  }, null, 2);
@@ -366,7 +366,7 @@ var AIMCQOutputFieldsSchema = zod.z.object({
366
366
  correctTempOptionId: zod.z.string().describe("The temporary ID of the correct option from the generated options array."),
367
367
  explanation: zod.z.string().optional().describe("A brief explanation of why the answer is correct."),
368
368
  points: zod.z.number().optional().default(10),
369
- difficulty: zod.z.enum(["easy", "medium", "hard"]).optional(),
369
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
370
370
  topic: zod.z.string().optional(),
371
371
  verifiedCategory: zod.z.string().optional().describe("The category this question actually addresses.")
372
372
  });
@@ -385,7 +385,7 @@ Previous attempts failed...
385
385
  const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and options must be directly related to the content of this image.` : "";
386
386
  const contextStrings = [
387
387
  `**Required Category:** ${category}`,
388
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
388
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
389
389
  imageContextInstruction,
390
390
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
391
391
  quizContext?.targetMisconception && `**Target Misconception:** Use this to create plausible incorrect answers: "${quizContext.targetMisconception}"`,
@@ -402,7 +402,7 @@ Previous attempts failed...
402
402
  correctTempOptionId: "C",
403
403
  explanation: `The 'guard' statement in ${category} provides an early exit from a scope (like a function) if a condition is false, enhancing code readability by handling required conditions upfront.`,
404
404
  points: 10,
405
- difficulty: "easy",
405
+ difficulty: "Easy",
406
406
  topic: `Control Flow in ${category}`,
407
407
  verifiedCategory: category
408
408
  }, null, 2);
@@ -544,7 +544,7 @@ var AIMRQOutputFieldsSchema = zod.z.object({
544
544
  correctTempOptionIds: zod.z.array(zod.z.string()).min(1),
545
545
  explanation: zod.z.string().optional(),
546
546
  points: zod.z.number().optional().default(10),
547
- difficulty: zod.z.enum(["easy", "medium", "hard"]).optional(),
547
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
548
548
  topic: zod.z.string().optional(),
549
549
  verifiedCategory: zod.z.string().optional().describe("The category this question actually addresses.")
550
550
  });
@@ -563,7 +563,7 @@ Previous attempts failed due to validation errors. Pay close attention to the nu
563
563
  const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and options must be directly related to the content of this image.` : "";
564
564
  const contextStrings = [
565
565
  `**Required Category:** ${category} (This is the ONLY language to be used)`,
566
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
566
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
567
567
  imageContextInstruction,
568
568
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
569
569
  quizContext?.targetMisconception && `**Target Misconception:** Use this to create plausible incorrect answers (distractors). The misconception is: "${quizContext.targetMisconception}"`,
@@ -581,7 +581,7 @@ Previous attempts failed due to validation errors. Pay close attention to the nu
581
581
  correctTempOptionIds: ["A", "C", "D"],
582
582
  explanation: "Object-Oriented, Functional, and Procedural are all major programming paradigms. Assembly is a low-level language, and Middleware is a type of software, not a paradigm.",
583
583
  points: 10,
584
- difficulty: "medium",
584
+ difficulty: "Medium",
585
585
  topic: "Programming Paradigms",
586
586
  verifiedCategory: category
587
587
  }, null, 2);
@@ -739,7 +739,7 @@ var AIShortAnswerOutputFieldsSchema = zod.z.object({
739
739
  // isCaseSensitive không cần thiết ở đây, chúng ta sẽ quản lý nó ở phía client
740
740
  explanation: zod.z.string().optional(),
741
741
  points: zod.z.number().optional().default(10),
742
- difficulty: zod.z.enum(["easy", "medium", "hard"]).optional(),
742
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
743
743
  topic: zod.z.string().optional(),
744
744
  verifiedCategory: zod.z.string().optional()
745
745
  // Thêm để xác thực
@@ -759,7 +759,7 @@ Previous attempts failed. Ensure 'acceptedAnswers' is a non-empty array of strin
759
759
  const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and its short answer must be directly related to the content of this image.` : "";
760
760
  const contextStrings = [
761
761
  `**Required Category:** ${category}`,
762
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
762
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
763
763
  imageContextInstruction,
764
764
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
765
765
  quizContext?.targetMisconception && `**Target Misconception:** The question should require an answer that corrects this specific misconception: "${quizContext.targetMisconception}"`
@@ -769,7 +769,7 @@ Previous attempts failed. Ensure 'acceptedAnswers' is a non-empty array of strin
769
769
  acceptedAnswers: ["let"],
770
770
  explanation: "The 'let' keyword is used to declare constants, which are values that cannot be changed after they are set. 'var' is used for variables.",
771
771
  points: 10,
772
- difficulty: "easy",
772
+ difficulty: "Easy",
773
773
  topic: "Swift Constants",
774
774
  verifiedCategory: category
775
775
  }, null, 2);
@@ -896,7 +896,7 @@ var AINumericOutputFieldsSchema = zod.z.object({
896
896
  tolerance: zod.z.number().min(0).optional(),
897
897
  explanation: zod.z.string().optional(),
898
898
  points: zod.z.number().optional().default(10),
899
- difficulty: zod.z.enum(["easy", "medium", "hard"]).optional(),
899
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
900
900
  topic: zod.z.string().optional(),
901
901
  verifiedCategory: zod.z.string().optional()
902
902
  // Thêm để xác thực
@@ -916,7 +916,7 @@ Previous attempts failed. Ensure the 'answer' is a valid number and fits within
916
916
  const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and its numerical answer must be directly related to the content of this image.` : "";
917
917
  const contextStrings = [
918
918
  `**Required Category:** ${category}`,
919
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
919
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
920
920
  imageContextInstruction,
921
921
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
922
922
  quizContext?.targetMisconception && `**Target Misconception:** The question should clarify this numerical error: "${quizContext.targetMisconception}"`
@@ -932,7 +932,7 @@ Previous attempts failed. Ensure the 'answer' is a valid number and fits within
932
932
  tolerance: 0,
933
933
  explanation: "An Int8 uses 8 bits. One bit is for the sign, leaving 7 bits for the value. The range is from -128 to 127 (2^7 - 1).",
934
934
  points: 10,
935
- difficulty: "medium",
935
+ difficulty: "Medium",
936
936
  topic: "Swift Data Types",
937
937
  verifiedCategory: category
938
938
  }, null, 2);
@@ -1076,7 +1076,7 @@ var AIFillInTheBlanksOutputFieldsSchema = zod.z.object({
1076
1076
  })).min(1).describe("An array of text and blank segments representing the question."),
1077
1077
  explanation: zod.z.string().optional(),
1078
1078
  points: zod.z.number().optional().default(10),
1079
- difficulty: zod.z.enum(["easy", "medium", "hard"]).optional(),
1079
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
1080
1080
  topic: zod.z.string().optional(),
1081
1081
  verifiedCategory: zod.z.string().optional()
1082
1082
  // Thêm để xác thực
@@ -1096,7 +1096,7 @@ Previous attempts failed. Pay strict attention to the JSON schema, especially th
1096
1096
  const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and blanks must be directly related to the content of this image.` : "";
1097
1097
  const contextStrings = [
1098
1098
  `**Required Category:** ${category}`,
1099
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
1099
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
1100
1100
  imageContextInstruction,
1101
1101
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
1102
1102
  quizContext?.targetMisconception && `**Target Misconception:** Design the blank to test this specific point: "${quizContext.targetMisconception}"`
@@ -1110,7 +1110,7 @@ Previous attempts failed. Pay strict attention to the JSON schema, especially th
1110
1110
  ],
1111
1111
  explanation: "The 'func' keyword is used to declare a function in the Swift programming language.",
1112
1112
  points: 10,
1113
- difficulty: "easy",
1113
+ difficulty: "Easy",
1114
1114
  topic: "Swift Function Declaration",
1115
1115
  verifiedCategory: category
1116
1116
  }, null, 2);
@@ -1258,7 +1258,7 @@ var AISequenceOutputFieldsSchema = zod.z.object({
1258
1258
  itemsInCorrectOrder: zod.z.array(zod.z.string().min(1)).min(2).describe("An array of strings, with each string representing an item to be sequenced. The array itself MUST be in the correct final order."),
1259
1259
  explanation: zod.z.string().optional(),
1260
1260
  points: zod.z.number().optional().default(10),
1261
- difficulty: zod.z.enum(["easy", "medium", "hard"]).optional(),
1261
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
1262
1262
  topic: zod.z.string().optional(),
1263
1263
  verifiedCategory: zod.z.string().optional()
1264
1264
  // Thêm để xác thực
@@ -1278,7 +1278,7 @@ Previous attempts failed. Ensure the 'itemsInCorrectOrder' array has exactly the
1278
1278
  const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The sequence of items must be directly related to the process or content shown in this image.` : "";
1279
1279
  const contextStrings = [
1280
1280
  `**Required Category:** ${category}`,
1281
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
1281
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
1282
1282
  imageContextInstruction,
1283
1283
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
1284
1284
  quizContext?.targetMisconception && `**Target Misconception:** The sequence should clarify this specific process error: "${quizContext.targetMisconception}"`
@@ -1293,7 +1293,7 @@ Previous attempts failed. Ensure the 'itemsInCorrectOrder' array has exactly the
1293
1293
  ],
1294
1294
  explanation: "This is the fundamental sequence for a basic data task in URLSession.",
1295
1295
  points: 10,
1296
- difficulty: "medium",
1296
+ difficulty: "Medium",
1297
1297
  topic: "Swift Networking",
1298
1298
  verifiedCategory: category
1299
1299
  }, null, 2);
@@ -1429,7 +1429,7 @@ var AIMatchingOutputFieldsSchema = zod.z.object({
1429
1429
  })).min(2),
1430
1430
  explanation: zod.z.string().optional(),
1431
1431
  points: zod.z.number().optional().default(10),
1432
- difficulty: zod.z.enum(["easy", "medium", "hard"]).optional(),
1432
+ difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
1433
1433
  topic: zod.z.string().optional(),
1434
1434
  verifiedCategory: zod.z.string().optional()
1435
1435
  // Thêm để xác thực
@@ -1449,7 +1449,7 @@ Previous attempts failed. Please ensure the 'correctPairs' array has exactly the
1449
1449
  const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The matching pairs must be directly related to the content of this image.` : "";
1450
1450
  const contextStrings = [
1451
1451
  `**Required Category:** ${category}`,
1452
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
1452
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
1453
1453
  imageContextInstruction,
1454
1454
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
1455
1455
  quizContext?.targetMisconception && `**Target Misconception:** Design a pair that specifically tests this confusion: "${quizContext.targetMisconception}"`
@@ -1463,7 +1463,7 @@ Previous attempts failed. Please ensure the 'correctPairs' array has exactly the
1463
1463
  ],
1464
1464
  explanation: "These are the fundamental characteristics of Swift's main collection types.",
1465
1465
  points: 10,
1466
- difficulty: "easy",
1466
+ difficulty: "Easy",
1467
1467
  topic: "Swift Collection Types",
1468
1468
  verifiedCategory: category
1469
1469
  }, null, 2);
@@ -1624,7 +1624,7 @@ Previous attempts failed. Pay strict attention to the JSON schema and all rules.
1624
1624
  const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The coding problem must be directly related to processing or interpreting the content of this image.` : "";
1625
1625
  const contextStrings = [
1626
1626
  `**Subject:** ${subject}`,
1627
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
1627
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
1628
1628
  imageContextInstruction,
1629
1629
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
1630
1630
  quizContext?.targetMisconception && `**Target Misconception:** The problem should test against this common error: "${quizContext.targetMisconception}"`
@@ -2496,10 +2496,6 @@ function validateConsecutiveTypes(quizPlan) {
2496
2496
 
2497
2497
  // src/services/TopicDataService.ts
2498
2498
  var TopicDataService = class {
2499
- /**
2500
- * Saves an array of LearningObjective objects to Local Storage, overwriting existing data.
2501
- * @param data The array of learning objectives to save.
2502
- */
2503
2499
  static saveData(data) {
2504
2500
  try {
2505
2501
  if (typeof window === "undefined") return;
@@ -2509,24 +2505,15 @@ var TopicDataService = class {
2509
2505
  console.error("Error saving learning objectives to Local Storage:", error);
2510
2506
  }
2511
2507
  }
2512
- /**
2513
- * Merges a new set of learning objectives with the existing data in Local Storage.
2514
- * If an LO ID from newData already exists, it will be updated. Otherwise, it will be added.
2515
- * @param newData The array of new or updated learning objectives.
2516
- */
2517
2508
  static mergeData(newData) {
2518
2509
  const existingData = this.getData();
2519
- const loMap = new Map(existingData.map((lo) => [lo.loId, lo]));
2510
+ const loMap = new Map(existingData.map((lo) => [lo.code, lo]));
2520
2511
  newData.forEach((newLo) => {
2521
- loMap.set(newLo.loId, newLo);
2512
+ loMap.set(newLo.code, newLo);
2522
2513
  });
2523
2514
  const mergedData = Array.from(loMap.values());
2524
2515
  this.saveData(mergedData);
2525
2516
  }
2526
- /**
2527
- * Retrieves the array of LearningObjective objects from Local Storage.
2528
- * @returns An array of learning objectives, or an empty array if none are found or an error occurs.
2529
- */
2530
2517
  static getData() {
2531
2518
  try {
2532
2519
  if (typeof window === "undefined") return [];
@@ -2538,9 +2525,6 @@ var TopicDataService = class {
2538
2525
  return [];
2539
2526
  }
2540
2527
  }
2541
- /**
2542
- * Removes all learning objective data from Local Storage.
2543
- */
2544
2528
  static clearData() {
2545
2529
  try {
2546
2530
  if (typeof window === "undefined") return;
@@ -2549,11 +2533,6 @@ var TopicDataService = class {
2549
2533
  console.error("Error clearing learning objectives from Local Storage:", error);
2550
2534
  }
2551
2535
  }
2552
- /**
2553
- * Parses TSV content into an array of LearningObjective objects.
2554
- * @param tsvContent The raw string content from a .tsv file.
2555
- * @returns An object containing the successfully parsed data and any errors encountered.
2556
- */
2557
2536
  static parseTSV(tsvContent) {
2558
2537
  const lines = tsvContent.split("\n").filter((line) => line.trim() !== "");
2559
2538
  if (lines.length < 2) {
@@ -2575,6 +2554,7 @@ var TopicDataService = class {
2575
2554
  }
2576
2555
  const [
2577
2556
  loId,
2557
+ name,
2578
2558
  loDescription,
2579
2559
  subject,
2580
2560
  category,
@@ -2584,18 +2564,21 @@ var TopicDataService = class {
2584
2564
  stemElementsStr,
2585
2565
  bloomLevelsStr
2586
2566
  ] = values;
2587
- if (!loId || !subject || !category || !topic) {
2588
- errors.push(`Line ${index + 2}: Missing required fields (LO ID, Subject, Category, or Topic).`);
2567
+ if (!loId || !loDescription || !subject || !category || !topic) {
2568
+ errors.push(`Line ${index + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
2589
2569
  return;
2590
2570
  }
2591
2571
  const learningObjective = {
2592
- loId,
2593
- loDescription,
2572
+ id: generateUniqueId("lo_"),
2573
+ code: loId,
2574
+ name,
2575
+ description: loDescription,
2576
+ // Can be the same as name or enhanced later
2594
2577
  subject,
2595
2578
  category,
2596
2579
  topic,
2597
- keywords: keywordsStr.split(",").map((k) => k.trim()).filter(Boolean),
2598
2580
  grade,
2581
+ keywords: keywordsStr.split(",").map((k) => k.trim()).filter(Boolean),
2599
2582
  stemElements: stemElementsStr.split(",").map((s) => s.trim()).filter(Boolean),
2600
2583
  bloomLevelsGuideline: bloomLevelsStr.split(",").map((b) => b.trim()).filter(Boolean)
2601
2584
  };
@@ -2603,40 +2586,21 @@ var TopicDataService = class {
2603
2586
  });
2604
2587
  return { data, errors };
2605
2588
  }
2606
- /**
2607
- * Gets a unique list of all subjects from the stored data.
2608
- * @returns An array of subject strings.
2609
- */
2610
2589
  static getSubjects() {
2611
2590
  const data = this.getData();
2612
2591
  const subjects = data.map((item) => item.subject);
2613
2592
  return [...new Set(subjects)].sort();
2614
2593
  }
2615
- /**
2616
- * Gets a unique list of categories for a given subject.
2617
- * @param subject The subject to filter by.
2618
- * @returns An array of category strings.
2619
- */
2620
2594
  static getCategoriesBySubject(subject) {
2621
2595
  const data = this.getData();
2622
2596
  const categories = data.filter((item) => item.subject === subject).map((item) => item.category);
2623
2597
  return [...new Set(categories)].sort();
2624
2598
  }
2625
- /**
2626
- * Gets a unique list of topics for a given category.
2627
- * @param category The category to filter by.
2628
- * @returns An array of topic strings.
2629
- */
2630
2599
  static getTopicsByCategory(category) {
2631
2600
  const data = this.getData();
2632
2601
  const topics = data.filter((item) => item.category === category).map((item) => item.topic);
2633
2602
  return [...new Set(topics)].sort();
2634
2603
  }
2635
- /**
2636
- * Retrieves all LearningObjective details for a given list of topics.
2637
- * @param topics An array of topic strings to search for.
2638
- * @returns An array of matching LearningObjective objects.
2639
- */
2640
2604
  static getLearningObjectivesByTopics(topics) {
2641
2605
  const data = this.getData();
2642
2606
  const topicSet = new Set(topics);
@@ -2684,9 +2648,9 @@ var calculateCombinedDifficulty = (plannedQ) => {
2684
2648
  break;
2685
2649
  }
2686
2650
  const totalScore = bloomScore + contextScore + questionTypeScore;
2687
- if (totalScore <= 4) return "easy";
2688
- if (totalScore <= 7) return "medium";
2689
- return "hard";
2651
+ if (totalScore <= 4) return "Easy";
2652
+ if (totalScore <= 7) return "Medium";
2653
+ return "Hard";
2690
2654
  };
2691
2655
  async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
2692
2656
  const { quizPlan, language, imageContexts } = clientInput;
@@ -2699,7 +2663,7 @@ async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
2699
2663
  let lastError = null;
2700
2664
  for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
2701
2665
  try {
2702
- const fullLO = plannedQ.originalLoId ? allLearningObjectives.find((lo) => lo.loId === plannedQ.originalLoId) : null;
2666
+ const fullLO = plannedQ.originalLoId ? allLearningObjectives.find((lo) => lo.code === plannedQ.originalLoId) : null;
2703
2667
  const quizContext = {
2704
2668
  plannedTopic: plannedQ.plannedTopic,
2705
2669
  plannedQuestionType: plannedQ.plannedQuestionType,
@@ -2712,7 +2676,7 @@ async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
2712
2676
  originalSubject: plannedQ.originalSubject,
2713
2677
  originalCategory: plannedQ.originalCategory,
2714
2678
  originalTopic: plannedQ.originalTopic,
2715
- loDescription: fullLO?.loDescription || plannedQ.plannedTopic
2679
+ description: fullLO?.description || plannedQ.plannedTopic
2716
2680
  };
2717
2681
  const imageUrl = plannedQ.imageId && imageContexts ? imageContexts.find((ctx) => ctx.id === plannedQ.imageId)?.imageUrl : void 0;
2718
2682
  const baseClientInput = {
@@ -2901,7 +2865,7 @@ zod.z.object({
2901
2865
  }))
2902
2866
  })).optional(),
2903
2867
  allAvailableTopics: zod.z.array(zod.z.object({
2904
- loId: zod.z.string(),
2868
+ code: zod.z.string(),
2905
2869
  subject: zod.z.string(),
2906
2870
  category: zod.z.string(),
2907
2871
  topic: zod.z.string()
@@ -2910,7 +2874,7 @@ zod.z.object({
2910
2874
  var PracticeSuggestionOutputSchema = zod.z.object({
2911
2875
  suggestionText: zod.z.string().describe("The personalized message from the AI tutor in Markdown format."),
2912
2876
  suggestedTopics: zod.z.array(zod.z.object({
2913
- loId: zod.z.string(),
2877
+ code: zod.z.string(),
2914
2878
  topicName: zod.z.string(),
2915
2879
  reason: zod.z.enum(["review", "explore"]),
2916
2880
  suggestedDifficulty: zod.z.enum(["Very Easy", "Easy", "Medium", "Hard", "Expert"])
@@ -2951,8 +2915,8 @@ Return a single, valid JSON object in this exact format. All text must be in ${l
2951
2915
  {
2952
2916
  "suggestionText": "Ch\xE0o ${userName || "b\u1EA1n"}, t\xF4i \u0111\xE3 xem qua k\u1EBFt qu\u1EA3 c\u1EE7a b\u1EA1n! \u0110\u1EC3 c\u1EE7ng c\u1ED1 ki\u1EBFn th\u1EE9c, ch\xFAng ta h\xE3y \xF4n l\u1EA1i ch\u1EE7 \u0111\u1EC1 [T\xEAn ch\u1EE7 \u0111\u1EC1 y\u1EBFu] \u1EDF m\u1EE9c \u0111\u1ED9 'Easy' nh\xE9. V\xEC b\u1EA1n \u0111\xE3 l\xE0m r\u1EA5t t\u1ED1t ph\u1EA7n [T\xEAn ch\u1EE7 \u0111\u1EC1 m\u1EA1nh], h\xE3y th\u1EED s\u1EE9c v\u1EDBi ch\u1EE7 \u0111\u1EC1 li\xEAn quan l\xE0 [T\xEAn ch\u1EE7 \u0111\u1EC1 kh\xE1m ph\xE1] \u1EDF m\u1EE9c \u0111\u1ED9 'Medium' xem sao!",
2953
2917
  "suggestedTopics": [
2954
- { "loId": "some-lo-id-1", "topicName": "[T\xEAn ch\u1EE7 \u0111\u1EC1 y\u1EBFu]", "reason": "review", "suggestedDifficulty": "Easy" },
2955
- { "loId": "some-lo-id-2", "topicName": "[T\xEAn ch\u1EE7 \u0111\u1EC1 kh\xE1m ph\xE1]", "reason": "explore", "suggestedDifficulty": "Medium" }
2918
+ { "code": "some-lo-id-1", "topicName": "[T\xEAn ch\u1EE7 \u0111\u1EC1 y\u1EBFu]", "reason": "review", "suggestedDifficulty": "Easy" },
2919
+ { "code": "some-lo-id-2", "topicName": "[T\xEAn ch\u1EE7 \u0111\u1EC1 kh\xE1m ph\xE1]", "reason": "explore", "suggestedDifficulty": "Medium" }
2956
2920
  ]
2957
2921
  }
2958
2922
 
@@ -2997,7 +2961,7 @@ zod.z.object({
2997
2961
  startDate: zod.z.string().describe("The start date for the analysis period in ISO format (YYYY-MM-DD)."),
2998
2962
  endDate: zod.z.string().describe("The end date for the analysis period in ISO format (YYYY-MM-DD)."),
2999
2963
  allAvailableTopics: zod.z.array(zod.z.object({
3000
- loId: zod.z.string(),
2964
+ code: zod.z.string(),
3001
2965
  subject: zod.z.string(),
3002
2966
  category: zod.z.string(),
3003
2967
  topic: zod.z.string()
@@ -3008,7 +2972,7 @@ var RoadmapItemSchema = zod.z.object({
3008
2972
  topicName: zod.z.string(),
3009
2973
  reason: zod.z.string(),
3010
2974
  suggestedDifficulty: zod.z.enum(["Very Easy", "Easy", "Medium", "Hard", "Expert"]),
3011
- loId: zod.z.string(),
2975
+ code: zod.z.string(),
3012
2976
  isCompleted: zod.z.boolean()
3013
2977
  });
3014
2978
  var WeeklyRoadmapSchema = zod.z.object({
@@ -3073,7 +3037,7 @@ All topic names and loIds in your "weeklyRoadmap" output MUST be chosen directly
3073
3037
  - **gamificationRemarks**: Write an encouraging message mentioning their achievements.
3074
3038
  2. **For "weeklyRoadmap":**
3075
3039
  - Create a 5-item roadmap for the upcoming week.
3076
- - Prioritize the "areasForImprovement" you identified. For each, find the corresponding entry in "All Available Topics" and use its "topicName" and "loId".
3040
+ - Prioritize the "areasForImprovement" you identified. For each, find the corresponding entry in "All Available Topics" and use its "topicName" and "code".
3077
3041
  - If more items are needed, select related topics from "All Available Topics".
3078
3042
 
3079
3043
  **IF Practice History IS EMPTY:**
@@ -3084,7 +3048,7 @@ All topic names and loIds in your "weeklyRoadmap" output MUST be chosen directly
3084
3048
  - **gamificationRemarks**: Write a general motivational message about starting to learn.
3085
3049
  2. **For "weeklyRoadmap":**
3086
3050
  - Create a 5-item "starter" roadmap.
3087
- - Select 5 diverse and foundational topics directly from the "All Available Topics" list. Use their exact "topicName" and "loId".
3051
+ - Select 5 diverse and foundational topics directly from the "All Available Topics" list. Use their exact "topicName" and "code".
3088
3052
  - For the "reason", explain that this is a good starting point to explore the subject.
3089
3053
 
3090
3054
  --- END LOGIC FLOW ---
@@ -3112,7 +3076,7 @@ The 'suggestedDifficulty' field MUST ALWAYS be one of these exact English string
3112
3076
  "topicName": "Topic C",
3113
3077
  "reason": "To strengthen your understanding of this key area.",
3114
3078
  "suggestedDifficulty": "Easy",
3115
- "loId": "lo-id-for-topic-c-from-the-list",
3079
+ "code": "lo-id-for-topic-c-from-the-list",
3116
3080
  "isCompleted": false
3117
3081
  }
3118
3082
  ]
@@ -3350,11 +3314,11 @@ Now, generate the JSON for the requested knowledge card.`;
3350
3314
  }
3351
3315
  }
3352
3316
  var LearningObjectiveContextSchema = zod.z.object({
3353
- loId: zod.z.string(),
3317
+ code: zod.z.string(),
3354
3318
  subject: zod.z.string(),
3355
3319
  category: zod.z.string(),
3356
3320
  topic: zod.z.string(),
3357
- loDescription: zod.z.string()
3321
+ description: zod.z.string()
3358
3322
  });
3359
3323
  zod.z.object({
3360
3324
  language: zod.z.string().default("English"),
@@ -3362,7 +3326,7 @@ zod.z.object({
3362
3326
  learningObjectives: zod.z.array(LearningObjectiveContextSchema).min(1, { message: "At least one learning objective is required for mapping." })
3363
3327
  });
3364
3328
  var MappedLOSchema = zod.z.object({
3365
- loId: zod.z.string().describe("The exact loId from the provided learning objectives list that matches the document content."),
3329
+ code: zod.z.string().describe("The exact code from the provided learning objectives list that matches the document content."),
3366
3330
  confidence: zod.z.number().min(0).max(100).describe("A confidence score (0-100) of how well the document maps to this LO."),
3367
3331
  reasoning: zod.z.string().describe("A brief explanation for why this mapping is relevant.")
3368
3332
  });
@@ -3398,7 +3362,7 @@ You are an expert curriculum analyst. Your task is to analyze a given document a
3398
3362
  1. **Overall Relevance Assessment:** Read the document content and compare it against the entire list of LOs. Assign an overall "relevanceScore" from 0 (completely unrelated) to 100 (perfectly aligned with one or more LOs).
3399
3363
 
3400
3364
  2. **Specific Mapping:** Identify which specific LOs from the list are directly addressed by the document. For each match you find, provide:
3401
- - The exact "loId" of the matched LO.
3365
+ - The exact "code" of the matched LO.
3402
3366
  - A "confidence" score (0-100) for that specific match.
3403
3367
  - A brief "reasoning" in ${language} explaining why the document content maps to that LO.
3404
3368
 
@@ -3413,7 +3377,7 @@ Return a single, valid JSON object in this EXACT format. Do not include any othe
3413
3377
  "isFreestyleRecommended": false,
3414
3378
  "mappedLOs": [
3415
3379
  {
3416
- "loId": "SWIFT_FUNC_01",
3380
+ "code": "SWIFT_FUNC_01",
3417
3381
  "confidence": 95,
3418
3382
  "reasoning": "The document provides a detailed explanation of function syntax and default parameters, which directly aligns with this learning objective."
3419
3383
  }
@@ -3502,7 +3466,7 @@ Return the response as a single JSON object with a key "generatedQuestions" cont
3502
3466
  "correctTempOptionId": "A",
3503
3467
  "explanation": "The document states that mitochondria are the powerhouses of the cell, responsible for cellular respiration.",
3504
3468
  "points": 10,
3505
- "difficulty": "medium",
3469
+ "difficulty": "Medium",
3506
3470
  "topic": "Cell Biology"
3507
3471
  },
3508
3472
  {
@@ -3511,7 +3475,7 @@ Return the response as a single JSON object with a key "generatedQuestions" cont
3511
3475
  "correctAnswer": false,
3512
3476
  "explanation": "The text specifies that the cell wall is a feature of plant cells, not animal cells.",
3513
3477
  "points": 10,
3514
- "difficulty": "easy",
3478
+ "difficulty": "Easy",
3515
3479
  "topic": "Cell Biology"
3516
3480
  }
3517
3481
  ]