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

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/dist/ai.mjs CHANGED
@@ -92,12 +92,12 @@ var QuizContextSchema = z.object({
92
92
  originalSubject: z.string().optional(),
93
93
  originalCategory: z.string().optional(),
94
94
  originalTopic: z.string().optional(),
95
- loDescription: z.string().optional().describe("The full description of the learning objective for deep context."),
95
+ description: z.string().optional().describe("The full description of the learning objective for deep context."),
96
96
  gradeBand: z.string().optional()
97
97
  });
98
98
  var BaseQuestionGenerationClientInputSchema = z.object({
99
99
  language: z.string().optional().default("English"),
100
- difficulty: z.enum(["easy", "medium", "hard"]),
100
+ difficulty: z.enum(["Easy", "Medium", "Hard"]),
101
101
  quizContext: QuizContextSchema.optional(),
102
102
  imageUrl: z.string().url().optional().describe("Optional URL of an image to be used as context.")
103
103
  });
@@ -106,7 +106,7 @@ var BaseQuestionZodSchema = z.object({
106
106
  prompt: z.string().min(1),
107
107
  points: z.number().min(0).optional(),
108
108
  explanation: z.string().optional(),
109
- difficulty: z.enum(["easy", "medium", "hard"]).optional(),
109
+ difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
110
110
  topic: z.string().optional(),
111
111
  category: z.string().optional(),
112
112
  subject: z.string().optional(),
@@ -202,7 +202,7 @@ var AITrueFalseOutputFieldsSchema = z.object({
202
202
  correctAnswer: z.boolean(),
203
203
  explanation: z.string().optional().describe("An explanation of why the statement is true or false, especially important if false."),
204
204
  points: z.number().optional().default(10),
205
- difficulty: z.enum(["easy", "medium", "hard"]).optional(),
205
+ difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
206
206
  topic: z.string().optional(),
207
207
  verifiedCategory: z.string().optional()
208
208
  // Thêm để xác thực
@@ -223,7 +223,7 @@ Previous attempts failed. Ensure the JSON is valid and 'correctAnswer' is a bool
223
223
  const misconceptionGuidance = quizContext?.targetMisconception ? `**Target Misconception:** The statement you create MUST be FALSE and based on this common mistake: "${quizContext.targetMisconception}"` : "";
224
224
  const contextStrings = [
225
225
  `**Required Category:** ${category}`,
226
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
226
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
227
227
  imageContextInstruction,
228
228
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
229
229
  misconceptionGuidance,
@@ -234,7 +234,7 @@ Previous attempts failed. Ensure the JSON is valid and 'correctAnswer' is a bool
234
234
  correctAnswer: true,
235
235
  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 '!'.",
236
236
  points: 10,
237
- difficulty: "easy",
237
+ difficulty: "Easy",
238
238
  topic: "Swift Optionals",
239
239
  verifiedCategory: category
240
240
  }, null, 2);
@@ -364,7 +364,7 @@ var AIMCQOutputFieldsSchema = z.object({
364
364
  correctTempOptionId: z.string().describe("The temporary ID of the correct option from the generated options array."),
365
365
  explanation: z.string().optional().describe("A brief explanation of why the answer is correct."),
366
366
  points: z.number().optional().default(10),
367
- difficulty: z.enum(["easy", "medium", "hard"]).optional(),
367
+ difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
368
368
  topic: z.string().optional(),
369
369
  verifiedCategory: z.string().optional().describe("The category this question actually addresses.")
370
370
  });
@@ -383,7 +383,7 @@ Previous attempts failed...
383
383
  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.` : "";
384
384
  const contextStrings = [
385
385
  `**Required Category:** ${category}`,
386
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
386
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
387
387
  imageContextInstruction,
388
388
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
389
389
  quizContext?.targetMisconception && `**Target Misconception:** Use this to create plausible incorrect answers: "${quizContext.targetMisconception}"`,
@@ -400,7 +400,7 @@ Previous attempts failed...
400
400
  correctTempOptionId: "C",
401
401
  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.`,
402
402
  points: 10,
403
- difficulty: "easy",
403
+ difficulty: "Easy",
404
404
  topic: `Control Flow in ${category}`,
405
405
  verifiedCategory: category
406
406
  }, null, 2);
@@ -542,7 +542,7 @@ var AIMRQOutputFieldsSchema = z.object({
542
542
  correctTempOptionIds: z.array(z.string()).min(1),
543
543
  explanation: z.string().optional(),
544
544
  points: z.number().optional().default(10),
545
- difficulty: z.enum(["easy", "medium", "hard"]).optional(),
545
+ difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
546
546
  topic: z.string().optional(),
547
547
  verifiedCategory: z.string().optional().describe("The category this question actually addresses.")
548
548
  });
@@ -561,7 +561,7 @@ Previous attempts failed due to validation errors. Pay close attention to the nu
561
561
  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.` : "";
562
562
  const contextStrings = [
563
563
  `**Required Category:** ${category} (This is the ONLY language to be used)`,
564
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
564
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
565
565
  imageContextInstruction,
566
566
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
567
567
  quizContext?.targetMisconception && `**Target Misconception:** Use this to create plausible incorrect answers (distractors). The misconception is: "${quizContext.targetMisconception}"`,
@@ -579,7 +579,7 @@ Previous attempts failed due to validation errors. Pay close attention to the nu
579
579
  correctTempOptionIds: ["A", "C", "D"],
580
580
  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.",
581
581
  points: 10,
582
- difficulty: "medium",
582
+ difficulty: "Medium",
583
583
  topic: "Programming Paradigms",
584
584
  verifiedCategory: category
585
585
  }, null, 2);
@@ -737,7 +737,7 @@ var AIShortAnswerOutputFieldsSchema = z.object({
737
737
  // isCaseSensitive không cần thiết ở đây, chúng ta sẽ quản lý nó ở phía client
738
738
  explanation: z.string().optional(),
739
739
  points: z.number().optional().default(10),
740
- difficulty: z.enum(["easy", "medium", "hard"]).optional(),
740
+ difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
741
741
  topic: z.string().optional(),
742
742
  verifiedCategory: z.string().optional()
743
743
  // Thêm để xác thực
@@ -757,7 +757,7 @@ Previous attempts failed. Ensure 'acceptedAnswers' is a non-empty array of strin
757
757
  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.` : "";
758
758
  const contextStrings = [
759
759
  `**Required Category:** ${category}`,
760
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
760
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
761
761
  imageContextInstruction,
762
762
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
763
763
  quizContext?.targetMisconception && `**Target Misconception:** The question should require an answer that corrects this specific misconception: "${quizContext.targetMisconception}"`
@@ -767,7 +767,7 @@ Previous attempts failed. Ensure 'acceptedAnswers' is a non-empty array of strin
767
767
  acceptedAnswers: ["let"],
768
768
  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.",
769
769
  points: 10,
770
- difficulty: "easy",
770
+ difficulty: "Easy",
771
771
  topic: "Swift Constants",
772
772
  verifiedCategory: category
773
773
  }, null, 2);
@@ -894,7 +894,7 @@ var AINumericOutputFieldsSchema = z.object({
894
894
  tolerance: z.number().min(0).optional(),
895
895
  explanation: z.string().optional(),
896
896
  points: z.number().optional().default(10),
897
- difficulty: z.enum(["easy", "medium", "hard"]).optional(),
897
+ difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
898
898
  topic: z.string().optional(),
899
899
  verifiedCategory: z.string().optional()
900
900
  // Thêm để xác thực
@@ -914,7 +914,7 @@ Previous attempts failed. Ensure the 'answer' is a valid number and fits within
914
914
  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.` : "";
915
915
  const contextStrings = [
916
916
  `**Required Category:** ${category}`,
917
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
917
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
918
918
  imageContextInstruction,
919
919
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
920
920
  quizContext?.targetMisconception && `**Target Misconception:** The question should clarify this numerical error: "${quizContext.targetMisconception}"`
@@ -930,7 +930,7 @@ Previous attempts failed. Ensure the 'answer' is a valid number and fits within
930
930
  tolerance: 0,
931
931
  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).",
932
932
  points: 10,
933
- difficulty: "medium",
933
+ difficulty: "Medium",
934
934
  topic: "Swift Data Types",
935
935
  verifiedCategory: category
936
936
  }, null, 2);
@@ -1074,7 +1074,7 @@ var AIFillInTheBlanksOutputFieldsSchema = z.object({
1074
1074
  })).min(1).describe("An array of text and blank segments representing the question."),
1075
1075
  explanation: z.string().optional(),
1076
1076
  points: z.number().optional().default(10),
1077
- difficulty: z.enum(["easy", "medium", "hard"]).optional(),
1077
+ difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
1078
1078
  topic: z.string().optional(),
1079
1079
  verifiedCategory: z.string().optional()
1080
1080
  // Thêm để xác thực
@@ -1094,7 +1094,7 @@ Previous attempts failed. Pay strict attention to the JSON schema, especially th
1094
1094
  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.` : "";
1095
1095
  const contextStrings = [
1096
1096
  `**Required Category:** ${category}`,
1097
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
1097
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
1098
1098
  imageContextInstruction,
1099
1099
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
1100
1100
  quizContext?.targetMisconception && `**Target Misconception:** Design the blank to test this specific point: "${quizContext.targetMisconception}"`
@@ -1108,7 +1108,7 @@ Previous attempts failed. Pay strict attention to the JSON schema, especially th
1108
1108
  ],
1109
1109
  explanation: "The 'func' keyword is used to declare a function in the Swift programming language.",
1110
1110
  points: 10,
1111
- difficulty: "easy",
1111
+ difficulty: "Easy",
1112
1112
  topic: "Swift Function Declaration",
1113
1113
  verifiedCategory: category
1114
1114
  }, null, 2);
@@ -1256,7 +1256,7 @@ var AISequenceOutputFieldsSchema = z.object({
1256
1256
  itemsInCorrectOrder: z.array(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."),
1257
1257
  explanation: z.string().optional(),
1258
1258
  points: z.number().optional().default(10),
1259
- difficulty: z.enum(["easy", "medium", "hard"]).optional(),
1259
+ difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
1260
1260
  topic: z.string().optional(),
1261
1261
  verifiedCategory: z.string().optional()
1262
1262
  // Thêm để xác thực
@@ -1276,7 +1276,7 @@ Previous attempts failed. Ensure the 'itemsInCorrectOrder' array has exactly the
1276
1276
  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.` : "";
1277
1277
  const contextStrings = [
1278
1278
  `**Required Category:** ${category}`,
1279
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
1279
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
1280
1280
  imageContextInstruction,
1281
1281
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
1282
1282
  quizContext?.targetMisconception && `**Target Misconception:** The sequence should clarify this specific process error: "${quizContext.targetMisconception}"`
@@ -1291,7 +1291,7 @@ Previous attempts failed. Ensure the 'itemsInCorrectOrder' array has exactly the
1291
1291
  ],
1292
1292
  explanation: "This is the fundamental sequence for a basic data task in URLSession.",
1293
1293
  points: 10,
1294
- difficulty: "medium",
1294
+ difficulty: "Medium",
1295
1295
  topic: "Swift Networking",
1296
1296
  verifiedCategory: category
1297
1297
  }, null, 2);
@@ -1427,7 +1427,7 @@ var AIMatchingOutputFieldsSchema = z.object({
1427
1427
  })).min(2),
1428
1428
  explanation: z.string().optional(),
1429
1429
  points: z.number().optional().default(10),
1430
- difficulty: z.enum(["easy", "medium", "hard"]).optional(),
1430
+ difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
1431
1431
  topic: z.string().optional(),
1432
1432
  verifiedCategory: z.string().optional()
1433
1433
  // Thêm để xác thực
@@ -1447,7 +1447,7 @@ Previous attempts failed. Please ensure the 'correctPairs' array has exactly the
1447
1447
  const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The matching pairs must be directly related to the content of this image.` : "";
1448
1448
  const contextStrings = [
1449
1449
  `**Required Category:** ${category}`,
1450
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
1450
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
1451
1451
  imageContextInstruction,
1452
1452
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
1453
1453
  quizContext?.targetMisconception && `**Target Misconception:** Design a pair that specifically tests this confusion: "${quizContext.targetMisconception}"`
@@ -1461,7 +1461,7 @@ Previous attempts failed. Please ensure the 'correctPairs' array has exactly the
1461
1461
  ],
1462
1462
  explanation: "These are the fundamental characteristics of Swift's main collection types.",
1463
1463
  points: 10,
1464
- difficulty: "easy",
1464
+ difficulty: "Easy",
1465
1465
  topic: "Swift Collection Types",
1466
1466
  verifiedCategory: category
1467
1467
  }, null, 2);
@@ -1622,7 +1622,7 @@ Previous attempts failed. Pay strict attention to the JSON schema and all rules.
1622
1622
  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.` : "";
1623
1623
  const contextStrings = [
1624
1624
  `**Subject:** ${subject}`,
1625
- quizContext?.loDescription && `**Learning Objective:** ${quizContext.loDescription}`,
1625
+ quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
1626
1626
  imageContextInstruction,
1627
1627
  quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
1628
1628
  quizContext?.targetMisconception && `**Target Misconception:** The problem should test against this common error: "${quizContext.targetMisconception}"`
@@ -2494,10 +2494,6 @@ function validateConsecutiveTypes(quizPlan) {
2494
2494
 
2495
2495
  // src/services/TopicDataService.ts
2496
2496
  var TopicDataService = class {
2497
- /**
2498
- * Saves an array of LearningObjective objects to Local Storage, overwriting existing data.
2499
- * @param data The array of learning objectives to save.
2500
- */
2501
2497
  static saveData(data) {
2502
2498
  try {
2503
2499
  if (typeof window === "undefined") return;
@@ -2507,24 +2503,15 @@ var TopicDataService = class {
2507
2503
  console.error("Error saving learning objectives to Local Storage:", error);
2508
2504
  }
2509
2505
  }
2510
- /**
2511
- * Merges a new set of learning objectives with the existing data in Local Storage.
2512
- * If an LO ID from newData already exists, it will be updated. Otherwise, it will be added.
2513
- * @param newData The array of new or updated learning objectives.
2514
- */
2515
2506
  static mergeData(newData) {
2516
2507
  const existingData = this.getData();
2517
- const loMap = new Map(existingData.map((lo) => [lo.loId, lo]));
2508
+ const loMap = new Map(existingData.map((lo) => [lo.code, lo]));
2518
2509
  newData.forEach((newLo) => {
2519
- loMap.set(newLo.loId, newLo);
2510
+ loMap.set(newLo.code, newLo);
2520
2511
  });
2521
2512
  const mergedData = Array.from(loMap.values());
2522
2513
  this.saveData(mergedData);
2523
2514
  }
2524
- /**
2525
- * Retrieves the array of LearningObjective objects from Local Storage.
2526
- * @returns An array of learning objectives, or an empty array if none are found or an error occurs.
2527
- */
2528
2515
  static getData() {
2529
2516
  try {
2530
2517
  if (typeof window === "undefined") return [];
@@ -2536,9 +2523,6 @@ var TopicDataService = class {
2536
2523
  return [];
2537
2524
  }
2538
2525
  }
2539
- /**
2540
- * Removes all learning objective data from Local Storage.
2541
- */
2542
2526
  static clearData() {
2543
2527
  try {
2544
2528
  if (typeof window === "undefined") return;
@@ -2547,11 +2531,6 @@ var TopicDataService = class {
2547
2531
  console.error("Error clearing learning objectives from Local Storage:", error);
2548
2532
  }
2549
2533
  }
2550
- /**
2551
- * Parses TSV content into an array of LearningObjective objects.
2552
- * @param tsvContent The raw string content from a .tsv file.
2553
- * @returns An object containing the successfully parsed data and any errors encountered.
2554
- */
2555
2534
  static parseTSV(tsvContent) {
2556
2535
  const lines = tsvContent.split("\n").filter((line) => line.trim() !== "");
2557
2536
  if (lines.length < 2) {
@@ -2573,6 +2552,7 @@ var TopicDataService = class {
2573
2552
  }
2574
2553
  const [
2575
2554
  loId,
2555
+ name,
2576
2556
  loDescription,
2577
2557
  subject,
2578
2558
  category,
@@ -2582,18 +2562,21 @@ var TopicDataService = class {
2582
2562
  stemElementsStr,
2583
2563
  bloomLevelsStr
2584
2564
  ] = values;
2585
- if (!loId || !subject || !category || !topic) {
2586
- errors.push(`Line ${index + 2}: Missing required fields (LO ID, Subject, Category, or Topic).`);
2565
+ if (!loId || !loDescription || !subject || !category || !topic) {
2566
+ errors.push(`Line ${index + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
2587
2567
  return;
2588
2568
  }
2589
2569
  const learningObjective = {
2590
- loId,
2591
- loDescription,
2570
+ id: generateUniqueId("lo_"),
2571
+ code: loId,
2572
+ name,
2573
+ description: loDescription,
2574
+ // Can be the same as name or enhanced later
2592
2575
  subject,
2593
2576
  category,
2594
2577
  topic,
2595
- keywords: keywordsStr.split(",").map((k) => k.trim()).filter(Boolean),
2596
2578
  grade,
2579
+ keywords: keywordsStr.split(",").map((k) => k.trim()).filter(Boolean),
2597
2580
  stemElements: stemElementsStr.split(",").map((s) => s.trim()).filter(Boolean),
2598
2581
  bloomLevelsGuideline: bloomLevelsStr.split(",").map((b) => b.trim()).filter(Boolean)
2599
2582
  };
@@ -2601,40 +2584,21 @@ var TopicDataService = class {
2601
2584
  });
2602
2585
  return { data, errors };
2603
2586
  }
2604
- /**
2605
- * Gets a unique list of all subjects from the stored data.
2606
- * @returns An array of subject strings.
2607
- */
2608
2587
  static getSubjects() {
2609
2588
  const data = this.getData();
2610
2589
  const subjects = data.map((item) => item.subject);
2611
2590
  return [...new Set(subjects)].sort();
2612
2591
  }
2613
- /**
2614
- * Gets a unique list of categories for a given subject.
2615
- * @param subject The subject to filter by.
2616
- * @returns An array of category strings.
2617
- */
2618
2592
  static getCategoriesBySubject(subject) {
2619
2593
  const data = this.getData();
2620
2594
  const categories = data.filter((item) => item.subject === subject).map((item) => item.category);
2621
2595
  return [...new Set(categories)].sort();
2622
2596
  }
2623
- /**
2624
- * Gets a unique list of topics for a given category.
2625
- * @param category The category to filter by.
2626
- * @returns An array of topic strings.
2627
- */
2628
2597
  static getTopicsByCategory(category) {
2629
2598
  const data = this.getData();
2630
2599
  const topics = data.filter((item) => item.category === category).map((item) => item.topic);
2631
2600
  return [...new Set(topics)].sort();
2632
2601
  }
2633
- /**
2634
- * Retrieves all LearningObjective details for a given list of topics.
2635
- * @param topics An array of topic strings to search for.
2636
- * @returns An array of matching LearningObjective objects.
2637
- */
2638
2602
  static getLearningObjectivesByTopics(topics) {
2639
2603
  const data = this.getData();
2640
2604
  const topicSet = new Set(topics);
@@ -2682,9 +2646,9 @@ var calculateCombinedDifficulty = (plannedQ) => {
2682
2646
  break;
2683
2647
  }
2684
2648
  const totalScore = bloomScore + contextScore + questionTypeScore;
2685
- if (totalScore <= 4) return "easy";
2686
- if (totalScore <= 7) return "medium";
2687
- return "hard";
2649
+ if (totalScore <= 4) return "Easy";
2650
+ if (totalScore <= 7) return "Medium";
2651
+ return "Hard";
2688
2652
  };
2689
2653
  async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
2690
2654
  const { quizPlan, language, imageContexts } = clientInput;
@@ -2697,7 +2661,7 @@ async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
2697
2661
  let lastError = null;
2698
2662
  for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
2699
2663
  try {
2700
- const fullLO = plannedQ.originalLoId ? allLearningObjectives.find((lo) => lo.loId === plannedQ.originalLoId) : null;
2664
+ const fullLO = plannedQ.originalLoId ? allLearningObjectives.find((lo) => lo.code === plannedQ.originalLoId) : null;
2701
2665
  const quizContext = {
2702
2666
  plannedTopic: plannedQ.plannedTopic,
2703
2667
  plannedQuestionType: plannedQ.plannedQuestionType,
@@ -2710,7 +2674,7 @@ async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
2710
2674
  originalSubject: plannedQ.originalSubject,
2711
2675
  originalCategory: plannedQ.originalCategory,
2712
2676
  originalTopic: plannedQ.originalTopic,
2713
- loDescription: fullLO?.loDescription || plannedQ.plannedTopic
2677
+ description: fullLO?.description || plannedQ.plannedTopic
2714
2678
  };
2715
2679
  const imageUrl = plannedQ.imageId && imageContexts ? imageContexts.find((ctx) => ctx.id === plannedQ.imageId)?.imageUrl : void 0;
2716
2680
  const baseClientInput = {
@@ -2899,7 +2863,7 @@ z.object({
2899
2863
  }))
2900
2864
  })).optional(),
2901
2865
  allAvailableTopics: z.array(z.object({
2902
- loId: z.string(),
2866
+ code: z.string(),
2903
2867
  subject: z.string(),
2904
2868
  category: z.string(),
2905
2869
  topic: z.string()
@@ -2908,7 +2872,7 @@ z.object({
2908
2872
  var PracticeSuggestionOutputSchema = z.object({
2909
2873
  suggestionText: z.string().describe("The personalized message from the AI tutor in Markdown format."),
2910
2874
  suggestedTopics: z.array(z.object({
2911
- loId: z.string(),
2875
+ code: z.string(),
2912
2876
  topicName: z.string(),
2913
2877
  reason: z.enum(["review", "explore"]),
2914
2878
  suggestedDifficulty: z.enum(["Very Easy", "Easy", "Medium", "Hard", "Expert"])
@@ -2949,8 +2913,8 @@ Return a single, valid JSON object in this exact format. All text must be in ${l
2949
2913
  {
2950
2914
  "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!",
2951
2915
  "suggestedTopics": [
2952
- { "loId": "some-lo-id-1", "topicName": "[T\xEAn ch\u1EE7 \u0111\u1EC1 y\u1EBFu]", "reason": "review", "suggestedDifficulty": "Easy" },
2953
- { "loId": "some-lo-id-2", "topicName": "[T\xEAn ch\u1EE7 \u0111\u1EC1 kh\xE1m ph\xE1]", "reason": "explore", "suggestedDifficulty": "Medium" }
2916
+ { "code": "some-lo-id-1", "topicName": "[T\xEAn ch\u1EE7 \u0111\u1EC1 y\u1EBFu]", "reason": "review", "suggestedDifficulty": "Easy" },
2917
+ { "code": "some-lo-id-2", "topicName": "[T\xEAn ch\u1EE7 \u0111\u1EC1 kh\xE1m ph\xE1]", "reason": "explore", "suggestedDifficulty": "Medium" }
2954
2918
  ]
2955
2919
  }
2956
2920
 
@@ -2995,7 +2959,7 @@ z.object({
2995
2959
  startDate: z.string().describe("The start date for the analysis period in ISO format (YYYY-MM-DD)."),
2996
2960
  endDate: z.string().describe("The end date for the analysis period in ISO format (YYYY-MM-DD)."),
2997
2961
  allAvailableTopics: z.array(z.object({
2998
- loId: z.string(),
2962
+ code: z.string(),
2999
2963
  subject: z.string(),
3000
2964
  category: z.string(),
3001
2965
  topic: z.string()
@@ -3006,7 +2970,7 @@ var RoadmapItemSchema = z.object({
3006
2970
  topicName: z.string(),
3007
2971
  reason: z.string(),
3008
2972
  suggestedDifficulty: z.enum(["Very Easy", "Easy", "Medium", "Hard", "Expert"]),
3009
- loId: z.string(),
2973
+ code: z.string(),
3010
2974
  isCompleted: z.boolean()
3011
2975
  });
3012
2976
  var WeeklyRoadmapSchema = z.object({
@@ -3071,7 +3035,7 @@ All topic names and loIds in your "weeklyRoadmap" output MUST be chosen directly
3071
3035
  - **gamificationRemarks**: Write an encouraging message mentioning their achievements.
3072
3036
  2. **For "weeklyRoadmap":**
3073
3037
  - Create a 5-item roadmap for the upcoming week.
3074
- - Prioritize the "areasForImprovement" you identified. For each, find the corresponding entry in "All Available Topics" and use its "topicName" and "loId".
3038
+ - Prioritize the "areasForImprovement" you identified. For each, find the corresponding entry in "All Available Topics" and use its "topicName" and "code".
3075
3039
  - If more items are needed, select related topics from "All Available Topics".
3076
3040
 
3077
3041
  **IF Practice History IS EMPTY:**
@@ -3082,7 +3046,7 @@ All topic names and loIds in your "weeklyRoadmap" output MUST be chosen directly
3082
3046
  - **gamificationRemarks**: Write a general motivational message about starting to learn.
3083
3047
  2. **For "weeklyRoadmap":**
3084
3048
  - Create a 5-item "starter" roadmap.
3085
- - Select 5 diverse and foundational topics directly from the "All Available Topics" list. Use their exact "topicName" and "loId".
3049
+ - Select 5 diverse and foundational topics directly from the "All Available Topics" list. Use their exact "topicName" and "code".
3086
3050
  - For the "reason", explain that this is a good starting point to explore the subject.
3087
3051
 
3088
3052
  --- END LOGIC FLOW ---
@@ -3110,7 +3074,7 @@ The 'suggestedDifficulty' field MUST ALWAYS be one of these exact English string
3110
3074
  "topicName": "Topic C",
3111
3075
  "reason": "To strengthen your understanding of this key area.",
3112
3076
  "suggestedDifficulty": "Easy",
3113
- "loId": "lo-id-for-topic-c-from-the-list",
3077
+ "code": "lo-id-for-topic-c-from-the-list",
3114
3078
  "isCompleted": false
3115
3079
  }
3116
3080
  ]
@@ -3348,11 +3312,11 @@ Now, generate the JSON for the requested knowledge card.`;
3348
3312
  }
3349
3313
  }
3350
3314
  var LearningObjectiveContextSchema = z.object({
3351
- loId: z.string(),
3315
+ code: z.string(),
3352
3316
  subject: z.string(),
3353
3317
  category: z.string(),
3354
3318
  topic: z.string(),
3355
- loDescription: z.string()
3319
+ description: z.string()
3356
3320
  });
3357
3321
  z.object({
3358
3322
  language: z.string().default("English"),
@@ -3360,7 +3324,7 @@ z.object({
3360
3324
  learningObjectives: z.array(LearningObjectiveContextSchema).min(1, { message: "At least one learning objective is required for mapping." })
3361
3325
  });
3362
3326
  var MappedLOSchema = z.object({
3363
- loId: z.string().describe("The exact loId from the provided learning objectives list that matches the document content."),
3327
+ code: z.string().describe("The exact code from the provided learning objectives list that matches the document content."),
3364
3328
  confidence: z.number().min(0).max(100).describe("A confidence score (0-100) of how well the document maps to this LO."),
3365
3329
  reasoning: z.string().describe("A brief explanation for why this mapping is relevant.")
3366
3330
  });
@@ -3396,7 +3360,7 @@ You are an expert curriculum analyst. Your task is to analyze a given document a
3396
3360
  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).
3397
3361
 
3398
3362
  2. **Specific Mapping:** Identify which specific LOs from the list are directly addressed by the document. For each match you find, provide:
3399
- - The exact "loId" of the matched LO.
3363
+ - The exact "code" of the matched LO.
3400
3364
  - A "confidence" score (0-100) for that specific match.
3401
3365
  - A brief "reasoning" in ${language} explaining why the document content maps to that LO.
3402
3366
 
@@ -3411,7 +3375,7 @@ Return a single, valid JSON object in this EXACT format. Do not include any othe
3411
3375
  "isFreestyleRecommended": false,
3412
3376
  "mappedLOs": [
3413
3377
  {
3414
- "loId": "SWIFT_FUNC_01",
3378
+ "code": "SWIFT_FUNC_01",
3415
3379
  "confidence": 95,
3416
3380
  "reasoning": "The document provides a detailed explanation of function syntax and default parameters, which directly aligns with this learning objective."
3417
3381
  }
@@ -3500,7 +3464,7 @@ Return the response as a single JSON object with a key "generatedQuestions" cont
3500
3464
  "correctTempOptionId": "A",
3501
3465
  "explanation": "The document states that mitochondria are the powerhouses of the cell, responsible for cellular respiration.",
3502
3466
  "points": 10,
3503
- "difficulty": "medium",
3467
+ "difficulty": "Medium",
3504
3468
  "topic": "Cell Biology"
3505
3469
  },
3506
3470
  {
@@ -3509,7 +3473,7 @@ Return the response as a single JSON object with a key "generatedQuestions" cont
3509
3473
  "correctAnswer": false,
3510
3474
  "explanation": "The text specifies that the cell wall is a feature of plant cells, not animal cells.",
3511
3475
  "points": 10,
3512
- "difficulty": "easy",
3476
+ "difficulty": "Easy",
3513
3477
  "topic": "Cell Biology"
3514
3478
  }
3515
3479
  ]