assessment-engine.js•17.7 kB
/**
* Assessment Generation Engine
* @module content-generation/assessment-engine
* @description Intelligent assessment generation with flashcards and quizzes
* @version 5.0.0-alpha
*/
import { FlashcardGenerator } from './flashcard-generator.js';
import { QuizGenerator } from './quiz-generator.js';
import { AnswerRandomizer } from './answer-randomizer.js';
import { ComplexityAdapter } from './complexity-adapter.js';
import { QualityValidator } from './quality-validator.js';
export class AssessmentEngine {
constructor(config = {}) {
this.config = {
language: 'pt-BR',
gradeLevel: 'auto',
minFlashcards: 8,
maxFlashcards: 25,
minQuestions: 5,
maxQuestions: 15,
enableRandomization: true,
qualityThreshold: 0.7,
...config
};
// Initialize assessment components
this.flashcardGenerator = new FlashcardGenerator(this.config);
this.quizGenerator = new QuizGenerator(this.config);
this.answerRandomizer = new AnswerRandomizer(this.config);
this.complexityAdapter = new ComplexityAdapter(this.config);
this.qualityValidator = new QualityValidator(this.config);
}
/**
* Generate comprehensive assessment package
* @param {Object} content - Generated educational content
* @param {Object} topicAnalysis - Topic analysis result
* @param {Object} requirements - Assessment requirements
* @returns {Promise<Object>} Complete assessment package
*/
async generateAssessment(content, topicAnalysis, requirements = {}) {
console.log('[ASSESSMENT-ENGINE] Generating comprehensive assessment');
try {
const assessmentRequirements = {
includeFlashcards: true,
includeQuiz: true,
gradeLevel: requirements.gradeLevel || topicAnalysis.gradeLevel || this.config.gradeLevel,
subject: topicAnalysis.subject,
complexity: topicAnalysis.complexity,
...requirements
};
// Generate assessment components
const assessment = {
metadata: this.generateAssessmentMetadata(topicAnalysis, assessmentRequirements),
flashcards: [],
quiz: {},
analytics: this.initializeAnalytics()
};
// Generate flashcards if requested
if (assessmentRequirements.includeFlashcards) {
assessment.flashcards = await this.generateFlashcards(content, topicAnalysis);
}
// Generate quiz if requested
if (assessmentRequirements.includeQuiz) {
assessment.quiz = await this.generateQuiz(content, topicAnalysis);
}
// Adapt complexity for grade level
const adapted = await this.adaptComplexity(assessment, assessmentRequirements.gradeLevel);
// Randomize answer positions
const randomized = await this.randomizeAnswers(adapted);
// Validate quality
const validated = await this.validateQuality(randomized);
console.log('[ASSESSMENT-ENGINE] Assessment generation complete');
return validated;
} catch (error) {
console.error('[ASSESSMENT-ENGINE] Assessment generation failed:', error);
throw new Error(`Assessment generation failed: ${error.message}`);
}
}
/**
* Generate flashcards from content
* @param {Object} content - Educational content
* @param {Object} topicAnalysis - Topic analysis
* @returns {Promise<Array>} Generated flashcards
*/
async generateFlashcards(content, topicAnalysis) {
console.log('[ASSESSMENT-ENGINE] Generating flashcards');
return this.flashcardGenerator.generateFlashcards(content, topicAnalysis);
}
/**
* Generate quiz questions from content
* @param {Object} content - Educational content
* @param {Object} topicAnalysis - Topic analysis
* @returns {Promise<Object>} Generated quiz
*/
async generateQuiz(content, topicAnalysis) {
console.log('[ASSESSMENT-ENGINE] Generating quiz questions');
return this.quizGenerator.generateQuiz(content, topicAnalysis);
}
/**
* Adapt assessment complexity for grade level
* @param {Object} assessment - Assessment package
* @param {string} gradeLevel - Target grade level
* @returns {Promise<Object>} Adapted assessment
*/
async adaptComplexity(assessment, gradeLevel) {
console.log('[ASSESSMENT-ENGINE] Adapting complexity for grade level:', gradeLevel);
return this.complexityAdapter.adaptAssessment(assessment, gradeLevel);
}
/**
* Randomize answer positions to prevent pattern gaming
* @param {Object} assessment - Assessment package
* @returns {Promise<Object>} Assessment with randomized answers
*/
async randomizeAnswers(assessment) {
if (!this.config.enableRandomization) return assessment;
console.log('[ASSESSMENT-ENGINE] Randomizing answer positions');
return this.answerRandomizer.randomizeAssessment(assessment);
}
/**
* Validate assessment quality
* @param {Object} assessment - Assessment package
* @returns {Promise<Object>} Validated assessment
*/
async validateQuality(assessment) {
console.log('[ASSESSMENT-ENGINE] Validating assessment quality');
return this.qualityValidator.validateAssessment(assessment);
}
/**
* Generate assessment metadata
* @param {Object} topicAnalysis - Topic analysis
* @param {Object} requirements - Assessment requirements
* @returns {Object} Assessment metadata
*/
generateAssessmentMetadata(topicAnalysis, requirements) {
return {
subject: topicAnalysis.subject,
gradeLevel: requirements.gradeLevel,
complexity: topicAnalysis.complexity,
language: this.config.language,
generatedAt: new Date().toISOString(),
estimatedDuration: this.estimateDuration(requirements),
learningObjectives: topicAnalysis.learningObjectives || [],
assessmentType: 'comprehensive',
version: '5.0.0-alpha'
};
}
/**
* Estimate assessment duration
* @param {Object} requirements - Assessment requirements
* @returns {string} Estimated duration
*/
estimateDuration(requirements) {
const flashcardTime = requirements.includeFlashcards ? 5 : 0; // 5 minutes for flashcards
const quizTime = requirements.includeQuiz ? 10 : 0; // 10 minutes for quiz
const totalMinutes = flashcardTime + quizTime;
return `${totalMinutes}-${totalMinutes + 5} minutos`;
}
/**
* Initialize analytics tracking
* @returns {Object} Analytics initialization
*/
initializeAnalytics() {
return {
generationTime: Date.now(),
componentsGenerated: [],
qualityScores: {},
randomizationApplied: this.config.enableRandomization,
adaptationLevel: null
};
}
/**
* Generate assessment for specific subject adapter
* @param {Object} content - Educational content
* @param {Object} topicAnalysis - Topic analysis
* @param {string} adapterType - Type of adapter (physics, chemistry, history)
* @param {Object} requirements - Assessment requirements
* @returns {Promise<Object>} Subject-specific assessment
*/
async generateSubjectSpecificAssessment(content, topicAnalysis, adapterType, requirements = {}) {
console.log(`[ASSESSMENT-ENGINE] Generating ${adapterType}-specific assessment`);
// Get base assessment
const baseAssessment = await this.generateAssessment(content, topicAnalysis, requirements);
// Apply subject-specific enhancements
const enhanced = await this.applySubjectEnhancements(baseAssessment, adapterType, topicAnalysis);
return enhanced;
}
/**
* Apply subject-specific assessment enhancements
* @param {Object} assessment - Base assessment
* @param {string} adapterType - Adapter type
* @param {Object} topicAnalysis - Topic analysis
* @returns {Promise<Object>} Enhanced assessment
*/
async applySubjectEnhancements(assessment, adapterType, topicAnalysis) {
const enhancements = {
physics: this.enhancePhysicsAssessment,
chemistry: this.enhanceChemistryAssessment,
history: this.enhanceHistoryAssessment
};
const enhancer = enhancements[adapterType];
if (enhancer) {
return enhancer.call(this, assessment, topicAnalysis);
}
return assessment;
}
/**
* Enhance assessment for physics content
* @param {Object} assessment - Base assessment
* @param {Object} topicAnalysis - Topic analysis
* @returns {Object} Physics-enhanced assessment
*/
enhancePhysicsAssessment(assessment, topicAnalysis) {
// Add physics-specific flashcards
assessment.flashcards.push(...this.generatePhysicsFlashcards(topicAnalysis));
// Add calculation questions
assessment.quiz.questions.push(...this.generatePhysicsQuestions(topicAnalysis));
// Update metadata
assessment.metadata.subjectEnhancements = ['equations', 'calculations', 'units'];
return assessment;
}
/**
* Enhance assessment for chemistry content
* @param {Object} assessment - Base assessment
* @param {Object} topicAnalysis - Topic analysis
* @returns {Object} Chemistry-enhanced assessment
*/
enhanceChemistryAssessment(assessment, topicAnalysis) {
// Add chemistry-specific flashcards
assessment.flashcards.push(...this.generateChemistryFlashcards(topicAnalysis));
// Add structure/reaction questions
assessment.quiz.questions.push(...this.generateChemistryQuestions(topicAnalysis));
// Update metadata
assessment.metadata.subjectEnhancements = ['structures', 'reactions', 'calculations'];
return assessment;
}
/**
* Enhance assessment for history content
* @param {Object} assessment - Base assessment
* @param {Object} topicAnalysis - Topic analysis
* @returns {Object} History-enhanced assessment
*/
enhanceHistoryAssessment(assessment, topicAnalysis) {
// Add history-specific flashcards
assessment.flashcards.push(...this.generateHistoryFlashcards(topicAnalysis));
// Add chronology/causality questions
assessment.quiz.questions.push(...this.generateHistoryQuestions(topicAnalysis));
// Update metadata
assessment.metadata.subjectEnhancements = ['timelines', 'causality', 'sources'];
return assessment;
}
/**
* Generate physics-specific flashcards
* @param {Object} topicAnalysis - Topic analysis
* @returns {Array} Physics flashcards
*/
generatePhysicsFlashcards(topicAnalysis) {
return [
{
id: `physics-formula-${Date.now()}`,
type: 'formula',
front: 'Fórmula fundamental da física',
back: 'F = ma (Segunda Lei de Newton)',
subject: 'física',
difficulty: 'medium',
tags: ['fórmula', 'newton', 'força']
},
{
id: `physics-unit-${Date.now()}`,
type: 'unit',
front: 'Unidade de força no SI',
back: 'Newton (N) = kg⋅m/s²',
subject: 'física',
difficulty: 'easy',
tags: ['unidade', 'força', 'sistema internacional']
}
];
}
/**
* Generate chemistry-specific flashcards
* @param {Object} topicAnalysis - Topic analysis
* @returns {Array} Chemistry flashcards
*/
generateChemistryFlashcards(topicAnalysis) {
return [
{
id: `chemistry-structure-${Date.now()}`,
type: 'structure',
front: 'Fórmula molecular da água',
back: 'H₂O (dois átomos de hidrogênio, um de oxigênio)',
subject: 'química',
difficulty: 'easy',
tags: ['fórmula', 'molecular', 'água']
},
{
id: `chemistry-reaction-${Date.now()}`,
type: 'reaction',
front: 'Tipo de reação: A + B → AB',
back: 'Reação de síntese ou combinação',
subject: 'química',
difficulty: 'medium',
tags: ['reação', 'síntese', 'tipos']
}
];
}
/**
* Generate history-specific flashcards
* @param {Object} topicAnalysis - Topic analysis
* @returns {Array} History flashcards
*/
generateHistoryFlashcards(topicAnalysis) {
return [
{
id: `history-date-${Date.now()}`,
type: 'chronology',
front: 'Início da Revolução Francesa',
back: '1789 - Tomada da Bastilha',
subject: 'história',
difficulty: 'medium',
tags: ['data', 'revolução francesa', 'século xviii']
},
{
id: `history-cause-${Date.now()}`,
type: 'causality',
front: 'Principal causa da Primeira Guerra Mundial',
back: 'Tensões imperialistas e sistema de alianças',
subject: 'história',
difficulty: 'hard',
tags: ['causas', 'primeira guerra', 'imperialismo']
}
];
}
/**
* Generate physics-specific questions
* @param {Object} topicAnalysis - Topic analysis
* @returns {Array} Physics questions
*/
generatePhysicsQuestions(topicAnalysis) {
return [
{
id: `physics-calc-${Date.now()}`,
type: 'calculation',
question: 'Um objeto de 5 kg acelera a 2 m/s². Qual é a força aplicada?',
answer: '10 N',
solution: 'F = ma = 5 kg × 2 m/s² = 10 N',
difficulty: 'medium',
subject: 'física',
tags: ['cálculo', 'força', 'segunda lei newton']
}
];
}
/**
* Generate chemistry-specific questions
* @param {Object} topicAnalysis - Topic analysis
* @returns {Array} Chemistry questions
*/
generateChemistryQuestions(topicAnalysis) {
return [
{
id: `chemistry-balance-${Date.now()}`,
type: 'balancing',
question: 'Balanceie a equação: __ H₂ + __ O₂ → __ H₂O',
answer: '2 H₂ + 1 O₂ → 2 H₂O',
explanation: 'Conservação da massa: 4 H e 2 O de cada lado',
difficulty: 'medium',
subject: 'química',
tags: ['balanceamento', 'equação', 'água']
}
];
}
/**
* Generate history-specific questions
* @param {Object} topicAnalysis - Topic analysis
* @returns {Array} History questions
*/
generateHistoryQuestions(topicAnalysis) {
return [
{
id: `history-sequence-${Date.now()}`,
type: 'chronological',
question: 'Ordene cronologicamente: Revolução Francesa, Revolução Industrial, Primeira Guerra Mundial',
answer: 'Revolução Industrial (1760-1840), Revolução Francesa (1789-1799), Primeira Guerra Mundial (1914-1918)',
difficulty: 'medium',
subject: 'história',
tags: ['cronologia', 'século xviii', 'século xix', 'século xx']
}
];
}
/**
* Calculate assessment statistics
* @param {Object} assessment - Assessment package
* @returns {Object} Assessment statistics
*/
calculateStatistics(assessment) {
const stats = {
flashcardCount: assessment.flashcards.length,
questionCount: assessment.quiz.questions ? assessment.quiz.questions.length : 0,
difficultyDistribution: this.analyzeDifficultyDistribution(assessment),
subjectCoverage: this.analyzeSubjectCoverage(assessment),
estimatedDuration: assessment.metadata.estimatedDuration,
qualityScore: this.calculateQualityScore(assessment)
};
return stats;
}
/**
* Analyze difficulty distribution
* @param {Object} assessment - Assessment package
* @returns {Object} Difficulty distribution
*/
analyzeDifficultyDistribution(assessment) {
const distribution = { easy: 0, medium: 0, hard: 0 };
// Count flashcard difficulties
assessment.flashcards.forEach(card => {
if (card.difficulty && distribution[card.difficulty] !== undefined) {
distribution[card.difficulty]++;
}
});
// Count question difficulties
if (assessment.quiz.questions) {
assessment.quiz.questions.forEach(question => {
if (question.difficulty && distribution[question.difficulty] !== undefined) {
distribution[question.difficulty]++;
}
});
}
return distribution;
}
/**
* Analyze subject coverage
* @param {Object} assessment - Assessment package
* @returns {Array} Subject coverage
*/
analyzeSubjectCoverage(assessment) {
const subjects = new Set();
assessment.flashcards.forEach(card => {
if (card.subject) subjects.add(card.subject);
});
if (assessment.quiz.questions) {
assessment.quiz.questions.forEach(question => {
if (question.subject) subjects.add(question.subject);
});
}
return Array.from(subjects);
}
/**
* Calculate overall quality score
* @param {Object} assessment - Assessment package
* @returns {number} Quality score (0-100)
*/
calculateQualityScore(assessment) {
let score = 100;
// Deduct for insufficient content
if (assessment.flashcards.length < this.config.minFlashcards) {
score -= 20;
}
if (assessment.quiz.questions && assessment.quiz.questions.length < this.config.minQuestions) {
score -= 20;
}
// Add for good difficulty balance
const distribution = this.analyzeDifficultyDistribution(assessment);
const total = distribution.easy + distribution.medium + distribution.hard;
if (total > 0) {
const balance = Math.min(distribution.easy, distribution.medium, distribution.hard) / total;
score += balance * 10; // Bonus for balanced difficulty
}
return Math.max(0, Math.min(100, score));
}
}
// Factory function for creating AssessmentEngine instances
export function createAssessmentEngine(config = {}) {
return new AssessmentEngine(config);
}