feat(VocabPracticeDialog): enhance vocabulary item expansion logic
All checks were successful
Deploy to production / deploy (push) Successful in 1m48s
All checks were successful
Deploy to production / deploy (push) Successful in 1m48s
- Added methods to split phrase alternatives and expand pool item alternatives, allowing for better handling of multiple valid translations and maintaining alignment between learning and reference phrases. - Updated the normalization process to incorporate these new methods, improving the accuracy and flexibility of vocabulary practice sessions.
This commit is contained in:
@@ -600,23 +600,51 @@ export default {
|
|||||||
|
|
||||||
return (leftLooksShortFragment && rightLooksSentence) || (rightLooksShortFragment && leftLooksSentence);
|
return (leftLooksShortFragment && rightLooksSentence) || (rightLooksShortFragment && leftLooksSentence);
|
||||||
},
|
},
|
||||||
|
splitPhraseAlternatives(value) {
|
||||||
|
const text = String(value || '').trim();
|
||||||
|
if (!text) return [];
|
||||||
|
const parts = text
|
||||||
|
.split(/\s+\/\s+/)
|
||||||
|
.map((part) => String(part || '').trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
return parts.length >= 2 ? parts : [text];
|
||||||
|
},
|
||||||
|
expandPoolItemAlternatives(item) {
|
||||||
|
const learning = String(item?.learning || '').trim();
|
||||||
|
const reference = String(item?.reference || '').trim();
|
||||||
|
const learningParts = this.splitPhraseAlternatives(learning);
|
||||||
|
const referenceParts = this.splitPhraseAlternatives(reference);
|
||||||
|
|
||||||
|
// Common case: one prompt with multiple valid translations.
|
||||||
|
// Split into separate vocab cards so each answer is trainable.
|
||||||
|
if (learningParts.length === 1 && referenceParts.length > 1) {
|
||||||
|
return referenceParts.map((ref) => ({ ...item, learning, reference: ref }));
|
||||||
|
}
|
||||||
|
if (referenceParts.length === 1 && learningParts.length > 1) {
|
||||||
|
return learningParts.map((lrn) => ({ ...item, learning: lrn, reference }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both sides contain parallel alternatives of equal length, keep pairs aligned.
|
||||||
|
if (learningParts.length > 1 && learningParts.length === referenceParts.length) {
|
||||||
|
return learningParts.map((lrn, idx) => ({ ...item, learning: lrn, reference: referenceParts[idx] }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [{ ...item, learning, reference }];
|
||||||
|
},
|
||||||
normalizePool(items = []) {
|
normalizePool(items = []) {
|
||||||
const seen = new Set();
|
const seen = new Set();
|
||||||
return (Array.isArray(items) ? items : [])
|
return (Array.isArray(items) ? items : [])
|
||||||
.map((item, index) => {
|
.flatMap((item, index) => this.expandPoolItemAlternatives(item).map((candidate, altIndex) => ({ candidate, index, altIndex })))
|
||||||
const learning = String(item?.learning || '').trim();
|
.map(({ candidate, index, altIndex }) => {
|
||||||
const reference = String(item?.reference || '').trim();
|
const learning = String(candidate?.learning || '').trim();
|
||||||
if (!this.isTrainablePair(learning, reference)) {
|
const reference = String(candidate?.reference || '').trim();
|
||||||
return null;
|
if (!this.isTrainablePair(learning, reference)) return null;
|
||||||
}
|
|
||||||
const key = `${this.normalize(learning)}|${this.normalize(reference)}`;
|
const key = `${this.normalize(learning)}|${this.normalize(reference)}`;
|
||||||
if (seen.has(key)) {
|
if (seen.has(key)) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
seen.add(key);
|
seen.add(key);
|
||||||
return {
|
return {
|
||||||
...item,
|
...candidate,
|
||||||
id: item?.id || item?.itemKey || item?.key || `${key}|${index}`,
|
id: candidate?.id || candidate?.itemKey || candidate?.key || `${key}|${index}|${altIndex}`,
|
||||||
learning,
|
learning,
|
||||||
reference
|
reference
|
||||||
};
|
};
|
||||||
@@ -766,10 +794,7 @@ export default {
|
|||||||
|
|
||||||
// Handle full-answer alternatives like "A / B" as separate valid answers.
|
// Handle full-answer alternatives like "A / B" as separate valid answers.
|
||||||
// Word-level slash expansion alone does not cover this reliably.
|
// Word-level slash expansion alone does not cover this reliably.
|
||||||
const phraseAlternatives = base
|
const phraseAlternatives = this.splitPhraseAlternatives(base);
|
||||||
.split(/\s+\/\s+/)
|
|
||||||
.map((part) => String(part || '').trim())
|
|
||||||
.filter(Boolean);
|
|
||||||
|
|
||||||
if (phraseAlternatives.length >= 2) {
|
if (phraseAlternatives.length >= 2) {
|
||||||
const expanded = phraseAlternatives.flatMap((part) => this.expandSingleAnswerVariants(part));
|
const expanded = phraseAlternatives.flatMap((part) => this.expandSingleAnswerVariants(part));
|
||||||
|
|||||||
Reference in New Issue
Block a user