From c907d2773dd0fcb5cf600634620ae90465d0df09 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Tue, 20 Jan 2026 15:05:48 +0100 Subject: [PATCH] Enhance Bisaya course content and VocabLessonView for improved clarity and functionality - Updated gap fill exercises in create-bisaya-course-content.js to include clearer instructions and contextual hints for better understanding. - Refined the logic in VocabLessonView.vue to prevent duplicate vocabulary entries and ensure only distinct translations are added, enhancing the learning experience. - Adjusted timing for transitioning between questions in VocabLessonView to improve user interaction flow. --- .../scripts/create-bisaya-course-content.js | 10 +-- backend/scripts/fix-begruessungen-gap-fill.js | 89 +++++++++++++++++++ frontend/src/views/social/VocabLessonView.vue | 59 ++++++++---- 3 files changed, 135 insertions(+), 23 deletions(-) create mode 100755 backend/scripts/fix-begruessungen-gap-fill.js diff --git a/backend/scripts/create-bisaya-course-content.js b/backend/scripts/create-bisaya-course-content.js index 35d3d13..7c5498c 100644 --- a/backend/scripts/create-bisaya-course-content.js +++ b/backend/scripts/create-bisaya-course-content.js @@ -39,14 +39,14 @@ const BISAYA_EXERCISES = { instruction: 'Fülle die Lücken mit den richtigen Bisaya-Wörtern.', questionData: { type: 'gap_fill', - text: 'Kumusta ka? Maayo {gap}. Salamat.', + text: 'Kumusta ka? Maayo {gap} (ich). Salamat.', gaps: 1 }, answerData: { type: 'gap_fill', answers: ['ko'] }, - explanation: '"Maayo ko" bedeutet "Mir geht es gut".' + explanation: '"Maayo ko" bedeutet "Mir geht es gut". "ko" ist "ich" auf Bisaya.' }, { exerciseTypeId: 2, // multiple_choice @@ -267,7 +267,7 @@ const BISAYA_EXERCISES = { instruction: 'Fülle die Lücken mit höflichen Wörtern.', questionData: { type: 'gap_fill', - text: '{gap} lang, wala ko kasabot. {gap} ka mubalik?', + text: '{gap} lang (Bitte langsam), wala ko kasabot. {gap} ka mubalik? (Bitte wiederholen)', gaps: 2 }, answerData: { @@ -331,7 +331,7 @@ const BISAYA_EXERCISES = { instruction: 'Fülle die Lücken mit den richtigen Bisaya-Wörtern.', questionData: { type: 'gap_fill', - text: '{gap} ko kasabot. {gap} ka mubalik? {gap} lang.', + text: '{gap} ko kasabot (Ich verstehe nicht). {gap} ka mubalik? (Bitte wiederholen) {gap} lang (Bitte langsam).', gaps: 3 }, answerData: { @@ -472,7 +472,7 @@ const BISAYA_EXERCISES = { instruction: 'Fülle die Lücken mit den richtigen Bisaya-Wörtern.', questionData: { type: 'gap_fill', - text: '{gap} ko kasabot. {gap} ka mubalik?', + text: '{gap} ko kasabot (Ich verstehe nicht). {gap} ka mubalik? (Bitte wiederholen)', gaps: 2 }, answerData: { diff --git a/backend/scripts/fix-begruessungen-gap-fill.js b/backend/scripts/fix-begruessungen-gap-fill.js new file mode 100755 index 0000000..7d52100 --- /dev/null +++ b/backend/scripts/fix-begruessungen-gap-fill.js @@ -0,0 +1,89 @@ +#!/usr/bin/env node +/** + * Script zum Korrigieren der Gap-Fill-Übung in "Begrüßungen & Höflichkeit" + * Fügt Muttersprache-Hinweise hinzu, damit Vokabeln korrekt extrahiert werden können + */ + +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'; + +async function fixBegruessungenGapFill() { + await sequelize.authenticate(); + console.log('Datenbankverbindung erfolgreich hergestellt.\n'); + + // Finde alle "Begrüßungen & Höflichkeit" Lektionen + const lessons = await VocabCourseLesson.findAll({ + where: { title: 'Begrüßungen & Höflichkeit' }, + include: [{ model: VocabCourse, as: 'course' }] + }); + + console.log(`Gefunden: ${lessons.length} "Begrüßungen & Höflichkeit"-Lektionen\n`); + + let totalUpdated = 0; + + for (const lesson of lessons) { + console.log(`📚 Kurs: ${lesson.course.title} (Kurs-ID: ${lesson.course.id}, Lektion-ID: ${lesson.id})`); + + // Finde Gap-Fill-Übung mit "ko" als Antwort + const exercises = await VocabGrammarExercise.findAll({ + where: { + lessonId: lesson.id, + exerciseTypeId: 1 // gap_fill + } + }); + + for (const exercise of exercises) { + const qData = typeof exercise.questionData === 'string' + ? JSON.parse(exercise.questionData) + : exercise.questionData; + const aData = typeof exercise.answerData === 'string' + ? JSON.parse(exercise.answerData) + : exercise.answerData; + + // Prüfe ob es die problematische Übung ist (enthält "ko" als Antwort ohne Muttersprache-Hinweis) + if (aData.answers && aData.answers.includes('ko')) { + const text = qData.text || ''; + + // Prüfe ob Muttersprache-Hinweise fehlen + if (!text.includes('(ich)') && !text.includes('(I)')) { + console.log(` 🔧 Korrigiere Übung "${exercise.title}" (ID: ${exercise.id})`); + + // Korrigiere den Text + const correctedText = text.replace( + 'Maayo {gap}.', + 'Maayo {gap} (ich).' + ); + + qData.text = correctedText; + + await exercise.update({ + questionData: qData + }); + + totalUpdated++; + console.log(` ✅ Aktualisiert: "${correctedText}"`); + } else { + console.log(` ✓ Übung "${exercise.title}" bereits korrekt`); + } + } + } + console.log(''); + } + + console.log(`\n🎉 Zusammenfassung:`); + console.log(` ${lessons.length} Lektionen verarbeitet`); + console.log(` ${totalUpdated} Übungen aktualisiert`); +} + +fixBegruessungenGapFill() + .then(() => { + sequelize.close(); + process.exit(0); + }) + .catch((error) => { + console.error('❌ Fehler:', error); + sequelize.close(); + process.exit(1); + }); diff --git a/frontend/src/views/social/VocabLessonView.vue b/frontend/src/views/social/VocabLessonView.vue index c85aa55..c53cb50 100644 --- a/frontend/src/views/social/VocabLessonView.vue +++ b/frontend/src/views/social/VocabLessonView.vue @@ -121,8 +121,8 @@ {{ $t('socialnetwork.vocab.courses.checkAnswer') }} - -
+ +
@@ -598,20 +598,30 @@ export default { console.log(`[importantVocab] Frage:`, question); // Pattern 1: "Wie sagt man 'X' auf Bisaya?" -> X ist Muttersprache (z.B. "Großmutter"), correctAnswer ist Bisaya (z.B. "Lola") - let match = question.match(/['"]([^'"]+)['"]/); + let match = question.match(/Wie sagt man ['"]([^'"]+)['"]/i); if (match) { const nativeWord = match[1]; // Das Wort in der Muttersprache - console.log(`[importantVocab] Pattern 1 gefunden - Muttersprache:`, nativeWord, `Bisaya:`, correctAnswer); - // learning = Muttersprache (was man lernt), reference = Bisaya (Zielsprache) - vocabMap.set(`${nativeWord}-${correctAnswer}`, { learning: nativeWord, reference: correctAnswer }); + // Nur hinzufügen, wenn Muttersprache und Bisaya unterschiedlich sind (verhindert "ko" -> "ko") + if (nativeWord && correctAnswer && nativeWord.trim() !== correctAnswer.trim()) { + console.log(`[importantVocab] Pattern 1 gefunden - Muttersprache:`, nativeWord, `Bisaya:`, correctAnswer); + // learning = Muttersprache (was man lernt), reference = Bisaya (Zielsprache) + vocabMap.set(`${nativeWord}-${correctAnswer}`, { learning: nativeWord, reference: correctAnswer }); + } else { + console.log(`[importantVocab] Pattern 1 übersprungen - Muttersprache und Bisaya sind gleich:`, nativeWord, correctAnswer); + } } else { // Pattern 2: "Was bedeutet 'X'?" -> X ist Bisaya, correctAnswer ist Muttersprache - match = question.match(/Was bedeutet ['"]([^'"]+)['"]/); + match = question.match(/Was bedeutet ['"]([^'"]+)['"]/i); if (match) { const bisayaWord = match[1]; - console.log(`[importantVocab] Pattern 2 gefunden - Bisaya:`, bisayaWord, `Muttersprache:`, correctAnswer); - // learning = Muttersprache (was man lernt), reference = Bisaya (Zielsprache) - vocabMap.set(`${correctAnswer}-${bisayaWord}`, { learning: correctAnswer, reference: bisayaWord }); + // Nur hinzufügen, wenn Bisaya und Muttersprache unterschiedlich sind (verhindert "ko" -> "ko") + if (bisayaWord && correctAnswer && bisayaWord.trim() !== correctAnswer.trim()) { + console.log(`[importantVocab] Pattern 2 gefunden - Bisaya:`, bisayaWord, `Muttersprache:`, correctAnswer); + // learning = Muttersprache (was man lernt), reference = Bisaya (Zielsprache) + vocabMap.set(`${correctAnswer}-${bisayaWord}`, { learning: correctAnswer, reference: bisayaWord }); + } else { + console.log(`[importantVocab] Pattern 2 übersprungen - Bisaya und Muttersprache sind gleich:`, bisayaWord, correctAnswer); + } } else { console.log(`[importantVocab] Kein Pattern gefunden, Überspringe diese Übung`); // Überspringe, wenn wir die Richtung nicht erkennen können @@ -632,13 +642,26 @@ export default { const matches = text.matchAll(/\(([^)]+)\)/g); const nativeWords = Array.from(matches, m => m[1]); - answers.forEach((answer, index) => { - if (answer && answer.trim()) { - const nativeWord = nativeWords[index] || answer; // Falls keine Klammer, verwende answer - // Die answer ist normalerweise Bisaya, nativeWord ist Muttersprache - vocabMap.set(`${nativeWord}-${answer}`, { learning: nativeWord, reference: answer }); - } - }); + console.log(`[importantVocab] Gap Fill - text:`, text, `nativeWords:`, nativeWords); + + // Nur extrahieren, wenn Muttersprache-Hinweise (Klammern) vorhanden sind + if (nativeWords.length > 0) { + answers.forEach((answer, index) => { + if (answer && answer.trim()) { + const nativeWord = nativeWords[index]; + if (nativeWord && nativeWord.trim() && nativeWord !== answer) { + // Die answer ist normalerweise Bisaya, nativeWord ist Muttersprache + // Nur hinzufügen, wenn sie unterschiedlich sind (verhindert "ko" -> "ko") + vocabMap.set(`${nativeWord}-${answer}`, { learning: nativeWord, reference: answer }); + console.log(`[importantVocab] Gap Fill extrahiert - Muttersprache:`, nativeWord, `Bisaya:`, answer); + } else { + console.log(`[importantVocab] Gap Fill übersprungen - keine Muttersprache oder gleich:`, nativeWord, answer); + } + } + }); + } else { + console.log(`[importantVocab] Gap Fill übersprungen - keine Muttersprache-Hinweise (Klammern) gefunden`); + } } } } @@ -1157,7 +1180,7 @@ export default { if (this.vocabTrainerLastCorrect) { // Prüfe ob noch Fragen vorhanden sind if (this.vocabTrainerPool && this.vocabTrainerPool.length > 0) { - const delay = this.vocabTrainerMode === 'multiple_choice' ? 2000 : 500; // 2 Sekunden für Multiple Choice, 500ms für Typing + const delay = this.vocabTrainerMode === 'multiple_choice' ? 1000 : 500; // 1 Sekunde für Multiple Choice, 500ms für Typing setTimeout(() => { // Prüfe erneut, ob noch Fragen vorhanden sind (könnte sich geändert haben) if (this.vocabTrainerPool && this.vocabTrainerPool.length > 0 && this.vocabTrainerActive) {