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': [
|
'Freies Sprechen - Alltag ohne Stütze': [
|
||||||
{
|
{
|
||||||
exerciseTypeId: 2,
|
exerciseTypeId: 2,
|
||||||
@@ -5167,16 +5234,64 @@ async function findOrCreateSystemUser() {
|
|||||||
return systemUser;
|
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) {
|
function getExercisesForLesson(lesson) {
|
||||||
const lessonTitle = lesson.title;
|
const lessonTitle = lesson.title;
|
||||||
|
const normalizedTitle = normalizeLessonTitleForMatch(lessonTitle);
|
||||||
// Alte Kurstitel (DB noch nicht migriert)
|
// 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'];
|
return BISAYA_EXERCISES['Zahlen 1–20'];
|
||||||
}
|
}
|
||||||
// Suche nach exaktem Titel
|
// Suche nach exaktem Titel
|
||||||
if (BISAYA_EXERCISES[lessonTitle]) {
|
if (BISAYA_EXERCISES[lessonTitle]) {
|
||||||
return BISAYA_EXERCISES[lessonTitle];
|
return BISAYA_EXERCISES[lessonTitle];
|
||||||
}
|
}
|
||||||
|
if (BISAYA_EXERCISES[normalizedTitle]) {
|
||||||
|
return BISAYA_EXERCISES[normalizedTitle];
|
||||||
|
}
|
||||||
|
|
||||||
// Fallback: Suche nach Teilstring
|
// Fallback: Suche nach Teilstring
|
||||||
for (const [key, exercises] of Object.entries(BISAYA_EXERCISES)) {
|
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
|
// Lektionen mit Platzhalter-Ersetzung: alte Übungen entfernen und durch echte ersetzen
|
||||||
const replacePlaceholders = [
|
const replacePlaceholders = lessonMatchesPlaceholderRebuildList(lesson);
|
||||||
'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 existingCount = await VocabGrammarExercise.count({
|
const existingCount = await VocabGrammarExercise.count({
|
||||||
where: { lessonId: lesson.id }
|
where: { lessonId: lesson.id }
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user