refactor(exercises): standardize answer language handling across exercise scripts
All checks were successful
Deploy to production / deploy (push) Successful in 2m48s

- Introduced a mechanism to infer answer language based on question phrasing in multiple exercise scripts, enhancing consistency in exercise data.
- Updated question formats to clarify the intent of exercises, improving user understanding and engagement.
- Streamlined the code for better maintainability and clarity in exercise generation processes.
This commit is contained in:
Torsten Schulz (local)
2026-04-07 14:32:44 +02:00
parent 160c9dafb2
commit ebb2283646
7 changed files with 107 additions and 6 deletions

View File

@@ -349,7 +349,8 @@ function createFamilyConversationExercises(nativeLanguageName) {
instruction: 'Übersetze den Bisaya-Satz ins ' + nativeLanguageName,
questionData: JSON.stringify({
type: 'multiple_choice',
question: `Wie sagt man "${conv.bisaya}" auf ${nativeLanguageName}?`,
answerLanguage: 'native',
question: `Was bedeutet "${conv.bisaya}"?`,
options: options
}),
answerData: JSON.stringify({
@@ -379,6 +380,7 @@ function createFamilyConversationExercises(nativeLanguageName) {
instruction: 'Was bedeutet dieser Bisaya-Satz?',
questionData: JSON.stringify({
type: 'multiple_choice',
answerLanguage: 'native',
question: `Was bedeutet "${conv.bisaya}"?`,
options: options
}),

View File

@@ -134,6 +134,7 @@ function createFamilyWordsExercises(nativeLanguageName) {
instruction: 'Wähle die richtige Übersetzung.',
questionData: {
type: 'multiple_choice',
answerLanguage: 'target',
question: `Wie sagt man "${nativeWord}" auf Bisaya?`,
options: options
},

View File

@@ -349,7 +349,8 @@ function createFeelingsAffectionExercises(nativeLanguageName) {
instruction: 'Übersetze den Bisaya-Satz ins ' + nativeLanguageName,
questionData: JSON.stringify({
type: 'multiple_choice',
question: `Wie sagt man "${conv.bisaya}" auf ${nativeLanguageName}?`,
answerLanguage: 'native',
question: `Was bedeutet "${conv.bisaya}"?`,
options: options
}),
answerData: JSON.stringify({
@@ -379,6 +380,7 @@ function createFeelingsAffectionExercises(nativeLanguageName) {
instruction: 'Was bedeutet dieser Bisaya-Satz?',
questionData: JSON.stringify({
type: 'multiple_choice',
answerLanguage: 'native',
question: `Was bedeutet "${conv.bisaya}"?`,
options: options
}),

View File

@@ -582,6 +582,7 @@ async function updateFoodCareExercises() {
instruction: 'Wähle die richtige Übersetzung.',
questionData: JSON.stringify({
type: 'multiple_choice',
answerLanguage: 'target',
question: `Wie sagt man "${conv.native}" auf Bisaya?`,
options: [
conv.bisaya,
@@ -608,6 +609,7 @@ async function updateFoodCareExercises() {
instruction: 'Wähle die richtige Übersetzung.',
questionData: JSON.stringify({
type: 'multiple_choice',
answerLanguage: 'native',
question: `Was bedeutet "${conv.bisaya}"?`,
options: [
conv.native,

View File

@@ -13,6 +13,31 @@ import VocabCourseLesson from '../models/community/vocab_course_lesson.js';
import VocabGrammarExercise from '../models/community/vocab_grammar_exercise.js';
import User from '../models/community/user.js';
function normalizeMcAnswerLanguage(question = '') {
const q = String(question || '').trim();
if (!q) return null;
if (/Wie sagt man/i.test(q) || /auf Bisaya\?/i.test(q)) return 'target';
if (/Was bedeutet/i.test(q) || /Was heißt/i.test(q)) return 'native';
return null;
}
function enrichAnswerLanguage(exercises = []) {
return exercises.map((exercise) => {
const qd = exercise?.questionData;
if (!qd || qd.type !== 'multiple_choice') return exercise;
if (qd.answerLanguage || qd.answerLanguageId) return exercise;
const inferred = normalizeMcAnswerLanguage(qd.question);
if (!inferred) return exercise;
return {
...exercise,
questionData: {
...qd,
answerLanguage: inferred
}
};
});
}
// Spezifische Übungen für Überlebenssätze
const SURVIVAL_EXERCISES = {
'Überlebenssätze - Teil 1': [
@@ -399,7 +424,7 @@ async function updateSurvivalExercises() {
console.log(` ${lessons.length} "Überlebenssätze"-Lektionen gefunden\n`);
for (const lesson of lessons) {
const exercises = SURVIVAL_EXERCISES[lesson.title];
const exercises = enrichAnswerLanguage(SURVIVAL_EXERCISES[lesson.title]);
if (!exercises || exercises.length === 0) {
console.log(` ⚠️ Lektion ${lesson.lessonNumber}: "${lesson.title}" - keine Übungen definiert`);

View File

@@ -23,6 +23,31 @@ function withTypeName(exerciseTypeName, exercise) {
const LESSON_TITLES = ['Woche 1 - Wiederholung', 'Woche 1 - Vokabeltest'];
function normalizeMcAnswerLanguage(question = '') {
const q = String(question || '').trim();
if (!q) return null;
if (/Wie sagt man/i.test(q) || /auf Bisaya\?/i.test(q)) return 'target';
if (/Was bedeutet/i.test(q) || /Was heißt/i.test(q)) return 'native';
return null;
}
function enrichAnswerLanguage(exercises = []) {
return exercises.map((exercise) => {
const qd = exercise?.questionData;
if (!qd || qd.type !== 'multiple_choice') return exercise;
if (qd.answerLanguage || qd.answerLanguageId) return exercise;
const inferred = normalizeMcAnswerLanguage(qd.question);
if (!inferred) return exercise;
return {
...exercise,
questionData: {
...qd,
answerLanguage: inferred
}
};
});
}
const BISAYA_EXERCISES = {
'Woche 1 - Wiederholung': [
{ exerciseTypeId: 2, title: 'Wiederholung: Wie sagt man "Wie geht es dir?"?', instruction: 'Wähle die richtige Begrüßung aus.', questionData: { type: 'multiple_choice', question: 'Wie sagt man "Wie geht es dir?" auf Bisaya?', options: ['Kumusta ka?', 'Maayo', 'Salamat', 'Palihug'] }, answerData: { type: 'multiple_choice', correctAnswer: 0 }, explanation: '"Kumusta ka?" ist die Standard-Begrüßung auf Bisaya.' },
@@ -111,7 +136,7 @@ async function updateWeek1BisayaExercises() {
console.log(`📚 Kurs: ${course.title} (ID: ${course.id})`);
for (const lessonTitle of LESSON_TITLES) {
const exercises = BISAYA_EXERCISES[lessonTitle];
const exercises = enrichAnswerLanguage(BISAYA_EXERCISES[lessonTitle]);
if (!exercises || exercises.length === 0) continue;
const lessons = await VocabCourseLesson.findAll({