feat(bisaya-course): add word count validation and exercise audit warnings
Some checks failed
Deploy to production / deploy (push) Has been cancelled
Some checks failed
Deploy to production / deploy (push) Has been cancelled
- Introduced a `countWords` function to calculate the number of words in a given text. - Added `collectExerciseAuditWarnings` function to generate warnings for gap-fill exercises with potentially misleading hints. - Updated the `createBisayaCourseContent` function to log audit warnings when the VOCAB_STRICT_AUDIT environment variable is set, enhancing the validation process for exercise content.
This commit is contained in:
@@ -36,6 +36,44 @@ function normalizeText(value) {
|
|||||||
.replace(/\s+/g, ' ');
|
.replace(/\s+/g, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function countWords(value) {
|
||||||
|
return normalizeText(value).split(' ').filter(Boolean).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectExerciseAuditWarnings(lessonTitle, exerciseData, exerciseNumber) {
|
||||||
|
const warnings = [];
|
||||||
|
const questionData = exerciseData?.questionData || {};
|
||||||
|
const answerData = exerciseData?.answerData || {};
|
||||||
|
if (questionData.type !== 'gap_fill') return warnings;
|
||||||
|
|
||||||
|
const text = String(questionData.text || '');
|
||||||
|
const answers = Array.isArray(answerData.answers) ? answerData.answers : [];
|
||||||
|
if (!text || !answers.length) return warnings;
|
||||||
|
|
||||||
|
const hints = [];
|
||||||
|
const hintRegex = /\(([^)]+)\)/g;
|
||||||
|
let match = hintRegex.exec(text);
|
||||||
|
while (match) {
|
||||||
|
hints.push(normalizeText(match[1]));
|
||||||
|
match = hintRegex.exec(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < Math.min(answers.length, hints.length); i += 1) {
|
||||||
|
const answer = normalizeText(answers[i]);
|
||||||
|
const hint = hints[i];
|
||||||
|
if (!answer || !hint) continue;
|
||||||
|
const answerWords = countWords(answer);
|
||||||
|
const hintWords = countWords(hint);
|
||||||
|
if (answerWords <= 2 && hintWords >= 4) {
|
||||||
|
warnings.push(
|
||||||
|
`[${lessonTitle} #${exerciseNumber}] Gap-Fill-Hinweis wirkt zu lang für eine Kurzantwort: "${answer}" <-> "${hint}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return warnings;
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeCorePatternEntry(entry) {
|
function normalizeCorePatternEntry(entry) {
|
||||||
if (entry === null || entry === undefined || entry === '') {
|
if (entry === null || entry === undefined || entry === '') {
|
||||||
return null;
|
return null;
|
||||||
@@ -2206,7 +2244,7 @@ const BISAYA_EXERCISES = {
|
|||||||
instruction: 'Fülle die Lücken mit den richtigen Bisaya-Wörtern.',
|
instruction: 'Fülle die Lücken mit den richtigen Bisaya-Wörtern.',
|
||||||
questionData: {
|
questionData: {
|
||||||
type: 'gap_fill',
|
type: 'gap_fill',
|
||||||
text: '{gap} ka padulong? (Wohin gehst du?) | {gap} imong plano? (Was ist dein Plan?)',
|
text: '{gap} ka padulong? (wo/wohin) | {gap} imong plano? (was)',
|
||||||
gaps: 2
|
gaps: 2
|
||||||
},
|
},
|
||||||
answerData: {
|
answerData: {
|
||||||
@@ -2221,7 +2259,7 @@ const BISAYA_EXERCISES = {
|
|||||||
instruction: 'Fülle die Lücken mit den richtigen Bisaya-Wörtern.',
|
instruction: 'Fülle die Lücken mit den richtigen Bisaya-Wörtern.',
|
||||||
questionData: {
|
questionData: {
|
||||||
type: 'gap_fill',
|
type: 'gap_fill',
|
||||||
text: 'Moadto ko sa {gap}. (Ich gehe nach Hause.) | Moadto ko sa {gap}. (Ich gehe zum Markt.)',
|
text: 'Moadto ko sa {gap}. (Haus) | Moadto ko sa {gap}. (Markt)',
|
||||||
gaps: 2
|
gaps: 2
|
||||||
},
|
},
|
||||||
answerData: {
|
answerData: {
|
||||||
@@ -4337,6 +4375,10 @@ async function createBisayaCourseContent() {
|
|||||||
// Erstelle Übungen
|
// Erstelle Übungen
|
||||||
let exerciseNumber = 1;
|
let exerciseNumber = 1;
|
||||||
for (const exerciseData of exercises) {
|
for (const exerciseData of exercises) {
|
||||||
|
if (process.env.VOCAB_STRICT_AUDIT === '1') {
|
||||||
|
const warnings = collectExerciseAuditWarnings(lesson.title, exerciseData, exerciseNumber);
|
||||||
|
warnings.forEach((warning) => console.warn(` ⚠️ ${warning}`));
|
||||||
|
}
|
||||||
const exerciseTypeId = await resolveExerciseTypeId(exerciseData);
|
const exerciseTypeId = await resolveExerciseTypeId(exerciseData);
|
||||||
await VocabGrammarExercise.create({
|
await VocabGrammarExercise.create({
|
||||||
lessonId: lesson.id,
|
lessonId: lesson.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user