Implement Intelligent QCM system with AI-generated plausible distractors
- Transform ContentLoader from hardcoded QCM to AI-powered exercises - Remove all mock content generators (_generateTextExercise, etc.) - Add pure AI content generation with 6-option QCM (1 correct + 5 distractors) - Create intelligent distractors testing common learning mistakes: * Text: main idea confusion, partial truths, logical but wrong conclusions * Audio: mishearing, speaker confusion, context misunderstanding * Image: object similarity, spatial confusion, descriptive errors * Grammar: common errors, tense mistakes, wrong constructions - Reduce random success chance from 25% to 16.7% for better learning assessment - Make AI mandatory - no fallback without IAEngine availability - Update CLAUDE.md plan with dual exercise approach documentation - Fix async/await issues in ContentLoader module loading chain 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
05142bdfbc
commit
a6c81a8ec3
29
CLAUDE.md
29
CLAUDE.md
@ -17,14 +17,27 @@ Building a **bulletproof modular system** with strict separation of concerns usi
|
||||
- ✅ **Application.js** - Auto-bootstrap system with lifecycle management
|
||||
- ✅ **Development Server** - HTTP server with ES6 modules and CORS support
|
||||
|
||||
**DRS SYSTEM COMPLETED ✅** - Advanced learning modules with AI integration:
|
||||
- ✅ **TextModule** - Reading comprehension exercises with AI text analysis
|
||||
- ✅ **AudioModule** - Listening exercises with AI audio comprehension
|
||||
- ✅ **ImageModule** - Visual comprehension with AI vision analysis
|
||||
- ✅ **GrammarModule** - Grammar exercises with AI linguistic analysis
|
||||
- ✅ **AI Integration** - OpenAI → DeepSeek → Disable fallback system
|
||||
- ✅ **Persistent Storage** - Progress tracking with timestamps and metadata
|
||||
- ✅ **Data Merge System** - Local/external data synchronization
|
||||
**DRS SYSTEM COMPLETED ✅** - Advanced learning modules with dual AI approach:
|
||||
|
||||
**Core Exercise Generation:**
|
||||
- ✅ **ContentLoader** - Pure AI content generation when no real content available
|
||||
- ✅ **IAEngine** - Multi-provider AI system (OpenAI → DeepSeek → Disable)
|
||||
- ✅ **LLMValidator** - Intelligent answer validation with detailed feedback
|
||||
- ✅ **AI Report System** - Session tracking with exportable reports (text/HTML/JSON)
|
||||
- ✅ **UnifiedDRS** - Component-based exercise presentation system
|
||||
|
||||
**Dual Exercise Modes:**
|
||||
- 🔄 **Intelligent QCM** - AI generates questions + 1 correct + 5 plausible wrong answers (16.7% random chance)
|
||||
- 🔄 **Open Analysis Modules** - Free-text responses validated by AI with personalized feedback
|
||||
- TextAnalysisModule - Deep comprehension with AI coaching
|
||||
- GrammarAnalysisModule - Grammar correction with explanations
|
||||
- TranslationModule - Translation validation with improvement tips
|
||||
- OpenResponseModule - Free-form questions with intelligent evaluation
|
||||
|
||||
**AI Architecture:**
|
||||
- ✅ **AI-Mandatory System** - No fallback without AI, ensures quality consistency
|
||||
- ✅ **Smart Preview Orchestrator** - Manages AI report sessions and shared services
|
||||
- ✅ **Dynamic Content Adaptation** - Real content + AI questions when available, pure AI when not
|
||||
|
||||
## 🔥 Critical Requirements
|
||||
|
||||
|
||||
@ -201,24 +201,30 @@ class Application {
|
||||
async _loadModules() {
|
||||
console.log(`🔄 Loading ${this._config.modules.length} modules...`);
|
||||
|
||||
// PHASE 1: Register all modules first
|
||||
console.log('📋 PHASE 1: Registering all modules...');
|
||||
for (const moduleConfig of this._config.modules) {
|
||||
try {
|
||||
const { name, path, dependencies = [], config = {} } = moduleConfig;
|
||||
|
||||
console.log(`📦 Loading module: ${name} from ${path}`);
|
||||
console.log(`📝 Registering module: ${name} from ${path}`);
|
||||
|
||||
// Dynamically import module
|
||||
const moduleModule = await import(path);
|
||||
const ModuleClass = moduleModule.default;
|
||||
|
||||
// Register and initialize
|
||||
this._moduleLoader.register(name, ModuleClass, dependencies);
|
||||
await this._moduleLoader.loadAndInitialize(name, config);
|
||||
if (!ModuleClass) {
|
||||
throw new Error(`Module ${name} does not export a default class`);
|
||||
}
|
||||
|
||||
console.log(`✅ Module ${name} loaded and initialized successfully`);
|
||||
// Register only
|
||||
this._moduleLoader.register(name, ModuleClass, dependencies);
|
||||
console.log(`✅ Registered module: ${name} with dependencies: [${dependencies.join(', ')}]`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Failed to load module ${moduleConfig.name}:`, error);
|
||||
console.error(`❌ Failed to register module ${moduleConfig.name}:`, error);
|
||||
console.error(`❌ Module config was:`, moduleConfig);
|
||||
console.error(`❌ Full error stack:`, error.stack);
|
||||
|
||||
// Emit module load error
|
||||
this._eventBus.emit('app:module-error', {
|
||||
@ -227,6 +233,37 @@ class Application {
|
||||
}, 'Application');
|
||||
}
|
||||
}
|
||||
|
||||
// Show registration status
|
||||
const status = this._moduleLoader.getStatus();
|
||||
console.log(`📊 Registration complete. Registered modules: [${status.registered.join(', ')}]`);
|
||||
|
||||
// PHASE 2: Load and initialize all modules
|
||||
console.log('🚀 PHASE 2: Loading and initializing modules...');
|
||||
for (const moduleConfig of this._config.modules) {
|
||||
try {
|
||||
const { name, config = {} } = moduleConfig;
|
||||
|
||||
console.log(`🔄 Loading and initializing module: ${name}`);
|
||||
await this._moduleLoader.loadAndInitialize(name, config);
|
||||
console.log(`✅ Module ${name} loaded and initialized successfully`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Failed to load/initialize module ${moduleConfig.name}:`, error);
|
||||
console.error(`❌ Module config was:`, moduleConfig);
|
||||
console.error(`❌ Full error stack:`, error.stack);
|
||||
|
||||
// Emit module load error
|
||||
this._eventBus.emit('app:module-error', {
|
||||
module: moduleConfig.name,
|
||||
error: error.message
|
||||
}, 'Application');
|
||||
}
|
||||
}
|
||||
|
||||
// Final status
|
||||
const finalStatus = this._moduleLoader.getStatus();
|
||||
console.log(`🎯 Module loading complete. Initialized modules: [${finalStatus.initialized.join(', ')}]`);
|
||||
}
|
||||
|
||||
async _startRouting() {
|
||||
|
||||
@ -221,7 +221,7 @@ class ContentLoader extends Module {
|
||||
});
|
||||
|
||||
// Generate exercise based on real content
|
||||
return this._generateExerciseFromRealContent(realContent, request);
|
||||
return await this._generateExerciseFromRealContent(realContent, request);
|
||||
|
||||
} catch (error) {
|
||||
console.warn(`❌ Error loading real content:`, error);
|
||||
@ -233,20 +233,20 @@ class ContentLoader extends Module {
|
||||
/**
|
||||
* Generate exercise from real content
|
||||
*/
|
||||
_generateExerciseFromRealContent(realContent, request) {
|
||||
async _generateExerciseFromRealContent(realContent, request) {
|
||||
const { subtype, difficulty } = request;
|
||||
|
||||
switch (subtype) {
|
||||
case 'text':
|
||||
// Text = vocabulary questions
|
||||
return this._generateTextFromRealContent(realContent, difficulty);
|
||||
return await this._generateTextFromRealContent(realContent, difficulty);
|
||||
case 'reading':
|
||||
// Reading = comprehension with real passages
|
||||
return this._generateReadingFromRealContent(realContent, difficulty);
|
||||
return await this._generateReadingFromRealContent(realContent, difficulty);
|
||||
case 'audio':
|
||||
return this._generateAudioFromRealContent(realContent, difficulty);
|
||||
return await this._generateAudioFromRealContent(realContent, difficulty);
|
||||
case 'image':
|
||||
return this._generateImageFromRealContent(realContent, difficulty);
|
||||
return await this._generateImageFromRealContent(realContent, difficulty);
|
||||
case 'grammar':
|
||||
return this._generateGrammarFromRealContent(realContent, difficulty);
|
||||
default:
|
||||
@ -255,22 +255,48 @@ class ContentLoader extends Module {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback to mock content
|
||||
* Generate AI-based exercises when no real content is available
|
||||
*/
|
||||
_generateMockContent(request) {
|
||||
const { subtype } = request;
|
||||
async _generateMockContent(request) {
|
||||
const { subtype, chapterId, bookId, difficulty = 'medium' } = request;
|
||||
|
||||
console.log(`🤖 No real content available for ${subtype} exercise - generating AI-based content`);
|
||||
console.log(`📚 Chapter/Book: ${chapterId || bookId}`);
|
||||
console.log(`🎯 Using pure AI generation for learning content`);
|
||||
|
||||
try {
|
||||
// Import IAEngine for pure AI generation
|
||||
let IAEngine;
|
||||
try {
|
||||
const module = await import('../DRS/services/IAEngine.js');
|
||||
IAEngine = module.default;
|
||||
} catch (error) {
|
||||
throw new Error('IAEngine not available for AI content generation');
|
||||
}
|
||||
|
||||
const iaEngine = new IAEngine();
|
||||
|
||||
// Generate content based on exercise type
|
||||
switch (subtype) {
|
||||
case 'text':
|
||||
return this._generateTextExercise(request);
|
||||
case 'reading':
|
||||
return await this._generateAITextExercise(iaEngine, request);
|
||||
case 'audio':
|
||||
return this._generateAudioExercise(request);
|
||||
return await this._generateAIAudioExercise(iaEngine, request);
|
||||
case 'image':
|
||||
return this._generateImageExercise(request);
|
||||
return await this._generateAIImageExercise(iaEngine, request);
|
||||
case 'grammar':
|
||||
return this._generateGrammarExercise(request);
|
||||
return await this._generateAIGrammarExercise(iaEngine, request);
|
||||
default:
|
||||
return this._generateDefaultExercise(request);
|
||||
return await this._generateAIGeneralExercise(iaEngine, request);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Failed to generate AI content for ${subtype}:`, error.message);
|
||||
console.error(`❌ AI is required for this system to function`);
|
||||
|
||||
// No fallback - AI is mandatory for this system
|
||||
throw new Error(`AI generation failed for ${subtype} exercise. IAEngine is required for this system to function. Original error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,7 +402,7 @@ class ContentLoader extends Module {
|
||||
};
|
||||
}
|
||||
|
||||
_generateReadingFromRealContent(realContent, difficulty) {
|
||||
async _generateReadingFromRealContent(realContent, difficulty) {
|
||||
console.log('📖 Generating reading exercise from real content');
|
||||
|
||||
// Priority 1: Check if reading exercises are defined in JSON
|
||||
@ -1752,246 +1778,485 @@ Return ONLY valid JSON:
|
||||
return typeTemplates[Math.floor(Math.random() * typeTemplates.length)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate text exercise content
|
||||
* @param {Object} request - Request details
|
||||
* @returns {Object} - Text exercise
|
||||
* @private
|
||||
*/
|
||||
_generateTextExercise(request) {
|
||||
const passages = {
|
||||
easy: {
|
||||
text: "The cat sits on the mat. It is a warm day. The cat likes to sleep in the sun.",
|
||||
questions: [
|
||||
{
|
||||
question: "Where does the cat sit?",
|
||||
options: ["On the chair", "On the mat", "On the bed", "On the floor"],
|
||||
correct: 1,
|
||||
hint: "Look at the first sentence."
|
||||
}
|
||||
]
|
||||
},
|
||||
medium: {
|
||||
text: "Solar energy is becoming increasingly popular around the world. Many countries are investing in solar panels and wind turbines to reduce their dependence on fossil fuels. This shift towards renewable energy is helping to combat climate change and create jobs in the green energy sector.",
|
||||
questions: [
|
||||
{
|
||||
question: "What is helping to combat climate change?",
|
||||
options: ["Fossil fuels", "Nuclear power", "Renewable energy", "Oil drilling"],
|
||||
correct: 2,
|
||||
hint: "Look for what countries are investing in."
|
||||
},
|
||||
{
|
||||
question: "What benefits are mentioned for renewable energy?",
|
||||
options: ["Only environmental", "Only economic", "Both environmental and economic", "Neither"],
|
||||
correct: 2,
|
||||
hint: "The passage mentions both climate change and job creation."
|
||||
}
|
||||
]
|
||||
},
|
||||
hard: {
|
||||
text: "The phenomenon of quantum entanglement, first described by Einstein as 'spooky action at a distance,' has evolved from a theoretical curiosity to a cornerstone of modern quantum physics. When two particles become entangled, measuring the state of one instantly affects the state of the other, regardless of the distance separating them. This seemingly impossible connection has profound implications for quantum computing, cryptography, and our understanding of the fundamental nature of reality.",
|
||||
questions: [
|
||||
{
|
||||
question: "How did Einstein describe quantum entanglement?",
|
||||
options: ["Theoretical impossibility", "Spooky action at a distance", "Quantum computing", "Fundamental reality"],
|
||||
correct: 1,
|
||||
hint: "Look for Einstein's specific phrase in the text."
|
||||
},
|
||||
{
|
||||
question: "What happens when entangled particles are measured?",
|
||||
options: ["Nothing occurs", "One affects the other instantly", "They separate", "They disappear"],
|
||||
correct: 1,
|
||||
hint: "Focus on what happens when measuring one particle."
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
// Pure AI content generation methods (no real content available)
|
||||
|
||||
const content = passages[request.difficulty] || passages.medium;
|
||||
async _generateAITextExercise(iaEngine, request) {
|
||||
const { difficulty = 'medium', chapterId, bookId } = request;
|
||||
const topic = chapterId || bookId || 'general English';
|
||||
|
||||
console.log(`🤖 Generating AI text comprehension for topic: ${topic}`);
|
||||
|
||||
const prompt = `Create an intelligent text comprehension exercise for ${difficulty} level English learners.
|
||||
|
||||
Topic area: ${topic}
|
||||
Requirements:
|
||||
- Create an educational text passage (100-200 words) about ${topic}
|
||||
- Make it appropriate for ${difficulty} level
|
||||
- Generate 2-3 comprehension questions about the text
|
||||
- For each question, create 1 CORRECT answer + 5 PLAUSIBLE wrong answers (distractors)
|
||||
- Wrong answers should be realistic mistakes students might make:
|
||||
* Partial truths or incomplete information
|
||||
* Common misconceptions about the topic
|
||||
* Details confused with main ideas
|
||||
* Logical but incorrect conclusions
|
||||
* Similar concepts that don't apply
|
||||
- Put correct answer FIRST, then 5 intelligent distractors
|
||||
- Include helpful hints that guide without giving away the answer
|
||||
- Focus on testing real comprehension, not just vocabulary
|
||||
|
||||
Return ONLY valid JSON:
|
||||
{
|
||||
"title": "Intelligent QCM: ${topic}",
|
||||
"passage": "Educational text about the topic...",
|
||||
"questions": [
|
||||
{
|
||||
"question": "What is the main idea of this passage?",
|
||||
"options": [
|
||||
"Correct comprehensive answer",
|
||||
"Plausible but too specific detail",
|
||||
"Common misconception about topic",
|
||||
"Logical but wrong conclusion",
|
||||
"Related but different concept",
|
||||
"Partially true but incomplete"
|
||||
],
|
||||
"hint": "Focus on the overall message, not specific details"
|
||||
}
|
||||
]
|
||||
}`;
|
||||
|
||||
try {
|
||||
const result = await iaEngine.validateEducationalContent(prompt, {
|
||||
systemPrompt: 'You are a text comprehension expert. Create engaging, educational content. Return ONLY valid JSON.',
|
||||
temperature: 0.6
|
||||
});
|
||||
|
||||
const aiContent = this._parseAIExerciseResponse(result);
|
||||
if (!aiContent) {
|
||||
throw new Error('Invalid AI response format');
|
||||
}
|
||||
|
||||
const steps = aiContent.questions.map((q, index) => {
|
||||
const shuffled = this._shuffleOptions(q.options, 0);
|
||||
return {
|
||||
title: `Reading Comprehension - ${request.difficulty}`,
|
||||
type: 'text',
|
||||
difficulty: request.difficulty,
|
||||
steps: content.questions.map((q, index) => ({
|
||||
instruction: index === 0 ? "Read the following passage and answer the questions." : "Continue answering questions about the passage.",
|
||||
text: content.text,
|
||||
id: `ai-text-${index}`,
|
||||
type: 'multiple-choice',
|
||||
content: {
|
||||
passage: aiContent.passage,
|
||||
question: q.question,
|
||||
options: q.options,
|
||||
correct: q.correct,
|
||||
hint: q.hint
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate audio exercise content
|
||||
* @param {Object} request - Request details
|
||||
* @returns {Object} - Audio exercise
|
||||
* @private
|
||||
*/
|
||||
_generateAudioExercise(request) {
|
||||
const audioExercises = {
|
||||
easy: {
|
||||
title: "Basic Listening",
|
||||
transcript: "Hello, my name is Sarah. I am twenty years old. I live in Paris.",
|
||||
questions: [
|
||||
{
|
||||
question: "What is the speaker's name?",
|
||||
options: ["Maria", "Sarah", "Anna", "Lisa"],
|
||||
correct: 1,
|
||||
hint: "Listen to the beginning of the recording."
|
||||
}
|
||||
]
|
||||
options: shuffled.options,
|
||||
correctAnswer: shuffled.correctAnswer
|
||||
},
|
||||
medium: {
|
||||
title: "Weather Forecast",
|
||||
transcript: "Good morning! Today's weather will be partly cloudy with temperatures reaching 22 degrees Celsius. There's a 30% chance of rain in the afternoon, so you might want to bring an umbrella. Tomorrow will be sunny with temperatures up to 25 degrees.",
|
||||
questions: [
|
||||
{
|
||||
question: "What will the temperature be today?",
|
||||
options: ["20 degrees", "22 degrees", "25 degrees", "30 degrees"],
|
||||
correct: 1,
|
||||
hint: "Listen for today's temperature, not tomorrow's."
|
||||
},
|
||||
{
|
||||
question: "What should you bring today?",
|
||||
options: ["Sunglasses", "Jacket", "Umbrella", "Hat"],
|
||||
correct: 2,
|
||||
hint: "Think about what you need when there's a chance of rain."
|
||||
}
|
||||
]
|
||||
}
|
||||
hint: q.hint || "Read carefully and think about the meaning"
|
||||
};
|
||||
|
||||
const content = audioExercises[request.difficulty] || audioExercises.medium;
|
||||
});
|
||||
|
||||
return {
|
||||
title: content.title,
|
||||
id: `ai-text-${Date.now()}`,
|
||||
type: 'text',
|
||||
title: aiContent.title || `AI Intelligent QCM: ${topic}`,
|
||||
description: `AI-generated text comprehension exercise about ${topic}`,
|
||||
difficulty,
|
||||
steps,
|
||||
metadata: {
|
||||
source: 'ai-generated-pure',
|
||||
topic,
|
||||
provider: 'multiple-ai-providers'
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.warn('AI text generation failed:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async _generateAIAudioExercise(iaEngine, request) {
|
||||
const { difficulty = 'medium', chapterId, bookId } = request;
|
||||
const topic = chapterId || bookId || 'general conversation';
|
||||
|
||||
console.log(`🤖 Generating AI audio comprehension for topic: ${topic}`);
|
||||
|
||||
const prompt = `Create an intelligent audio comprehension exercise for ${difficulty} level English learners.
|
||||
|
||||
Topic: ${topic}
|
||||
Requirements:
|
||||
- Create a realistic dialogue or monologue transcript (50-100 words)
|
||||
- Make it sound natural and conversational for ${difficulty} level
|
||||
- Generate 2 listening comprehension questions
|
||||
- For each question, create 1 CORRECT answer + 5 PLAUSIBLE wrong answers
|
||||
- Wrong answers should test common listening mistakes:
|
||||
* Mishearing similar-sounding words
|
||||
* Confusing speakers in dialogues
|
||||
* Missing context clues
|
||||
* Focusing on wrong details
|
||||
* Misunderstanding tone or intent
|
||||
- Put correct answer FIRST, then 5 intelligent distractors
|
||||
- Focus on what learners would actually hear and misunderstand
|
||||
|
||||
Return ONLY valid JSON:
|
||||
{
|
||||
"title": "Intelligent Audio QCM: ${topic}",
|
||||
"transcript": "Realistic dialogue or speech...",
|
||||
"questions": [
|
||||
{
|
||||
"question": "What did the speaker say about...?",
|
||||
"options": [
|
||||
"Correct interpretation of what was said",
|
||||
"Similar-sounding but wrong information",
|
||||
"Wrong speaker attribution",
|
||||
"Misunderstood context",
|
||||
"Wrong detail focus",
|
||||
"Opposite of what was meant"
|
||||
],
|
||||
"hint": "Listen carefully to the exact words and context"
|
||||
}
|
||||
]
|
||||
}`;
|
||||
|
||||
try {
|
||||
const result = await iaEngine.validateEducationalContent(prompt, {
|
||||
systemPrompt: 'You are a listening comprehension expert. Create realistic audio content. Return ONLY valid JSON.',
|
||||
temperature: 0.6
|
||||
});
|
||||
|
||||
const aiContent = this._parseAIExerciseResponse(result);
|
||||
if (!aiContent) {
|
||||
throw new Error('Invalid AI response format');
|
||||
}
|
||||
|
||||
const steps = aiContent.questions.map((q, index) => {
|
||||
const shuffled = this._shuffleOptions(q.options, 0);
|
||||
return {
|
||||
id: `ai-audio-${index}`,
|
||||
type: 'multiple-choice',
|
||||
content: {
|
||||
passage: `🎧 **Listen carefully:**\n\n"${aiContent.transcript}"`,
|
||||
question: q.question,
|
||||
options: shuffled.options,
|
||||
correctAnswer: shuffled.correctAnswer,
|
||||
audioText: aiContent.transcript
|
||||
},
|
||||
hint: q.hint || "Listen for the key information"
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
id: `ai-audio-${Date.now()}`,
|
||||
type: 'audio',
|
||||
difficulty: request.difficulty,
|
||||
steps: [
|
||||
title: aiContent.title || `AI Listening: ${topic}`,
|
||||
description: `AI-generated listening exercise about ${topic}`,
|
||||
difficulty,
|
||||
steps,
|
||||
metadata: {
|
||||
source: 'ai-generated-pure',
|
||||
topic,
|
||||
provider: 'multiple-ai-providers'
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.warn('AI audio generation failed:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async _generateAIImageExercise(iaEngine, request) {
|
||||
const { difficulty = 'medium', chapterId, bookId } = request;
|
||||
const topic = chapterId || bookId || 'everyday objects';
|
||||
|
||||
console.log(`🤖 Generating AI image analysis for topic: ${topic}`);
|
||||
|
||||
const prompt = `Create an intelligent visual description exercise for ${difficulty} level English learners.
|
||||
|
||||
Topic: ${topic}
|
||||
Requirements:
|
||||
- Describe a realistic scene or object related to ${topic}
|
||||
- Create detailed visual description (50-80 words) with specific visual elements
|
||||
- Generate 2 questions about what learners would see
|
||||
- For each question, create 1 CORRECT answer + 5 PLAUSIBLE wrong answers
|
||||
- Wrong answers should test common visual interpretation mistakes:
|
||||
* Confusing similar objects or colors
|
||||
* Missing important visual details
|
||||
* Misinterpreting spatial relationships
|
||||
* Confusing foreground/background elements
|
||||
* Misunderstanding descriptive adjectives
|
||||
- Put correct answer FIRST, then 5 intelligent visual distractors
|
||||
- Focus on precise visual vocabulary and observation skills
|
||||
|
||||
Return ONLY valid JSON:
|
||||
{
|
||||
instruction: "Listen to the audio carefully and answer the questions.",
|
||||
audioUrl: "data:audio/wav;base64,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",
|
||||
transcript: content.transcript,
|
||||
questions: content.questions
|
||||
"title": "Intelligent Visual QCM: ${topic}",
|
||||
"description": "Detailed description of what you would see...",
|
||||
"questions": [
|
||||
{
|
||||
"question": "What is the main object in this scene?",
|
||||
"options": [
|
||||
"Correct identification of main object",
|
||||
"Similar-looking but wrong object",
|
||||
"Background object confused as main",
|
||||
"Wrong color or size description",
|
||||
"Related but different item",
|
||||
"Completely different category"
|
||||
],
|
||||
"hint": "Focus on the most prominent visual element described"
|
||||
}
|
||||
]
|
||||
};
|
||||
}`;
|
||||
|
||||
try {
|
||||
const result = await iaEngine.validateEducationalContent(prompt, {
|
||||
systemPrompt: 'You are a visual description expert. Create vivid, educational descriptions. Return ONLY valid JSON.',
|
||||
temperature: 0.6
|
||||
});
|
||||
|
||||
const aiContent = this._parseAIExerciseResponse(result);
|
||||
if (!aiContent) {
|
||||
throw new Error('Invalid AI response format');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate image exercise content
|
||||
* @param {Object} request - Request details
|
||||
* @returns {Object} - Image exercise
|
||||
* @private
|
||||
*/
|
||||
_generateImageExercise(request) {
|
||||
const images = {
|
||||
easy: "https://via.placeholder.com/400x300/87CEEB/ffffff?text=Sunny+Day",
|
||||
medium: "https://via.placeholder.com/400x300/228B22/ffffff?text=Green+Forest",
|
||||
hard: "https://via.placeholder.com/400x300/FF6347/ffffff?text=Complex+Scene"
|
||||
};
|
||||
|
||||
const steps = aiContent.questions.map((q, index) => {
|
||||
const shuffled = this._shuffleOptions(q.options, 0);
|
||||
return {
|
||||
title: `Image Analysis - ${request.difficulty}`,
|
||||
type: 'image',
|
||||
difficulty: request.difficulty,
|
||||
steps: [
|
||||
{
|
||||
instruction: "Look at the image carefully and answer the question.",
|
||||
imageUrl: images[request.difficulty] || images.medium,
|
||||
question: "What do you see in this image?",
|
||||
options: ["A sunny day", "A forest", "A complex scene", "Cannot determine"],
|
||||
correct: 0,
|
||||
hint: "Look at the text and colors in the placeholder image."
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate grammar exercise content
|
||||
* @param {Object} request - Request details
|
||||
* @returns {Object} - Grammar exercise
|
||||
* @private
|
||||
*/
|
||||
_generateGrammarExercise(request) {
|
||||
const exercises = {
|
||||
easy: [
|
||||
{
|
||||
instruction: "Fill in the blank with the correct verb form.",
|
||||
sentence: "The dog _____ in the park.",
|
||||
question: "Complete the sentence with the correct present tense form of 'run'.",
|
||||
options: ["run", "runs", "running", "ran"],
|
||||
correct: 1,
|
||||
explanation: "Use 'runs' because 'dog' is singular and requires the third person singular form.",
|
||||
hint: "Remember: he/she/it + verb + s"
|
||||
}
|
||||
],
|
||||
medium: [
|
||||
{
|
||||
instruction: "Choose the correct grammatical form.",
|
||||
question: "Which sentence uses the present perfect correctly?",
|
||||
options: [
|
||||
"I have went to the store",
|
||||
"I have gone to the store",
|
||||
"I have go to the store",
|
||||
"I have going to the store"
|
||||
],
|
||||
correct: 1,
|
||||
explanation: "The correct past participle of 'go' is 'gone', not 'went'.",
|
||||
hint: "Present perfect uses 'have/has + past participle'"
|
||||
id: `ai-image-${index}`,
|
||||
type: 'multiple-choice',
|
||||
content: {
|
||||
passage: `🖼️ **Imagine this scene:**\n\n${aiContent.description}`,
|
||||
question: q.question,
|
||||
options: shuffled.options,
|
||||
correctAnswer: shuffled.correctAnswer,
|
||||
imageAlt: aiContent.description
|
||||
},
|
||||
{
|
||||
instruction: "Fill in the blank with the correct form.",
|
||||
sentence: "If I _____ rich, I would travel the world.",
|
||||
question: "Complete the conditional sentence.",
|
||||
options: ["am", "was", "were", "be"],
|
||||
correct: 2,
|
||||
explanation: "In hypothetical conditionals, use 'were' for all persons with 'if'.",
|
||||
hint: "This is a hypothetical condition about the present."
|
||||
}
|
||||
]
|
||||
hint: q.hint || "Think about what you would actually see"
|
||||
};
|
||||
|
||||
const content = exercises[request.difficulty] || exercises.medium;
|
||||
});
|
||||
|
||||
return {
|
||||
title: `Grammar Practice - ${request.difficulty}`,
|
||||
id: `ai-image-${Date.now()}`,
|
||||
type: 'image',
|
||||
title: aiContent.title || `AI Visual: ${topic}`,
|
||||
description: `AI-generated visual description exercise about ${topic}`,
|
||||
difficulty,
|
||||
steps,
|
||||
metadata: {
|
||||
source: 'ai-generated-pure',
|
||||
topic,
|
||||
provider: 'multiple-ai-providers'
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.warn('AI image generation failed:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async _generateAIGrammarExercise(iaEngine, request) {
|
||||
const { difficulty = 'medium', chapterId, bookId } = request;
|
||||
const topic = chapterId || bookId || 'practical grammar';
|
||||
|
||||
console.log(`🤖 Generating AI grammar exercise for topic: ${topic}`);
|
||||
|
||||
const prompt = `Create an intelligent grammar exercise for ${difficulty} level English learners.
|
||||
|
||||
Focus area: ${topic} related grammar
|
||||
Requirements:
|
||||
- Create 3 practical grammar questions for ${difficulty} level
|
||||
- Use real-world contexts and situations
|
||||
- For each question, create 1 CORRECT answer + 5 PLAUSIBLE wrong answers
|
||||
- Wrong answers should represent common grammar mistakes:
|
||||
* Wrong verb tenses
|
||||
* Subject-verb disagreement
|
||||
* Incorrect word forms (adjective/adverb confusion)
|
||||
* Common pronunciation-based errors
|
||||
* Logical but grammatically wrong constructions
|
||||
- Put correct answer FIRST, then 5 intelligent grammar distractors
|
||||
- Include clear explanations for the correct answer
|
||||
- Focus on mistakes students actually make
|
||||
|
||||
Return ONLY valid JSON:
|
||||
{
|
||||
"title": "Intelligent Grammar QCM: ${topic}",
|
||||
"questions": [
|
||||
{
|
||||
"question": "Complete the sentence: I ___ to work every day.",
|
||||
"options": [
|
||||
"go",
|
||||
"goes",
|
||||
"going",
|
||||
"went",
|
||||
"am go",
|
||||
"goed"
|
||||
],
|
||||
"explanation": "Use 'go' with 'I' in present tense - first person singular doesn't add 's'",
|
||||
"hint": "Think about present tense with 'I' - what ending does the verb need?"
|
||||
}
|
||||
]
|
||||
}`;
|
||||
|
||||
try {
|
||||
const result = await iaEngine.validateEducationalContent(prompt, {
|
||||
systemPrompt: 'You are a grammar expert. Create practical, useful exercises. Return ONLY valid JSON.',
|
||||
temperature: 0.5
|
||||
});
|
||||
|
||||
const aiContent = this._parseAIExerciseResponse(result);
|
||||
if (!aiContent) {
|
||||
throw new Error('Invalid AI response format');
|
||||
}
|
||||
|
||||
const steps = aiContent.questions.map((q, index) => {
|
||||
const shuffled = this._shuffleOptions(q.options, 0);
|
||||
return {
|
||||
id: `ai-grammar-${index}`,
|
||||
type: 'multiple-choice',
|
||||
content: {
|
||||
question: q.question,
|
||||
options: shuffled.options,
|
||||
correctAnswer: shuffled.correctAnswer
|
||||
},
|
||||
hint: q.hint || q.explanation || "Think about the grammar rule that applies"
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
id: `ai-grammar-${Date.now()}`,
|
||||
type: 'grammar',
|
||||
difficulty: request.difficulty,
|
||||
steps: content.map(exercise => ({
|
||||
...exercise,
|
||||
hint: exercise.hint || "Think about the grammatical rules that apply here."
|
||||
}))
|
||||
title: aiContent.title || `AI Grammar: ${topic}`,
|
||||
description: `AI-generated grammar exercise for ${topic}`,
|
||||
difficulty,
|
||||
steps,
|
||||
metadata: {
|
||||
source: 'ai-generated-pure',
|
||||
topic,
|
||||
provider: 'multiple-ai-providers'
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.warn('AI grammar generation failed:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate default exercise content
|
||||
* @param {Object} request - Request details
|
||||
* @returns {Object} - Default exercise
|
||||
* @private
|
||||
*/
|
||||
_generateDefaultExercise(request) {
|
||||
return {
|
||||
title: `General Exercise - ${request.difficulty || 'medium'}`,
|
||||
type: request.subtype || 'general',
|
||||
difficulty: request.difficulty || 'medium',
|
||||
steps: [
|
||||
async _generateAIGeneralExercise(iaEngine, request) {
|
||||
const { difficulty = 'medium', chapterId, bookId, subtype } = request;
|
||||
const topic = chapterId || bookId || 'general English';
|
||||
|
||||
console.log(`🤖 Generating AI general exercise for topic: ${topic}, type: ${subtype}`);
|
||||
|
||||
const prompt = `Create an intelligent general English exercise for ${difficulty} level learners.
|
||||
|
||||
Topic: ${topic}
|
||||
Exercise type: ${subtype || 'general'}
|
||||
Requirements:
|
||||
- Create educational content appropriate for ${difficulty} level
|
||||
- Generate 2-3 practical questions about real-world English usage
|
||||
- For each question, create 1 CORRECT answer + 5 PLAUSIBLE wrong answers
|
||||
- Wrong answers should test common English learning mistakes:
|
||||
* Vocabulary confusion (similar meanings)
|
||||
* Cultural misunderstandings
|
||||
* False friends or cognates
|
||||
* Formal vs informal register confusion
|
||||
* Common usage errors by non-native speakers
|
||||
- Put correct answer FIRST, then 5 intelligent distractors
|
||||
- Focus on practical, useful English skills for daily life
|
||||
|
||||
Return ONLY valid JSON:
|
||||
{
|
||||
instruction: "This is a sample exercise.",
|
||||
question: "What type of exercise is this?",
|
||||
options: ["Text", "Audio", "Image", "General"],
|
||||
correct: 3,
|
||||
hint: "Look at the title of the exercise."
|
||||
"title": "Intelligent English QCM: ${topic}",
|
||||
"content": "Educational content or context...",
|
||||
"questions": [
|
||||
{
|
||||
"question": "In this situation, what would be the most appropriate response?",
|
||||
"options": [
|
||||
"Correct and culturally appropriate response",
|
||||
"Too formal for the situation",
|
||||
"Too casual/informal for context",
|
||||
"Grammatically wrong but common mistake",
|
||||
"Literal translation that sounds odd",
|
||||
"Right idea but wrong cultural context"
|
||||
],
|
||||
"hint": "Consider both grammar and cultural appropriateness"
|
||||
}
|
||||
]
|
||||
};
|
||||
}`;
|
||||
|
||||
try {
|
||||
const result = await iaEngine.validateEducationalContent(prompt, {
|
||||
systemPrompt: 'You are an English learning expert. Create practical, engaging exercises. Return ONLY valid JSON.',
|
||||
temperature: 0.6
|
||||
});
|
||||
|
||||
const aiContent = this._parseAIExerciseResponse(result);
|
||||
if (!aiContent) {
|
||||
throw new Error('Invalid AI response format');
|
||||
}
|
||||
|
||||
const steps = aiContent.questions.map((q, index) => {
|
||||
const shuffled = this._shuffleOptions(q.options, 0);
|
||||
return {
|
||||
id: `ai-general-${index}`,
|
||||
type: 'multiple-choice',
|
||||
content: {
|
||||
passage: aiContent.content || aiContent.passage,
|
||||
question: q.question,
|
||||
options: shuffled.options,
|
||||
correctAnswer: shuffled.correctAnswer
|
||||
},
|
||||
hint: q.hint || "Think carefully about the context"
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
id: `ai-general-${Date.now()}`,
|
||||
type: subtype || 'general',
|
||||
title: aiContent.title || `AI Practice: ${topic}`,
|
||||
description: `AI-generated exercise for ${topic}`,
|
||||
difficulty,
|
||||
steps,
|
||||
metadata: {
|
||||
source: 'ai-generated-pure',
|
||||
topic,
|
||||
provider: 'multiple-ai-providers'
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.warn('AI general generation failed:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
_parseAIExerciseResponse(result) {
|
||||
try {
|
||||
let content = null;
|
||||
|
||||
if (result.content) {
|
||||
try {
|
||||
content = JSON.parse(result.content);
|
||||
} catch (parseError) {
|
||||
// Try to extract JSON from text
|
||||
const jsonMatch = result.content.match(/\{[\s\S]*\}/);
|
||||
if (jsonMatch) {
|
||||
content = JSON.parse(jsonMatch[0]);
|
||||
}
|
||||
}
|
||||
} else if (typeof result === 'object' && result.title) {
|
||||
content = result;
|
||||
}
|
||||
|
||||
if (content && (content.questions || content.passage || content.description)) {
|
||||
return content;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.warn('Failed to parse AI exercise response:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Event handlers
|
||||
|
||||
/**
|
||||
@ -2025,202 +2290,6 @@ Return ONLY valid JSON:
|
||||
_handleClearCache(event) {
|
||||
this.clearCache(event.data?.pattern);
|
||||
}
|
||||
|
||||
async _generateImageAnalysisWithAI(realContent, difficulty) {
|
||||
// Import IAEngine
|
||||
let IAEngine;
|
||||
try {
|
||||
const module = await import('../DRS/services/IAEngine.js');
|
||||
IAEngine = module.default;
|
||||
} catch (error) {
|
||||
throw new Error('IAEngine not available for image analysis');
|
||||
}
|
||||
|
||||
const iaEngine = new IAEngine();
|
||||
const images = realContent.images.slice(0, difficulty === 'easy' ? 2 : 3);
|
||||
const steps = [];
|
||||
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
const image = images[i];
|
||||
const imageUrl = image.url || image.src || image.imageUrl;
|
||||
const description = image.description || image.alt || image.caption || '';
|
||||
const title = image.title || `Image ${i + 1}`;
|
||||
|
||||
try {
|
||||
console.log(`🤖 Generating image analysis for: "${title}"`);
|
||||
|
||||
const prompt = `Create an image analysis and explanation question for language learning:
|
||||
|
||||
**Image: ${title}**
|
||||
Description: "${description}"
|
||||
Image URL: ${imageUrl}
|
||||
|
||||
Create ONE question that tests:
|
||||
- Visual analysis and description skills
|
||||
- Ability to explain what is seen
|
||||
- Understanding of visual context and details
|
||||
- Language skills for describing images
|
||||
|
||||
Requirements:
|
||||
- ${difficulty} difficulty level
|
||||
- Focus on analysis and explanation
|
||||
- Test descriptive language abilities
|
||||
- 4 multiple choice options, correct answer FIRST
|
||||
|
||||
Return ONLY valid JSON:
|
||||
{
|
||||
"question": "What is the best way to describe or explain this image?",
|
||||
"options": ["Correct description/analysis", "Wrong description 1", "Wrong description 2", "Wrong description 3"],
|
||||
"hint": "Look carefully at the details and context"
|
||||
}`;
|
||||
|
||||
const result = await iaEngine.validateEducationalContent(prompt, {
|
||||
systemPrompt: 'You are a visual analysis expert for language learning. Create questions that test descriptive and analytical skills. Return ONLY valid JSON.',
|
||||
temperature: 0.4
|
||||
});
|
||||
|
||||
const aiQuestion = this._parseAIQuestionResponse(result);
|
||||
if (aiQuestion) {
|
||||
steps.push({
|
||||
id: `image-analysis-ai-${i}`,
|
||||
type: 'multiple-choice',
|
||||
content: {
|
||||
passage: `**🖼️ Image Analysis: ${title}**\n\n*Study this image carefully and analyze what you see.*\n\n**Description:** ${description}`,
|
||||
question: aiQuestion.question,
|
||||
options: aiQuestion.options,
|
||||
correctAnswer: 0,
|
||||
imageUrl: imageUrl,
|
||||
imageAlt: description || `Analysis image ${i + 1}`
|
||||
},
|
||||
hint: aiQuestion.hint || "Look at the details and think about how to describe them"
|
||||
});
|
||||
}
|
||||
} catch (aiError) {
|
||||
console.warn(`⚠️ AI failed for image ${i}:`, aiError.message);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (steps.length === 0) {
|
||||
throw new Error('AI could not generate image analysis questions');
|
||||
}
|
||||
|
||||
// Shuffle options
|
||||
steps.forEach(step => {
|
||||
const shuffled = this._shuffleOptions(step.content.options, step.content.correctAnswer);
|
||||
step.content.options = shuffled.options;
|
||||
step.content.correctAnswer = shuffled.correctAnswer;
|
||||
});
|
||||
|
||||
return {
|
||||
id: `image-analysis-${Date.now()}`,
|
||||
type: 'image',
|
||||
title: `AI Image Analysis: ${realContent.name}`,
|
||||
description: `Analyze and explain images with AI guidance`,
|
||||
difficulty,
|
||||
steps,
|
||||
metadata: {
|
||||
source: 'ai-image-analysis',
|
||||
chapterInfo: realContent.metadata
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async _generateVocabularyImageAnalysisWithAI(realContent, difficulty, visualWords) {
|
||||
// Import IAEngine
|
||||
let IAEngine;
|
||||
try {
|
||||
const module = await import('../DRS/services/IAEngine.js');
|
||||
IAEngine = module.default;
|
||||
} catch (error) {
|
||||
throw new Error('IAEngine not available for vocabulary image analysis');
|
||||
}
|
||||
|
||||
const iaEngine = new IAEngine();
|
||||
const selectedWords = visualWords.slice(0, difficulty === 'easy' ? 2 : 3);
|
||||
const steps = [];
|
||||
|
||||
for (let i = 0; i < selectedWords.length; i++) {
|
||||
const [word, data] = selectedWords[i];
|
||||
|
||||
try {
|
||||
console.log(`🤖 Generating image analysis for word: "${word}"`);
|
||||
|
||||
const prompt = `Create a visual analysis question for this vocabulary word in a learning context:
|
||||
|
||||
**Word:** "${word}"
|
||||
**Meaning:** "${data.user_language}"
|
||||
**Type:** ${data.type}
|
||||
|
||||
Create ONE question that tests:
|
||||
- Visual understanding and explanation of the concept
|
||||
- Ability to analyze and describe the word's visual representation
|
||||
- Language skills for explaining what the word represents visually
|
||||
|
||||
Requirements:
|
||||
- ${difficulty} difficulty level
|
||||
- Focus on visual analysis and description
|
||||
- Help students understand how to describe and explain this concept
|
||||
- 4 multiple choice options, correct answer FIRST
|
||||
|
||||
Return ONLY valid JSON:
|
||||
{
|
||||
"question": "How would you visually describe or analyze what '${word}' represents?",
|
||||
"options": ["Correct visual analysis", "Wrong description 1", "Wrong description 2", "Wrong description 3"],
|
||||
"hint": "Think about the visual characteristics and what you would see"
|
||||
}`;
|
||||
|
||||
const result = await iaEngine.validateEducationalContent(prompt, {
|
||||
systemPrompt: 'You are a vocabulary visualization expert for language learning. Create questions that test visual understanding and descriptive skills. Return ONLY valid JSON.',
|
||||
temperature: 0.4
|
||||
});
|
||||
|
||||
const aiQuestion = this._parseAIQuestionResponse(result);
|
||||
if (aiQuestion) {
|
||||
steps.push({
|
||||
id: `vocab-image-ai-${i}`,
|
||||
type: 'multiple-choice',
|
||||
content: {
|
||||
passage: `**🔍 Visual Analysis: "${word}"**\n\n*Think about how you would visually describe or analyze this concept.*\n\n**Word:** ${word}\n**Meaning:** ${data.user_language}\n**Type:** ${data.type}`,
|
||||
question: aiQuestion.question,
|
||||
options: aiQuestion.options,
|
||||
correctAnswer: 0,
|
||||
imageUrl: `https://via.placeholder.com/300x200?text=${encodeURIComponent(word)}`,
|
||||
imageAlt: `Visual representation of ${word}`
|
||||
},
|
||||
hint: aiQuestion.hint || "Think about what you would see and how you would describe it"
|
||||
});
|
||||
}
|
||||
} catch (aiError) {
|
||||
console.warn(`⚠️ AI failed for vocabulary image ${i}:`, aiError.message);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (steps.length === 0) {
|
||||
throw new Error('AI could not generate vocabulary image analysis questions');
|
||||
}
|
||||
|
||||
// Shuffle options
|
||||
steps.forEach(step => {
|
||||
const shuffled = this._shuffleOptions(step.content.options, step.content.correctAnswer);
|
||||
step.content.options = shuffled.options;
|
||||
step.content.correctAnswer = shuffled.correctAnswer;
|
||||
});
|
||||
|
||||
return {
|
||||
id: `vocab-image-analysis-${Date.now()}`,
|
||||
type: 'image',
|
||||
title: `AI Visual Analysis: ${realContent.name}`,
|
||||
description: `Analyze and explain vocabulary concepts visually`,
|
||||
difficulty,
|
||||
steps,
|
||||
metadata: {
|
||||
source: 'ai-vocabulary-image-analysis',
|
||||
chapterInfo: realContent.metadata
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default ContentLoader;
|
||||
Loading…
Reference in New Issue
Block a user