@thanh01.pmt/interactive-quiz-kit 1.0.32 → 1.0.34
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.cjs +124 -65
- package/dist/ai.mjs +124 -65
- package/dist/authoring.cjs +143 -81
- package/dist/authoring.d.cts +1 -1
- package/dist/authoring.d.ts +1 -1
- package/dist/authoring.mjs +143 -81
- package/dist/index.cjs +13 -8
- package/dist/index.mjs +13 -8
- package/dist/player.cjs +13 -8
- package/dist/player.mjs +13 -8
- package/dist/react-ui.cjs +140 -184
- package/dist/react-ui.d.cts +1 -1
- package/dist/react-ui.d.ts +1 -1
- package/dist/react-ui.mjs +140 -184
- package/dist/{toaster-Blf5k3DP.d.cts → toaster-D1bLqmd_.d.cts} +1 -1
- package/dist/{toaster-BrChkQ23.d.ts → toaster-eWZIxSVc.d.ts} +1 -1
- package/package.json +1 -1
package/dist/react-ui.mjs
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import * as React162 from 'react';
|
|
2
2
|
import React162__default, { createContext, forwardRef, createElement, useRef, useState, useImperativeHandle, useCallback, useEffect, useLayoutEffect, useContext, useMemo, cloneElement, isValidElement, Children, useTransition, PureComponent, Component as Component$1, memo, Suspense, useReducer } from 'react';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import {
|
|
5
|
-
import { gemini20Flash, googleAI } from '@genkit-ai/googleai';
|
|
4
|
+
import { GoogleGenAI } from '@google/genai';
|
|
6
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
6
|
import * as ReactDOM4 from 'react-dom';
|
|
8
7
|
import ReactDOM4__default, { unstable_batchedUpdates, createPortal } from 'react-dom';
|
|
9
8
|
import default2 from 'path';
|
|
10
9
|
import default3 from 'process';
|
|
11
10
|
import { fileURLToPath } from 'url';
|
|
12
|
-
import { GoogleGenAI } from '@google/genai';
|
|
13
11
|
import JSZip from 'jszip';
|
|
14
12
|
import { useRouter } from 'next/navigation';
|
|
15
13
|
|
|
@@ -7836,10 +7834,7 @@ var EvaluateUserCodeOutputSchema = AIEvaluationOutputSchema;
|
|
|
7836
7834
|
// src/ai/flows/evaluate-user-code.ts
|
|
7837
7835
|
async function evaluateUserCode(clientInput, apiKey) {
|
|
7838
7836
|
try {
|
|
7839
|
-
const
|
|
7840
|
-
plugins: [googleAI({ apiKey })],
|
|
7841
|
-
model: gemini20Flash
|
|
7842
|
-
});
|
|
7837
|
+
const genAI = new GoogleGenAI({ apiKey });
|
|
7843
7838
|
const { language: language3, problemPrompt, userCode, testCase } = clientInput;
|
|
7844
7839
|
const promptText = `
|
|
7845
7840
|
You are an expert Code Judge and Teaching Assistant for a ${language3} programming course.
|
|
@@ -7876,8 +7871,17 @@ Return ONLY the JSON object with this EXACT structure.
|
|
|
7876
7871
|
\`\`\`
|
|
7877
7872
|
|
|
7878
7873
|
Return only the JSON response.`;
|
|
7879
|
-
const
|
|
7880
|
-
const
|
|
7874
|
+
const modelName = "gemini-1.5-flash";
|
|
7875
|
+
const contents = [{ role: "user", parts: [{ text: promptText }] }];
|
|
7876
|
+
const result = await genAI.models.generateContent({
|
|
7877
|
+
model: modelName,
|
|
7878
|
+
contents
|
|
7879
|
+
});
|
|
7880
|
+
const response = result;
|
|
7881
|
+
const rawText = response.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
7882
|
+
if (!rawText) {
|
|
7883
|
+
throw new Error("AI returned an empty response.");
|
|
7884
|
+
}
|
|
7881
7885
|
const jsonText = extractJsonFromMarkdown(rawText);
|
|
7882
7886
|
const aiGeneratedContent = JSON.parse(jsonText);
|
|
7883
7887
|
return EvaluateUserCodeOutputSchema.parse(aiGeneratedContent);
|
|
@@ -128421,109 +128425,6 @@ function QuestionFilters({
|
|
|
128421
128425
|
}
|
|
128422
128426
|
), /* @__PURE__ */ React162__default.createElement(Select2, { value: subjectCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setSubjectCode) }, /* @__PURE__ */ React162__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React162__default.createElement(SelectValue2, { placeholder: "Subject" })), /* @__PURE__ */ React162__default.createElement(SelectContent2, null, /* @__PURE__ */ React162__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Subjects"), subjects.map((s4) => /* @__PURE__ */ React162__default.createElement(SelectItem2, { key: s4.code, value: s4.code }, s4.name)))), /* @__PURE__ */ React162__default.createElement(Select2, { value: topicCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setTopicCode), disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React162__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React162__default.createElement(SelectValue2, { placeholder: "Topic" })), /* @__PURE__ */ React162__default.createElement(SelectContent2, null, /* @__PURE__ */ React162__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Topics"), filteredTopics.map((t4) => /* @__PURE__ */ React162__default.createElement(SelectItem2, { key: t4.code, value: t4.code }, t4.name)))), /* @__PURE__ */ React162__default.createElement(Select2, { value: gradeLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setGradeLevelCode) }, /* @__PURE__ */ React162__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React162__default.createElement(SelectValue2, { placeholder: "Grade Level" })), /* @__PURE__ */ React162__default.createElement(SelectContent2, null, /* @__PURE__ */ React162__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Grade Levels"), gradeLevels.map((gl) => /* @__PURE__ */ React162__default.createElement(SelectItem2, { key: gl.code, value: gl.code }, gl.name)))), /* @__PURE__ */ React162__default.createElement(Select2, { value: bloomLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setBloomLevelCode) }, /* @__PURE__ */ React162__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React162__default.createElement(SelectValue2, { placeholder: "Bloom's Level" })), /* @__PURE__ */ React162__default.createElement(SelectContent2, null, /* @__PURE__ */ React162__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Levels"), bloomLevels.map((bl) => /* @__PURE__ */ React162__default.createElement(SelectItem2, { key: bl.code, value: bl.code }, bl.name)))), /* @__PURE__ */ React162__default.createElement(Select2, { value: questionTypeCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setQuestionTypeCode) }, /* @__PURE__ */ React162__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React162__default.createElement(SelectValue2, { placeholder: "Question Type" })), /* @__PURE__ */ React162__default.createElement(SelectContent2, null, /* @__PURE__ */ React162__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Types"), questionTypes.map((qt) => /* @__PURE__ */ React162__default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name)))), /* @__PURE__ */ React162__default.createElement(Select2, { value: difficulty || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setDifficulty) }, /* @__PURE__ */ React162__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React162__default.createElement(SelectValue2, { placeholder: "Difficulty" })), /* @__PURE__ */ React162__default.createElement(SelectContent2, null, /* @__PURE__ */ React162__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Difficulties"), /* @__PURE__ */ React162__default.createElement(SelectItem2, { value: "easy" }, "Easy"), /* @__PURE__ */ React162__default.createElement(SelectItem2, { value: "medium" }, "Medium"), /* @__PURE__ */ React162__default.createElement(SelectItem2, { value: "hard" }, "Hard"))), /* @__PURE__ */ React162__default.createElement("div", { className: "flex gap-2 col-span-full sm:col-span-1 xl:col-span-2 xl:col-start-6" }, /* @__PURE__ */ React162__default.createElement(Button, { onClick: handleApplyFilters, className: "w-full sm:w-auto flex-grow" }, /* @__PURE__ */ React162__default.createElement(Search, { className: "mr-2 h-4 w-4" }), " Apply"), /* @__PURE__ */ React162__default.createElement(Button, { onClick: handleClearFilters, variant: "outline", className: "w-full sm:w-auto flex-grow" }, /* @__PURE__ */ React162__default.createElement(CircleX, { className: "mr-2 h-4 w-4" }), " Clear"))));
|
|
128423
128427
|
}
|
|
128424
|
-
|
|
128425
|
-
// src/services/questionBankService.ts
|
|
128426
|
-
var LocalStorageManager2 = class {
|
|
128427
|
-
constructor(key) {
|
|
128428
|
-
this.key = key;
|
|
128429
|
-
}
|
|
128430
|
-
getAll() {
|
|
128431
|
-
if (typeof window === "undefined") return [];
|
|
128432
|
-
try {
|
|
128433
|
-
const stored = localStorage.getItem(this.key);
|
|
128434
|
-
return stored ? JSON.parse(stored) : [];
|
|
128435
|
-
} catch (e3) {
|
|
128436
|
-
console.error(`Error reading from localStorage key ${this.key}:`, e3);
|
|
128437
|
-
return [];
|
|
128438
|
-
}
|
|
128439
|
-
}
|
|
128440
|
-
saveAll(items) {
|
|
128441
|
-
if (typeof window === "undefined") return;
|
|
128442
|
-
try {
|
|
128443
|
-
localStorage.setItem(this.key, JSON.stringify(items));
|
|
128444
|
-
} catch (e3) {
|
|
128445
|
-
console.error(`Error writing to localStorage key ${this.key}:`, e3);
|
|
128446
|
-
}
|
|
128447
|
-
}
|
|
128448
|
-
};
|
|
128449
|
-
var questionBankManager = new LocalStorageManager2("iqk_question_bank");
|
|
128450
|
-
var QuestionBankService = class {
|
|
128451
|
-
static getQuestions(filters) {
|
|
128452
|
-
let questions = questionBankManager.getAll();
|
|
128453
|
-
if (filters) {
|
|
128454
|
-
if (filters.subjectCode) {
|
|
128455
|
-
questions = questions.filter((q2) => q2.subjectCode === filters.subjectCode);
|
|
128456
|
-
}
|
|
128457
|
-
if (filters.topicCode) {
|
|
128458
|
-
questions = questions.filter((q2) => q2.topicCode === filters.topicCode);
|
|
128459
|
-
}
|
|
128460
|
-
if (filters.gradeLevelCode) {
|
|
128461
|
-
questions = questions.filter((q2) => q2.gradeLevelCode === filters.gradeLevelCode);
|
|
128462
|
-
}
|
|
128463
|
-
if (filters.bloomLevelCode) {
|
|
128464
|
-
questions = questions.filter((q2) => q2.bloomLevelCode === filters.bloomLevelCode);
|
|
128465
|
-
}
|
|
128466
|
-
if (filters.questionTypeCode) {
|
|
128467
|
-
questions = questions.filter((q2) => q2.questionTypeCode === filters.questionTypeCode);
|
|
128468
|
-
}
|
|
128469
|
-
if (filters.difficulty) {
|
|
128470
|
-
questions = questions.filter((q2) => q2.difficulty === filters.difficulty);
|
|
128471
|
-
}
|
|
128472
|
-
if (filters.searchTerm) {
|
|
128473
|
-
const lowercasedTerm = filters.searchTerm.toLowerCase();
|
|
128474
|
-
questions = questions.filter(
|
|
128475
|
-
(q2) => q2.text.toLowerCase().includes(lowercasedTerm) || q2.code.toLowerCase().includes(lowercasedTerm)
|
|
128476
|
-
);
|
|
128477
|
-
}
|
|
128478
|
-
}
|
|
128479
|
-
return questions.sort((a4, b2) => new Date(b2.lastModified).getTime() - new Date(a4.lastModified).getTime());
|
|
128480
|
-
}
|
|
128481
|
-
static getQuestionByCode(code4) {
|
|
128482
|
-
return questionBankManager.getAll().find((q2) => q2.code === code4);
|
|
128483
|
-
}
|
|
128484
|
-
// CHANGE 2: Simplified function signature. It now takes the full object to be added.
|
|
128485
|
-
static addQuestion(questionData) {
|
|
128486
|
-
const allQuestions = questionBankManager.getAll();
|
|
128487
|
-
if (allQuestions.some((q2) => q2.code === questionData.code)) {
|
|
128488
|
-
throw new Error(`A question with code "${questionData.code}" already exists.`);
|
|
128489
|
-
}
|
|
128490
|
-
const newQuestion = {
|
|
128491
|
-
...questionData,
|
|
128492
|
-
id: generateUniqueId("qb_"),
|
|
128493
|
-
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
128494
|
-
};
|
|
128495
|
-
questionBankManager.saveAll([...allQuestions, newQuestion]);
|
|
128496
|
-
return newQuestion;
|
|
128497
|
-
}
|
|
128498
|
-
// CHANGE 2: Simplified function signature.
|
|
128499
|
-
static updateQuestion(id3, updates) {
|
|
128500
|
-
const allQuestions = questionBankManager.getAll();
|
|
128501
|
-
const index3 = allQuestions.findIndex((q2) => q2.id === id3);
|
|
128502
|
-
if (index3 === -1) {
|
|
128503
|
-
console.warn(`Question with id "${id3}" not found for update.`);
|
|
128504
|
-
return null;
|
|
128505
|
-
}
|
|
128506
|
-
const updatedQuestion = {
|
|
128507
|
-
...allQuestions[index3],
|
|
128508
|
-
...updates,
|
|
128509
|
-
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
128510
|
-
};
|
|
128511
|
-
allQuestions[index3] = updatedQuestion;
|
|
128512
|
-
questionBankManager.saveAll(allQuestions);
|
|
128513
|
-
return updatedQuestion;
|
|
128514
|
-
}
|
|
128515
|
-
static deleteQuestionByCode(code4) {
|
|
128516
|
-
const allQuestions = questionBankManager.getAll();
|
|
128517
|
-
const newQuestions = allQuestions.filter((q2) => q2.code !== code4);
|
|
128518
|
-
if (allQuestions.length === newQuestions.length) {
|
|
128519
|
-
return false;
|
|
128520
|
-
}
|
|
128521
|
-
questionBankManager.saveAll(newQuestions);
|
|
128522
|
-
return true;
|
|
128523
|
-
}
|
|
128524
|
-
};
|
|
128525
|
-
|
|
128526
|
-
// src/react-ui/components/authoring/QuestionFormDialog.tsx
|
|
128527
128428
|
function QuestionFormDialog({
|
|
128528
128429
|
isOpen,
|
|
128529
128430
|
onOpenChange,
|
|
@@ -128608,9 +128509,11 @@ function QuestionFormDialog({
|
|
|
128608
128509
|
toast2({ title: "Validation Error", description: "Question content is missing. Please create or edit the question details.", variant: "destructive" });
|
|
128609
128510
|
return;
|
|
128610
128511
|
}
|
|
128611
|
-
startTransition(() => {
|
|
128512
|
+
startTransition(async () => {
|
|
128612
128513
|
try {
|
|
128613
128514
|
const finalDataPayload = {
|
|
128515
|
+
id: questionToEdit?.id || "",
|
|
128516
|
+
// Will be ignored for new items, used for updates
|
|
128614
128517
|
code: code4,
|
|
128615
128518
|
text: questionConfig.prompt.replace(/<[^>]*>?/gm, "").substring(0, 200),
|
|
128616
128519
|
subjectCode,
|
|
@@ -128619,6 +128522,8 @@ function QuestionFormDialog({
|
|
|
128619
128522
|
bloomLevelCode,
|
|
128620
128523
|
questionTypeCode: questionConfig.questionType,
|
|
128621
128524
|
difficulty: questionConfig.difficulty,
|
|
128525
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
128526
|
+
// This will be set by the saving service
|
|
128622
128527
|
questionConfig: {
|
|
128623
128528
|
...questionConfig,
|
|
128624
128529
|
subject: subjectCode,
|
|
@@ -128627,14 +128532,7 @@ function QuestionFormDialog({
|
|
|
128627
128532
|
bloomLevel: bloomLevelCode
|
|
128628
128533
|
}
|
|
128629
128534
|
};
|
|
128630
|
-
|
|
128631
|
-
QuestionBankService.updateQuestion(questionToEdit.id, finalDataPayload);
|
|
128632
|
-
toast2({ title: "Success", description: "Question updated." });
|
|
128633
|
-
} else {
|
|
128634
|
-
QuestionBankService.addQuestion(finalDataPayload);
|
|
128635
|
-
toast2({ title: "Success", description: "Question added." });
|
|
128636
|
-
}
|
|
128637
|
-
onSave();
|
|
128535
|
+
await onSave(finalDataPayload);
|
|
128638
128536
|
onOpenChange(false);
|
|
128639
128537
|
} catch (error) {
|
|
128640
128538
|
toast2({ title: "Error", description: error.message || "Failed to save question.", variant: "destructive" });
|
|
@@ -133475,10 +133373,7 @@ var AIQuizReviewOutputSchema = z.object({
|
|
|
133475
133373
|
// src/ai/flows/generate-quiz-review.ts
|
|
133476
133374
|
async function generateQuizReview(clientInput, apiKey) {
|
|
133477
133375
|
try {
|
|
133478
|
-
const
|
|
133479
|
-
plugins: [googleAI({ apiKey })],
|
|
133480
|
-
model: gemini20Flash
|
|
133481
|
-
});
|
|
133376
|
+
const genAI = new GoogleGenAI({ apiKey });
|
|
133482
133377
|
const resultsString = JSON.stringify(clientInput.questionResults, null, 2);
|
|
133483
133378
|
const promptText = `
|
|
133484
133379
|
You are an expert educational tutor. Your task is to analyze a student's quiz results and provide a detailed, helpful review in ${clientInput.language}.
|
|
@@ -133515,8 +133410,17 @@ Return a single, valid JSON object with this EXACT format.
|
|
|
133515
133410
|
\`\`\`
|
|
133516
133411
|
|
|
133517
133412
|
Return only the valid JSON response.`;
|
|
133518
|
-
const
|
|
133519
|
-
const
|
|
133413
|
+
const modelName = "gemini-1.5-flash";
|
|
133414
|
+
const contents = [{ role: "user", parts: [{ text: promptText }] }];
|
|
133415
|
+
const result = await genAI.models.generateContent({
|
|
133416
|
+
model: modelName,
|
|
133417
|
+
contents
|
|
133418
|
+
});
|
|
133419
|
+
const response = result;
|
|
133420
|
+
const rawText = response.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
133421
|
+
if (!rawText) {
|
|
133422
|
+
throw new Error("AI returned an empty response.");
|
|
133423
|
+
}
|
|
133520
133424
|
const jsonText = extractJsonFromMarkdown(rawText);
|
|
133521
133425
|
const aiGeneratedContent = JSON.parse(jsonText);
|
|
133522
133426
|
const validatedOutput = AIQuizReviewOutputSchema.parse(aiGeneratedContent);
|
|
@@ -133581,10 +133485,7 @@ var LearningAnalysisOutputSchema = z.object({
|
|
|
133581
133485
|
// src/ai/flows/generate-learning-analysis.ts
|
|
133582
133486
|
async function generateLearningAnalysis(clientInput, apiKey) {
|
|
133583
133487
|
try {
|
|
133584
|
-
const
|
|
133585
|
-
plugins: [googleAI({ apiKey })],
|
|
133586
|
-
model: gemini20Flash
|
|
133587
|
-
});
|
|
133488
|
+
const genAI = new GoogleGenAI({ apiKey });
|
|
133588
133489
|
const {
|
|
133589
133490
|
language: language3,
|
|
133590
133491
|
userName = "learner",
|
|
@@ -133672,8 +133573,17 @@ The 'suggestedDifficulty' field MUST ALWAYS be one of these exact English string
|
|
|
133672
133573
|
}
|
|
133673
133574
|
\`\`\`
|
|
133674
133575
|
`;
|
|
133675
|
-
const
|
|
133676
|
-
const
|
|
133576
|
+
const modelName = "gemini-1.5-flash";
|
|
133577
|
+
const contents = [{ role: "user", parts: [{ text: promptText }] }];
|
|
133578
|
+
const result = await genAI.models.generateContent({
|
|
133579
|
+
model: modelName,
|
|
133580
|
+
contents
|
|
133581
|
+
});
|
|
133582
|
+
const response = result;
|
|
133583
|
+
const rawText = response.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
133584
|
+
if (!rawText) {
|
|
133585
|
+
throw new Error("AI returned an empty response.");
|
|
133586
|
+
}
|
|
133677
133587
|
const jsonText = extractJsonFromMarkdown(rawText);
|
|
133678
133588
|
const aiGeneratedContent = JSON.parse(jsonText);
|
|
133679
133589
|
const validatedOutput = LearningAnalysisOutputSchema.parse(aiGeneratedContent);
|
|
@@ -133704,10 +133614,7 @@ var GenerateMotivationalQuoteOutputSchema = z.object({
|
|
|
133704
133614
|
// src/ai/flows/generate-motivational-quote.ts
|
|
133705
133615
|
async function generateMotivationalQuote(clientInput, apiKey) {
|
|
133706
133616
|
try {
|
|
133707
|
-
const
|
|
133708
|
-
plugins: [googleAI({ apiKey })],
|
|
133709
|
-
model: gemini20Flash
|
|
133710
|
-
});
|
|
133617
|
+
const genAI = new GoogleGenAI({ apiKey });
|
|
133711
133618
|
const { language: language3, userName, currentStreak, weakestTopic } = clientInput;
|
|
133712
133619
|
let contextPrompt = "";
|
|
133713
133620
|
if (userName) {
|
|
@@ -133740,8 +133647,17 @@ Return the response as a single, valid JSON object with this EXACT format:
|
|
|
133740
133647
|
|
|
133741
133648
|
Return only the JSON response.`;
|
|
133742
133649
|
try {
|
|
133743
|
-
const
|
|
133744
|
-
const
|
|
133650
|
+
const modelName = "gemini-1.5-flash";
|
|
133651
|
+
const contents = [{ role: "user", parts: [{ text: promptText }] }];
|
|
133652
|
+
const result = await genAI.models.generateContent({
|
|
133653
|
+
model: modelName,
|
|
133654
|
+
contents
|
|
133655
|
+
});
|
|
133656
|
+
const response = result;
|
|
133657
|
+
const rawText = response.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
133658
|
+
if (!rawText) {
|
|
133659
|
+
throw new Error("AI returned an empty response.");
|
|
133660
|
+
}
|
|
133745
133661
|
const jsonText = extractJsonFromMarkdown(rawText);
|
|
133746
133662
|
const aiGeneratedContent = JSON.parse(jsonText);
|
|
133747
133663
|
const validatedOutput = GenerateMotivationalQuoteOutputSchema.parse(aiGeneratedContent);
|
|
@@ -133767,10 +133683,7 @@ var PlanKnowledgeCardsOutputSchema = z.object({
|
|
|
133767
133683
|
// src/ai/flows/plan-knowledge-cards.ts
|
|
133768
133684
|
async function planKnowledgeCards(clientInput, apiKey) {
|
|
133769
133685
|
try {
|
|
133770
|
-
const
|
|
133771
|
-
plugins: [googleAI({ apiKey })],
|
|
133772
|
-
model: gemini20Flash
|
|
133773
|
-
});
|
|
133686
|
+
const genAI = new GoogleGenAI({ apiKey });
|
|
133774
133687
|
const { language: language3, learningObjectivesContent, overallSubject } = clientInput;
|
|
133775
133688
|
const promptText = `
|
|
133776
133689
|
You are an expert curriculum designer specializing in the subject of "${overallSubject}".
|
|
@@ -133790,18 +133703,28 @@ ${learningObjectivesContent}
|
|
|
133790
133703
|
|
|
133791
133704
|
**JSON OUTPUT FORMAT:**
|
|
133792
133705
|
Return a single, valid JSON object with this EXACT format:
|
|
133706
|
+
\`\`\`json
|
|
133793
133707
|
{
|
|
133794
133708
|
"concepts": [
|
|
133795
133709
|
"First Concept",
|
|
133796
133710
|
"Second Concept",
|
|
133797
|
-
"Third Concept"
|
|
133798
|
-
...
|
|
133711
|
+
"Third Concept"
|
|
133799
133712
|
]
|
|
133800
133713
|
}
|
|
133714
|
+
\`\`\`
|
|
133801
133715
|
|
|
133802
133716
|
Return only the JSON response.`;
|
|
133803
|
-
const
|
|
133804
|
-
const
|
|
133717
|
+
const modelName = "gemini-1.5-flash";
|
|
133718
|
+
const contents = [{ role: "user", parts: [{ text: promptText }] }];
|
|
133719
|
+
const result = await genAI.models.generateContent({
|
|
133720
|
+
model: modelName,
|
|
133721
|
+
contents
|
|
133722
|
+
});
|
|
133723
|
+
const response = result;
|
|
133724
|
+
const rawText = response.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
133725
|
+
if (!rawText) {
|
|
133726
|
+
throw new Error("AI returned an empty response.");
|
|
133727
|
+
}
|
|
133805
133728
|
const jsonText = extractJsonFromMarkdown(rawText);
|
|
133806
133729
|
const aiGeneratedContent = JSON.parse(jsonText);
|
|
133807
133730
|
const validatedOutput = PlanKnowledgeCardsOutputSchema.parse(aiGeneratedContent);
|
|
@@ -133828,30 +133751,48 @@ var GenerateSingleKnowledgeCardOutputSchema = z.object({
|
|
|
133828
133751
|
|
|
133829
133752
|
// src/ai/flows/generate-single-knowledge-card.ts
|
|
133830
133753
|
async function generateSingleKnowledgeCard(clientInput, apiKey) {
|
|
133831
|
-
const ai = genkit({
|
|
133832
|
-
plugins: [googleAI({ apiKey })],
|
|
133833
|
-
model: gemini20Flash
|
|
133834
|
-
});
|
|
133835
133754
|
try {
|
|
133836
|
-
const
|
|
133755
|
+
const genAI = new GoogleGenAI({ apiKey });
|
|
133756
|
+
const { language: language3, concept, overallSubject } = clientInput;
|
|
133837
133757
|
const promptText = `
|
|
133838
|
-
You are an expert educator for "${overallSubject}".
|
|
133839
|
-
|
|
133840
|
-
|
|
133841
|
-
|
|
133842
|
-
|
|
133843
|
-
|
|
133844
|
-
|
|
133845
|
-
|
|
133846
|
-
|
|
133847
|
-
|
|
133848
|
-
|
|
133849
|
-
|
|
133758
|
+
You are an expert educator for "${overallSubject}". Your task is to create content for a single knowledge card based on the provided concept.
|
|
133759
|
+
|
|
133760
|
+
**Target Concept:**
|
|
133761
|
+
${concept}
|
|
133762
|
+
|
|
133763
|
+
**Instructions:**
|
|
133764
|
+
1. **Definition:** Write a concise definition for the concept (under 40 words).
|
|
133765
|
+
2. **Example:** Provide a practical example (code or real-world scenario) relevant to "${overallSubject}".
|
|
133766
|
+
3. **Language:** All content must be in ${language3}.
|
|
133767
|
+
4. **Format:** You MUST return ONLY a single, valid JSON object that strictly follows the provided schema. Do not include any extra text, comments, or markdown formatting.
|
|
133768
|
+
|
|
133769
|
+
**Required JSON Output Format:**
|
|
133770
|
+
Your response must be ONLY the JSON object, matching this exact structure. The 'concept' field must exactly match the Target Concept provided above.
|
|
133771
|
+
|
|
133772
|
+
{
|
|
133773
|
+
"concept": "${concept}",
|
|
133774
|
+
"definition": "A concise explanation of the concept goes here, in ${language3}.",
|
|
133775
|
+
"example": "A practical code snippet or real-world example goes here, in ${language3}."
|
|
133776
|
+
}
|
|
133777
|
+
|
|
133778
|
+
Now, generate the JSON for the requested knowledge card.`;
|
|
133779
|
+
const modelName = "gemini-1.5-flash";
|
|
133780
|
+
const config3 = {
|
|
133781
|
+
responseMimeType: "application/json"
|
|
133782
|
+
};
|
|
133783
|
+
const contents = [{ role: "user", parts: [{ text: promptText }] }];
|
|
133784
|
+
const result = await genAI.models.generateContent({
|
|
133785
|
+
model: modelName,
|
|
133786
|
+
contents,
|
|
133787
|
+
config: config3
|
|
133850
133788
|
});
|
|
133851
|
-
const
|
|
133852
|
-
|
|
133789
|
+
const response = result;
|
|
133790
|
+
const rawText = response.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
133791
|
+
if (!rawText) {
|
|
133853
133792
|
throw new Error("AI did not return a valid structured output.");
|
|
133854
133793
|
}
|
|
133794
|
+
const aiGeneratedContent = JSON.parse(rawText);
|
|
133795
|
+
const validatedOutput = GenerateSingleKnowledgeCardOutputSchema.parse(aiGeneratedContent);
|
|
133855
133796
|
return validatedOutput;
|
|
133856
133797
|
} catch (error) {
|
|
133857
133798
|
console.error(`Error generating knowledge card for concept "${clientInput.concept}":`, error);
|
|
@@ -133887,10 +133828,7 @@ var AssessAndMapDocumentOutputSchema = z.object({
|
|
|
133887
133828
|
// src/ai/flows/assess-and-map-document.ts
|
|
133888
133829
|
async function assessAndMapDocument(clientInput, apiKey) {
|
|
133889
133830
|
try {
|
|
133890
|
-
const
|
|
133891
|
-
plugins: [googleAI({ apiKey })],
|
|
133892
|
-
model: gemini20Flash
|
|
133893
|
-
});
|
|
133831
|
+
const genAI = new GoogleGenAI({ apiKey });
|
|
133894
133832
|
const { language: language3, documentContent, learningObjectives } = clientInput;
|
|
133895
133833
|
const relevanceThreshold = 40;
|
|
133896
133834
|
const promptText = `
|
|
@@ -133938,8 +133876,17 @@ Return a single, valid JSON object in this EXACT format. Do not include any othe
|
|
|
133938
133876
|
|
|
133939
133877
|
If the document is not relevant at all, the "mappedLOs" array should be empty, and the "relevanceScore" should be low.
|
|
133940
133878
|
`;
|
|
133941
|
-
const
|
|
133942
|
-
const
|
|
133879
|
+
const modelName = "gemini-1.5-flash";
|
|
133880
|
+
const contents = [{ role: "user", parts: [{ text: promptText }] }];
|
|
133881
|
+
const result = await genAI.models.generateContent({
|
|
133882
|
+
model: modelName,
|
|
133883
|
+
contents
|
|
133884
|
+
});
|
|
133885
|
+
const response = result;
|
|
133886
|
+
const rawText = response.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
133887
|
+
if (!rawText) {
|
|
133888
|
+
throw new Error("AI returned an empty response.");
|
|
133889
|
+
}
|
|
133943
133890
|
const jsonText = extractJsonFromMarkdown(rawText);
|
|
133944
133891
|
const aiGeneratedContent = JSON.parse(jsonText);
|
|
133945
133892
|
const validatedOutput = AssessAndMapDocumentOutputSchema.parse(aiGeneratedContent);
|
|
@@ -133971,10 +133918,7 @@ var GenerateQuizFromTextOutputSchema = z.object({
|
|
|
133971
133918
|
var AnyGeneratedQuestionSchema2 = GenerateQuizFromTextOutputSchema.shape.generatedQuestions.element;
|
|
133972
133919
|
async function generateQuizFromText(clientInput, apiKey) {
|
|
133973
133920
|
try {
|
|
133974
|
-
const
|
|
133975
|
-
plugins: [googleAI({ apiKey })],
|
|
133976
|
-
model: gemini20Flash
|
|
133977
|
-
});
|
|
133921
|
+
const genAI = new GoogleGenAI({ apiKey });
|
|
133978
133922
|
const { language: language3, documentContent, numQuestions, questionTypes } = clientInput;
|
|
133979
133923
|
const allowedTypes = questionTypes || ["multiple_choice", "true_false"];
|
|
133980
133924
|
const promptText = `
|
|
@@ -134028,8 +133972,17 @@ Return the response as a single JSON object with a key "generatedQuestions" cont
|
|
|
134028
133972
|
\`\`\`
|
|
134029
133973
|
|
|
134030
133974
|
Now, generate the JSON response.`;
|
|
134031
|
-
const
|
|
134032
|
-
const
|
|
133975
|
+
const modelName = "gemini-1.5-flash";
|
|
133976
|
+
const contents = [{ role: "user", parts: [{ text: promptText }] }];
|
|
133977
|
+
const result = await genAI.models.generateContent({
|
|
133978
|
+
model: modelName,
|
|
133979
|
+
contents
|
|
133980
|
+
});
|
|
133981
|
+
const response = result;
|
|
133982
|
+
const rawText = response.candidates?.[0]?.content?.parts?.[0]?.text || "";
|
|
133983
|
+
if (!rawText) {
|
|
133984
|
+
throw new Error("AI returned an empty response.");
|
|
133985
|
+
}
|
|
134033
133986
|
const jsonText = extractJsonFromMarkdown(rawText);
|
|
134034
133987
|
const aiGeneratedContent = JSON.parse(jsonText);
|
|
134035
133988
|
if (!aiGeneratedContent.generatedQuestions || !Array.isArray(aiGeneratedContent.generatedQuestions)) {
|
|
@@ -162947,10 +162900,7 @@ var AskTutorChatOutputSchema = z.object({
|
|
|
162947
162900
|
// src/ai/flows/ask-tutor-chat.ts
|
|
162948
162901
|
async function askTutorChat(clientInput, apiKey) {
|
|
162949
162902
|
try {
|
|
162950
|
-
const
|
|
162951
|
-
plugins: [googleAI({ apiKey })],
|
|
162952
|
-
model: gemini20Flash
|
|
162953
|
-
});
|
|
162903
|
+
const genAI = new GoogleGenAI({ apiKey });
|
|
162954
162904
|
const { language: language3, currentQuestion, chatHistory, knowledgeContext } = clientInput;
|
|
162955
162905
|
const historyString = chatHistory.map((msg) => `${msg.role}: ${msg.content}`).join("\n");
|
|
162956
162906
|
const contextString = knowledgeContext && knowledgeContext.length > 0 ? `--- KNOWLEDGE CONTEXT ---
|
|
@@ -162977,8 +162927,14 @@ user: ${currentQuestion}
|
|
|
162977
162927
|
|
|
162978
162928
|
**Your Response (as 'assistant'):**
|
|
162979
162929
|
`;
|
|
162980
|
-
const
|
|
162981
|
-
const
|
|
162930
|
+
const modelName = "gemini-1.5-flash";
|
|
162931
|
+
const contents = [{ role: "user", parts: [{ text: promptText }] }];
|
|
162932
|
+
const result = await genAI.models.generateContent({
|
|
162933
|
+
model: modelName,
|
|
162934
|
+
contents
|
|
162935
|
+
});
|
|
162936
|
+
const response = result;
|
|
162937
|
+
const aiResponseText = response.candidates?.[0]?.content?.parts?.[0]?.text?.trim() || "";
|
|
162982
162938
|
if (!aiResponseText) {
|
|
162983
162939
|
throw new Error("AI returned an empty response.");
|
|
162984
162940
|
}
|
|
@@ -71,7 +71,7 @@ declare function QuestionFilters({ onFilterChange, initialFilters, }: QuestionFi
|
|
|
71
71
|
interface QuestionFormDialogProps {
|
|
72
72
|
isOpen: boolean;
|
|
73
73
|
onOpenChange: (isOpen: boolean) => void;
|
|
74
|
-
onSave: () => void;
|
|
74
|
+
onSave: (question: QuestionInBank) => Promise<void> | void;
|
|
75
75
|
questionToEdit?: QuestionInBank | null;
|
|
76
76
|
}
|
|
77
77
|
declare function QuestionFormDialog({ isOpen, onOpenChange, onSave, questionToEdit, }: QuestionFormDialogProps): React__default.JSX.Element;
|
|
@@ -71,7 +71,7 @@ declare function QuestionFilters({ onFilterChange, initialFilters, }: QuestionFi
|
|
|
71
71
|
interface QuestionFormDialogProps {
|
|
72
72
|
isOpen: boolean;
|
|
73
73
|
onOpenChange: (isOpen: boolean) => void;
|
|
74
|
-
onSave: () => void;
|
|
74
|
+
onSave: (question: QuestionInBank) => Promise<void> | void;
|
|
75
75
|
questionToEdit?: QuestionInBank | null;
|
|
76
76
|
}
|
|
77
77
|
declare function QuestionFormDialog({ isOpen, onOpenChange, onSave, questionToEdit, }: QuestionFormDialogProps): React__default.JSX.Element;
|
package/package.json
CHANGED