From fddb97b3857b55fe636b271165a00d3c2dfe021e Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Tue, 3 Nov 2026 11:19:29 +0100 Subject: [PATCH] fix(vocab): exclude counting tasks from SRS --- ...103000000-remove-srs-counting-task-prompt.cjs | 16 ++++++++++++++++ backend/services/vocabService.js | 4 ++-- .../socialnetwork/VocabPracticeDialog.vue | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 backend/migrations-active/20261103000000-remove-srs-counting-task-prompt.cjs diff --git a/backend/migrations-active/20261103000000-remove-srs-counting-task-prompt.cjs b/backend/migrations-active/20261103000000-remove-srs-counting-task-prompt.cjs new file mode 100644 index 0000000..ced14a7 --- /dev/null +++ b/backend/migrations-active/20261103000000-remove-srs-counting-task-prompt.cjs @@ -0,0 +1,16 @@ +'use strict'; + +/** Removes counting exercise instructions accidentally stored as SRS cards. */ +module.exports = { + async up(queryInterface) { + await queryInterface.sequelize.query(` + DELETE FROM community.vocab_srs_item + WHERE course_id = 1 + AND lower(trim(learning)) ~ '^(zähle|zaehle)'; + `); + }, + + async down() { + // The invalid generated SRS cards must not be restored. + } +}; diff --git a/backend/services/vocabService.js b/backend/services/vocabService.js index ea1eb38..c54fa95 100755 --- a/backend/services/vocabService.js +++ b/backend/services/vocabService.js @@ -171,13 +171,13 @@ export default class VocabService { } const normalized = text.toLowerCase().normalize('NFKC'); - const startsWithTaskVerb = /^(sage|sag|schreibe|schreib|wünsche|wunsche|frage|frag|bitte|stelle|sprich|erzähle|erzaehle|beschreibe|bilde|baue|bau|wähle|waehle|ordne|übersetze|uebersetze|nenne|nenn|beginne|verwende|nutze|reagiere|kombiniere|spiele|löse|loese|beantworte|ergänze|ergaenze|formuliere|lies|entscheide|zeige|begrüße|begruesse|grüße|gruesse|drücke|druecke)\b/i.test(normalized); + const startsWithTaskVerb = /^(sage|sag|schreibe|schreib|wünsche|wunsche|zähle|zaehle|frage|frag|bitte|stelle|sprich|erzähle|erzaehle|beschreibe|bilde|baue|bau|wähle|waehle|ordne|übersetze|uebersetze|nenne|nenn|beginne|verwende|nutze|reagiere|kombiniere|spiele|löse|loese|beantworte|ergänze|ergaenze|formuliere|lies|entscheide|zeige|begrüße|begruesse|grüße|gruesse|drücke|druecke)\b/i.test(normalized); const startsWithTakeTask = /^nimm\b/i.test(normalized) && ( /\b(ein|eine|einen|zwei|drei|vier|fünf|fuenf|sechs|sieben|acht|neun|zehn|\d+)\b/i.test(normalized) || /\b(w[oö]rter|verben|gegenstände|gegenstaende|sätze|saetze|muster|beispiele)\b/i.test(normalized) ); - const containsTaskChain = /\b(und|,)\s*(sage|sag|schreibe|schreib|wünsche|wunsche|frage|frag|bitte|stelle|sprich|erzähle|erzaehle|beschreibe|bilde|baue|bau|wähle|waehle|ordne|übersetze|uebersetze|nenne|nenn|verwende|nutze|reagiere|kombiniere|spiele|löse|loese|beantworte|ergänze|ergaenze|formuliere|lies|entscheide|zeige|begrüße|begruesse|grüße|gruesse|drücke|druecke)\b/i.test(normalized); + const containsTaskChain = /\b(und|,)\s*(sage|sag|schreibe|schreib|wünsche|wunsche|zähle|zaehle|frage|frag|bitte|stelle|sprich|erzähle|erzaehle|beschreibe|bilde|baue|bau|wähle|waehle|ordne|übersetze|uebersetze|nenne|nenn|verwende|nutze|reagiere|kombiniere|spiele|löse|loese|beantworte|ergänze|ergaenze|formuliere|lies|entscheide|zeige|begrüße|begruesse|grüße|gruesse|drücke|druecke)\b/i.test(normalized); const containsPracticeMarker = /\b(laut|jeweils|zu jedem|zu jeder|umgebung|alltagsszene|rollenspiel|mini-dialog|szene)\b/i.test(normalized); return startsWithTaskVerb || startsWithTakeTask || (containsTaskChain && containsPracticeMarker); diff --git a/frontend/src/dialogues/socialnetwork/VocabPracticeDialog.vue b/frontend/src/dialogues/socialnetwork/VocabPracticeDialog.vue index 5da6041..b6e9e86 100755 --- a/frontend/src/dialogues/socialnetwork/VocabPracticeDialog.vue +++ b/frontend/src/dialogues/socialnetwork/VocabPracticeDialog.vue @@ -703,13 +703,13 @@ export default { if (wordCount < 3) return false; const normalized = text.toLowerCase().normalize('NFKC'); - const startsWithTaskVerb = /^(sage|sag|schreibe|schreib|wünsche|wunsche|frage|frag|bitte|stelle|sprich|erzähle|erzaehle|beschreibe|bilde|baue|bau|wähle|waehle|ordne|übersetze|uebersetze|nenne|nenn|beginne|verwende|nutze|reagiere|kombiniere|spiele|löse|loese|beantworte|ergänze|ergaenze|formuliere|lies|entscheide|zeige|begrüße|begruesse|grüße|gruesse|drücke|druecke)\b/i.test(normalized); + const startsWithTaskVerb = /^(sage|sag|schreibe|schreib|wünsche|wunsche|zähle|zaehle|frage|frag|bitte|stelle|sprich|erzähle|erzaehle|beschreibe|bilde|baue|bau|wähle|waehle|ordne|übersetze|uebersetze|nenne|nenn|beginne|verwende|nutze|reagiere|kombiniere|spiele|löse|loese|beantworte|ergänze|ergaenze|formuliere|lies|entscheide|zeige|begrüße|begruesse|grüße|gruesse|drücke|druecke)\b/i.test(normalized); const startsWithTakeTask = /^nimm\b/i.test(normalized) && ( /\b(ein|eine|einen|zwei|drei|vier|fünf|fuenf|sechs|sieben|acht|neun|zehn|\d+)\b/i.test(normalized) || /\b(w[oö]rter|verben|gegenstände|gegenstaende|sätze|saetze|muster|beispiele)\b/i.test(normalized) ); - const containsTaskChain = /\b(und|,)\s*(sage|sag|schreibe|schreib|wünsche|wunsche|frage|frag|bitte|stelle|sprich|erzähle|erzaehle|beschreibe|bilde|baue|bau|wähle|waehle|ordne|übersetze|uebersetze|nenne|nenn|verwende|nutze|reagiere|kombiniere|spiele|löse|loese|beantworte|ergänze|ergaenze|formuliere|lies|entscheide|zeige|begrüße|begruesse|grüße|gruesse|drücke|druecke)\b/i.test(normalized); + const containsTaskChain = /\b(und|,)\s*(sage|sag|schreibe|schreib|wünsche|wunsche|zähle|zaehle|frage|frag|bitte|stelle|sprich|erzähle|erzaehle|beschreibe|bilde|baue|bau|wähle|waehle|ordne|übersetze|uebersetze|nenne|nenn|verwende|nutze|reagiere|kombiniere|spiele|löse|loese|beantworte|ergänze|ergaenze|formuliere|lies|entscheide|zeige|begrüße|begruesse|grüße|gruesse|drücke|druecke)\b/i.test(normalized); const containsPracticeMarker = /\b(laut|jeweils|zu jedem|zu jeder|umgebung|alltagsszene|rollenspiel|mini-dialog|szene)\b/i.test(normalized); return startsWithTaskVerb || startsWithTakeTask || (containsTaskChain && containsPracticeMarker);