Implement Server-Side AI Question Bank Generator, Adaptive Weakness Sampling 60/40, and Curriculum Studio One-Click Generation
This commit is contained in:
@@ -70,7 +70,61 @@ class ExamController
|
||||
return;
|
||||
}
|
||||
|
||||
$questions = Database::select("SELECT * FROM questions WHERE exam_id = ? ORDER BY id ASC", [$examId]);
|
||||
$allQuestions = Database::select("SELECT * FROM questions WHERE exam_id = ? ORDER BY id ASC", [$examId]);
|
||||
|
||||
$questions = [];
|
||||
if (count($allQuestions) > 15) {
|
||||
// Adaptive Sampling Engine based on Student Weakness History
|
||||
$studentId = $request->user_id ?? 0;
|
||||
$weakTopics = [];
|
||||
|
||||
if ($studentId > 0) {
|
||||
// Fetch failed topics from student's answers
|
||||
$fails = Database::select(
|
||||
"SELECT q.topic_tag, COUNT(*) as cnt
|
||||
FROM student_question_answers sqa
|
||||
JOIN questions q ON sqa.question_id = q.id
|
||||
WHERE sqa.student_id = ? AND sqa.is_correct = 0 AND q.topic_tag IS NOT NULL
|
||||
GROUP BY q.topic_tag ORDER BY cnt DESC LIMIT 5",
|
||||
[$studentId]
|
||||
);
|
||||
foreach ($fails as $f) {
|
||||
$weakTopics[] = $f['topic_tag'];
|
||||
}
|
||||
}
|
||||
|
||||
// Split questions into weak vs other topics
|
||||
$weakPool = [];
|
||||
$otherPool = [];
|
||||
|
||||
foreach ($allQuestions as $q) {
|
||||
if (!empty($weakTopics) && in_array($q['topic_tag'], $weakTopics)) {
|
||||
$weakPool[] = $q;
|
||||
} else {
|
||||
$otherPool[] = $q;
|
||||
}
|
||||
}
|
||||
|
||||
shuffle($weakPool);
|
||||
shuffle($otherPool);
|
||||
|
||||
if (!empty($weakPool)) {
|
||||
// 60% focused on weak concepts for adaptive remediation
|
||||
$targetWeakCount = min(count($weakPool), 9);
|
||||
$questions = array_slice($weakPool, 0, $targetWeakCount);
|
||||
|
||||
// 40% from rest of unit concepts
|
||||
$needed = 15 - count($questions);
|
||||
$questions = array_merge($questions, array_slice($otherPool, 0, $needed));
|
||||
} else {
|
||||
// Stratified random sampling from the comprehensive bank
|
||||
$questions = array_slice($otherPool, 0, 15);
|
||||
}
|
||||
|
||||
shuffle($questions);
|
||||
} else {
|
||||
$questions = $allQuestions;
|
||||
}
|
||||
|
||||
foreach ($questions as &$q) {
|
||||
$options = Database::select("SELECT id, option_text, feedback_text" . ($isTeacher ? ", is_correct" : "") . " FROM question_options WHERE question_id = ? ORDER BY id ASC", [$q['id']]);
|
||||
@@ -78,6 +132,7 @@ class ExamController
|
||||
}
|
||||
|
||||
$exam['questions'] = $questions;
|
||||
$exam['questions_count'] = count($questions);
|
||||
|
||||
$response->json([
|
||||
'status' => 'success',
|
||||
@@ -394,27 +449,17 @@ class ExamController
|
||||
}
|
||||
}
|
||||
|
||||
if (count($existingQuestions) < 15 || $hasCalculus) {
|
||||
if (count($existingQuestions) < 45 || $hasCalculus) {
|
||||
// Wipe legacy corrupt questions
|
||||
foreach ($existingQuestions as $oq) {
|
||||
Database::query("DELETE FROM question_options WHERE question_id = ?", [$oq['id']]);
|
||||
}
|
||||
Database::query("DELETE FROM questions WHERE exam_id = ?", [$examId]);
|
||||
|
||||
$bank = self::getUnit1QuestionBank();
|
||||
foreach ($bank as $qData) {
|
||||
$qId = (int)Database::insert(
|
||||
"INSERT INTO questions (uuid, exam_id, question_text, question_type, bloom_taxonomy, topic_tag, explanation_text, points)
|
||||
VALUES (UUID(), ?, ?, 'multiple_choice', ?, ?, ?, ?)",
|
||||
[$examId, $qData['question_text'], $qData['bloom'], $qData['topic'], $qData['explanation'], $qData['points']]
|
||||
);
|
||||
foreach ($qData['options'] as $idx => $optText) {
|
||||
Database::insert(
|
||||
"INSERT INTO question_options (question_id, option_text, is_correct) VALUES (?, ?, ?)",
|
||||
[$qId, $optText, ($idx === $qData['correct_index']) ? 1 : 0]
|
||||
);
|
||||
}
|
||||
}
|
||||
require_once __DIR__ . '/../Services/AiQuestionBankGeneratorService.php';
|
||||
$unitPath = 'grade_10/math_10/semester_1/unit_01';
|
||||
$res = \App\Services\AiQuestionBankGeneratorService::generateUnitQuestionBank($unitPath, 1, 50);
|
||||
return (int)$res['exam_id'];
|
||||
}
|
||||
|
||||
return $examId;
|
||||
|
||||
Reference in New Issue
Block a user