Skip to main content
Glama
assessment-engine.js17.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); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rkm097git/euconquisto-composer-mcp-poc'

If you have feedback or need assistance with the MCP directory API, please join our Discord server