feat(bisaya-course): add new exercises for situational role plays and enhance lesson normalization
All checks were successful
Deploy to production / deploy (push) Successful in 3m3s
All checks were successful
Deploy to production / deploy (push) Successful in 3m3s
- Introduced a new section titled "Rollenspiele - echte Situationen" with multiple exercises focusing on real-life scenarios in Bisaya, including multiple-choice, gap-fill, and transformation tasks. - Implemented a normalization function for lesson titles to improve matching accuracy and facilitate the rebuilding of placeholder lessons. - Updated the course content generation logic to replace outdated exercises with new ones based on normalized titles, ensuring a more relevant learning experience.
This commit is contained in:
@@ -4323,6 +4323,73 @@ const BISAYA_EXERCISES = {
|
||||
})
|
||||
],
|
||||
|
||||
'Rollenspiele - echte Situationen': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Szene wählen',
|
||||
instruction: 'Wähle die Bisaya-Formulierung, die am besten zu einer gemischten Alltagsszene (Weg + Termin + Hilfe) passt.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Ihr müsst in die Stadt, habt einen Termin und willst kurz Hilfe anbieten. Was passt am ehesten?',
|
||||
options: [
|
||||
'Moadto mi sa lungsod. Aduna mi appointment. Tabangan tika.',
|
||||
'Asa ang CR?',
|
||||
'Nikaon na ka?',
|
||||
'Magdula ta.'
|
||||
]
|
||||
},
|
||||
answerData: { type: 'multiple_choice', correctAnswer: 0 },
|
||||
explanation: 'Rollenspiele verbinden oft Weg, Termin und Hilfe in einer kurzen Kette.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Arzt und Weg',
|
||||
instruction: 'Fülle die Lücke: Arzt und Bewegung.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Adto ta sa {gap}.',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['doktor']
|
||||
},
|
||||
explanation: '„Adto ta sa doktor." ist ein typischer Rollenspiel-Satz zum Arztbesuch.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 4,
|
||||
title: 'Kind sicher holen',
|
||||
instruction: 'Übersetze ins Bisaya.',
|
||||
questionData: {
|
||||
type: 'transformation',
|
||||
text: 'Ich hole das Kind.',
|
||||
sourceLanguage: 'Deutsch',
|
||||
targetLanguage: 'Bisaya'
|
||||
},
|
||||
answerData: {
|
||||
type: 'transformation',
|
||||
correct: 'Kuhaon nako ang bata.',
|
||||
alternatives: ['Kuhaon nako si bata.', 'Akong kuhaon ang bata.']
|
||||
},
|
||||
explanation: 'Im Familienalltag taucht „bata" in Rollenspielen sehr häufig auf.'
|
||||
},
|
||||
withTypeName('situational_response', {
|
||||
title: 'Drei Mini-Sätze',
|
||||
instruction: 'Antworte in drei kurzen Sätzen (Rollenspiel).',
|
||||
questionData: {
|
||||
type: 'situational_response',
|
||||
question:
|
||||
'Spiel eine kurze Szene: ihr geht zum Arzt, braucht den Weg zur Haltestelle und bietet jemandem Hilfe an.',
|
||||
keywords: ['doktor', 'sakayan', 'tabang']
|
||||
},
|
||||
answerData: {
|
||||
modelAnswer: 'Adto ta sa doktor. Asa ang sakayan? Pwede ko motabang nimo?',
|
||||
keywords: ['doktor', 'sakayan', 'tabang']
|
||||
},
|
||||
explanation: 'Mehrere kurze Sätze hintereinander üben typische Rollenspiel-Ketten.'
|
||||
})
|
||||
],
|
||||
|
||||
'Freies Sprechen - Alltag ohne Stütze': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
@@ -5167,16 +5234,64 @@ async function findOrCreateSystemUser() {
|
||||
return systemUser;
|
||||
}
|
||||
|
||||
function normalizeLessonTitleForMatch(title) {
|
||||
return String(title || '')
|
||||
.normalize('NFKC')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
/** Lektionen, bei denen alte Platzhalter-Übungen verworfen und neu erzeugt werden sollen. */
|
||||
const PLACEHOLDER_REBUILD_TITLES = new Set([
|
||||
'Woche 1 - Wiederholung',
|
||||
'Woche 1 - Vokabeltest',
|
||||
'Begrüßungen & Höflichkeit',
|
||||
'Familienwörter',
|
||||
'Essen & Fürsorge',
|
||||
'Alltagsgespräche - Teil 1',
|
||||
'Alltagsgespräche - Teil 2',
|
||||
'Haus & Familie',
|
||||
'Ort & Richtung',
|
||||
'Zeitformen - Grundlagen',
|
||||
'Zeit & Datum',
|
||||
'Einkaufen & Preise',
|
||||
'Zahlen & Preise',
|
||||
'Zahlen 1–20',
|
||||
'Zahlen: Zehner',
|
||||
'Zahlen: Hunderter',
|
||||
'Zahlen: Tausender',
|
||||
'Woche 2 - Wiederholung',
|
||||
'Woche 2 - Vokabeltest',
|
||||
'Familie - Verwandte & Stieffamilie',
|
||||
'Rollenspiele - echte Situationen'
|
||||
]);
|
||||
|
||||
function lessonMatchesPlaceholderRebuildList(lesson) {
|
||||
const n = normalizeLessonTitleForMatch(lesson.title);
|
||||
if (PLACEHOLDER_REBUILD_TITLES.has(n)) return true;
|
||||
// Lektion 18: alte Bezeichnung „Zahlen & Preise“ trotz Leerzeichen/Varianten
|
||||
const num = Number(lesson.lessonNumber);
|
||||
if (num === 18 && /\bzahlen\b/i.test(n) && /\bpreis/i.test(n)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function getExercisesForLesson(lesson) {
|
||||
const lessonTitle = lesson.title;
|
||||
const normalizedTitle = normalizeLessonTitleForMatch(lessonTitle);
|
||||
// Alte Kurstitel (DB noch nicht migriert)
|
||||
if (lessonTitle === 'Zahlen & Preise' && BISAYA_EXERCISES['Zahlen 1–20']) {
|
||||
const isLegacyZahlenPreise =
|
||||
normalizedTitle === 'Zahlen & Preise' ||
|
||||
(Number(lesson.lessonNumber) === 18 && /\bzahlen\b/i.test(normalizedTitle) && /\bpreis/i.test(normalizedTitle));
|
||||
if (isLegacyZahlenPreise && BISAYA_EXERCISES['Zahlen 1–20']) {
|
||||
return BISAYA_EXERCISES['Zahlen 1–20'];
|
||||
}
|
||||
// Suche nach exaktem Titel
|
||||
if (BISAYA_EXERCISES[lessonTitle]) {
|
||||
return BISAYA_EXERCISES[lessonTitle];
|
||||
}
|
||||
if (BISAYA_EXERCISES[normalizedTitle]) {
|
||||
return BISAYA_EXERCISES[normalizedTitle];
|
||||
}
|
||||
|
||||
// Fallback: Suche nach Teilstring
|
||||
for (const [key, exercises] of Object.entries(BISAYA_EXERCISES)) {
|
||||
@@ -5245,28 +5360,7 @@ async function createBisayaCourseContent() {
|
||||
}
|
||||
|
||||
// Lektionen mit Platzhalter-Ersetzung: alte Übungen entfernen und durch echte ersetzen
|
||||
const replacePlaceholders = [
|
||||
'Woche 1 - Wiederholung',
|
||||
'Woche 1 - Vokabeltest',
|
||||
'Begrüßungen & Höflichkeit',
|
||||
'Familienwörter',
|
||||
'Essen & Fürsorge',
|
||||
'Alltagsgespräche - Teil 1',
|
||||
'Alltagsgespräche - Teil 2',
|
||||
'Haus & Familie',
|
||||
'Ort & Richtung',
|
||||
'Zeitformen - Grundlagen',
|
||||
'Zeit & Datum',
|
||||
'Einkaufen & Preise',
|
||||
'Zahlen & Preise',
|
||||
'Zahlen 1–20',
|
||||
'Zahlen: Zehner',
|
||||
'Zahlen: Hunderter',
|
||||
'Zahlen: Tausender',
|
||||
'Woche 2 - Wiederholung',
|
||||
'Woche 2 - Vokabeltest',
|
||||
'Familie - Verwandte & Stieffamilie'
|
||||
].includes(lesson.title);
|
||||
const replacePlaceholders = lessonMatchesPlaceholderRebuildList(lesson);
|
||||
const existingCount = await VocabGrammarExercise.count({
|
||||
where: { lessonId: lesson.id }
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user