using DramaLing.Api.Data; using DramaLing.Api.Models.Configuration; using DramaLing.Api.Models.Entities; using DramaLing.Api.Services.Monitoring; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using System.Diagnostics; namespace DramaLing.Api.Services; /// /// 選項詞彙庫服務實作 /// 提供基於 CEFR 等級、詞性和字數的智能選項生成 /// public class OptionsVocabularyService : IOptionsVocabularyService { private readonly DramaLingDbContext _context; private readonly IMemoryCache _cache; private readonly ILogger _logger; private readonly OptionsVocabularyOptions _options; private readonly OptionsVocabularyMetrics _metrics; public OptionsVocabularyService( DramaLingDbContext context, IMemoryCache cache, ILogger logger, IOptions options, OptionsVocabularyMetrics metrics) { _context = context; _cache = cache; _logger = logger; _options = options.Value; _metrics = metrics; } /// /// 生成智能干擾選項 /// public async Task> GenerateDistractorsAsync( string targetWord, string cefrLevel, string partOfSpeech, int count = 3) { var distractorsWithDetails = await GenerateDistractorsWithDetailsAsync( targetWord, cefrLevel, partOfSpeech, count); return distractorsWithDetails.Select(v => v.Word).ToList(); } /// /// 生成智能干擾選項(含詳細資訊) /// public async Task> GenerateDistractorsWithDetailsAsync( string targetWord, string cefrLevel, string partOfSpeech, int count = 3) { var stopwatch = Stopwatch.StartNew(); try { // 記錄請求指標 _metrics.RecordGenerationRequest(cefrLevel, partOfSpeech, count); _logger.LogInformation("Generating {Count} distractors for word '{Word}' (CEFR: {CEFR}, PartOfSpeech: {PartOfSpeech}) - Using fixed options", count, targetWord, cefrLevel, partOfSpeech); // 暫時使用固定選項,跳過複雜的詞彙篩選機制 var fixedDistractors = new List { new OptionsVocabulary { Id = Guid.NewGuid(), Word = "apple", CEFRLevel = cefrLevel, PartOfSpeech = partOfSpeech, IsActive = true, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }, new OptionsVocabulary { Id = Guid.NewGuid(), Word = "orange", CEFRLevel = cefrLevel, PartOfSpeech = partOfSpeech, IsActive = true, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }, new OptionsVocabulary { Id = Guid.NewGuid(), Word = "banana", CEFRLevel = cefrLevel, PartOfSpeech = partOfSpeech, IsActive = true, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow } }; // 計算字數長度 foreach (var distractor in fixedDistractors) { distractor.CalculateWordLength(); } // 排除目標詞彙本身(如果匹配) var selectedDistractors = fixedDistractors .Where(v => !string.Equals(v.Word, targetWord, StringComparison.OrdinalIgnoreCase)) .Take(count) .ToList(); _logger.LogInformation("Successfully generated {Count} fixed distractors for '{Word}': {Distractors}", selectedDistractors.Count, targetWord, string.Join(", ", selectedDistractors.Select(d => d.Word))); // 記錄生成完成指標 stopwatch.Stop(); _metrics.RecordGenerationDuration(stopwatch.Elapsed, selectedDistractors.Count); return selectedDistractors; } catch (Exception ex) { _logger.LogError(ex, "Error generating distractors for word '{Word}'", targetWord); _metrics.RecordError("generation_failed", "GenerateDistractorsWithDetailsAsync"); return new List(); } } /// /// 檢查詞彙庫是否有足夠的詞彙支援選項生成 /// public async Task HasSufficientVocabularyAsync(string cefrLevel, string partOfSpeech) { try { var allowedLevels = GetAllowedCEFRLevels(cefrLevel); var count = await _context.OptionsVocabularies .Where(v => v.IsActive && allowedLevels.Contains(v.CEFRLevel) && v.PartOfSpeech == partOfSpeech) .CountAsync(); var hasSufficient = count >= _options.MinimumVocabularyThreshold; _logger.LogDebug("Vocabulary count for CEFR: {CEFR}, PartOfSpeech: {PartOfSpeech}: {Count} (sufficient: {HasSufficient})", cefrLevel, partOfSpeech, count, hasSufficient); return hasSufficient; } catch (Exception ex) { _logger.LogError(ex, "Error checking vocabulary sufficiency for CEFR: {CEFR}, PartOfSpeech: {PartOfSpeech}", cefrLevel, partOfSpeech); return false; } } /// /// 獲取允許的 CEFR 等級(包含相鄰等級) /// private static List GetAllowedCEFRLevels(string targetLevel) { var levels = new[] { "A1", "A2", "B1", "B2", "C1", "C2" }; var targetIndex = Array.IndexOf(levels, targetLevel); if (targetIndex == -1) { // 如果不是標準 CEFR 等級,只返回原等級 return new List { targetLevel }; } var allowed = new List { targetLevel }; // 加入相鄰等級(允許難度稍有差異) if (targetIndex > 0) allowed.Add(levels[targetIndex - 1]); if (targetIndex < levels.Length - 1) allowed.Add(levels[targetIndex + 1]); return allowed; } }