diff --git a/backend/DramaLing.Api/Controllers/AIController.cs b/backend/DramaLing.Api/Controllers/AIController.cs new file mode 100644 index 0000000..66d8e5b --- /dev/null +++ b/backend/DramaLing.Api/Controllers/AIController.cs @@ -0,0 +1,133 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using DramaLing.Api.Models.DTOs; +using DramaLing.Api.Services; +using System.Diagnostics; + +namespace DramaLing.Api.Controllers; + +[ApiController] +[Route("api/ai")] +public class AIController : ControllerBase +{ + private readonly IGeminiService _geminiService; + private readonly ILogger _logger; + + public AIController( + IGeminiService geminiService, + ILogger logger) + { + _geminiService = geminiService; + _logger = logger; + } + + /// + /// 智能分析英文句子 + /// + /// 分析請求 + /// 分析結果 + [HttpPost("analyze-sentence")] + [AllowAnonymous] + public async Task> AnalyzeSentence( + [FromBody] SentenceAnalysisRequest request) + { + var requestId = Guid.NewGuid().ToString(); + var stopwatch = Stopwatch.StartNew(); + + try + { + // For testing without auth - use dummy user ID + var userId = "test-user-id"; + + _logger.LogInformation("Processing sentence analysis request {RequestId} for user {UserId}", + requestId, userId); + + // Input validation + if (!ModelState.IsValid) + { + return BadRequest(CreateErrorResponse("INVALID_INPUT", "輸入格式錯誤", + ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage).ToList(), + requestId)); + } + + // 直接執行 AI 分析,不使用快取 + var options = request.Options ?? new AnalysisOptions(); + var analysisData = await _geminiService.AnalyzeSentenceAsync( + request.InputText, request.UserLevel, options); + + stopwatch.Stop(); + analysisData.Metadata.ProcessingDate = DateTime.UtcNow; + + _logger.LogInformation("Sentence analysis completed for request {RequestId} in {ElapsedMs}ms", + requestId, stopwatch.ElapsedMilliseconds); + + return Ok(new SentenceAnalysisResponse + { + Success = true, + ProcessingTime = stopwatch.Elapsed.TotalSeconds, + Data = analysisData + }); + } + catch (ArgumentException ex) + { + _logger.LogWarning(ex, "Invalid input for request {RequestId}", requestId); + return BadRequest(CreateErrorResponse("INVALID_INPUT", ex.Message, null, requestId)); + } + catch (InvalidOperationException ex) + { + _logger.LogError(ex, "AI service error for request {RequestId}", requestId); + return StatusCode(500, CreateErrorResponse("AI_SERVICE_ERROR", "AI服務暫時不可用", null, requestId)); + } + catch (Exception ex) + { + _logger.LogError(ex, "Unexpected error processing request {RequestId}", requestId); + return StatusCode(500, CreateErrorResponse("INTERNAL_ERROR", "伺服器內部錯誤", null, requestId)); + } + } + + /// + /// 健康檢查端點 + /// + [HttpGet("health")] + [AllowAnonymous] + public ActionResult GetHealth() + { + return Ok(new + { + Status = "Healthy", + Service = "AI Analysis Service", + Timestamp = DateTime.UtcNow, + Version = "1.0" + }); + } + + private ApiErrorResponse CreateErrorResponse(string code, string message, object? details, string requestId) + { + var suggestions = GetSuggestionsForError(code); + + return new ApiErrorResponse + { + Success = false, + Error = new ApiError + { + Code = code, + Message = message, + Details = details, + Suggestions = suggestions + }, + RequestId = requestId, + Timestamp = DateTime.UtcNow + }; + } + + private List GetSuggestionsForError(string errorCode) + { + return errorCode switch + { + "INVALID_INPUT" => new List { "請檢查輸入格式", "確保文本長度在限制內" }, + "RATE_LIMIT_EXCEEDED" => new List { "升級到Premium帳戶以獲得無限使用", "明天重新嘗試" }, + "AI_SERVICE_ERROR" => new List { "請稍後重試", "如果問題持續,請聯繫客服" }, + _ => new List { "請稍後重試" } + }; + } +} \ No newline at end of file