refactor: 移除AIController中的所有測試和假資料API
- 刪除test/generate測試端點和TestGenerateCards方法 - 刪除test/save測試端點和TestSaveCards方法 - 移除GenerateMockCards假資料生成方法 - 移除TestSaveCardsRequest測試用請求類別 - 清理generate API中的mock邏輯,改為直接錯誤回應 - 提升API安全性,移除無認證的測試端點 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
11e19d5e1c
commit
be1126e7db
|
|
@ -36,87 +36,6 @@ public class AIController : ControllerBase
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// AI 生成詞卡測試端點 (開發用,無需認證)
|
|
||||||
/// </summary>
|
|
||||||
[HttpPost("test/generate")]
|
|
||||||
[AllowAnonymous]
|
|
||||||
public async Task<ActionResult> TestGenerateCards([FromBody] GenerateCardsRequest request)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 基本驗證
|
|
||||||
if (string.IsNullOrWhiteSpace(request.InputText))
|
|
||||||
{
|
|
||||||
return BadRequest(new { Success = false, Error = "Input text is required" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.InputText.Length > 5000)
|
|
||||||
{
|
|
||||||
return BadRequest(new { Success = false, Error = "Input text must be less than 5000 characters" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!new[] { "vocabulary", "smart" }.Contains(request.ExtractionType))
|
|
||||||
{
|
|
||||||
return BadRequest(new { Success = false, Error = "Invalid extraction type" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.CardCount < 1 || request.CardCount > 20)
|
|
||||||
{
|
|
||||||
return BadRequest(new { Success = false, Error = "Card count must be between 1 and 20" });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 測試模式:直接使用模擬資料
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var generatedCards = await _geminiService.GenerateCardsAsync(
|
|
||||||
request.InputText,
|
|
||||||
request.ExtractionType,
|
|
||||||
request.CardCount);
|
|
||||||
|
|
||||||
return Ok(new
|
|
||||||
{
|
|
||||||
Success = true,
|
|
||||||
Data = new
|
|
||||||
{
|
|
||||||
TaskId = Guid.NewGuid(),
|
|
||||||
Status = "completed",
|
|
||||||
GeneratedCards = generatedCards
|
|
||||||
},
|
|
||||||
Message = $"Successfully generated {generatedCards.Count} cards"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (InvalidOperationException ex) when (ex.Message.Contains("API key"))
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Gemini API key not configured, using mock data");
|
|
||||||
|
|
||||||
// 返回模擬資料
|
|
||||||
var mockCards = GenerateMockCards(request.CardCount);
|
|
||||||
return Ok(new
|
|
||||||
{
|
|
||||||
Success = true,
|
|
||||||
Data = new
|
|
||||||
{
|
|
||||||
TaskId = Guid.NewGuid(),
|
|
||||||
Status = "completed",
|
|
||||||
GeneratedCards = mockCards
|
|
||||||
},
|
|
||||||
Message = $"Generated {mockCards.Count} mock cards (Test mode)"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error in AI card generation test");
|
|
||||||
return StatusCode(500, new
|
|
||||||
{
|
|
||||||
Success = false,
|
|
||||||
Error = "Failed to generate cards",
|
|
||||||
Details = ex.Message,
|
|
||||||
Timestamp = DateTime.UtcNow
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AI 生成詞卡 (支援 /frontend/app/generate/page.tsx)
|
/// AI 生成詞卡 (支援 /frontend/app/generate/page.tsx)
|
||||||
|
|
@ -215,20 +134,12 @@ public class AIController : ControllerBase
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex) when (ex.Message.Contains("API key"))
|
catch (InvalidOperationException ex) when (ex.Message.Contains("API key"))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Gemini API key not configured, using mock data");
|
_logger.LogError("Gemini API key not configured");
|
||||||
|
return StatusCode(500, new
|
||||||
// 返回模擬資料(開發階段)
|
|
||||||
var mockCards = GenerateMockCards(request.CardCount);
|
|
||||||
return Ok(new
|
|
||||||
{
|
{
|
||||||
Success = true,
|
Success = false,
|
||||||
Data = new
|
Error = "AI service not configured",
|
||||||
{
|
Timestamp = DateTime.UtcNow
|
||||||
TaskId = Guid.NewGuid(),
|
|
||||||
Status = "completed",
|
|
||||||
GeneratedCards = mockCards
|
|
||||||
},
|
|
||||||
Message = $"Generated {mockCards.Count} mock cards (Gemini API not configured)"
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -244,99 +155,6 @@ public class AIController : ControllerBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 測試版保存生成的詞卡 (無需認證)
|
|
||||||
/// </summary>
|
|
||||||
[HttpPost("test/save")]
|
|
||||||
[AllowAnonymous]
|
|
||||||
public async Task<ActionResult> TestSaveCards([FromBody] TestSaveCardsRequest request)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 基本驗證
|
|
||||||
if (request.SelectedCards == null || request.SelectedCards.Count == 0)
|
|
||||||
{
|
|
||||||
return BadRequest(new { Success = false, Error = "Selected cards are required" });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 創建或使用預設卡組
|
|
||||||
var defaultCardSet = await _context.CardSets
|
|
||||||
.FirstOrDefaultAsync(cs => cs.IsDefault);
|
|
||||||
|
|
||||||
if (defaultCardSet == null)
|
|
||||||
{
|
|
||||||
// 創建預設卡組
|
|
||||||
defaultCardSet = new CardSet
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
UserId = Guid.NewGuid(), // 測試用戶 ID
|
|
||||||
Name = "AI 生成詞卡",
|
|
||||||
Description = "通過 AI 智能生成的詞卡集合",
|
|
||||||
Color = "#3B82F6",
|
|
||||||
IsDefault = true,
|
|
||||||
CreatedAt = DateTime.UtcNow,
|
|
||||||
UpdatedAt = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
_context.CardSets.Add(defaultCardSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 將生成的詞卡轉換為資料庫實體
|
|
||||||
var flashcardsToSave = request.SelectedCards.Select(card => new Flashcard
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
UserId = defaultCardSet.UserId,
|
|
||||||
CardSetId = defaultCardSet.Id,
|
|
||||||
Word = card.Word,
|
|
||||||
Translation = card.Translation,
|
|
||||||
Definition = card.Definition,
|
|
||||||
PartOfSpeech = card.PartOfSpeech,
|
|
||||||
Pronunciation = card.Pronunciation,
|
|
||||||
Example = card.Example,
|
|
||||||
ExampleTranslation = card.ExampleTranslation,
|
|
||||||
DifficultyLevel = card.DifficultyLevel,
|
|
||||||
CreatedAt = DateTime.UtcNow,
|
|
||||||
UpdatedAt = DateTime.UtcNow
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
_context.Flashcards.AddRange(flashcardsToSave);
|
|
||||||
|
|
||||||
// 更新卡組計數
|
|
||||||
defaultCardSet.CardCount += flashcardsToSave.Count;
|
|
||||||
defaultCardSet.UpdatedAt = DateTime.UtcNow;
|
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
return Ok(new
|
|
||||||
{
|
|
||||||
Success = true,
|
|
||||||
Data = new
|
|
||||||
{
|
|
||||||
SavedCount = flashcardsToSave.Count,
|
|
||||||
CardSetId = defaultCardSet.Id,
|
|
||||||
CardSetName = defaultCardSet.Name,
|
|
||||||
Cards = flashcardsToSave.Select(f => new
|
|
||||||
{
|
|
||||||
f.Id,
|
|
||||||
f.Word,
|
|
||||||
f.Translation,
|
|
||||||
f.Definition
|
|
||||||
})
|
|
||||||
},
|
|
||||||
Message = $"Successfully saved {flashcardsToSave.Count} cards to deck '{defaultCardSet.Name}'"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error saving generated cards");
|
|
||||||
return StatusCode(500, new
|
|
||||||
{
|
|
||||||
Success = false,
|
|
||||||
Error = "Failed to save cards",
|
|
||||||
Details = ex.Message,
|
|
||||||
Timestamp = DateTime.UtcNow
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存生成的詞卡
|
/// 保存生成的詞卡
|
||||||
|
|
@ -1417,50 +1235,6 @@ public class AIController : ControllerBase
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 生成模擬資料 (開發階段使用)
|
|
||||||
/// </summary>
|
|
||||||
private List<GeneratedCard> GenerateMockCards(int count)
|
|
||||||
{
|
|
||||||
var mockCards = new List<GeneratedCard>
|
|
||||||
{
|
|
||||||
new() {
|
|
||||||
Word = "accomplish",
|
|
||||||
PartOfSpeech = "verb",
|
|
||||||
Pronunciation = "/əˈkʌmplɪʃ/",
|
|
||||||
Translation = "完成、達成",
|
|
||||||
Definition = "To finish something successfully or to achieve something",
|
|
||||||
Synonyms = new() { "achieve", "complete" },
|
|
||||||
Example = "She accomplished her goal of learning English.",
|
|
||||||
ExampleTranslation = "她達成了學習英語的目標。",
|
|
||||||
DifficultyLevel = "B1"
|
|
||||||
},
|
|
||||||
new() {
|
|
||||||
Word = "negotiate",
|
|
||||||
PartOfSpeech = "verb",
|
|
||||||
Pronunciation = "/nɪˈɡəʊʃieɪt/",
|
|
||||||
Translation = "協商、談判",
|
|
||||||
Definition = "To discuss something with someone in order to reach an agreement",
|
|
||||||
Synonyms = new() { "bargain", "discuss" },
|
|
||||||
Example = "We need to negotiate a better deal.",
|
|
||||||
ExampleTranslation = "我們需要協商一個更好的交易。",
|
|
||||||
DifficultyLevel = "B2"
|
|
||||||
},
|
|
||||||
new() {
|
|
||||||
Word = "perspective",
|
|
||||||
PartOfSpeech = "noun",
|
|
||||||
Pronunciation = "/pərˈspektɪv/",
|
|
||||||
Translation = "觀點、看法",
|
|
||||||
Definition = "A particular way of considering something",
|
|
||||||
Synonyms = new() { "viewpoint", "opinion" },
|
|
||||||
Example = "From my perspective, this is the best solution.",
|
|
||||||
ExampleTranslation = "從我的觀點來看,這是最好的解決方案。",
|
|
||||||
DifficultyLevel = "B2"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return mockCards.Take(Math.Min(count, mockCards.Count)).ToList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request DTOs
|
// Request DTOs
|
||||||
|
|
@ -1483,10 +1257,6 @@ public class ValidateCardRequest
|
||||||
public Guid? ErrorReportId { get; set; }
|
public Guid? ErrorReportId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestSaveCardsRequest
|
|
||||||
{
|
|
||||||
public List<GeneratedCard> SelectedCards { get; set; } = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增的API請求/響應 DTOs
|
// 新增的API請求/響應 DTOs
|
||||||
public class AnalyzeSentenceRequest
|
public class AnalyzeSentenceRequest
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue