@thanh01.pmt/interactive-quiz-kit 1.0.12 → 1.0.15

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
@@ -1,170 +1,63 @@
1
- # Chế độ Headless: Sử dụng Logic của `interactive-quiz-kit` không cần Giao diện
1
+ # Headless Mode: Using `interactive-quiz-kit` Logic Without the UI
2
2
 
3
- **`interactive-quiz-kit`** được thiết kế với kiến trúc module hóa, cho phép bạn sử dụng toàn bộ logic lõi của một cách độc lập mà không cần đến các thành phần giao diện người dùng React. Chế độ "headless" này tưởng cho các trường hợp sử dụng như sau:
3
+ **`interactive-quiz-kit`** is designed with a modular architecture, allowing you to use its entire core logic independently of the React UI components. This "headless" mode is ideal for use cases such as:
4
4
 
5
- * Xây dựng một backend để quản tạo quiz.
6
- * Tích hợp logic quiz vào một ứng dụng di động (React Native, Flutter,...).
7
- * Chạy các script tự động để tạo nội dung hoặc xử lý dữ liệu quiz.
8
- * Tích hợp vào các framework JavaScript khác ngoài React.
5
+ * Building a backend to manage and generate quizzes.
6
+ * Integrating quiz logic into a mobile application (React Native, Flutter, etc.).
7
+ * Running automated scripts for content creation or data processing.
8
+ * Integrating with JavaScript frameworks other than React.
9
9
 
10
- Tài liệu này sẽ hướng dẫn bạn cách import sử dụng các tính năng headless chính của thư viện.
10
+ This document will guide you on how to import and use the library's main headless features.
11
11
 
12
- ## I. Tổng quan các Thành phần Headless
12
+ ## I. Overview of Headless Components & Entry Points
13
13
 
14
- Các thành phần non-UI của thư viện được phân bổ trong các thư mục sau:
14
+ The non-UI components of the library are accessible through specific entry points for optimized, modular usage.
15
15
 
16
- | Thư mục/File | Chức năng Chính |
17
- | :-------------------- | :------------------------------------------------------------------------ |
18
- | `types.ts` | **(Cốt lõi)** Định nghĩa tất cả các cấu trúc dữ liệu (interfaces) cho quiz. |
19
- | `services/` | **(Cốt lõi)** Chứa các service để chạy, quản lý, đóng gói quiz. |
20
- | `ai/` | Chứa các flow để tạo nội dung quiz bằng Trí tuệ Nhân tạo. |
21
- | `utils/idGenerators.ts` | Các hàm tiện ích, dụ như tạo ID duy nhất. |
22
- | `schemas/` | Các file JSON Schema để xác thực cấu trúc dữ liệu của quiz. |
16
+ | Entry Point / File | Main Function |
17
+ | :----------------------------------------------- | :------------------------------------------------------------------------------ |
18
+ | `@thanh01.pmt/interactive-quiz-kit` | **(Core)** Contains all types, core services, and utilities. |
19
+ | `@thanh01.pmt/interactive-quiz-kit/ai` | **(AI)** Contains flows for generating quiz content using Artificial Intelligence. |
20
+ | `src/services/TopicDataService.ts` | **(Service)** Manages curriculum data imported from TSV files. |
21
+ | `src/services/SCORMService.ts` & related files | **(Service)** Provides tools for SCORM packaging and communication. |
23
22
 
24
- ### 1. Chế độ Headless Tại sao nó quan trọng?
23
+ ### 1. What is Headless Mode and Why is it Important?
25
24
 
26
- Hãy tưởng tượng thư viện của bạn như một chiếc xe hơi hoàn chỉnh. Giao diện người dùng (`react-ui/`) chính phần thân vỏ, nội thất, lăng, bảng điều khiểntất cả những bạn thấy và tương tác. "Chế độ headless" chính việc bạn thể lấy toàn bộ **động cơ, khung gầm, hệ thống truyền động và bộ não điều khiển (ECU)** của chiếc xe đó ra lắp vào một thân vỏ khác dụ như một chiếc xe tải, một chiếc thuyền, hoặc thậm chí một cỗ máy công nghiệp.
25
+ Imagine the library is a complete car. The UI (`react-ui/`) is the body, interior, steering wheel, and dashboardeverything you see and interact with. "Headless mode" means you can take the entire **engine, chassis, drivetrain, and control unit (ECU)** and fit it into a different bodylike a truck, a boat, or even an industrial machine.
27
26
 
28
- Nói cách khác, **chế độ headless cho phép bạn sử dụng tất cả các logic, quy trình nghiệp vụ, khả năng xử dữ liệu của thư viện mà không cần đến giao diện người dùng React đi kèm.**
27
+ In other words, **headless mode allows you to use all the logic, business processes, and data handling capabilities of the library without the bundled React UI.**
29
28
 
30
- **Tại sao quan trọng?**
29
+ **Why is this important?**
31
30
 
32
- * **Linh hoạt tối đa:** Bạn không bị trói buộc vào React. Bạn thể xây dựng giao diện bằng Vue, Svelte, Angular, hoặc thậm chí ứng dụng di động native (iOS, Android) chỉ cần gọi đến logic lõi của thư viện.
33
- * **Tự động hóa & Tích hợp Backend:** Bạn thể chạy các quy trình trên server, dụ:
34
- * Một cron job hàng đêm dùng module AI để tự động tạo ra hàng trăm câu hỏi mới lưu vào cơ sở dữ liệu.
35
- * Xây dựng một API endpoint để quản lý, chỉnh sửa, xuất bản các bài quiz.
36
- * **Tái sử dụng Logic:** Đảm bảo logic nghiệp vụ ( dụ: cách chấm điểm một câu hỏi) nhất quán mọi nơi, từ web, mobile đến các script nội bộ.
31
+ * **Maximum Flexibility:** You are not tied to React. You can build your UI with Vue, Svelte, Angular, or even native mobile apps (iOS, Android) and simply call the library's core logic.
32
+ * **Automation & Backend Integration:** You can run processes on a server, for example:
33
+ * A nightly cron job that uses the AI module to automatically generate hundreds of new questions and save them to a database.
34
+ * An API endpoint to manage, edit, and publish quizzes.
35
+ * **Logic Reusability:** Ensures that business logic (e.g., how a question is graded) is consistent everywhere, from the web and mobile to internal scripts.
37
36
 
38
37
  ---
39
38
 
40
- ### 2. Phân tích chi tiết các Thành phần Headless
39
+ ## II. Core Headless Services
41
40
 
42
- Dưới đây từng thành phần, vai trò, và tầm quan trọng của chúng trong chế độ headless.
41
+ ### 1. Types - The Foundation
43
42
 
44
- #### **A. `types.ts` & `schemas/` - Nền tảng & Quy tắc**
45
-
46
- * **Vai trò:** Là "Hiến pháp" và "Bộ luật" của thư viện. Chúng định nghĩa cấu trúc dữ liệu và các quy tắc mà mọi thành phần khác phải tuân theo.
47
- * **Mô tả chi tiết:**
48
- * **`types.ts`:** Đây là file quan trọng nhất. Nó chứa các `interface` TypeScript như `QuizConfig`, `QuizQuestion`, `QuizResult`. Đây là "nguồn chân lý duy nhất" (single source of truth) cho hình dạng của dữ liệu. Bất kỳ hàm nào bạn viết để tương tác với quiz đều sẽ nhận và trả về các kiểu dữ liệu được định nghĩa ở đây.
49
- * **`schemas/`:** Chứa các file JSON Schema. Trong môi trường headless, chúng cực kỳ hữu ích để **xác thực (validate)** dữ liệu. Ví dụ, khi một hệ thống khác gửi cho bạn một file JSON `quiz.json`, bạn có thể dùng schema này để kiểm tra xem file đó có hợp lệ hay không trước khi xử lý.
50
- * **Tầm quan trọng:** **Nền tảng (Fundamental)**. Không thể sử dụng thư viện nếu không hiểu các kiểu dữ liệu này.
51
-
52
- ---
53
-
54
- #### **B. `services/QuizEditorService.ts` - Người Thợ Xây**
55
-
56
- * **Vai trò:** Công cụ để **tạo, sửa, xóa, và sắp xếp** các câu hỏi bên trong một đối tượng `QuizConfig`. Đây là service dành cho khâu *biên soạn (authoring)*.
57
- * **Mô tả chi tiết:**
58
- * Đây là một lớp (class) bạn khởi tạo với một đối tượng `QuizConfig` ban đầu. Nó sẽ làm việc trên một bản sao sâu (deep copy), đảm bảo không làm thay đổi đối tượng gốc một cách không mong muốn (nguyên tắc immutability).
59
- * **`createNewQuestionTemplate(type)` (Static Method):** Tạo ra một "khuôn mẫu" câu hỏi rỗng với các giá trị mặc định. Rất hữu ích khi bạn muốn thêm một câu hỏi mới.
60
- * **`addQuestion(question)`:** Thêm một câu hỏi vào danh sách.
61
- * **`updateQuestion(updatedQuestion)`:** Cập nhật một câu hỏi đã có dựa trên `id` của nó.
62
- * **`deleteQuestionByIndex(index)`:** Xóa một câu hỏi dựa trên vị trí của nó.
63
- * **`moveQuestion(fromIndex, toIndex)`:** Thay đổi thứ tự các câu hỏi.
64
- * **Tầm quan trọng:** **Cốt lõi (Core)** cho bất kỳ tác vụ nào liên quan đến việc quản lý nội dung quiz.
65
-
66
- * **Ví dụ sử dụng:**
67
-
68
- ```typescript
69
- import { QuizEditorService, emptyQuiz } from 'interactive-quiz-kit/services';
70
-
71
- // Bắt đầu với một quiz rỗng
72
- let myQuiz = emptyQuiz;
73
- const editor = new QuizEditorService(myQuiz);
74
-
75
- // Thêm một câu hỏi True/False
76
- const tfQuestion = QuizEditorService.createNewQuestionTemplate('true_false');
77
- tfQuestion.prompt = "Trái Đất có phải là một hình cầu hoàn hảo không?";
78
- if (tfQuestion.questionType === 'true_false') tfQuestion.correctAnswer = false;
79
-
80
- myQuiz = editor.addQuestion(tfQuestion);
81
-
82
- // Cập nhật lại tiêu đề quiz
83
- myQuiz.title = "Quiz đã được cập nhật bằng code";
84
-
85
- console.log(myQuiz);
86
- ```
87
-
88
- ---
89
-
90
- #### **C. `services/QuizEngine.ts` - Nhạc trưởng Điều hành**
91
-
92
- * **Vai trò:** Quản lý toàn bộ vòng đời của một **phiên làm bài quiz thực tế**. Đây là service dành cho khâu *thực thi (runtime)*.
93
- * **Mô tả chi tiết:**
94
- * Khởi tạo với một `QuizConfig` và một bộ `callbacks`. Thiết kế dựa trên callback này làm cho nó cực kỳ linh hoạt để tích hợp vào bất kỳ hệ thống nào.
95
- * Nó quản lý trạng thái nội bộ: câu hỏi hiện tại, câu trả lời của người dùng, thời gian còn lại.
96
- * Cung cấp các phương thức công khai (public methods) như `nextQuestion()`, `previousQuestion()`, `submitAnswer()`, và `calculateResults()` để điều khiển luồng làm bài.
97
- * Logic chấm điểm phức tạp cho 12 loại câu hỏi được đóng gói hoàn toàn bên trong `evaluateQuestion`.
98
- * **Tầm quan trọng:** **Cốt lõi (Core)** cho bất kỳ ứng dụng nào muốn cho người dùng *làm* bài quiz.
99
-
100
- ---
101
-
102
- #### **D. `ai/flows/` - Bộ não Sáng tạo**
103
-
104
- * **Vai trò:** Cung cấp các hàm `async` để giao tiếp với AI và tự động tạo ra nội dung quiz.
105
- * **Mô tả chi tiết:**
106
- * Mỗi file là một "flow" có thể gọi được. Chúng nhận đầu vào có cấu trúc (nhờ `zod`) và trả về kết quả cũng có cấu trúc.
107
- * **`generate...Question`:** Các flow tạo câu hỏi đơn lẻ.
108
- * **`generateQuizPlan` & `generateQuestionsFromQuizPlan`:** Một quy trình 2 giai đoạn mạnh mẽ cho phép tạo ra một bài quiz hoàn chỉnh, cân bằng về chủ đề và độ khó, thay vì chỉ là một mớ câu hỏi ngẫu nhiên.
109
- * **Tầm quan trọng:** **Tính năng nâng cao (Advanced Feature)**. Lý tưởng cho các hệ thống muốn tự động hóa việc tạo nội dung.
110
-
111
- * **Ví dụ sử dụng (trong một script backend):**
112
-
113
- ```typescript
114
- import { generateQuizPlan, generateQuestionsFromQuizPlan } from 'interactive-quiz-kit/ai';
115
-
116
- async function generateFullQuiz() {
117
- const planInput = {
118
- totalQuestions: 5,
119
- topics: [{ topic: 'Lịch sử Việt Nam', ratio: 100 }],
120
- bloomLevels: [{ level: 'remembering', ratio: 60 }, { level: 'understanding', ratio: 40 }],
121
- selectedQuestionTypes: ['multiple_choice', 'true_false']
122
- };
123
-
124
- const plan = await generateQuizPlan(planInput);
125
-
126
- const quizResult = await generateQuestionsFromQuizPlan({ quizPlan: plan.quizPlan });
127
-
128
- console.log(`${quizResult.generatedQuestions.length} câu hỏi đã được tạo.`);
129
- // => Lưu các câu hỏi này vào DB
130
- }
131
- ```
132
-
133
- ---
134
-
135
- #### **E. `services/` (các file liên quan đến SCORM) & `utils/` - Hộp Dụng cụ & Giao tiếp**
136
-
137
- * **Vai trò:** Cung cấp các công cụ chuyên biệt để hoàn thành các tác vụ cụ thể.
138
- * **Mô tả chi tiết:**
139
- * **`SCORMService.ts`:** Một lớp độc lập để nói chuyện với LMS. Nó không biết gì về quiz, chỉ biết về các lệnh SCORM. `QuizEngine` sẽ sử dụng nó.
140
- * **`generateSCORMManifest`, `generateLauncherHTML`:** Các hàm này nhận dữ liệu và trả về các chuỗi văn bản (XML, HTML). Chúng không có tác dụng phụ (side-effect) và hoàn toàn "thuần khiết" (pure), rất phù hợp cho môi trường headless.
141
- * **`idGenerators.ts`:** Cung cấp hàm `generateUniqueId`, một tiện ích nhỏ nhưng cần thiết khi bạn tạo dữ liệu mới.
142
- * **Tầm quan trọng:** **Hỗ trợ (Supporting)**. Cần thiết cho các chức năng cụ thể như SCORM hoặc khi cần tạo dữ liệu mới.
143
-
144
- Bằng cách kết hợp các thành phần này, bạn có thể xây dựng một hệ thống hoàn chỉnh ở phía backend để tạo, quản lý quiz, và thậm chí mô phỏng các phiên làm bài để kiểm thử mà không cần viết một dòng code giao diện nào.
145
-
146
- ---
147
-
148
- ## II. Các Kiểu Dữ liệu (Types) - Nền tảng của Thư viện
149
-
150
- Trước khi bắt đầu, bạn cần làm quen với các kiểu dữ liệu chính. Mọi tương tác với thư viện đều xoay quanh chúng.
43
+ Before you start, familiarize yourself with the main data types. All interactions with the library revolve around them.
151
44
 
152
45
  ```typescript
153
- import { QuizConfig, QuizQuestion, TrueFalseQuestion } from 'interactive-quiz-kit';
46
+ import { QuizConfig, TrueFalseQuestion } from '@thanh01.pmt/interactive-quiz-kit';
154
47
 
155
- // Tạo một câu hỏi
48
+ // Create a question
156
49
  const myQuestion: TrueFalseQuestion = {
157
50
  id: 'tf-001',
158
51
  questionType: 'true_false',
159
- prompt: 'Mặt trời mọc hướng Tây.',
52
+ prompt: 'The sun rises in the west.',
160
53
  correctAnswer: false,
161
54
  points: 10
162
55
  };
163
56
 
164
- // Tạo một cấu hình quiz hoàn chỉnh
57
+ // Create a complete quiz configuration
165
58
  const myQuizConfig: QuizConfig = {
166
59
  id: 'my-first-headless-quiz',
167
- title: 'Quiz Khoa Học Vui',
60
+ title: 'Fun Science Quiz',
168
61
  questions: [myQuestion],
169
62
  settings: {
170
63
  shuffleQuestions: true,
@@ -173,87 +66,68 @@ const myQuizConfig: QuizConfig = {
173
66
  };
174
67
  ```
175
68
 
176
- **Các kiểu dữ liệu quan trọng nhất:**
177
-
178
- * `QuizConfig`: Toàn bộ cấu hình quiz.
179
- * `QuizQuestion`: Union type của tất cả các loại câu hỏi.
180
- * Các kiểu câu hỏi cụ thể: `MultipleChoiceQuestion`, `FillInTheBlanksQuestion`, `BlocklyProgrammingQuestion`, v.v.
181
- * `QuizResult`: Cấu trúc dữ liệu kết quả trả về.
182
-
183
- ---
184
-
185
- ## III. Sử dụng Dịch vụ Lõi
69
+ **Most important types:** `QuizConfig`, `QuizQuestion`, `QuizResultType`, and specific question types like `MultipleChoiceQuestion`.
186
70
 
187
- ### 1. `QuizEditorService`: Tạo Chỉnh sửa Quiz
71
+ ### 2. `QuizEditorService`: The Quiz Builder
188
72
 
189
- Service này cho phép bạn thực hiện các thao tác CRUD (Create, Read, Update, Delete) trên một đối tượng `QuizConfig`.
73
+ This service allows you to perform CRUD (Create, Read, Update, Delete) operations on a `QuizConfig` object.
190
74
 
191
75
  ```typescript
192
- import { QuizEditorService, emptyQuiz } from 'interactive-quiz-kit/services';
193
- import type { QuestionTypeStrings } from 'interactive-quiz-kit';
76
+ import { QuizEditorService, emptyQuiz } from '@thanh01.pmt/interactive-quiz-kit';
77
+ import type { TrueFalseQuestion } from '@thanh01.pmt/interactive-quiz-kit';
194
78
 
195
- // Bắt đầu với một quiz rỗng
79
+ // Start with an empty quiz
196
80
  const editor = new QuizEditorService(emptyQuiz);
197
81
 
198
- // Tạo một template câu hỏi trắc nghiệm mới
199
- const mcqTemplate = QuizEditorService.createNewQuestionTemplate('multiple_choice');
200
-
201
- // Cập nhật thông tin cho câu hỏi
202
- mcqTemplate.prompt = "Hành tinh nào gần mặt trời nhất?";
203
- if (mcqTemplate.questionType === 'multiple_choice') {
204
- mcqTemplate.options = [
205
- { id: 'opt1', text: 'Trái Đất' },
206
- { id: 'opt2', text: 'Sao Hỏa' },
207
- { id: 'opt3', text: 'Sao Thủy' },
208
- ];
209
- mcqTemplate.correctAnswerId = 'opt3';
210
- }
82
+ // Create a new True/False question template
83
+ const tfQuestion = QuizEditorService.createNewQuestionTemplate('true_false') as TrueFalseQuestion;
211
84
 
212
- // Thêm câu hỏi vào quiz
213
- editor.addQuestion(mcqTemplate);
85
+ // Update the question's details
86
+ tfQuestion.prompt = "Is the Earth a perfect sphere?";
87
+ tfQuestion.correctAnswer = false;
214
88
 
215
- // Xóa câu hỏi (nếu cần, ví dụ tại index 0)
216
- // editor.deleteQuestionByIndex(0);
89
+ // Add the question to the quiz
90
+ editor.addQuestion(tfQuestion);
217
91
 
218
- // Lấy đối tượng QuizConfig cuối cùng
92
+ // Get the final QuizConfig object
219
93
  const finalQuizConfig = editor.getQuiz();
220
94
 
221
95
  console.log(JSON.stringify(finalQuizConfig, null, 2));
222
96
  ```
223
97
 
224
- ### 2. `QuizEngine`: Chạy một Phiên làm bài Quiz
98
+ ### 3. `QuizEngine`: The Runtime Conductor
225
99
 
226
- Service này bộ não xử logic khi một người dùng đang làm bài quiz.
100
+ This service is the brain that processes the logic when a user is taking a quiz.
227
101
 
228
102
  ```typescript
229
- import { QuizEngine } from 'interactive-quiz-kit/services';
230
- import type { QuizConfig, QuizResult } from 'interactive-quiz-kit';
103
+ import { QuizEngine } from '@thanh01.pmt/interactive-quiz-kit';
104
+ import type { QuizConfig, QuizResultType } from '@thanh01.pmt/interactive-quiz-kit';
231
105
 
232
- // Giả sử bạn đã một đối tượng myQuizConfig
106
+ // Assume you have a myQuizConfig object
233
107
  const myQuizConfig: QuizConfig = /* ... */;
234
108
 
235
- console.log("Bắt đầu quiz...");
109
+ console.log("Starting quiz...");
236
110
 
237
111
  const engine = new QuizEngine({
238
112
  config: myQuizConfig,
239
113
  callbacks: {
240
114
  onQuestionChange: (question, qNum, total) => {
241
- console.log(`\n--- Câu hỏi ${qNum}/${total} ---`);
115
+ console.log(`\n--- Question ${qNum}/${total} ---`);
242
116
  console.log(question?.prompt);
243
117
  },
244
- onQuizFinish: (result: QuizResult) => {
245
- console.log("\n--- KẾT QUẢ ---");
246
- console.log(`Điểm số: ${result.score}/${result.maxScore}`);
247
- console.log(`Phần trăm: ${result.percentage.toFixed(2)}%`);
248
- console.log(`Trạng thái: ${result.passed ? 'Đạt' : 'Không đạt'}`);
118
+ onQuizFinish: (result: QuizResultType) => {
119
+ console.log("\n--- RESULTS ---");
120
+ console.log(`Score: ${result.score}/${result.maxScore}`);
121
+ console.log(`Percentage: ${result.percentage.toFixed(2)}%`);
122
+ console.log(`Status: ${result.passed ? 'Passed' : 'Failed'}`);
249
123
  }
250
124
  }
251
125
  });
252
126
 
253
- // phỏng quá trình làm bài
127
+ // Simulate the quiz-taking process
254
128
  const question1 = engine.getCurrentQuestion();
255
129
  if (question1) {
256
- // Giả sử câu 1 True/False
130
+ // Assuming question 1 is True/False
257
131
  engine.submitAnswer(question1.id, false);
258
132
  }
259
133
 
@@ -261,73 +135,112 @@ engine.nextQuestion();
261
135
 
262
136
  const question2 = engine.getCurrentQuestion();
263
137
  if (question2) {
264
- // Giả sử câu 2 Multiple Choice
265
- engine.submitAnswer(question2.id, 'id_cua_dap_an_dung');
138
+ // Assuming question 2 is Multiple Choice
139
+ engine.submitAnswer(question2.id, 'id_of_the_correct_answer');
266
140
  }
267
141
 
268
- // Kết thúc quiz
142
+ // Finish the quiz
269
143
  engine.calculateResults();
270
144
  ```
271
145
 
146
+ ### 4. `TopicDataService`: The Curriculum Manager
147
+
148
+ This service manages learning objective data imported from TSV files, powering the "Practice with AI" feature.
149
+
150
+ ```typescript
151
+ import { TopicDataService } from '@thanh01.pmt/interactive-quiz-kit';
152
+ import type { LearningObjective } from '@thanh01.pmt/interactive-quiz-kit';
153
+ // In a browser environment:
154
+ // import tsvContent from './my_curriculum.tsv?raw';
155
+
156
+ // const { data, errors } = TopicDataService.parseTSV(tsvContent);
157
+ // if (errors.length === 0) {
158
+ // TopicDataService.saveData(data);
159
+ // }
160
+
161
+ // const subjects = TopicDataService.getSubjects();
162
+ // console.log('Available Subjects:', subjects);
163
+ ```
164
+
272
165
  ---
273
166
 
274
- ## IV. Tạo Nội dung bằng AI
167
+ ## III. AI-Powered Content Generation
275
168
 
276
- Bạn thể sử dụng các flow AI để tự động tạo câu hỏi. Các hàm này `async`.
169
+ You can use the AI flows to automatically generate quiz content. These functions are `async`.
277
170
 
278
- *Lưu ý: Để sử dụng, bạn cần môi trường đã cấu hình Google Genkit các biến môi trường cần thiết ( dụ: `GOOGLE_API_KEY`).*
171
+ *Note: To use these, you need a configured Google Genkit environment and the necessary environment variables (e.g., `GOOGLE_API_KEY`).*
279
172
 
280
173
  ```typescript
281
- import { generateMCQQuestion, generateQuizPlan } from 'interactive-quiz-kit/ai';
174
+ import { generateMCQQuestion, generatePracticeQuiz } from '@thanh01.pmt/interactive-quiz-kit/ai';
175
+ import type { LearningObjective } from '@thanh01.pmt/interactive-quiz-kit';
282
176
 
283
177
  async function createAIQuestion() {
284
178
  try {
285
- console.log('Đang tạo câu hỏi trắc nghiệm về Hệ Mặt Trời...');
179
+ console.log('Generating a Multiple Choice question about the Solar System...');
286
180
  const result = await generateMCQQuestion({
287
- topic: 'Hệ Mặt Trời',
288
- difficulty: 'easy'
289
- });
181
+ topic: 'The Solar System',
182
+ difficulty: 'easy',
183
+ language: 'English'
184
+ }, 'YOUR_API_KEY');
290
185
 
291
186
  if (result.question) {
292
- console.log('Câu hỏi đã được tạo:');
293
- console.log(JSON.stringify(result.question, null, 2));
294
- } else {
295
- console.log('AI không thể tạo câu hỏi.');
187
+ console.log('Generated Question:', JSON.stringify(result.question, null, 2));
296
188
  }
297
-
298
189
  } catch (error) {
299
- console.error('Lỗi khi tạo câu hỏi AI:', error);
190
+ console.error('Error generating AI question:', error);
300
191
  }
301
192
  }
302
193
 
194
+ async function createAIPracticeQuiz() {
195
+ try {
196
+ // Assume 'selectedLOs' is an array of LearningObjective objects
197
+ const selectedLOs: LearningObjective[] = /* ... from TopicDataService ... */;
198
+ const result = await generatePracticeQuiz({
199
+ learningObjectives: selectedLOs,
200
+ quizDifficulty: 'Medium',
201
+ language: 'English'
202
+ }, 'YOUR_API_KEY');
203
+
204
+ console.log(`Generated ${result.generatedQuestions?.length || 0} practice questions.`);
205
+ } catch (error) {
206
+ console.error('Error generating practice quiz:', error);
207
+ }
208
+ }
209
+
303
210
  // createAIQuestion();
304
211
  ```
305
212
 
306
213
  ---
307
214
 
308
- ## V. Đóng gói và Xuất bản
215
+ ## IV. Packaging and Publishing
309
216
 
310
- Các hàm này giúp tạo ra các thành phần của một gói SCORM. Chúng trả về nội dung dạng chuỗi (string) bạn thể ghi ra file.
217
+ These functions help create the components of a SCORM package. They return string content that you can write to files.
311
218
 
312
219
  ```typescript
313
- import { generateSCORMManifest, generateLauncherHTML } from 'interactive-quiz-kit/services';
314
- import type { QuizConfig } from 'interactive-quiz-kit';
315
- // import * as fs from 'fs'; // Dùng trong môi trường Node.js
220
+ import { generateSCORMManifest, generateLauncherHTML } from '@thanh01.pmt/interactive-quiz-kit';
221
+ import type { QuizConfig } from '@thanh01.pmt/interactive-quiz-kit';
222
+ // import * as fs from 'fs'; // For use in a Node.js environment
316
223
 
317
- // Giả sử bạn đã một đối tượng myQuizConfig
224
+ // Assume you have a myQuizConfig object
318
225
  const myQuizConfig: QuizConfig = /* ... */;
319
226
 
320
- // Tạo nội dung manifest
227
+ // Generate manifest content
321
228
  const manifestXML = generateSCORMManifest(myQuizConfig, "1.2");
322
229
  console.log('--- imsmanifest.xml ---');
323
230
  console.log(manifestXML);
324
231
  // fs.writeFileSync('dist/imsmanifest.xml', manifestXML);
325
232
 
326
- // Tạo nội dung file HTML launcher
327
- const launcherHTML = generateLauncherHTML(myQuizConfig);
233
+ // Generate HTML launcher content
234
+ const launcherHTML = generateLauncherHTML(
235
+ myQuizConfig,
236
+ 'player.js', // Path to the JS bundle inside the ZIP
237
+ 'quiz_data.json', // Path to the quiz data inside the ZIP
238
+ 'blockly-styles.css', // Path to blockly css
239
+ 'styles.css' // Path to main css
240
+ );
328
241
  console.log('\n--- index.html ---');
329
242
  console.log(launcherHTML);
330
243
  // fs.writeFileSync('dist/index.html', launcherHTML);
331
244
  ```
332
245
 
333
- **Lưu ý:** Hàm `exportQuizAsSCORMZip` được thiết kế để chạy trên trình duyệt tương tác với DOM để kích hoạt tải file. Nếu bạn muốn đóng gói ZIP phía backend, bạn cần sử dụng một thư viện như `jszip` tự mình thực hiện các bước tương tự như trong file `services/scormPackaging.ts`.
246
+ **Note:** The `exportQuizAsSCORMZip` function is designed to run in the browser as it interacts with the DOM to trigger a file download. To package a ZIP on the backend, you would use a library like `jszip` and follow the steps outlined in `services/scormPackaging.ts`.