refactor: 強化 Quiz Option 生成機制防止重複詞彙

- 加強 AI 生成後的詞彙過濾,確保不包含目標詞彙
- 改進 fallback 選項品質,使用更具挑戰性的詞彙池
- 添加詳細日誌追蹤選項生成過程(📚💡🤖)
- 修復資料庫重複詞彙問題,確保選項品質

測試驗證:happy -> efficient, essential, fundamental

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
鄭沛軒 2025-10-07 05:12:15 +08:00
parent f24f2b0445
commit 1eb28e83c5
1 changed files with 32 additions and 13 deletions

View File

@ -79,7 +79,7 @@ public class OptionsVocabularyService : IOptionsVocabularyService
if (_cache.TryGetValue(cacheKey, out List<OptionsVocabulary>? cachedOptions) && cachedOptions != null)
{
_logger.LogInformation("Using cached distractors for '{Word}': {Distractors}",
_logger.LogInformation("Using cached distractors for '{Word}': {Distractors}",
targetWord, string.Join(", ", cachedOptions.Select(d => d.Word)));
return cachedOptions.Take(count).ToList();
}
@ -104,11 +104,14 @@ public class OptionsVocabularyService : IOptionsVocabularyService
// 快取結果
_cache.Set(cacheKey, selectedExisting, TimeSpan.FromHours(1));
_logger.LogInformation("Using existing distractors for '{Word}': {Distractors}",
_logger.LogInformation("📚 Using existing database distractors for '{Word}': {Distractors}",
targetWord, string.Join(", ", selectedExisting.Select(d => d.Word)));
return selectedExisting;
}
_logger.LogInformation("💡 Insufficient database options ({ExistingCount}/{RequiredCount}), proceeding to AI generation for '{Word}'",
existingOptions.Count, count, targetWord);
// 3. 使用 AI 生成新的混淆選項
var aiGeneratedOptions = await GenerateOptionsWithAI(targetWord, cefrLevel, partOfSpeech, count);
@ -122,7 +125,7 @@ public class OptionsVocabularyService : IOptionsVocabularyService
_cache.Set(cacheKey, aiGeneratedOptions, TimeSpan.FromHours(1));
}
_logger.LogInformation("Successfully generated {Count} AI distractors for '{Word}': {Distractors}",
_logger.LogInformation("🤖 Successfully generated {Count} AI distractors for '{Word}': {Distractors}",
aiGeneratedOptions.Count, targetWord,
string.Join(", ", aiGeneratedOptions.Select(d => d.Word)));
@ -247,8 +250,14 @@ Please respond with ONLY a JSON array of strings, like: [""word1"", ""word2"", "
return GetFallbackDistractors(targetWord, cefrLevel, partOfSpeech, count);
}
// 轉換為 OptionsVocabulary 實體
var options = generatedWords.Take(count).Select(word => new OptionsVocabulary
// 轉換為 OptionsVocabulary 實體,並過濾掉與目標詞彙相同的詞彙
var targetWordLower = targetWord.ToLower();
var filteredWords = generatedWords
.Where(word => !string.IsNullOrWhiteSpace(word) &&
word.Trim().ToLower() != targetWordLower)
.Take(count);
var options = filteredWords.Select(word => new OptionsVocabulary
{
Id = Guid.NewGuid(),
Word = word.Trim(),
@ -259,6 +268,9 @@ Please respond with ONLY a JSON array of strings, like: [""word1"", ""word2"", "
UpdatedAt = DateTime.UtcNow
}).ToList();
_logger.LogInformation("Filtered AI generated words from {OriginalCount} to {FilteredCount} options for '{TargetWord}'",
generatedWords.Length, options.Count, targetWord);
// 計算字數長度
foreach (var option in options)
{
@ -283,20 +295,27 @@ Please respond with ONLY a JSON array of strings, like: [""word1"", ""word2"", "
string partOfSpeech,
int count)
{
// 根據詞性提供不同的固定選項
// 根據詞性提供不同的固定選項(避免常見目標詞彙)
var fallbackWords = partOfSpeech.ToLower() switch
{
"verb" => new[] { "create", "destroy", "change", "develop", "improve", "reduce" },
"noun" => new[] { "example", "result", "problem", "method", "system", "process" },
"adjective" => new[] { "important", "different", "special", "general", "common", "simple" },
"adverb" => new[] { "quickly", "carefully", "easily", "slowly", "clearly", "directly" },
_ => new[] { "option", "choice", "answer", "question", "test", "study" }
"verb" => new[] { "accomplish", "construct", "transform", "establish", "generate", "implement", "maintain", "organize", "validate", "coordinate" },
"noun" => new[] { "solution", "approach", "framework", "component", "structure", "mechanism", "principle", "strategy", "technique", "procedure" },
"adjective" => new[] { "efficient", "comprehensive", "innovative", "sophisticated", "fundamental", "essential", "remarkable", "outstanding", "significant", "substantial" },
"adverb" => new[] { "thoroughly", "efficiently", "precisely", "consistently", "systematically", "effectively", "accurately", "appropriately", "specifically", "particularly" },
_ => new[] { "element", "aspect", "feature", "component", "factor", "criteria", "parameter", "attribute", "characteristic", "specification" }
};
var targetWordLower = targetWord.ToLower();
return fallbackWords
var selectedWords = fallbackWords
.Where(word => word.ToLower() != targetWordLower)
.Take(count)
.Take(count * 2) // 取更多選項用於隨機選擇
.OrderBy(x => Guid.NewGuid()) // 隨機排序
.Take(count);
_logger.LogInformation("Using fallback distractors for '{TargetWord}': {FallbackWords}",
targetWord, string.Join(", ", selectedWords));
return selectedWords
.Select(word => new OptionsVocabulary
{
Id = Guid.NewGuid(),