Files
yourpart3/backend/scripts/update-family-words-exercises.js
Torsten Schulz (local) 14eb28d37f Refactor family vocabulary exercises generation for improved flexibility
- Replaced static family vocabulary exercises with a dynamic structure that generates exercises based on native language input, enhancing adaptability for different languages.
- Introduced a mapping for family words and their translations, allowing for a more comprehensive and organized approach to exercise creation.
- Updated logging to include native language context during exercise generation, improving clarity for developers and users.
- Streamlined the gap fill and transformation exercises to ensure accurate and relevant content for learners.
2026-01-19 22:59:46 +01:00

294 lines
8.4 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Script zum Aktualisieren der "Familienwörter"-Übungen in Bisaya-Kursen
*
* Verwendung:
* node backend/scripts/update-family-words-exercises.js
*
* Ersetzt bestehende Dummy-Übungen durch spezifische Familienwörter-Übungen.
*/
import { sequelize } from '../utils/sequelize.js';
import VocabCourseLesson from '../models/community/vocab_course_lesson.js';
import VocabGrammarExercise from '../models/community/vocab_grammar_exercise.js';
import VocabCourse from '../models/community/vocab_course.js';
import User from '../models/community/user.js';
// Familienwörter-Übersetzungen in verschiedene Muttersprachen
const FAMILY_WORDS = {
Mutter: {
de: 'Mutter',
en: 'Mother',
es: 'Madre',
fr: 'Mère',
it: 'Madre',
pt: 'Mãe'
},
Vater: {
de: 'Vater',
en: 'Father',
es: 'Padre',
fr: 'Père',
it: 'Padre',
pt: 'Pai'
},
'älterer Bruder': {
de: 'älterer Bruder',
en: 'older brother',
es: 'hermano mayor',
fr: 'frère aîné',
it: 'fratello maggiore',
pt: 'irmão mais velho'
},
'ältere Schwester': {
de: 'ältere Schwester',
en: 'older sister',
es: 'hermana mayor',
fr: 'sœur aînée',
it: 'sorella maggiore',
pt: 'irmã mais velha'
},
Großmutter: {
de: 'Großmutter',
en: 'Grandmother',
es: 'Abuela',
fr: 'Grand-mère',
it: 'Nonna',
pt: 'Avó'
},
Großvater: {
de: 'Großvater',
en: 'Grandfather',
es: 'Abuelo',
fr: 'Grand-père',
it: 'Nonno',
pt: 'Avô'
}
};
// Bisaya-Übersetzungen
const BISAYA_TRANSLATIONS = {
'Mutter': 'Nanay',
'Vater': 'Tatay',
'älterer Bruder': 'Kuya',
'ältere Schwester': 'Ate',
'Großmutter': 'Lola',
'Großvater': 'Lolo'
};
// Sprach-Codes für Mapping
const LANGUAGE_CODES = {
'Deutsch': 'de',
'English': 'en',
'Español': 'es',
'Français': 'fr',
'Italiano': 'it',
'Português': 'pt',
'Spanish': 'es',
'French': 'fr',
'Italian': 'it',
'Portuguese': 'pt'
};
// Erstelle Übungen basierend auf Muttersprache
function createFamilyWordsExercises(nativeLanguageName) {
const langCode = LANGUAGE_CODES[nativeLanguageName] || 'de'; // Fallback zu Deutsch
const exercises = [];
// Multiple Choice Übungen für jedes Familienwort
const familyWords = Object.keys(FAMILY_WORDS);
const bisayaWords = ['Nanay', 'Tatay', 'Kuya', 'Ate', 'Lola', 'Lolo'];
familyWords.forEach((key, index) => {
const nativeWord = FAMILY_WORDS[key][langCode];
const bisayaWord = BISAYA_TRANSLATIONS[key];
// Erstelle Multiple Choice mit falschen Antworten
const wrongAnswers = bisayaWords.filter(w => w !== bisayaWord);
const shuffledWrong = wrongAnswers.sort(() => Math.random() - 0.5).slice(0, 3);
const options = [bisayaWord, ...shuffledWrong].sort(() => Math.random() - 0.5);
const correctIndex = options.indexOf(bisayaWord);
exercises.push({
exerciseTypeId: 2, // multiple_choice
title: `Wie sagt man "${nativeWord}" auf Bisaya?`,
instruction: 'Wähle die richtige Übersetzung.',
questionData: {
type: 'multiple_choice',
question: `Wie sagt man "${nativeWord}" auf Bisaya?`,
options: options
},
answerData: {
type: 'multiple_choice',
correctAnswer: correctIndex
},
explanation: `"${bisayaWord}" bedeutet "${nativeWord}" auf Bisaya.`
});
});
// Gap Fill Übung
const nativeWords = familyWords.map(key => FAMILY_WORDS[key][langCode]);
exercises.push({
exerciseTypeId: 1, // gap_fill
title: 'Familienwörter vervollständigen',
instruction: `Fülle die Lücken mit den richtigen Bisaya-Familienwörtern.`,
questionData: {
type: 'gap_fill',
text: familyWords.map((key, i) => `{gap} (${nativeWords[i]})`).join(' | '),
gaps: familyWords.length
},
answerData: {
type: 'gap_fill',
answers: bisayaWords
},
explanation: bisayaWords.map((bw, i) => `${bw} = ${nativeWords[i]}`).join(', ') + '.'
});
// Transformation Übung
exercises.push({
exerciseTypeId: 4, // transformation
title: 'Familienwörter übersetzen',
instruction: `Übersetze das Familienwort ins Bisaya.`,
questionData: {
type: 'transformation',
text: nativeWords[0], // Erste Muttersprache als Beispiel
sourceLanguage: nativeLanguageName || 'Deutsch',
targetLanguage: 'Bisaya'
},
answerData: {
type: 'transformation',
correct: bisayaWords[0],
alternatives: [bisayaWords[0]] // Nur die korrekte Antwort
},
explanation: `"${bisayaWords[0]}" bedeutet "${nativeWords[0]}" auf Bisaya.`
});
return exercises;
}
async function findOrCreateSystemUser() {
let systemUser = await User.findOne({
where: {
username: 'system'
}
});
if (!systemUser) {
systemUser = await User.findOne({
where: {
username: 'admin'
}
});
}
if (!systemUser) {
console.error('❌ System-Benutzer nicht gefunden.');
throw new Error('System user not found');
}
return systemUser;
}
async function updateFamilyWordsExercises() {
await sequelize.authenticate();
console.log('Datenbankverbindung erfolgreich hergestellt.\n');
const systemUser = await findOrCreateSystemUser();
console.log(`Verwende System-Benutzer: ${systemUser.username} (ID: ${systemUser.id})\n`);
// Finde alle Bisaya-Kurse
const [bisayaLanguage] = await sequelize.query(
`SELECT id FROM community.vocab_language WHERE name = 'Bisaya' LIMIT 1`,
{
type: sequelize.QueryTypes.SELECT
}
);
if (!bisayaLanguage) {
console.error('❌ Bisaya-Sprache nicht gefunden.');
return;
}
const courses = await sequelize.query(
`SELECT c.id, c.title, c.owner_user_id, c.native_language_id, nl.name as native_language_name
FROM community.vocab_course c
LEFT JOIN community.vocab_language nl ON c.native_language_id = nl.id
WHERE c.language_id = :languageId`,
{
replacements: { languageId: bisayaLanguage.id },
type: sequelize.QueryTypes.SELECT
}
);
console.log(`Gefunden: ${courses.length} Bisaya-Kurse\n`);
let totalExercisesUpdated = 0;
let totalLessonsUpdated = 0;
for (const course of courses) {
const nativeLangName = course.native_language_name || 'Deutsch'; // Fallback zu Deutsch
console.log(`📚 Kurs: ${course.title} (ID: ${course.id}, Muttersprache: ${nativeLangName})`);
// Erstelle Übungen für diese Muttersprache
const exercises = createFamilyWordsExercises(nativeLangName);
// Finde "Familienwörter"-Lektionen
const lessons = await VocabCourseLesson.findAll({
where: {
courseId: course.id,
title: 'Familienwörter'
},
order: [['lessonNumber', 'ASC']]
});
console.log(` ${lessons.length} "Familienwörter"-Lektionen gefunden\n`);
for (const lesson of lessons) {
// Lösche bestehende Übungen (inkl. Dummy-Übungen)
const deletedCount = await VocabGrammarExercise.destroy({
where: { lessonId: lesson.id }
});
console.log(` 🗑️ Lektion ${lesson.lessonNumber}: "${lesson.title}" - ${deletedCount} alte Übung(en) gelöscht`);
// Erstelle neue Übungen
let exerciseNumber = 1;
for (const exerciseData of exercises) {
await VocabGrammarExercise.create({
lessonId: lesson.id,
exerciseTypeId: exerciseData.exerciseTypeId,
exerciseNumber: exerciseNumber++,
title: exerciseData.title,
instruction: exerciseData.instruction,
questionData: JSON.stringify(exerciseData.questionData),
answerData: JSON.stringify(exerciseData.answerData),
explanation: exerciseData.explanation,
createdByUserId: course.owner_user_id || systemUser.id
});
totalExercisesUpdated++;
}
console.log(` ✅ Lektion ${lesson.lessonNumber}: "${lesson.title}" - ${exercises.length} neue Übung(en) erstellt (${nativeLangName} → Bisaya)`);
totalLessonsUpdated++;
}
console.log('');
}
console.log(`\n🎉 Zusammenfassung:`);
console.log(` ${totalLessonsUpdated} Lektionen aktualisiert`);
console.log(` ${totalExercisesUpdated} neue Grammatik-Übungen erstellt`);
}
updateFamilyWordsExercises()
.then(() => {
sequelize.close();
process.exit(0);
})
.catch((error) => {
console.error('❌ Fehler:', error);
sequelize.close();
process.exit(1);
});