docs: 整理AI句子分析功能規格文檔到note目錄
📁 文檔重組: • 將AI句子分析相關規格文檔移至note/AI句子分析規格目錄 • 統一文檔管理和版本控制 • 提升文檔可讀性和查找效率 📋 包含文檔: • AI分析API技術實現規格.md - 技術實現細節 • AI句子分析功能產品需求規格.md - 產品需求與用戶故事 • DramaLing AI句子分析功能前後端串接實施計劃.md - 實施計劃與進度 • 文件結構說明.md - 文檔結構說明 • 系統整合與部署規格.md - 部署和整合指南 🎯 改善效果: • 文檔結構清晰化 • 便於開發團隊查閱 • 支援未來功能擴展 🚀 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
a2c2ada8a9
commit
ad919ec5b7
|
|
@ -0,0 +1,815 @@
|
||||||
|
# AI分析API技術實現規格
|
||||||
|
|
||||||
|
## 📋 **文件資訊**
|
||||||
|
|
||||||
|
- **文件名稱**: AI分析API技術實現規格
|
||||||
|
- **版本**: v2.0
|
||||||
|
- **建立日期**: 2025-01-25
|
||||||
|
- **最後更新**: 2025-01-25
|
||||||
|
- **負責團隊**: DramaLing後端技術團隊
|
||||||
|
- **對應產品需求**: 《AI句子分析功能產品需求規格》
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠 **技術架構概述**
|
||||||
|
|
||||||
|
### **系統架構設計**
|
||||||
|
```yaml
|
||||||
|
分層架構:
|
||||||
|
- API Gateway: 認證、限流、路由
|
||||||
|
- Controllers: HTTP請求處理、參數驗證
|
||||||
|
- Services: 業務邏輯、AI整合
|
||||||
|
- Data Access: 資料庫操作、快取管理
|
||||||
|
- External APIs: AI服務、第三方整合
|
||||||
|
|
||||||
|
技術棧:
|
||||||
|
- 語言: C# / .NET 8
|
||||||
|
- 框架: ASP.NET Core Web API
|
||||||
|
- AI服務: Google Gemini 1.5 Flash
|
||||||
|
- 資料庫: SQLite (開發) / PostgreSQL (生產)
|
||||||
|
- 快取: Redis (生產) / In-Memory (開發)
|
||||||
|
- 監控: Application Insights
|
||||||
|
```
|
||||||
|
|
||||||
|
### **核心設計原則**
|
||||||
|
- **單一職責**: 每個服務類別職責明確
|
||||||
|
- **依賴注入**: 基於介面的鬆耦合設計
|
||||||
|
- **配置外部化**: 強型別配置管理
|
||||||
|
- **錯誤恢復**: 重試機制和降級策略
|
||||||
|
- **可觀測性**: 結構化日誌和健康檢查
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 **API端點設計**
|
||||||
|
|
||||||
|
### **核心分析端點**
|
||||||
|
|
||||||
|
#### **POST /api/ai/analyze-sentence**
|
||||||
|
**功能**: 智能英文句子分析
|
||||||
|
|
||||||
|
**請求格式**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"inputText": "She just join the team, so let's cut her some slack until she get used to the workflow.",
|
||||||
|
"analysisMode": "full",
|
||||||
|
"options": {
|
||||||
|
"includeGrammarCheck": true,
|
||||||
|
"includeVocabularyAnalysis": true,
|
||||||
|
"includeTranslation": true,
|
||||||
|
"includeIdiomDetection": true,
|
||||||
|
"includeExamples": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**回應格式**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"processingTime": 2.34,
|
||||||
|
"data": {
|
||||||
|
"analysisId": "uuid-string",
|
||||||
|
"originalText": "原始輸入文本",
|
||||||
|
"grammarCorrection": {
|
||||||
|
"hasErrors": true,
|
||||||
|
"correctedText": "修正後文本",
|
||||||
|
"corrections": [
|
||||||
|
{
|
||||||
|
"position": { "start": 9, "end": 13 },
|
||||||
|
"error": "join",
|
||||||
|
"correction": "joined",
|
||||||
|
"type": "時態錯誤",
|
||||||
|
"explanation": "第三人稱單數過去式應使用 'joined'",
|
||||||
|
"severity": "high"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sentenceMeaning": "中文翻譯",
|
||||||
|
"vocabularyAnalysis": {
|
||||||
|
"word": {
|
||||||
|
"word": "詞彙",
|
||||||
|
"translation": "中文翻譯",
|
||||||
|
"definition": "英文定義",
|
||||||
|
"partOfSpeech": "詞性",
|
||||||
|
"pronunciation": "/IPA發音/",
|
||||||
|
"difficultyLevel": "A1-C2",
|
||||||
|
"frequency": "high/medium/low",
|
||||||
|
"synonyms": ["同義詞陣列"],
|
||||||
|
"example": "例句",
|
||||||
|
"exampleTranslation": "例句翻譯"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idioms": [
|
||||||
|
{
|
||||||
|
"idiom": "cut someone some slack",
|
||||||
|
"translation": "對某人寬容一點",
|
||||||
|
"definition": "to be more lenient or forgiving",
|
||||||
|
"pronunciation": "/發音/",
|
||||||
|
"difficultyLevel": "B2",
|
||||||
|
"frequency": "medium",
|
||||||
|
"synonyms": ["be lenient", "give leeway"],
|
||||||
|
"example": "例句",
|
||||||
|
"exampleTranslation": "例句翻譯"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"analysisModel": "gemini-1.5-flash",
|
||||||
|
"analysisVersion": "2.0",
|
||||||
|
"processingDate": "2025-01-25T10:30:00Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **GET /api/ai/health**
|
||||||
|
**功能**: 服務健康檢查
|
||||||
|
|
||||||
|
**回應格式**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "Healthy",
|
||||||
|
"service": "AI Analysis Service",
|
||||||
|
"timestamp": "2025-01-25T10:30:00Z",
|
||||||
|
"version": "2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"geminiApi": "healthy",
|
||||||
|
"database": "healthy",
|
||||||
|
"cache": "healthy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤖 **AI集成架構**
|
||||||
|
|
||||||
|
### **Prompt工程設計**
|
||||||
|
|
||||||
|
#### **核心Prompt模板**
|
||||||
|
```text
|
||||||
|
You are an English learning assistant. Analyze this sentence and return ONLY a valid JSON response.
|
||||||
|
|
||||||
|
**Input Sentence**: "{inputText}"
|
||||||
|
|
||||||
|
**Required JSON Structure:**
|
||||||
|
{
|
||||||
|
"sentenceTranslation": "Traditional Chinese translation of the entire sentence",
|
||||||
|
"hasGrammarErrors": true/false,
|
||||||
|
"grammarCorrections": [
|
||||||
|
{
|
||||||
|
"original": "incorrect text",
|
||||||
|
"corrected": "correct text",
|
||||||
|
"type": "error type (tense/subject-verb/preposition/word-order)",
|
||||||
|
"explanation": "brief explanation in Traditional Chinese"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vocabularyAnalysis": {
|
||||||
|
"word1": {
|
||||||
|
"word": "the word",
|
||||||
|
"translation": "Traditional Chinese translation",
|
||||||
|
"definition": "English definition",
|
||||||
|
"partOfSpeech": "noun/verb/adjective/etc",
|
||||||
|
"pronunciation": "/phonetic/",
|
||||||
|
"difficultyLevel": "A1/A2/B1/B2/C1/C2",
|
||||||
|
"frequency": "high/medium/low",
|
||||||
|
"synonyms": ["synonym1", "synonym2"],
|
||||||
|
"example": "example sentence",
|
||||||
|
"exampleTranslation": "Traditional Chinese example translation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idioms": [
|
||||||
|
{
|
||||||
|
"idiom": "idiomatic expression",
|
||||||
|
"translation": "Traditional Chinese meaning",
|
||||||
|
"definition": "English explanation",
|
||||||
|
"pronunciation": "/phonetic notation/",
|
||||||
|
"difficultyLevel": "A1/A2/B1/B2/C1/C2",
|
||||||
|
"frequency": "high/medium/low",
|
||||||
|
"synonyms": ["synonym1", "synonym2"],
|
||||||
|
"example": "usage example",
|
||||||
|
"exampleTranslation": "Traditional Chinese example"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
**Analysis Guidelines:**
|
||||||
|
1. **Grammar Check**: Detect tense errors, subject-verb agreement, preposition usage, word order
|
||||||
|
2. **Vocabulary Analysis**: Include ALL significant words (exclude articles: a, an, the)
|
||||||
|
3. **CEFR Levels**: Assign accurate A1-C2 levels for each word
|
||||||
|
4. **Idioms**: Identify any idiomatic expressions or phrasal verbs
|
||||||
|
5. **Translations**: Use Traditional Chinese (Taiwan standard)
|
||||||
|
|
||||||
|
**IMPORTANT**: Return ONLY the JSON object, no additional text or explanation.
|
||||||
|
```
|
||||||
|
|
||||||
|
### **AI服務配置**
|
||||||
|
|
||||||
|
#### **Gemini API配置**
|
||||||
|
```yaml
|
||||||
|
模型配置:
|
||||||
|
- 模型: gemini-1.5-flash
|
||||||
|
- 溫度: 0.7 (平衡創造性和準確性)
|
||||||
|
- 最大輸出: 2000 tokens
|
||||||
|
- 超時: 30秒
|
||||||
|
|
||||||
|
重試策略:
|
||||||
|
- 最大重試: 3次
|
||||||
|
- 退避策略: 指數退避 (1s, 2s, 4s)
|
||||||
|
- 重試條件: 網路錯誤、超時、5xx錯誤
|
||||||
|
- 熔斷條件: 連續失敗 > 5次
|
||||||
|
|
||||||
|
降級策略:
|
||||||
|
- 備用回應: 基礎翻譯和詞性分析
|
||||||
|
- 快取回退: 相似句子的歷史分析結果
|
||||||
|
- 服務狀態: 實時監控和告警
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 **數據模型設計**
|
||||||
|
|
||||||
|
### **請求模型**
|
||||||
|
|
||||||
|
#### **SentenceAnalysisRequest**
|
||||||
|
```csharp
|
||||||
|
public class SentenceAnalysisRequest
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[StringLength(300, MinimumLength = 1)]
|
||||||
|
public string InputText { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string AnalysisMode { get; set; } = "full";
|
||||||
|
|
||||||
|
public AnalysisOptions? Options { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AnalysisOptions
|
||||||
|
{
|
||||||
|
public bool IncludeGrammarCheck { get; set; } = true;
|
||||||
|
public bool IncludeVocabularyAnalysis { get; set; } = true;
|
||||||
|
public bool IncludeTranslation { get; set; } = true;
|
||||||
|
public bool IncludeIdiomDetection { get; set; } = true;
|
||||||
|
public bool IncludeExamples { get; set; } = true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **回應模型**
|
||||||
|
|
||||||
|
#### **核心資料模型**
|
||||||
|
```csharp
|
||||||
|
public class SentenceAnalysisResponse
|
||||||
|
{
|
||||||
|
public bool Success { get; set; } = true;
|
||||||
|
public double ProcessingTime { get; set; }
|
||||||
|
public SentenceAnalysisData? Data { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SentenceAnalysisData
|
||||||
|
{
|
||||||
|
public string AnalysisId { get; set; } = Guid.NewGuid().ToString();
|
||||||
|
public string OriginalText { get; set; } = string.Empty;
|
||||||
|
public GrammarCorrectionDto? GrammarCorrection { get; set; }
|
||||||
|
public string SentenceMeaning { get; set; } = string.Empty;
|
||||||
|
public Dictionary<string, VocabularyAnalysisDto> VocabularyAnalysis { get; set; } = new();
|
||||||
|
public List<IdiomDto> Idioms { get; set; } = new();
|
||||||
|
public AnalysisMetadata Metadata { get; set; } = new();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **詳細模型定義**
|
||||||
|
```csharp
|
||||||
|
public class VocabularyAnalysisDto
|
||||||
|
{
|
||||||
|
public string Word { get; set; } = string.Empty;
|
||||||
|
public string Translation { get; set; } = string.Empty;
|
||||||
|
public string Definition { get; set; } = string.Empty;
|
||||||
|
public string PartOfSpeech { get; set; } = string.Empty;
|
||||||
|
public string Pronunciation { get; set; } = string.Empty;
|
||||||
|
public string DifficultyLevel { get; set; } = string.Empty;
|
||||||
|
public string Frequency { get; set; } = string.Empty;
|
||||||
|
public List<string> Synonyms { get; set; } = new();
|
||||||
|
public string? Example { get; set; }
|
||||||
|
public string? ExampleTranslation { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdiomDto
|
||||||
|
{
|
||||||
|
public string Idiom { get; set; } = string.Empty;
|
||||||
|
public string Translation { get; set; } = string.Empty;
|
||||||
|
public string Definition { get; set; } = string.Empty;
|
||||||
|
public string Pronunciation { get; set; } = string.Empty;
|
||||||
|
public string DifficultyLevel { get; set; } = string.Empty;
|
||||||
|
public string Frequency { get; set; } = string.Empty;
|
||||||
|
public List<string> Synonyms { get; set; } = new();
|
||||||
|
public string? Example { get; set; }
|
||||||
|
public string? ExampleTranslation { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GrammarCorrectionDto
|
||||||
|
{
|
||||||
|
public bool HasErrors { get; set; }
|
||||||
|
public string CorrectedText { get; set; } = string.Empty;
|
||||||
|
public List<GrammarErrorDto> Corrections { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GrammarErrorDto
|
||||||
|
{
|
||||||
|
public ErrorPosition Position { get; set; } = new();
|
||||||
|
public string Error { get; set; } = string.Empty;
|
||||||
|
public string Correction { get; set; } = string.Empty;
|
||||||
|
public string Type { get; set; } = string.Empty;
|
||||||
|
public string Explanation { get; set; } = string.Empty;
|
||||||
|
public string Severity { get; set; } = "medium";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 **服務層架構**
|
||||||
|
|
||||||
|
### **核心服務設計**
|
||||||
|
|
||||||
|
#### **IGeminiService介面**
|
||||||
|
```csharp
|
||||||
|
public interface IGeminiService
|
||||||
|
{
|
||||||
|
Task<SentenceAnalysisData> AnalyzeSentenceAsync(string inputText, AnalysisOptions options);
|
||||||
|
Task<bool> HealthCheckAsync();
|
||||||
|
Task<string> GetModelVersionAsync();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **服務實現重點**
|
||||||
|
```csharp
|
||||||
|
public class GeminiService : IGeminiService
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
private readonly IOptions<GeminiOptions> _options;
|
||||||
|
private readonly ILogger<GeminiService> _logger;
|
||||||
|
|
||||||
|
// ✅ 強型別配置注入
|
||||||
|
public GeminiService(HttpClient httpClient, IOptions<GeminiOptions> options, ILogger<GeminiService> logger)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
_options = options;
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
|
ConfigureHttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ 結構化錯誤處理
|
||||||
|
public async Task<SentenceAnalysisData> AnalyzeSentenceAsync(string inputText, AnalysisOptions options)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var prompt = BuildPrompt(inputText, options);
|
||||||
|
var aiResponse = await CallGeminiAPIWithRetry(prompt);
|
||||||
|
return ParseResponse(inputText, aiResponse);
|
||||||
|
}
|
||||||
|
catch (HttpRequestException ex)
|
||||||
|
{
|
||||||
|
throw new AIServiceException("Gemini", "Network error", ex);
|
||||||
|
}
|
||||||
|
catch (JsonException ex)
|
||||||
|
{
|
||||||
|
throw new AIServiceException("Gemini", "Invalid response format", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **配置管理架構**
|
||||||
|
|
||||||
|
#### **強型別配置**
|
||||||
|
```csharp
|
||||||
|
public class GeminiOptions
|
||||||
|
{
|
||||||
|
public const string SectionName = "Gemini";
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string ApiKey { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Range(1, 120)]
|
||||||
|
public int TimeoutSeconds { get; set; } = 30;
|
||||||
|
|
||||||
|
[Range(1, 10)]
|
||||||
|
public int MaxRetries { get; set; } = 3;
|
||||||
|
|
||||||
|
public string Model { get; set; } = "gemini-1.5-flash";
|
||||||
|
public double Temperature { get; set; } = 0.7;
|
||||||
|
public int MaxOutputTokens { get; set; } = 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置驗證器
|
||||||
|
public class GeminiOptionsValidator : IValidateOptions<GeminiOptions>
|
||||||
|
{
|
||||||
|
public ValidateOptionsResult Validate(string name, GeminiOptions options)
|
||||||
|
{
|
||||||
|
var failures = new List<string>();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(options.ApiKey))
|
||||||
|
failures.Add("Gemini API key is required");
|
||||||
|
|
||||||
|
if (!IsValidApiKey(options.ApiKey))
|
||||||
|
failures.Add("Invalid Gemini API key format");
|
||||||
|
|
||||||
|
return failures.Any()
|
||||||
|
? ValidateOptionsResult.Fail(failures)
|
||||||
|
: ValidateOptionsResult.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛡️ **錯誤處理與穩定性**
|
||||||
|
|
||||||
|
### **異常層次結構**
|
||||||
|
```csharp
|
||||||
|
public abstract class DramaLingException : Exception
|
||||||
|
{
|
||||||
|
public string ErrorCode { get; }
|
||||||
|
public Dictionary<string, object> Context { get; }
|
||||||
|
|
||||||
|
protected DramaLingException(string errorCode, string message) : base(message)
|
||||||
|
{
|
||||||
|
ErrorCode = errorCode;
|
||||||
|
Context = new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AIServiceException : DramaLingException
|
||||||
|
{
|
||||||
|
public AIServiceException(string provider, string details)
|
||||||
|
: base("AI_SERVICE_ERROR", $"AI service '{provider}' failed: {details}")
|
||||||
|
{
|
||||||
|
Context["Provider"] = provider;
|
||||||
|
Context["Details"] = details;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ValidationException : DramaLingException
|
||||||
|
{
|
||||||
|
public ValidationException(string field, string message)
|
||||||
|
: base("VALIDATION_ERROR", $"Validation failed for {field}: {message}")
|
||||||
|
{
|
||||||
|
Context["Field"] = field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **錯誤回應標準**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"error": {
|
||||||
|
"code": "AI_SERVICE_ERROR",
|
||||||
|
"message": "AI服務暫時不可用",
|
||||||
|
"details": {
|
||||||
|
"provider": "gemini",
|
||||||
|
"originalError": "Network timeout"
|
||||||
|
},
|
||||||
|
"suggestions": [
|
||||||
|
"請稍後重試",
|
||||||
|
"如果問題持續,請聯繫客服"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timestamp": "2025-01-25T10:30:00Z",
|
||||||
|
"requestId": "uuid-string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **重試與熔斷機制**
|
||||||
|
```csharp
|
||||||
|
// 使用Polly實現重試策略
|
||||||
|
services.AddHttpClient<IGeminiService, GeminiService>()
|
||||||
|
.AddPolicyHandler(GetRetryPolicy())
|
||||||
|
.AddPolicyHandler(GetCircuitBreakerPolicy());
|
||||||
|
|
||||||
|
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
|
||||||
|
{
|
||||||
|
return HttpPolicyExtensions
|
||||||
|
.HandleTransientHttpError()
|
||||||
|
.WaitAndRetryAsync(
|
||||||
|
retryCount: 3,
|
||||||
|
sleepDurationProvider: retryAttempt =>
|
||||||
|
TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
||||||
|
onRetry: (outcome, timespan, retryCount, context) =>
|
||||||
|
{
|
||||||
|
logger.LogWarning("Retry {RetryCount} after {Delay}ms",
|
||||||
|
retryCount, timespan.TotalMilliseconds);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **性能優化設計**
|
||||||
|
|
||||||
|
### **快取策略**
|
||||||
|
```yaml
|
||||||
|
多層快取架構:
|
||||||
|
L1: 應用程序記憶體快取 (5分鐘)
|
||||||
|
L2: Redis分散式快取 (1小時)
|
||||||
|
L3: 資料庫持久快取 (24小時)
|
||||||
|
|
||||||
|
快取鍵設計:
|
||||||
|
- 格式: "analysis:{hash(inputText)}"
|
||||||
|
- 過期: 基於內容複雜度動態調整
|
||||||
|
- 清理: 背景服務定期清理過期快取
|
||||||
|
|
||||||
|
快取命中率目標: > 70%
|
||||||
|
```
|
||||||
|
|
||||||
|
### **資料庫優化**
|
||||||
|
```csharp
|
||||||
|
// 查詢優化範例
|
||||||
|
public async Task<AnalysisCache> GetCachedAnalysisAsync(string inputText)
|
||||||
|
{
|
||||||
|
var textHash = ComputeHash(inputText);
|
||||||
|
|
||||||
|
return await _context.AnalysisCache
|
||||||
|
.AsNoTracking() // 只讀查詢優化
|
||||||
|
.Where(c => c.InputTextHash == textHash && c.ExpiresAt > DateTime.UtcNow)
|
||||||
|
.Select(c => new AnalysisCache // 投影查詢,只選需要的欄位
|
||||||
|
{
|
||||||
|
Id = c.Id,
|
||||||
|
CachedData = c.CachedData,
|
||||||
|
CreatedAt = c.CreatedAt
|
||||||
|
})
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 **安全架構設計**
|
||||||
|
|
||||||
|
### **API安全**
|
||||||
|
```yaml
|
||||||
|
認證機制:
|
||||||
|
- JWT Bearer Token認證
|
||||||
|
- Token過期時間: 24小時
|
||||||
|
- 刷新機制: Refresh Token
|
||||||
|
|
||||||
|
授權控制:
|
||||||
|
- 角色基礎存取控制 (RBAC)
|
||||||
|
- 資源級別權限
|
||||||
|
- API速率限制
|
||||||
|
|
||||||
|
輸入驗證:
|
||||||
|
- 參數類型檢查
|
||||||
|
- 字符長度限制
|
||||||
|
- XSS防護過濾
|
||||||
|
- SQL注入防護
|
||||||
|
```
|
||||||
|
|
||||||
|
### **資料安全**
|
||||||
|
```yaml
|
||||||
|
傳輸安全:
|
||||||
|
- TLS 1.3強制加密
|
||||||
|
- HSTS標頭
|
||||||
|
- 安全標頭 (CSP, X-Frame-Options)
|
||||||
|
|
||||||
|
存儲安全:
|
||||||
|
- 敏感資料加密
|
||||||
|
- API金鑰安全管理
|
||||||
|
- 個人資料匿名化
|
||||||
|
- 定期安全掃描
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 **測試策略**
|
||||||
|
|
||||||
|
### **測試金字塔**
|
||||||
|
```yaml
|
||||||
|
單元測試 (70%):
|
||||||
|
- 服務邏輯測試
|
||||||
|
- 配置驗證測試
|
||||||
|
- 錯誤處理測試
|
||||||
|
- Mock外部依賴
|
||||||
|
|
||||||
|
整合測試 (20%):
|
||||||
|
- API端點測試
|
||||||
|
- 資料庫整合測試
|
||||||
|
- 快取系統測試
|
||||||
|
- 健康檢查測試
|
||||||
|
|
||||||
|
E2E測試 (10%):
|
||||||
|
- 完整分析流程測試
|
||||||
|
- 真實AI API測試
|
||||||
|
- 性能基準測試
|
||||||
|
- 安全滲透測試
|
||||||
|
```
|
||||||
|
|
||||||
|
### **測試案例設計**
|
||||||
|
```csharp
|
||||||
|
[TestFixture]
|
||||||
|
public class AIAnalysisServiceTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public async Task AnalyzeAsync_WithValidInput_ReturnsAnalysisResult()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var request = new AnalysisRequest { InputText = "She just joined the team." };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _service.AnalyzeAsync(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.That(result.VocabularyAnalysis.Count, Is.GreaterThan(0));
|
||||||
|
Assert.That(result.SentenceMeaning, Is.Not.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task AnalyzeAsync_WhenAIServiceFails_ThrowsAIServiceException()
|
||||||
|
{
|
||||||
|
// 測試AI服務故障時的錯誤處理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 **監控與可觀測性**
|
||||||
|
|
||||||
|
### **日誌標準**
|
||||||
|
```csharp
|
||||||
|
// 結構化日誌擴展
|
||||||
|
public static class LoggerExtensions
|
||||||
|
{
|
||||||
|
public static void LogAIRequest(this ILogger logger, string requestId,
|
||||||
|
string inputText, string provider, double processingTime)
|
||||||
|
{
|
||||||
|
logger.LogInformation("AI Request: {RequestId} Provider: {Provider} " +
|
||||||
|
"Length: {Length} Time: {Time}ms",
|
||||||
|
requestId, provider, inputText.Length, processingTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **健康檢查**
|
||||||
|
```csharp
|
||||||
|
public class AIServiceHealthCheck : IHealthCheck
|
||||||
|
{
|
||||||
|
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var checks = new Dictionary<string, bool>
|
||||||
|
{
|
||||||
|
["gemini_api"] = await CheckGeminiHealthAsync(),
|
||||||
|
["database"] = await CheckDatabaseHealthAsync(),
|
||||||
|
["cache"] = await CheckCacheHealthAsync()
|
||||||
|
};
|
||||||
|
|
||||||
|
var failedChecks = checks.Where(c => !c.Value).Select(c => c.Key).ToList();
|
||||||
|
|
||||||
|
return failedChecks.Any()
|
||||||
|
? HealthCheckResult.Unhealthy($"Failed: {string.Join(", ", failedChecks)}")
|
||||||
|
: HealthCheckResult.Healthy("All systems operational");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **性能指標**
|
||||||
|
```yaml
|
||||||
|
關鍵指標:
|
||||||
|
- API回應時間分佈 (P50, P95, P99)
|
||||||
|
- AI API調用成功率
|
||||||
|
- 快取命中率
|
||||||
|
- 記憶體和CPU使用率
|
||||||
|
- 錯誤率和異常分佈
|
||||||
|
|
||||||
|
告警閾值:
|
||||||
|
- 回應時間P95 > 5秒
|
||||||
|
- 錯誤率 > 5%
|
||||||
|
- AI API失敗率 > 10%
|
||||||
|
- 記憶體使用 > 80%
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 **部署與配置**
|
||||||
|
|
||||||
|
### **環境配置**
|
||||||
|
```yaml
|
||||||
|
Development:
|
||||||
|
- Database: SQLite
|
||||||
|
- Cache: In-Memory
|
||||||
|
- AI Provider: Gemini (測試Key)
|
||||||
|
- Logging: Debug Level
|
||||||
|
|
||||||
|
Production:
|
||||||
|
- Database: PostgreSQL (HA)
|
||||||
|
- Cache: Redis Cluster
|
||||||
|
- AI Provider: Gemini (生產Key)
|
||||||
|
- Logging: Information Level
|
||||||
|
- Monitoring: Application Insights
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Docker配置**
|
||||||
|
```dockerfile
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 5008
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["DramaLing.Api.csproj", "."]
|
||||||
|
RUN dotnet restore
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN dotnet publish -c Release -o /app/publish
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/publish .
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s \
|
||||||
|
CMD curl -f http://localhost:5008/health || exit 1
|
||||||
|
|
||||||
|
ENTRYPOINT ["dotnet", "DramaLing.Api.dll"]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 **開發指導**
|
||||||
|
|
||||||
|
### **程式碼規範**
|
||||||
|
```yaml
|
||||||
|
命名規範:
|
||||||
|
- 類別: PascalCase (UserService)
|
||||||
|
- 方法: PascalCase (AnalyzeAsync)
|
||||||
|
- 參數: camelCase (inputText)
|
||||||
|
- 常數: UPPER_CASE (MAX_LENGTH)
|
||||||
|
|
||||||
|
註釋規範:
|
||||||
|
- 公開API: 完整XML註釋
|
||||||
|
- 複雜邏輯: 行內註釋解釋
|
||||||
|
- 業務邏輯: 意圖說明註釋
|
||||||
|
- TODO: 使用標準格式
|
||||||
|
|
||||||
|
錯誤處理:
|
||||||
|
- 自訂異常類型
|
||||||
|
- 結構化錯誤回應
|
||||||
|
- 日誌記錄完整
|
||||||
|
- 用戶友善訊息
|
||||||
|
```
|
||||||
|
|
||||||
|
### **API設計原則**
|
||||||
|
```yaml
|
||||||
|
RESTful設計:
|
||||||
|
- 使用標準HTTP動詞
|
||||||
|
- 資源導向URL設計
|
||||||
|
- 狀態碼語義明確
|
||||||
|
- 一致的回應格式
|
||||||
|
|
||||||
|
版本管理:
|
||||||
|
- URL版本控制 (/api/v1/)
|
||||||
|
- 向下相容保證
|
||||||
|
- 淘汰策略明確
|
||||||
|
- 版本變更文檔
|
||||||
|
|
||||||
|
安全實踐:
|
||||||
|
- 最小權限原則
|
||||||
|
- 輸入驗證完整
|
||||||
|
- 輸出編碼安全
|
||||||
|
- 審計日誌記錄
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **變更管理**
|
||||||
|
|
||||||
|
### **API版本演進**
|
||||||
|
- **v1.0**: 基礎分析功能 (2025-01-20)
|
||||||
|
- **v1.1**: 移除userLevel,簡化API (2025-01-25)
|
||||||
|
- **v2.0**: 重構技術規格,標準化設計 (2025-01-25)
|
||||||
|
|
||||||
|
### **技術債務管理**
|
||||||
|
```yaml
|
||||||
|
已解決:
|
||||||
|
- 硬編碼配置移除
|
||||||
|
- 強型別配置實施
|
||||||
|
- API規格標準化
|
||||||
|
|
||||||
|
待解決:
|
||||||
|
- 重試機制實施
|
||||||
|
- 健康檢查完善
|
||||||
|
- 監控指標實施
|
||||||
|
- 性能優化
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文件版本**: v2.0
|
||||||
|
**技術負責人**: DramaLing後端技術團隊
|
||||||
|
**最後更新**: 2025-01-25
|
||||||
|
**下次審查**: 2025-02-25
|
||||||
|
|
||||||
|
**關聯文件**:
|
||||||
|
- 《AI句子分析功能產品需求規格》- 業務需求和用戶故事
|
||||||
|
- 《系統整合與部署規格》- 整合和部署細節
|
||||||
|
- 《AI驅動產品後端技術架構指南》- 架構設計指導原則
|
||||||
|
|
@ -0,0 +1,569 @@
|
||||||
|
# AI句子分析功能產品需求規格
|
||||||
|
|
||||||
|
## 📋 **文件資訊**
|
||||||
|
|
||||||
|
- **文件名稱**: AI句子分析功能產品需求規格
|
||||||
|
- **版本**: v2.0
|
||||||
|
- **建立日期**: 2025-01-25
|
||||||
|
- **最後更新**: 2025-01-25
|
||||||
|
- **負責團隊**: DramaLing產品團隊
|
||||||
|
- **適用範圍**: 全平台 (Web、API、未來Mobile)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 **產品概述**
|
||||||
|
|
||||||
|
### **產品定位**
|
||||||
|
DramaLing AI句子分析功能是個人化英語學習平台的核心功能,專注於提供智能句子分析、個人化詞彙標記和互動式學習體驗。
|
||||||
|
|
||||||
|
### **商業目標**
|
||||||
|
- 🎯 **提升學習效率**: 通過AI分析幫助用戶快速理解句子結構
|
||||||
|
- 💡 **個人化學習**: 基於用戶程度提供適合的學習內容
|
||||||
|
- 📈 **用戶留存**: 通過互動式體驗增加平台黏性
|
||||||
|
- 🌍 **市場差異化**: 提供業界領先的AI驅動語言學習體驗
|
||||||
|
|
||||||
|
### **核心價值主張**
|
||||||
|
- 🤖 **AI驅動分析** - 即時語法檢查和詞彙解析
|
||||||
|
- 🎯 **個人化學習** - 基於CEFR等級的智能詞彙分類
|
||||||
|
- 📊 **視覺化回饋** - 直觀的學習進度和統計展示
|
||||||
|
- 💡 **互動式學習** - 點擊探索式的深度學習體驗
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎭 **用戶故事與使用場景**
|
||||||
|
|
||||||
|
### **US1. 核心學習流程**
|
||||||
|
|
||||||
|
#### **US1.1 智能句子分析**
|
||||||
|
```gherkin
|
||||||
|
功能: 智能英文句子分析
|
||||||
|
背景: 用戶想要學習和理解英文句子
|
||||||
|
|
||||||
|
場景: 用戶分析英文句子
|
||||||
|
給定 用戶是英語學習者
|
||||||
|
當 用戶輸入英文句子 "She just join the team, so let's cut her some slack until she get used to the workflow."
|
||||||
|
並且 點擊「分析句子」按鈕
|
||||||
|
那麼 系統應該顯示語法修正建議
|
||||||
|
並且 系統應該提供詞彙難度標記
|
||||||
|
並且 系統應該識別慣用語 "cut someone some slack"
|
||||||
|
並且 系統應該提供完整的中文翻譯
|
||||||
|
|
||||||
|
驗收標準:
|
||||||
|
- 能輸入最多300字的英文句子
|
||||||
|
- 分析回應時間 < 5秒
|
||||||
|
- 語法檢查準確率 > 85%
|
||||||
|
- 詞彙CEFR分級準確率 > 90%
|
||||||
|
- 慣用語識別覆蓋率 > 80%
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **US1.2 個人化詞彙學習**
|
||||||
|
```gherkin
|
||||||
|
功能: 基於CEFR等級的個人化詞彙標記
|
||||||
|
背景: 不同程度的學習者需要不同的學習重點
|
||||||
|
|
||||||
|
場景: A2程度學習者查看句子分析
|
||||||
|
給定 用戶的CEFR等級是A2
|
||||||
|
當 系統分析句子中的詞彙
|
||||||
|
那麼 A1詞彙應該顯示為「太簡單啦」(灰色虛線)
|
||||||
|
並且 A2詞彙應該顯示為「重點學習」(綠色邊框)
|
||||||
|
並且 B1+詞彙應該顯示為「有點挑戰」(橙色邊框)
|
||||||
|
並且 慣用語應該獨立顯示為「慣用語」(藍色邊框)
|
||||||
|
|
||||||
|
驗收標準:
|
||||||
|
- 詞彙分類基於用戶當前CEFR等級動態計算
|
||||||
|
- 用戶可以調整CEFR等級設定
|
||||||
|
- 等級變更時詞彙標記即時更新
|
||||||
|
- 統計卡片數字與實際標記一致
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **US1.3 語法修正學習**
|
||||||
|
```gherkin
|
||||||
|
功能: 智能語法錯誤檢測和修正建議
|
||||||
|
背景: 學習者需要了解和改正語法錯誤
|
||||||
|
|
||||||
|
場景: 用戶獲得語法修正建議
|
||||||
|
給定 用戶輸入有語法錯誤的句子
|
||||||
|
當 系統完成分析
|
||||||
|
那麼 系統應該顯示語法修正面板
|
||||||
|
並且 提供原句與修正句的對比
|
||||||
|
並且 解釋每個錯誤的類型和原因
|
||||||
|
並且 用戶可以選擇採用修正或保持原樣
|
||||||
|
|
||||||
|
驗收標準:
|
||||||
|
- 檢測時態錯誤、主謂一致、介詞使用、詞序問題
|
||||||
|
- 提供繁體中文的錯誤解釋
|
||||||
|
- 修正建議自然且符合語言習慣
|
||||||
|
- 用戶選擇後影響後續的詞彙學習內容
|
||||||
|
```
|
||||||
|
|
||||||
|
### **US2. 深度學習互動**
|
||||||
|
|
||||||
|
#### **US2.1 詞彙探索學習**
|
||||||
|
```gherkin
|
||||||
|
功能: 互動式詞彙詳情查看
|
||||||
|
背景: 學習者想要深入了解特定詞彙
|
||||||
|
|
||||||
|
場景: 用戶點擊詞彙查看詳情
|
||||||
|
給定 句子已完成分析並顯示詞彙標記
|
||||||
|
當 用戶點擊任何標記的詞彙
|
||||||
|
那麼 系統應該顯示詞彙詳情彈窗
|
||||||
|
並且 包含中文翻譯、英文定義、發音
|
||||||
|
並且 提供同義詞和實用例句
|
||||||
|
並且 提供「保存到詞卡」功能
|
||||||
|
|
||||||
|
驗收標準:
|
||||||
|
- 所有標記詞彙都可點擊
|
||||||
|
- 彈窗定位智能,不超出螢幕邊界
|
||||||
|
- 彈窗開啟時間 < 200ms
|
||||||
|
- 詞彙資料完整且準確
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **US2.2 慣用語學習**
|
||||||
|
```gherkin
|
||||||
|
功能: 慣用語識別和學習
|
||||||
|
背景: 學習者需要掌握地道的英語表達
|
||||||
|
|
||||||
|
場景: 用戶學習句子中的慣用語
|
||||||
|
給定 句子包含慣用語表達
|
||||||
|
當 系統完成分析
|
||||||
|
那麼 慣用語應該在專門區域顯示
|
||||||
|
並且 不在句子中重複標記
|
||||||
|
並且 點擊慣用語可查看詳細解釋
|
||||||
|
並且 包含文化背景和使用場景
|
||||||
|
|
||||||
|
驗收標準:
|
||||||
|
- 慣用語、片語動詞、固定搭配的準確識別
|
||||||
|
- 提供文化背景和使用建議
|
||||||
|
- 與詞彙詳情彈窗一致的視覺設計
|
||||||
|
- 支援保存到個人詞彙庫
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 **功能需求規格 (Functional Requirements)**
|
||||||
|
|
||||||
|
### **FR1. 智能分析引擎**
|
||||||
|
|
||||||
|
#### **FR1.1 文本輸入處理**
|
||||||
|
**優先級**: P0 (必須)
|
||||||
|
|
||||||
|
**需求描述**:
|
||||||
|
- 支援多語言文本輸入(主要英文)
|
||||||
|
- 文本長度限制和即時驗證
|
||||||
|
- 特殊字符和格式處理
|
||||||
|
|
||||||
|
**詳細規格**:
|
||||||
|
```yaml
|
||||||
|
輸入限制:
|
||||||
|
- 最大長度: 300字符
|
||||||
|
- 支援字符: 英文字母、數字、標點符號
|
||||||
|
- 警告機制: 280字符黃色警告,300字符禁止輸入
|
||||||
|
- 即時驗證: 字符計數顯示,超限阻止提交
|
||||||
|
|
||||||
|
錯誤處理:
|
||||||
|
- 空字串: 禁用分析按鈕
|
||||||
|
- 無效字符: 自動過濾或提示
|
||||||
|
- 超長文本: 截斷並警告用戶
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **FR1.2 AI分析核心**
|
||||||
|
**優先級**: P0 (必須)
|
||||||
|
|
||||||
|
**需求描述**:
|
||||||
|
- 整合AI語言模型進行句子分析
|
||||||
|
- 支援多維度分析結果
|
||||||
|
- 確保分析準確性和一致性
|
||||||
|
|
||||||
|
**詳細規格**:
|
||||||
|
```yaml
|
||||||
|
分析範圍:
|
||||||
|
- 語法檢查: 時態、主謂一致、介詞、詞序
|
||||||
|
- 詞彙分析: CEFR等級、詞性、發音、翻譯
|
||||||
|
- 句子翻譯: 自然流暢的繁體中文
|
||||||
|
- 慣用語識別: 慣用語、片語動詞、固定搭配
|
||||||
|
|
||||||
|
品質要求:
|
||||||
|
- 語法檢查準確率: > 85%
|
||||||
|
- CEFR分級準確率: > 90%
|
||||||
|
- 翻譯自然度評分: > 4.0/5.0
|
||||||
|
- 慣用語識別率: > 80%
|
||||||
|
|
||||||
|
性能要求:
|
||||||
|
- 分析響應時間: < 5秒
|
||||||
|
- 同時支援用戶數: > 100
|
||||||
|
- 服務可用性: > 99.5%
|
||||||
|
```
|
||||||
|
|
||||||
|
### **FR2. 個人化學習系統**
|
||||||
|
|
||||||
|
#### **FR2.1 CEFR等級個人化**
|
||||||
|
**優先級**: P0 (必須)
|
||||||
|
|
||||||
|
**需求描述**:
|
||||||
|
- 基於用戶CEFR等級提供個人化詞彙分類
|
||||||
|
- 支援等級調整和即時更新
|
||||||
|
- 提供學習進度指引
|
||||||
|
|
||||||
|
**詳細規格**:
|
||||||
|
```yaml
|
||||||
|
分類邏輯:
|
||||||
|
- 簡單詞彙: 用戶等級 > 詞彙等級
|
||||||
|
- 適中詞彙: 用戶等級 = 詞彙等級
|
||||||
|
- 困難詞彙: 用戶等級 < 詞彙等級
|
||||||
|
- 慣用語: 獨立分類,不參與等級比較
|
||||||
|
|
||||||
|
支援等級:
|
||||||
|
- A1: 初學者 (約1000詞彙)
|
||||||
|
- A2: 基礎 (約2000詞彙)
|
||||||
|
- B1: 中級 (約3000詞彙)
|
||||||
|
- B2: 中高級 (約4000詞彙)
|
||||||
|
- C1: 高級 (約8000詞彙)
|
||||||
|
- C2: 精通 (約15000詞彙)
|
||||||
|
|
||||||
|
更新機制:
|
||||||
|
- 等級變更即時重新分類
|
||||||
|
- 本地存儲用戶設定
|
||||||
|
- 跨設備同步 (未來功能)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **FR2.2 學習進度可視化**
|
||||||
|
**優先級**: P0 (必須)
|
||||||
|
|
||||||
|
**需求描述**:
|
||||||
|
- 提供直觀的詞彙難度分布統計
|
||||||
|
- 支援學習重點識別
|
||||||
|
- 幫助用戶評估學習挑戰
|
||||||
|
|
||||||
|
**詳細規格**:
|
||||||
|
```yaml
|
||||||
|
統計卡片:
|
||||||
|
- 簡單詞彙卡片: 灰色虛線,「太簡單啦」
|
||||||
|
- 適中詞彙卡片: 綠色邊框,「重點學習」
|
||||||
|
- 困難詞彙卡片: 橙色邊框,「有點挑戰」
|
||||||
|
- 慣用語卡片: 藍色邊框,「慣用語」
|
||||||
|
|
||||||
|
計算邏輯:
|
||||||
|
- 前端即時計算統計數據
|
||||||
|
- 基於當前用戶等級動態分類
|
||||||
|
- 統計數字與實際標記保持一致
|
||||||
|
- 用戶等級變更時即時更新
|
||||||
|
```
|
||||||
|
|
||||||
|
### **FR3. 互動學習體驗**
|
||||||
|
|
||||||
|
#### **FR3.1 詞彙深度探索**
|
||||||
|
**優先級**: P0 (必須)
|
||||||
|
|
||||||
|
**需求描述**:
|
||||||
|
- 提供豐富的詞彙學習資訊
|
||||||
|
- 支援多感官學習體驗
|
||||||
|
- 整合個人詞彙管理
|
||||||
|
|
||||||
|
**詳細規格**:
|
||||||
|
```yaml
|
||||||
|
詞彙詳情內容:
|
||||||
|
- 基礎資訊: 詞彙、翻譯、定義、詞性
|
||||||
|
- 語音資訊: IPA發音標記、音頻播放 (未來)
|
||||||
|
- 學習輔助: 同義詞、例句、例句翻譯
|
||||||
|
- 個人化: CEFR等級、使用頻率、學習狀態
|
||||||
|
|
||||||
|
互動功能:
|
||||||
|
- 點擊詞彙開啟詳情彈窗
|
||||||
|
- 一鍵保存到個人詞卡庫
|
||||||
|
- 發音練習 (未來功能)
|
||||||
|
- 相關詞彙推薦 (未來功能)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **FR3.2 慣用語文化學習**
|
||||||
|
**優先級**: P0 (必須)
|
||||||
|
|
||||||
|
**需求描述**:
|
||||||
|
- 深度學習英語慣用語和文化表達
|
||||||
|
- 提供使用場景和文化背景
|
||||||
|
- 支援實際應用練習
|
||||||
|
|
||||||
|
**詳細規格**:
|
||||||
|
```yaml
|
||||||
|
慣用語資訊:
|
||||||
|
- 基礎定義: 慣用語、中英文解釋、發音
|
||||||
|
- 文化背景: 起源、使用場景、語域標記
|
||||||
|
- 學習輔助: 同義表達、實用例句
|
||||||
|
- 難度標記: CEFR等級、使用頻率
|
||||||
|
|
||||||
|
展示方式:
|
||||||
|
- 獨立區域展示,不與一般詞彙混淆
|
||||||
|
- 統一的視覺設計和互動體驗
|
||||||
|
- 支援多個慣用語並排顯示
|
||||||
|
- 與詞彙詳情一致的彈窗設計
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 **非功能性需求 (Non-Functional Requirements)**
|
||||||
|
|
||||||
|
### **NFR1. 性能需求**
|
||||||
|
|
||||||
|
#### **NFR1.1 響應時間要求**
|
||||||
|
```yaml
|
||||||
|
核心功能:
|
||||||
|
- 文本輸入響應: < 100ms
|
||||||
|
- AI分析處理: < 5秒
|
||||||
|
- 詞彙標記渲染: < 200ms
|
||||||
|
- 詞彙詳情彈窗: < 100ms
|
||||||
|
- 統計卡片更新: < 50ms
|
||||||
|
|
||||||
|
系統負載:
|
||||||
|
- 同時在線用戶: > 100
|
||||||
|
- 每日分析請求: > 10,000
|
||||||
|
- 峰值處理能力: > 200 req/min
|
||||||
|
- 系統可用性: > 99.5%
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **NFR1.2 可擴展性要求**
|
||||||
|
```yaml
|
||||||
|
用戶擴展:
|
||||||
|
- 支援用戶數: 10,000+ (第一年)
|
||||||
|
- 數據存儲: 100GB+ (分析記錄)
|
||||||
|
- 並發處理: 500+ 同時請求
|
||||||
|
|
||||||
|
功能擴展:
|
||||||
|
- 多語言支援: 法語、德語 (未來)
|
||||||
|
- 多模態分析: 語音、圖片 (未來)
|
||||||
|
- 實時協作: 團隊學習 (未來)
|
||||||
|
```
|
||||||
|
|
||||||
|
### **NFR2. 用戶體驗需求**
|
||||||
|
|
||||||
|
#### **NFR2.1 易用性標準**
|
||||||
|
```yaml
|
||||||
|
學習曲線:
|
||||||
|
- 新用戶上手時間: < 5分鐘
|
||||||
|
- 完整分析流程: < 2分鐘
|
||||||
|
- 功能發現時間: < 30秒
|
||||||
|
|
||||||
|
操作效率:
|
||||||
|
- 點擊響應時間: < 100ms
|
||||||
|
- 頁面載入時間: < 2秒
|
||||||
|
- 功能切換時間: < 500ms
|
||||||
|
- 錯誤恢復時間: < 3秒
|
||||||
|
|
||||||
|
滿意度指標:
|
||||||
|
- 用戶體驗評分: > 4.5/5
|
||||||
|
- 功能完成率: > 95%
|
||||||
|
- 錯誤率: < 5%
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **NFR2.2 無障礙需求**
|
||||||
|
```yaml
|
||||||
|
WCAG 2.1 AA 合規:
|
||||||
|
- 顏色對比度: > 4.5:1
|
||||||
|
- 鍵盤導航: 完整支援
|
||||||
|
- 螢幕閱讀器: 適當的ARIA標籤
|
||||||
|
- 字體縮放: 支援200%放大
|
||||||
|
|
||||||
|
多設備支援:
|
||||||
|
- 桌面瀏覽器: Chrome 90+, Safari 14+, Firefox 88+
|
||||||
|
- 移動設備: iOS 14+, Android 10+
|
||||||
|
- 響應式設計: 320px - 2560px
|
||||||
|
```
|
||||||
|
|
||||||
|
### **NFR3. 安全與隱私需求**
|
||||||
|
|
||||||
|
#### **NFR3.1 數據安全**
|
||||||
|
```yaml
|
||||||
|
輸入安全:
|
||||||
|
- XSS防護: 輸入內容過濾和轉義
|
||||||
|
- 內容驗證: 惡意內容檢測
|
||||||
|
- 長度限制: 嚴格執行字符限制
|
||||||
|
|
||||||
|
數據隱私:
|
||||||
|
- 個人數據: 符合GDPR要求
|
||||||
|
- 學習記錄: 用戶控制和導出
|
||||||
|
- 數據保留: 明確的保留政策
|
||||||
|
- 匿名化: 分析統計數據去識別
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **NFR3.2 API安全**
|
||||||
|
```yaml
|
||||||
|
認證授權:
|
||||||
|
- JWT Token認證
|
||||||
|
- 角色權限控制
|
||||||
|
- 速率限制保護
|
||||||
|
|
||||||
|
數據傳輸:
|
||||||
|
- HTTPS強制加密
|
||||||
|
- API金鑰安全管理
|
||||||
|
- 請求簽名驗證
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 **用戶介面需求**
|
||||||
|
|
||||||
|
### **UI1. 視覺設計標準**
|
||||||
|
|
||||||
|
#### **UI1.1 詞彙標記設計**
|
||||||
|
```yaml
|
||||||
|
視覺層次:
|
||||||
|
- 簡單詞彙: bg-gray-50, border-dashed, border-gray-300, text-gray-600, opacity-80
|
||||||
|
- 適中詞彙: bg-green-50, border-green-200, text-green-700, font-medium
|
||||||
|
- 困難詞彙: bg-orange-50, border-orange-200, text-orange-700, font-medium
|
||||||
|
- 慣用語: bg-blue-50, border-blue-200, text-blue-700
|
||||||
|
|
||||||
|
互動效果:
|
||||||
|
- hover: 陰影提升,輕微上移
|
||||||
|
- focus: 鍵盤導航支援
|
||||||
|
- active: 點擊回饋動畫
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **UI1.2 統計卡片設計**
|
||||||
|
```yaml
|
||||||
|
卡片規格:
|
||||||
|
- 響應式佈局: 桌面1行4張,移動設備2行2張
|
||||||
|
- 數字突出: 大字體顯示統計數量
|
||||||
|
- 顏色一致: 與對應詞彙標記顏色匹配
|
||||||
|
- 即時更新: 分析完成後動畫顯示
|
||||||
|
```
|
||||||
|
|
||||||
|
### **UI2. 互動體驗設計**
|
||||||
|
|
||||||
|
#### **UI2.1 彈窗系統設計**
|
||||||
|
```yaml
|
||||||
|
詞彙詳情彈窗:
|
||||||
|
- 標題區: 漸層藍色背景,詞彙名稱,CEFR標籤
|
||||||
|
- 內容區: 翻譯(綠)、定義(灰)、例句(藍)、同義詞(紫)
|
||||||
|
- 操作區: 保存按鈕,關閉按鈕
|
||||||
|
- 定位: 智能計算,避免螢幕邊界
|
||||||
|
|
||||||
|
語法修正面板:
|
||||||
|
- 警告樣式: 黃色背景,警告圖標
|
||||||
|
- 對比顯示: 原句 vs 修正句
|
||||||
|
- 操作按鈕: 採用修正(綠色),保持原樣(灰色)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 **驗收標準與測試需求**
|
||||||
|
|
||||||
|
### **AC1. 功能驗收標準**
|
||||||
|
|
||||||
|
#### **AC1.1 核心功能檢查表**
|
||||||
|
- [ ] 文本輸入和字符限制正常運作
|
||||||
|
- [ ] AI分析在5秒內完成並返回結果
|
||||||
|
- [ ] 語法修正準確檢測並提供合理建議
|
||||||
|
- [ ] 詞彙CEFR分級準確率達到90%以上
|
||||||
|
- [ ] 慣用語識別覆蓋率達到80%以上
|
||||||
|
- [ ] 個人化詞彙標記根據用戶等級正確分類
|
||||||
|
- [ ] 統計卡片數字與實際詞彙標記一致
|
||||||
|
- [ ] 詞彙和慣用語詳情彈窗正常運作
|
||||||
|
- [ ] 保存到詞卡功能完整可用
|
||||||
|
|
||||||
|
#### **AC1.2 用戶體驗檢查表**
|
||||||
|
- [ ] 新用戶能在5分鐘內完成首次完整分析
|
||||||
|
- [ ] 所有互動響應時間符合性能要求
|
||||||
|
- [ ] 響應式設計在所有目標設備正常顯示
|
||||||
|
- [ ] 錯誤處理友善且提供有用指導
|
||||||
|
- [ ] 視覺設計一致且符合品牌標準
|
||||||
|
|
||||||
|
### **AC2. 技術驗收標準**
|
||||||
|
|
||||||
|
#### **AC2.1 API品質檢查**
|
||||||
|
- [ ] API回應格式穩定一致
|
||||||
|
- [ ] 錯誤處理涵蓋所有邊界情況
|
||||||
|
- [ ] 性能指標達到要求基準
|
||||||
|
- [ ] 安全檢查通過滲透測試
|
||||||
|
|
||||||
|
#### **AC2.2 資料品質檢查**
|
||||||
|
- [ ] AI分析結果準確性達標
|
||||||
|
- [ ] 繁體中文翻譯自然流暢
|
||||||
|
- [ ] CEFR等級分配符合標準
|
||||||
|
- [ ] 慣用語解釋準確且完整
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 **產品路線圖**
|
||||||
|
|
||||||
|
### **Phase 1: 核心功能 (已完成)**
|
||||||
|
- ✅ 基礎AI句子分析
|
||||||
|
- ✅ 詞彙標記和分類
|
||||||
|
- ✅ 語法修正功能
|
||||||
|
- ✅ 慣用語識別
|
||||||
|
|
||||||
|
### **Phase 2: 體驗優化 (當前階段)**
|
||||||
|
- 🔄 性能優化和穩定性提升
|
||||||
|
- 🔄 用戶介面細節優化
|
||||||
|
- ⏳ 錯誤處理完善
|
||||||
|
- ⏳ 無障礙功能實施
|
||||||
|
|
||||||
|
### **Phase 3: 功能擴展 (規劃中)**
|
||||||
|
- 📅 批次分析功能
|
||||||
|
- 📅 學習歷史記錄
|
||||||
|
- 📅 個人詞彙庫進階管理
|
||||||
|
- 📅 語音集成 (TTS/STT)
|
||||||
|
|
||||||
|
### **Phase 4: 平台擴展 (未來)**
|
||||||
|
- 🔮 多語言學習支援
|
||||||
|
- 🔮 移動應用開發
|
||||||
|
- 🔮 團隊協作功能
|
||||||
|
- 🔮 AI模型自定義
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **成功指標 (KPIs)**
|
||||||
|
|
||||||
|
### **產品指標**
|
||||||
|
```yaml
|
||||||
|
用戶參與度:
|
||||||
|
- 日活躍用戶數 (DAU): > 1,000
|
||||||
|
- 平均每用戶分析次數: > 5次/日
|
||||||
|
- 用戶留存率 (7天): > 70%
|
||||||
|
- 功能使用率: > 80%
|
||||||
|
|
||||||
|
學習效果:
|
||||||
|
- 用戶滿意度評分: > 4.5/5
|
||||||
|
- 學習目標完成率: > 85%
|
||||||
|
- 詞彙掌握改善度: > 30%
|
||||||
|
- 重複使用率: > 60%
|
||||||
|
```
|
||||||
|
|
||||||
|
### **技術指標**
|
||||||
|
```yaml
|
||||||
|
性能指標:
|
||||||
|
- API回應時間P95: < 5秒
|
||||||
|
- 頁面載入時間P95: < 2秒
|
||||||
|
- 系統可用性: > 99.5%
|
||||||
|
- 錯誤率: < 1%
|
||||||
|
|
||||||
|
品質指標:
|
||||||
|
- AI分析準確率: > 90%
|
||||||
|
- 代碼覆蓋率: > 80%
|
||||||
|
- 安全掃描通過率: 100%
|
||||||
|
- 用戶回報問題解決率: > 95%
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **變更管理**
|
||||||
|
|
||||||
|
### **需求變更流程**
|
||||||
|
1. **提出變更**: 產品經理、開發團隊、用戶回饋
|
||||||
|
2. **影響評估**: 技術可行性、工期影響、資源需求
|
||||||
|
3. **優先級評定**: 商業價值、緊急程度、實施成本
|
||||||
|
4. **審核批准**: 產品委員會審核決定
|
||||||
|
5. **實施追蹤**: 開發進度、測試驗證、上線監控
|
||||||
|
|
||||||
|
### **文件版本管理**
|
||||||
|
- **v1.0**: 初始需求規格 (2025-09-21)
|
||||||
|
- **v2.0**: 整合統一產品需求規格 (2025-01-25)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文件版本**: v2.0
|
||||||
|
**產品負責人**: DramaLing產品團隊
|
||||||
|
**最後更新**: 2025-01-25
|
||||||
|
**下次審查**: 2025-02-25
|
||||||
|
|
||||||
|
**關聯文件**:
|
||||||
|
- 《AI分析API技術實現規格》- 技術實現細節
|
||||||
|
- 《系統整合與部署規格》- 系統整合和部署
|
||||||
|
- 《AI驅動產品後端技術架構指南》- 架構設計指導
|
||||||
|
|
@ -0,0 +1,711 @@
|
||||||
|
# DramaLing AI句子分析功能前後端串接實施計劃
|
||||||
|
|
||||||
|
## 📋 **文件資訊**
|
||||||
|
|
||||||
|
- **文件名稱**: DramaLing AI句子分析功能前後端串接實施計劃
|
||||||
|
- **版本**: v1.0
|
||||||
|
- **建立日期**: 2025-01-25
|
||||||
|
- **最後更新**: 2025-01-25
|
||||||
|
- **負責團隊**: DramaLing技術團隊
|
||||||
|
- **專案階段**: 後端完成,準備前後端整合
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 **計劃概述**
|
||||||
|
|
||||||
|
### **目標**
|
||||||
|
完成DramaLing AI句子分析功能的前後端串接,實現完整的智能英語學習體驗。
|
||||||
|
|
||||||
|
### **現狀分析**
|
||||||
|
- ✅ **後端API**: 已完成開發並運行在 localhost:5008
|
||||||
|
- ✅ **前端架構**: Next.js 15 + TypeScript + Tailwind CSS
|
||||||
|
- ✅ **AI整合**: Google Gemini 1.5 Flash API 已整合
|
||||||
|
- ⏳ **串接狀態**: 需要調整前端API調用邏輯以對接新後端
|
||||||
|
|
||||||
|
### **串接範圍**
|
||||||
|
1. AI句子分析核心功能
|
||||||
|
2. 詞彙分析與CEFR分級
|
||||||
|
3. 語法修正功能
|
||||||
|
4. 慣用語檢測
|
||||||
|
5. 個人化學習統計
|
||||||
|
6. 錯誤處理與用戶體驗
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **當前架構對比分析**
|
||||||
|
|
||||||
|
### **後端API架構 (.NET 8)**
|
||||||
|
```yaml
|
||||||
|
核心端點:
|
||||||
|
- POST /api/ai/analyze-sentence # 主要分析API (backend/DramaLing.Api/Controllers/AIController.cs)
|
||||||
|
- GET /api/ai/health # 健康檢查 (backend/DramaLing.Api/Controllers/AIController.cs)
|
||||||
|
- POST /api/flashcards # 詞卡管理 (backend/DramaLing.Api/Controllers/FlashcardsController.cs)
|
||||||
|
- POST /api/auth/login # 用戶認證 (backend/DramaLing.Api/Controllers/AuthController.cs)
|
||||||
|
|
||||||
|
技術棧:
|
||||||
|
- .NET 8 Web API
|
||||||
|
- Entity Framework Core
|
||||||
|
- SQLite (開發) / PostgreSQL (生產)
|
||||||
|
- Google Gemini 1.5 Flash AI
|
||||||
|
- JWT認證機制
|
||||||
|
```
|
||||||
|
|
||||||
|
### **前端架構 (Next.js 15)**
|
||||||
|
```yaml
|
||||||
|
核心功能:
|
||||||
|
- 句子輸入與分析 (/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/generate/page.tsx)
|
||||||
|
- 詞彙標記與統計 (/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/components/ClickableTextV2.tsx)
|
||||||
|
- 語法修正面板 (/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/components/GrammarCorrectionPanel.tsx)
|
||||||
|
- 詞彙詳情彈窗 (VocabPopup - 位於ClickableTextV2.tsx內)
|
||||||
|
- 學習模式整合 (/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/learn/page.tsx)
|
||||||
|
|
||||||
|
技術棧:
|
||||||
|
- Next.js 15.5.3 + React 19
|
||||||
|
- TypeScript + Tailwind CSS
|
||||||
|
- localStorage (用戶設定)
|
||||||
|
- Fetch API (HTTP請求)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **API整合對比**
|
||||||
|
|
||||||
|
### **現有前端API調用**
|
||||||
|
```typescript
|
||||||
|
// 檔案位置: /Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/generate/page.tsx
|
||||||
|
// 函數: handleAnalyzeSentence (約在第185-220行)
|
||||||
|
const response = await fetch('http://localhost:5008/api/ai/analyze-sentence', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
inputText: textInput,
|
||||||
|
userLevel: userLevel, // ⚠️ 後端不需要此欄位
|
||||||
|
analysisMode: 'full',
|
||||||
|
options: {
|
||||||
|
includeGrammarCheck: true,
|
||||||
|
includeVocabularyAnalysis: true,
|
||||||
|
includeTranslation: true,
|
||||||
|
includeIdiomDetection: true,
|
||||||
|
includeExamples: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### **後端API規格**
|
||||||
|
```json
|
||||||
|
// 檔案參考: backend/DramaLing.Api/Controllers/AIController.cs
|
||||||
|
// 端點: POST /api/ai/analyze-sentence
|
||||||
|
// 請求格式
|
||||||
|
{
|
||||||
|
"inputText": "英文句子",
|
||||||
|
"analysisMode": "full",
|
||||||
|
"options": {
|
||||||
|
"includeGrammarCheck": true,
|
||||||
|
"includeVocabularyAnalysis": true,
|
||||||
|
"includeTranslation": true,
|
||||||
|
"includeIdiomDetection": true,
|
||||||
|
"includeExamples": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回應格式
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"processingTime": 2.34,
|
||||||
|
"data": {
|
||||||
|
"analysisId": "uuid-string",
|
||||||
|
"originalText": "原始句子",
|
||||||
|
"sentenceMeaning": "中文翻譯",
|
||||||
|
"grammarCorrection": {
|
||||||
|
"hasErrors": true,
|
||||||
|
"correctedText": "修正後文本",
|
||||||
|
"corrections": [...]
|
||||||
|
},
|
||||||
|
"vocabularyAnalysis": {
|
||||||
|
"word1": {
|
||||||
|
"word": "詞彙",
|
||||||
|
"translation": "翻譯",
|
||||||
|
"definition": "定義",
|
||||||
|
"partOfSpeech": "詞性",
|
||||||
|
"pronunciation": "發音",
|
||||||
|
"difficultyLevel": "A1-C2",
|
||||||
|
"frequency": "high/medium/low",
|
||||||
|
"synonyms": ["同義詞"],
|
||||||
|
"example": "例句",
|
||||||
|
"exampleTranslation": "例句翻譯"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idioms": [...],
|
||||||
|
"metadata": {...}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ **實施計劃**
|
||||||
|
|
||||||
|
### **階段一:API適配與調整 (1-2天)**
|
||||||
|
|
||||||
|
#### **1.1 前端API調用更新**
|
||||||
|
**目標**: 移除後端不需要的userLevel參數,確保請求格式正確
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/generate/page.tsx`
|
||||||
|
**函數**: `handleAnalyzeSentence` (約在第185-220行)
|
||||||
|
```typescript
|
||||||
|
// 修改前
|
||||||
|
body: JSON.stringify({
|
||||||
|
inputText: textInput,
|
||||||
|
userLevel: userLevel, // 移除此行
|
||||||
|
analysisMode: 'full',
|
||||||
|
options: { ... }
|
||||||
|
})
|
||||||
|
|
||||||
|
// 修改後
|
||||||
|
body: JSON.stringify({
|
||||||
|
inputText: textInput,
|
||||||
|
analysisMode: 'full',
|
||||||
|
options: {
|
||||||
|
includeGrammarCheck: true,
|
||||||
|
includeVocabularyAnalysis: true,
|
||||||
|
includeTranslation: true,
|
||||||
|
includeIdiomDetection: true,
|
||||||
|
includeExamples: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **1.2 回應數據結構適配**
|
||||||
|
**目標**: 更新前端以處理新的API回應格式
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/generate/page.tsx`
|
||||||
|
**函數**: `handleAnalysisResult` (需新增)
|
||||||
|
```typescript
|
||||||
|
// 修改回應處理邏輯
|
||||||
|
const handleAnalysisResult = (result) => {
|
||||||
|
// 後端回應結構: result.data.vocabularyAnalysis
|
||||||
|
// 前端期望結構: result.vocabularyAnalysis
|
||||||
|
|
||||||
|
const analysisData = {
|
||||||
|
originalText: result.data.originalText,
|
||||||
|
sentenceMeaning: result.data.sentenceMeaning,
|
||||||
|
grammarCorrection: result.data.grammarCorrection,
|
||||||
|
vocabularyAnalysis: result.data.vocabularyAnalysis,
|
||||||
|
idioms: result.data.idioms,
|
||||||
|
processingTime: result.processingTime
|
||||||
|
};
|
||||||
|
|
||||||
|
setSentenceAnalysis(analysisData);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### **階段二:詞彙分析整合 (2-3天)**
|
||||||
|
|
||||||
|
#### **2.1 詞彙數據格式統一**
|
||||||
|
**目標**: 確保前端詞彙分析邏輯與後端回應格式匹配
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/components/ClickableTextV2.tsx`
|
||||||
|
**函數**: `findWordAnalysis`, `getWordProperty` (約在第50-80行)
|
||||||
|
```typescript
|
||||||
|
// 更新詞彙分析資料存取邏輯
|
||||||
|
const findWordAnalysis = useCallback((word: string) => {
|
||||||
|
if (!sentenceAnalysis?.vocabularyAnalysis) return null;
|
||||||
|
|
||||||
|
// 後端格式: vocabularyAnalysis[word]
|
||||||
|
return sentenceAnalysis.vocabularyAnalysis[word] || null;
|
||||||
|
}, [sentenceAnalysis]);
|
||||||
|
|
||||||
|
// 更新CEFR難度取得邏輯
|
||||||
|
const getWordProperty = useCallback((word: string, property: string) => {
|
||||||
|
const analysis = findWordAnalysis(word);
|
||||||
|
return analysis?.[property] || '';
|
||||||
|
}, [findWordAnalysis]);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **2.2 統計計算邏輯優化**
|
||||||
|
**目標**: 基於新的API回應格式重新計算詞彙統計
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/generate/page.tsx`
|
||||||
|
**函數**: `vocabularyStats` useMemo hook (約在第250-280行)
|
||||||
|
```typescript
|
||||||
|
const vocabularyStats = useMemo(() => {
|
||||||
|
if (!sentenceAnalysis?.vocabularyAnalysis) {
|
||||||
|
return { simpleCount: 0, moderateCount: 0, difficultCount: 0, idiomCount: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const userIndex = CEFR_LEVELS.indexOf(userLevel);
|
||||||
|
let simple = 0, moderate = 0, difficult = 0;
|
||||||
|
|
||||||
|
// 遍歷vocabularyAnalysis物件
|
||||||
|
Object.values(sentenceAnalysis.vocabularyAnalysis).forEach(word => {
|
||||||
|
const wordIndex = CEFR_LEVELS.indexOf(word.difficultyLevel);
|
||||||
|
if (userIndex > wordIndex) simple++;
|
||||||
|
else if (userIndex === wordIndex) moderate++;
|
||||||
|
else difficult++;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
simpleCount: simple,
|
||||||
|
moderateCount: moderate,
|
||||||
|
difficultCount: difficult,
|
||||||
|
idiomCount: sentenceAnalysis.idioms?.length || 0
|
||||||
|
};
|
||||||
|
}, [sentenceAnalysis, userLevel]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### **階段三:語法修正整合 (1-2天)**
|
||||||
|
|
||||||
|
#### **3.1 語法修正數據適配**
|
||||||
|
**目標**: 更新語法修正面板以處理新的錯誤格式
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/components/GrammarCorrectionPanel.tsx`
|
||||||
|
**介面定義**: `GrammarError` interface (需新增)
|
||||||
|
**函數**: `renderCorrections` (需修改)
|
||||||
|
```typescript
|
||||||
|
// 更新錯誤數據結構處理
|
||||||
|
interface GrammarError {
|
||||||
|
position: { start: number; end: number };
|
||||||
|
error: string;
|
||||||
|
correction: string;
|
||||||
|
type: string;
|
||||||
|
explanation: string;
|
||||||
|
severity: 'high' | 'medium' | 'low';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新組件以使用新的錯誤格式
|
||||||
|
const renderCorrections = () => {
|
||||||
|
return grammarCorrection.corrections.map((correction, index) => (
|
||||||
|
<div key={index} className="correction-item">
|
||||||
|
<span className="error-text">{correction.error}</span>
|
||||||
|
<span className="arrow">→</span>
|
||||||
|
<span className="corrected-text">{correction.correction}</span>
|
||||||
|
<div className="explanation">{correction.explanation}</div>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### **階段四:慣用語功能整合 (1-2天)**
|
||||||
|
|
||||||
|
#### **4.1 慣用語顯示邏輯**
|
||||||
|
**目標**: 整合後端慣用語檢測結果
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/generate/page.tsx`
|
||||||
|
**函數**: `renderIdioms`, `handleIdiomClick` (需新增)
|
||||||
|
```typescript
|
||||||
|
// 慣用語渲染邏輯
|
||||||
|
const renderIdioms = () => {
|
||||||
|
if (!sentenceAnalysis?.idioms || sentenceAnalysis.idioms.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="idioms-section">
|
||||||
|
<h3>慣用語解析</h3>
|
||||||
|
{sentenceAnalysis.idioms.map((idiom, index) => (
|
||||||
|
<div key={index} className="idiom-chip" onClick={() => handleIdiomClick(idiom)}>
|
||||||
|
{idiom.idiom}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 慣用語點擊處理
|
||||||
|
const handleIdiomClick = (idiom) => {
|
||||||
|
setSelectedVocab({
|
||||||
|
word: idiom.idiom,
|
||||||
|
translation: idiom.translation,
|
||||||
|
definition: idiom.definition,
|
||||||
|
pronunciation: idiom.pronunciation,
|
||||||
|
partOfSpeech: 'idiom',
|
||||||
|
difficultyLevel: idiom.difficultyLevel,
|
||||||
|
frequency: idiom.frequency,
|
||||||
|
synonyms: idiom.synonyms,
|
||||||
|
example: idiom.example,
|
||||||
|
exampleTranslation: idiom.exampleTranslation
|
||||||
|
});
|
||||||
|
setIsPopupVisible(true);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### **階段五:錯誤處理與用戶體驗 (1-2天)**
|
||||||
|
|
||||||
|
#### **5.1 統一錯誤處理**
|
||||||
|
**目標**: 實現友善的錯誤提示和降級體驗
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/generate/page.tsx`
|
||||||
|
**函數**: `handleAnalysisError`, `setFallbackAnalysisView` (需新增或修改)
|
||||||
|
```typescript
|
||||||
|
const handleAnalysisError = (error) => {
|
||||||
|
console.error('Analysis error:', error);
|
||||||
|
setIsAnalyzing(false);
|
||||||
|
|
||||||
|
// 根據錯誤類型提供不同的用戶提示
|
||||||
|
if (error.message.includes('timeout')) {
|
||||||
|
setErrorMessage('分析服務繁忙,請稍後再試');
|
||||||
|
} else if (error.message.includes('network')) {
|
||||||
|
setErrorMessage('網路連接問題,請檢查網路狀態');
|
||||||
|
} else if (error.message.includes('500')) {
|
||||||
|
setErrorMessage('服務器暫時不可用,請稍後重試');
|
||||||
|
} else {
|
||||||
|
setErrorMessage('分析過程中發生錯誤,請稍後再試');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提供降級體驗:基礎翻譯
|
||||||
|
setFallbackAnalysisView(textInput);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 降級體驗實現
|
||||||
|
const setFallbackAnalysisView = (text) => {
|
||||||
|
setSentenceAnalysis({
|
||||||
|
originalText: text,
|
||||||
|
sentenceMeaning: '暫時無法提供完整分析,請稍後重試',
|
||||||
|
grammarCorrection: { hasErrors: false, corrections: [] },
|
||||||
|
vocabularyAnalysis: {},
|
||||||
|
idioms: []
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **5.2 載入狀態優化**
|
||||||
|
**目標**: 提供清晰的載入反饋
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/generate/page.tsx`
|
||||||
|
**狀態管理**: 新增 `analysisState` state
|
||||||
|
**函數**: 修改 `handleAnalyzeSentence`
|
||||||
|
```typescript
|
||||||
|
// 分析狀態管理
|
||||||
|
const [analysisState, setAnalysisState] = useState({
|
||||||
|
isAnalyzing: false,
|
||||||
|
progress: 0,
|
||||||
|
stage: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleAnalyzeSentence = async () => {
|
||||||
|
setAnalysisState({ isAnalyzing: true, progress: 20, stage: '正在分析句子...' });
|
||||||
|
|
||||||
|
try {
|
||||||
|
setAnalysisState(prev => ({ ...prev, progress: 60, stage: '處理詞彙分析...' }));
|
||||||
|
const response = await fetch(API_URL, { ... });
|
||||||
|
|
||||||
|
setAnalysisState(prev => ({ ...prev, progress: 90, stage: '整理分析結果...' }));
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
handleAnalysisResult(result);
|
||||||
|
setAnalysisState({ isAnalyzing: false, progress: 100, stage: '分析完成' });
|
||||||
|
} catch (error) {
|
||||||
|
handleAnalysisError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### **階段六:閃卡整合 (2-3天)**
|
||||||
|
|
||||||
|
#### **6.1 閃卡保存API整合**
|
||||||
|
**目標**: 整合後端閃卡API用於詞彙保存
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/services/flashcardsService.ts` (需新建)
|
||||||
|
**類別**: `FlashcardsService`
|
||||||
|
**方法**: `createFlashcard`, `getAuthToken`
|
||||||
|
```typescript
|
||||||
|
class FlashcardsService {
|
||||||
|
private baseURL = 'http://localhost:5008/api/flashcards';
|
||||||
|
|
||||||
|
async createFlashcard(cardData: FlashcardData): Promise<{success: boolean}> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(this.baseURL, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${this.getAuthToken()}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
word: cardData.word,
|
||||||
|
translation: cardData.translation,
|
||||||
|
definition: cardData.definition,
|
||||||
|
pronunciation: cardData.pronunciation,
|
||||||
|
partOfSpeech: cardData.partOfSpeech,
|
||||||
|
difficultyLevel: cardData.difficultyLevel,
|
||||||
|
example: cardData.example,
|
||||||
|
exampleTranslation: cardData.exampleTranslation
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`API request failed: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Save flashcard error:', error);
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAuthToken(): string | null {
|
||||||
|
return localStorage.getItem('auth_token');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const flashcardsService = new FlashcardsService();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **6.2 認證機制整合**
|
||||||
|
**目標**: 實現JWT認證用於保護閃卡API
|
||||||
|
|
||||||
|
**檔案**: `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/services/authService.ts` (需新建)
|
||||||
|
**類別**: `AuthService`
|
||||||
|
**方法**: `login`, `logout`, `isAuthenticated`
|
||||||
|
```typescript
|
||||||
|
class AuthService {
|
||||||
|
private baseURL = 'http://localhost:5008/api/auth';
|
||||||
|
|
||||||
|
async login(username: string, password: string): Promise<{success: boolean, token?: string}> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${this.baseURL}/login`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ username, password })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('登入失敗');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success && result.token) {
|
||||||
|
localStorage.setItem('auth_token', result.token);
|
||||||
|
return { success: true, token: result.token };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: false };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Login error:', error);
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logout(): void {
|
||||||
|
localStorage.removeItem('auth_token');
|
||||||
|
}
|
||||||
|
|
||||||
|
isAuthenticated(): boolean {
|
||||||
|
return !!localStorage.getItem('auth_token');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const authService = new AuthService();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ **測試計劃**
|
||||||
|
|
||||||
|
### **單元測試**
|
||||||
|
1. API調用函數測試
|
||||||
|
2. 數據轉換邏輯測試
|
||||||
|
3. 錯誤處理機制測試
|
||||||
|
4. 統計計算邏輯測試
|
||||||
|
|
||||||
|
### **整合測試**
|
||||||
|
1. 完整分析流程測試
|
||||||
|
2. 詞彙保存流程測試
|
||||||
|
3. 認證機制測試
|
||||||
|
4. 錯誤恢復機制測試
|
||||||
|
|
||||||
|
### **E2E測試**
|
||||||
|
1. 用戶完整使用流程
|
||||||
|
2. 各種輸入情況測試
|
||||||
|
3. 錯誤邊界情況測試
|
||||||
|
4. 性能和載入測試
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 **實施檢查清單**
|
||||||
|
|
||||||
|
### **前端調整**
|
||||||
|
- [x] 移除API請求中的userLevel參數 ✅ **已完成**
|
||||||
|
- [x] 更新回應數據結構處理邏輯 ✅ **已完成**
|
||||||
|
- [x] 適配新的vocabularyAnalysis格式 ✅ **已完成**
|
||||||
|
- [ ] 更新語法修正面板數據處理 ⏳ **進行中**
|
||||||
|
- [x] 整合慣用語顯示邏輯 ✅ **已完成**ㄎ
|
||||||
|
- [ ] 實現統一錯誤處理機制 ⏳ **進行中**
|
||||||
|
- [ ] 優化載入狀態提示 ⏳ **進行中**
|
||||||
|
- [ ] 整合閃卡保存API ⏳ **進行中**
|
||||||
|
- [ ] 實現JWT認證機制 📅 **計劃中**
|
||||||
|
|
||||||
|
### **後端驗證**
|
||||||
|
- [x] 確認API端點正常運行 ✅ **已完成** - API健康檢查通過
|
||||||
|
- [x] 驗證回應格式正確性 ✅ **已完成** - 格式完全符合規格
|
||||||
|
- [x] 測試錯誤處理機制 ✅ **已完成** - 錯誤處理正常
|
||||||
|
- [ ] 確認認證機制有效 📅 **待實施** - JWT功能需要用戶系統
|
||||||
|
- [x] 驗證CORS設定正確 ✅ **已完成** - 前端可正常訪問
|
||||||
|
|
||||||
|
### **整合測試**
|
||||||
|
- [x] 前後端通信正常 ✅ **已完成** - API調用成功
|
||||||
|
- [x] 數據格式完全匹配 ✅ **已完成** - vocabularyAnalysis格式正確
|
||||||
|
- [x] 錯誤處理機制有效 ✅ **已完成** - 錯誤回饋正常
|
||||||
|
- [x] 性能表現符合預期 ✅ **已完成** - 3.5秒分析時間符合<5秒要求
|
||||||
|
- [x] 用戶體驗流暢 ✅ **已完成** - 前端頁面正常載入
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 **部署準備**
|
||||||
|
|
||||||
|
### **開發環境**
|
||||||
|
1. 確保後端運行在 localhost:5008
|
||||||
|
2. 確保前端運行在 localhost:3000
|
||||||
|
3. 配置CORS允許前端域名
|
||||||
|
4. 設定開發環境的Gemini API密鑰
|
||||||
|
|
||||||
|
### **測試環境**
|
||||||
|
1. 部署到測試服務器
|
||||||
|
2. 配置測試環境的環境變數
|
||||||
|
3. 執行完整的E2E測試
|
||||||
|
4. 進行性能和安全測試
|
||||||
|
|
||||||
|
### **生產環境**
|
||||||
|
1. 配置生產環境域名和SSL
|
||||||
|
2. 設定生產環境API密鑰
|
||||||
|
3. 配置監控和日誌系統
|
||||||
|
4. 準備回滾計劃
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **風險評估與緩解**
|
||||||
|
|
||||||
|
### **技術風險**
|
||||||
|
1. **API格式不匹配**
|
||||||
|
- 風險: 前後端數據格式差異
|
||||||
|
- 緩解: 詳細的格式驗證和測試
|
||||||
|
|
||||||
|
2. **性能問題**
|
||||||
|
- 風險: AI API響應時間過長
|
||||||
|
- 緩解: 實現載入狀態和超時處理
|
||||||
|
|
||||||
|
3. **錯誤處理不完善**
|
||||||
|
- 風險: 用戶體驗受影響
|
||||||
|
- 緩解: 完整的錯誤處理和降級機制
|
||||||
|
|
||||||
|
### **業務風險**
|
||||||
|
1. **功能缺失**
|
||||||
|
- 風險: 某些功能無法正常工作
|
||||||
|
- 緩解: 逐步測試和驗證
|
||||||
|
|
||||||
|
2. **用戶體驗下降**
|
||||||
|
- 風險: 串接過程中影響現有功能
|
||||||
|
- 緩解: 保持現有功能的向後兼容性
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 **成功指標**
|
||||||
|
|
||||||
|
### **技術指標**
|
||||||
|
- API回應時間 < 5秒
|
||||||
|
- 錯誤率 < 1%
|
||||||
|
- 前端載入時間 < 2秒
|
||||||
|
- 詞彙分析準確率 > 90%
|
||||||
|
|
||||||
|
### **用戶體驗指標**
|
||||||
|
- 分析完成率 > 95%
|
||||||
|
- 用戶滿意度 > 4.5/5
|
||||||
|
- 功能使用率 > 80%
|
||||||
|
- 錯誤恢復時間 < 3秒
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **後續維護計劃**
|
||||||
|
|
||||||
|
### **監控機制**
|
||||||
|
1. API調用成功率監控
|
||||||
|
2. 用戶行為數據收集
|
||||||
|
3. 錯誤日誌分析
|
||||||
|
4. 性能指標追蹤
|
||||||
|
|
||||||
|
### **優化計劃**
|
||||||
|
1. 基於用戶反饋優化UI/UX
|
||||||
|
2. AI分析結果質量提升
|
||||||
|
3. 新功能開發和整合
|
||||||
|
4. 性能持續優化
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 **參考文件**
|
||||||
|
|
||||||
|
### **產品需求文件**
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/AI句子分析功能產品需求規格.md`
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/AI分析API技術實現規格.md`
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/系統整合與部署規格.md`
|
||||||
|
|
||||||
|
### **關鍵源碼檔案**
|
||||||
|
#### **後端檔案**
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/backend/DramaLing.Api/Controllers/AIController.cs`
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/backend/DramaLing.Api/Controllers/FlashcardsController.cs`
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/backend/DramaLing.Api/Controllers/AuthController.cs`
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/backend/DramaLing.Api/Services/GeminiService.cs`
|
||||||
|
|
||||||
|
#### **前端檔案**
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/generate/page.tsx` (主要分析頁面)
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/components/ClickableTextV2.tsx` (詞彙標記組件)
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/components/GrammarCorrectionPanel.tsx` (語法修正組件)
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/app/learn/page.tsx` (學習模式頁面)
|
||||||
|
|
||||||
|
### **配置檔案**
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/backend/DramaLing.Api/appsettings.json`
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/package.json`
|
||||||
|
- `/Users/jettcheng1018/code/dramaling-vocab-learning/frontend/next.config.js`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 **實施狀態總結**
|
||||||
|
|
||||||
|
### **第一階段完成狀況 (2025-01-25)**
|
||||||
|
|
||||||
|
#### **✅ 已完成功能 (核心串接)**
|
||||||
|
1. **API格式適配** - 移除userLevel參數,更新請求格式
|
||||||
|
2. **回應數據處理** - 適配新的`result.data`結構
|
||||||
|
3. **詞彙分析整合** - 使用`vocabularyAnalysis`對象格式
|
||||||
|
4. **慣用語功能** - 整合`idioms`陣列顯示
|
||||||
|
5. **統計計算** - 修正詞彙難度統計邏輯
|
||||||
|
6. **API測試** - 驗證前後端通信正常
|
||||||
|
|
||||||
|
#### **📊 測試結果**
|
||||||
|
- ✅ **後端API健康檢查**: 正常運行
|
||||||
|
- ✅ **句子分析API**: 3.5秒回應時間,符合<5秒要求
|
||||||
|
- ✅ **數據格式匹配**: 100%兼容新後端格式
|
||||||
|
- ✅ **詞彙分析**: CEFR分級和統計正確
|
||||||
|
- ✅ **語法修正**: 錯誤檢測和修正建議正常
|
||||||
|
- ✅ **慣用語檢測**: 顯示和交互功能正常
|
||||||
|
|
||||||
|
#### **🚀 核心功能狀態**
|
||||||
|
- **AI句子分析**: ✅ **生產就緒**
|
||||||
|
- **詞彙標記**: ✅ **生產就緒**
|
||||||
|
- **語法修正**: ✅ **生產就緒**
|
||||||
|
- **慣用語學習**: ✅ **生產就緒**
|
||||||
|
- **統計卡片**: ✅ **生產就緒**
|
||||||
|
- **響應式設計**: ✅ **生產就緒**
|
||||||
|
|
||||||
|
#### **📈 性能指標達成**
|
||||||
|
- **API回應時間**: 3.5秒 < 5秒目標 ✅
|
||||||
|
- **前端載入**: <2秒 ✅
|
||||||
|
- **詞彙分析準確**: 基於Gemini 1.5 Flash ✅
|
||||||
|
- **用戶體驗**: 流暢互動 ✅
|
||||||
|
|
||||||
|
### **下一階段建議 (可選優化)**
|
||||||
|
1. **JWT認證整合** - 用於保護閃卡功能
|
||||||
|
2. **錯誤處理增強** - 更友善的錯誤提示
|
||||||
|
3. **載入狀態優化** - 進度指示器
|
||||||
|
4. **離線快取** - 分析結果本地存儲
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**計劃制定者**: DramaLing技術團隊
|
||||||
|
**計劃版本**: v1.1 - 第一階段完成
|
||||||
|
**實際完成時間**: 1個工作天 (提前完成)
|
||||||
|
**完成狀態**: 🎯 **核心功能100%可用,生產就緒**
|
||||||
|
**下次評估**: 基於用戶回饋進行功能優化
|
||||||
|
|
@ -0,0 +1,265 @@
|
||||||
|
# DramaLing 文件結構說明
|
||||||
|
|
||||||
|
## 📁 **文件組織架構**
|
||||||
|
|
||||||
|
### **核心規格文件**
|
||||||
|
```
|
||||||
|
📋 產品與技術規格 (按關注點分離)
|
||||||
|
├── 🎯 AI句子分析功能產品需求規格.md # 產品需求、用戶故事、商業目標
|
||||||
|
├── 🔧 AI分析API技術實現規格.md # API設計、數據模型、技術實現
|
||||||
|
└── 🚀 系統整合與部署規格.md # 系統整合、部署、監控
|
||||||
|
|
||||||
|
📚 架構與指導文件
|
||||||
|
├── 🏗️ docs/AI驅動產品後端技術架構指南.md # 後端架構設計原則和最佳實踐
|
||||||
|
└── 📋 後端架構優化待辦清單.md # 當前優化項目和進度追蹤
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 **文件用途說明**
|
||||||
|
|
||||||
|
### **產品團隊使用**
|
||||||
|
- **📋 產品需求規格** - 產品經理、UX設計師、QA測試
|
||||||
|
- 用戶故事和使用場景
|
||||||
|
- 功能需求和驗收標準
|
||||||
|
- 產品路線圖和KPI指標
|
||||||
|
- 非功能性需求
|
||||||
|
|
||||||
|
### **開發團隊使用**
|
||||||
|
- **🔧 API技術規格** - 後端開發工程師
|
||||||
|
- API端點設計和數據模型
|
||||||
|
- AI Prompt設計和版本管理
|
||||||
|
- 錯誤處理和安全設計
|
||||||
|
- 性能要求和優化策略
|
||||||
|
|
||||||
|
- **🏗️ 架構指南** - 技術主管、資深工程師
|
||||||
|
- 分層架構設計原則
|
||||||
|
- 程式碼組織和最佳實踐
|
||||||
|
- 性能優化和穩定性設計
|
||||||
|
- 擴展性和維護性指導
|
||||||
|
|
||||||
|
### **運維團隊使用**
|
||||||
|
- **🚀 整合部署規格** - DevOps工程師、運維團隊
|
||||||
|
- 環境配置和容器化
|
||||||
|
- CI/CD流程和部署策略
|
||||||
|
- 監控告警和故障排除
|
||||||
|
- 安全配置和合規要求
|
||||||
|
|
||||||
|
### **全團隊使用**
|
||||||
|
- **📋 優化待辦清單** - 所有技術團隊成員
|
||||||
|
- 當前優化項目和優先級
|
||||||
|
- 進度追蹤和責任分配
|
||||||
|
- 技術債務管理
|
||||||
|
- 架構改進記錄
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **文件維護流程**
|
||||||
|
|
||||||
|
### **更新觸發條件**
|
||||||
|
```yaml
|
||||||
|
產品需求規格:
|
||||||
|
- 新功能規劃
|
||||||
|
- 用戶回饋整合
|
||||||
|
- 商業目標調整
|
||||||
|
- 定期產品審查
|
||||||
|
|
||||||
|
技術實現規格:
|
||||||
|
- API設計變更
|
||||||
|
- 數據模型調整
|
||||||
|
- 技術棧更新
|
||||||
|
- 安全要求變更
|
||||||
|
|
||||||
|
整合部署規格:
|
||||||
|
- 基礎設施變更
|
||||||
|
- 部署流程優化
|
||||||
|
- 監控需求更新
|
||||||
|
- 安全政策調整
|
||||||
|
|
||||||
|
架構指南:
|
||||||
|
- 技術決策更新
|
||||||
|
- 最佳實踐演進
|
||||||
|
- 工具和框架升級
|
||||||
|
- 團隊規模變化
|
||||||
|
```
|
||||||
|
|
||||||
|
### **版本管理策略**
|
||||||
|
```yaml
|
||||||
|
版本命名:
|
||||||
|
- 主要改版: v2.0, v3.0 (架構重大變更)
|
||||||
|
- 次要更新: v2.1, v2.2 (功能增加或修改)
|
||||||
|
- 修正更新: v2.1.1 (錯誤修正和澄清)
|
||||||
|
|
||||||
|
變更記錄:
|
||||||
|
- 每個文件包含詳細的更新記錄
|
||||||
|
- 記錄變更原因和影響範圍
|
||||||
|
- 標注向下相容性影響
|
||||||
|
- 提供遷移指導 (如需要)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 **閱讀指南**
|
||||||
|
|
||||||
|
### **新成員入門順序**
|
||||||
|
1. **📋 產品需求規格** - 了解產品目標和用戶需求
|
||||||
|
2. **🏗️ 架構指南** - 理解技術架構和設計原則
|
||||||
|
3. **🔧 API技術規格** - 掌握具體實現細節
|
||||||
|
4. **🚀 整合部署規格** - 了解系統整合和部署
|
||||||
|
5. **📋 優化待辦清單** - 參與當前改進項目
|
||||||
|
|
||||||
|
### **角色專用指南**
|
||||||
|
|
||||||
|
#### **產品經理**
|
||||||
|
```yaml
|
||||||
|
重點文件:
|
||||||
|
- 產品需求規格 (詳細閱讀)
|
||||||
|
- API技術規格 (概要了解)
|
||||||
|
- 整合部署規格 (監控部分)
|
||||||
|
|
||||||
|
關注要點:
|
||||||
|
- 用戶故事完整性
|
||||||
|
- 驗收標準明確性
|
||||||
|
- KPI指標合理性
|
||||||
|
- 技術可行性評估
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **前端開發**
|
||||||
|
```yaml
|
||||||
|
重點文件:
|
||||||
|
- 產品需求規格 (UI/UX需求)
|
||||||
|
- API技術規格 (API端點和數據模型)
|
||||||
|
- 整合部署規格 (前端部分)
|
||||||
|
|
||||||
|
關注要點:
|
||||||
|
- API接口設計
|
||||||
|
- 數據結構定義
|
||||||
|
- 錯誤處理邏輯
|
||||||
|
- 性能要求
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **後端開發**
|
||||||
|
```yaml
|
||||||
|
重點文件:
|
||||||
|
- API技術規格 (詳細閱讀)
|
||||||
|
- 架構指南 (詳細閱讀)
|
||||||
|
- 優化待辦清單 (參與執行)
|
||||||
|
|
||||||
|
關注要點:
|
||||||
|
- 服務架構設計
|
||||||
|
- 數據模型實現
|
||||||
|
- 錯誤處理策略
|
||||||
|
- 性能優化方案
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **DevOps/運維**
|
||||||
|
```yaml
|
||||||
|
重點文件:
|
||||||
|
- 整合部署規格 (詳細閱讀)
|
||||||
|
- 架構指南 (基礎設施部分)
|
||||||
|
- API技術規格 (監控需求)
|
||||||
|
|
||||||
|
關注要點:
|
||||||
|
- 部署流程設計
|
||||||
|
- 監控告警配置
|
||||||
|
- 安全策略實施
|
||||||
|
- 災難恢復計劃
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 **文件間關聯**
|
||||||
|
|
||||||
|
### **依賴關係**
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[產品需求規格] --> B[API技術規格]
|
||||||
|
A --> C[整合部署規格]
|
||||||
|
B --> C
|
||||||
|
D[架構指南] --> B
|
||||||
|
D --> E[優化待辦清單]
|
||||||
|
B --> E
|
||||||
|
```
|
||||||
|
|
||||||
|
### **交叉引用索引**
|
||||||
|
```yaml
|
||||||
|
功能需求 → 技術實現:
|
||||||
|
- FR1.1 文本輸入處理 → API端點 POST /api/ai/analyze-sentence
|
||||||
|
- FR1.2 AI分析核心 → Gemini服務整合和Prompt設計
|
||||||
|
- FR2.1 CEFR個人化 → 前端統計計算邏輯
|
||||||
|
- FR2.2 學習進度可視化 → 前端UI組件設計
|
||||||
|
|
||||||
|
技術實現 → 部署配置:
|
||||||
|
- GeminiOptions配置 → 環境變數和配置管理
|
||||||
|
- 健康檢查實現 → 監控和告警配置
|
||||||
|
- 錯誤處理設計 → 日誌和調試策略
|
||||||
|
- 性能要求 → 負載測試和優化
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ **廢棄文件說明**
|
||||||
|
|
||||||
|
### **已移除的重複文件**
|
||||||
|
```yaml
|
||||||
|
舊文件結構 (v1.0):
|
||||||
|
❌ AI生成網頁前端需求規格.md → 整合到產品需求規格
|
||||||
|
❌ AI生成功能後端API規格.md → 重構為API技術規格
|
||||||
|
❌ AI生成功能前後端串接規格.md → 整合到部署規格
|
||||||
|
|
||||||
|
移除原因:
|
||||||
|
- 內容重疊和矛盾
|
||||||
|
- 前後端界限模糊
|
||||||
|
- 維護成本高
|
||||||
|
- 不符合行業標準
|
||||||
|
```
|
||||||
|
|
||||||
|
### **遷移對照表**
|
||||||
|
```yaml
|
||||||
|
內容遷移映射:
|
||||||
|
舊檔案 → 新檔案位置:
|
||||||
|
- 產品定位和用戶故事 → 產品需求規格
|
||||||
|
- API設計和數據模型 → API技術規格
|
||||||
|
- UI/UX需求和視覺設計 → 產品需求規格 (UI章節)
|
||||||
|
- 前後端整合邏輯 → 整合部署規格
|
||||||
|
- 開發環境配置 → 整合部署規格
|
||||||
|
- 測試策略和驗證 → 整合部署規格
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 **維護計劃**
|
||||||
|
|
||||||
|
### **定期審查週期**
|
||||||
|
```yaml
|
||||||
|
月度審查:
|
||||||
|
- 優化待辦清單進度檢查
|
||||||
|
- 技術債務評估
|
||||||
|
- 新需求整合評估
|
||||||
|
|
||||||
|
季度審查:
|
||||||
|
- 產品需求規格更新
|
||||||
|
- 技術架構演進評估
|
||||||
|
- 文件結構優化
|
||||||
|
|
||||||
|
年度審查:
|
||||||
|
- 整體架構重新評估
|
||||||
|
- 文件體系重構
|
||||||
|
- 工具和流程升級
|
||||||
|
```
|
||||||
|
|
||||||
|
### **責任分工**
|
||||||
|
```yaml
|
||||||
|
文件擁有者:
|
||||||
|
- 產品需求規格: 產品經理
|
||||||
|
- API技術規格: 後端技術主管
|
||||||
|
- 整合部署規格: DevOps負責人
|
||||||
|
- 架構指南: 技術架構師
|
||||||
|
- 優化待辦清單: 開發團隊共同維護
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**建立時間**: 2025-01-25
|
||||||
|
**維護團隊**: DramaLing全體技術團隊
|
||||||
|
**下次審查**: 2025-02-25
|
||||||
|
|
@ -0,0 +1,887 @@
|
||||||
|
# 系統整合與部署規格
|
||||||
|
|
||||||
|
## 📋 **文件資訊**
|
||||||
|
|
||||||
|
- **文件名稱**: 系統整合與部署規格
|
||||||
|
- **版本**: v2.0
|
||||||
|
- **建立日期**: 2025-01-25
|
||||||
|
- **最後更新**: 2025-01-25
|
||||||
|
- **負責團隊**: DramaLing DevOps團隊
|
||||||
|
- **適用系統**: AI句子分析功能全棧系統
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ **系統架構圖**
|
||||||
|
|
||||||
|
### **整體架構**
|
||||||
|
```
|
||||||
|
┌─────────────────┐ HTTP/JSON ┌──────────────────┐ Gemini API ┌─────────────────┐
|
||||||
|
│ │ Request │ │ Request │ │
|
||||||
|
│ Frontend │ ──────────────► │ Backend API │ ──────────────► │ Google Gemini │
|
||||||
|
│ (Next.js) │ │ (.NET Core) │ │ AI Service │
|
||||||
|
│ Port 3000 │ ◄────────────── │ Port 5008 │ ◄────────────── │ │
|
||||||
|
│ │ Response │ │ Response │ │
|
||||||
|
└─────────────────┘ └──────────────────┘ └─────────────────┘
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
┌─────────────────┐ ┌──────────────────┐
|
||||||
|
│ Local Storage │ │ SQLite Database │
|
||||||
|
│ - user_level │ │ - Cache Data │
|
||||||
|
│ - auth_token │ │ - Usage Stats │
|
||||||
|
└─────────────────┘ └──────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### **數據流向**
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant U as 用戶
|
||||||
|
participant F as 前端(3000)
|
||||||
|
participant B as 後端(5008)
|
||||||
|
participant G as Gemini API
|
||||||
|
participant D as 資料庫
|
||||||
|
|
||||||
|
U->>F: 1. 輸入英文句子
|
||||||
|
U->>F: 2. 點擊「分析句子」
|
||||||
|
F->>F: 3. 驗證輸入(≤300字符)
|
||||||
|
F->>F: 4. 讀取userLevel (localStorage)
|
||||||
|
F->>B: 5. POST /api/ai/analyze-sentence
|
||||||
|
B->>B: 6. 輸入驗證和處理
|
||||||
|
B->>G: 7. 調用Gemini API
|
||||||
|
G->>B: 8. 返回AI分析結果
|
||||||
|
B->>B: 9. 解析和格式化數據
|
||||||
|
B->>D: 10. 記錄使用統計 (可選)
|
||||||
|
B->>F: 11. 返回結構化分析結果
|
||||||
|
F->>F: 12. 計算個人化統計
|
||||||
|
F->>F: 13. 渲染詞彙標記和統計卡片
|
||||||
|
F->>U: 14. 顯示完整分析結果
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **前後端整合規格**
|
||||||
|
|
||||||
|
### **API整合詳細設計**
|
||||||
|
|
||||||
|
#### **前端請求實現**
|
||||||
|
```typescript
|
||||||
|
// 位置: frontend/app/generate/page.tsx
|
||||||
|
const handleAnalyzeSentence = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('http://localhost:5008/api/ai/analyze-sentence', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${getAuthToken()}` // 可選
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
inputText: textInput,
|
||||||
|
analysisMode: 'full',
|
||||||
|
options: {
|
||||||
|
includeGrammarCheck: true,
|
||||||
|
includeVocabularyAnalysis: true,
|
||||||
|
includeTranslation: true,
|
||||||
|
includeIdiomDetection: true,
|
||||||
|
includeExamples: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`API請求失敗: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
handleAnalysisResult(result.data);
|
||||||
|
} catch (error) {
|
||||||
|
handleAnalysisError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **數據處理邏輯**
|
||||||
|
```typescript
|
||||||
|
// 前端個人化統計計算
|
||||||
|
const calculateVocabularyStats = (vocabularyAnalysis, idioms, userLevel) => {
|
||||||
|
const userIndex = CEFR_LEVELS.indexOf(userLevel);
|
||||||
|
let simple = 0, moderate = 0, difficult = 0;
|
||||||
|
|
||||||
|
Object.values(vocabularyAnalysis).forEach(word => {
|
||||||
|
const wordIndex = CEFR_LEVELS.indexOf(word.difficultyLevel);
|
||||||
|
if (userIndex > wordIndex) simple++;
|
||||||
|
else if (userIndex === wordIndex) moderate++;
|
||||||
|
else difficult++;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
simpleCount: simple,
|
||||||
|
moderateCount: moderate,
|
||||||
|
difficultCount: difficult,
|
||||||
|
idiomCount: idioms.length
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### **錯誤處理整合**
|
||||||
|
|
||||||
|
#### **前端錯誤處理**
|
||||||
|
```typescript
|
||||||
|
const handleAnalysisError = (error) => {
|
||||||
|
console.error('Analysis error:', error);
|
||||||
|
|
||||||
|
// 顯示用戶友善的錯誤訊息
|
||||||
|
if (error.message.includes('timeout')) {
|
||||||
|
setErrorMessage('分析服務繁忙,請稍後再試');
|
||||||
|
} else if (error.message.includes('network')) {
|
||||||
|
setErrorMessage('網路連接問題,請檢查網路狀態');
|
||||||
|
} else {
|
||||||
|
setErrorMessage('分析過程中發生錯誤,請稍後再試');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提供降級體驗
|
||||||
|
setFallbackAnalysisView(textInput);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **後端錯誤映射**
|
||||||
|
```csharp
|
||||||
|
// 位置: backend/Controllers/AIController.cs
|
||||||
|
private ApiErrorResponse CreateErrorResponse(string code, string message, object? details, string requestId)
|
||||||
|
{
|
||||||
|
var userFriendlyMessage = code switch
|
||||||
|
{
|
||||||
|
"INVALID_INPUT" => "輸入格式不正確,請檢查文本內容",
|
||||||
|
"AI_SERVICE_ERROR" => "AI分析服務暫時不可用,請稍後重試",
|
||||||
|
"RATE_LIMIT_EXCEEDED" => "請求過於頻繁,請稍候再試",
|
||||||
|
"TIMEOUT" => "分析超時,請嘗試較短的句子",
|
||||||
|
_ => "系統暫時不可用,請稍後重試"
|
||||||
|
};
|
||||||
|
|
||||||
|
return new ApiErrorResponse
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
Error = new ApiError
|
||||||
|
{
|
||||||
|
Code = code,
|
||||||
|
Message = userFriendlyMessage,
|
||||||
|
Details = details,
|
||||||
|
Suggestions = GetSuggestionsForError(code)
|
||||||
|
},
|
||||||
|
RequestId = requestId,
|
||||||
|
Timestamp = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 **開發環境配置**
|
||||||
|
|
||||||
|
### **環境準備**
|
||||||
|
|
||||||
|
#### **必要軟體**
|
||||||
|
```yaml
|
||||||
|
開發工具:
|
||||||
|
- Node.js: >= 18.0.0
|
||||||
|
- .NET SDK: >= 8.0.0
|
||||||
|
- Git: >= 2.40.0
|
||||||
|
- VSCode: 最新版本
|
||||||
|
|
||||||
|
瀏覽器支援:
|
||||||
|
- Chrome: >= 90 (開發調試用)
|
||||||
|
- Safari: >= 14 (測試用)
|
||||||
|
- Firefox: >= 88 (測試用)
|
||||||
|
|
||||||
|
可選工具:
|
||||||
|
- Docker: >= 20.0 (容器化部署)
|
||||||
|
- Redis: >= 6.0 (本地快取測試)
|
||||||
|
- Postman: API測試
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **環境變數配置**
|
||||||
|
```bash
|
||||||
|
# 後端環境變數
|
||||||
|
export GEMINI_API_KEY="your-gemini-api-key"
|
||||||
|
export ASPNETCORE_ENVIRONMENT="Development"
|
||||||
|
export DRAMALING_DB_CONNECTION="Data Source=dramaling_test.db"
|
||||||
|
|
||||||
|
# 前端環境變數 (可選)
|
||||||
|
export NEXT_PUBLIC_API_URL="http://localhost:5008"
|
||||||
|
export NEXT_PUBLIC_ENVIRONMENT="development"
|
||||||
|
```
|
||||||
|
|
||||||
|
### **啟動流程**
|
||||||
|
|
||||||
|
#### **開發環境啟動腳本**
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# 位置: start-development.sh
|
||||||
|
|
||||||
|
echo "🚀 啟動 DramaLing 開發環境..."
|
||||||
|
|
||||||
|
# 1. 檢查必要軟體
|
||||||
|
check_prerequisites() {
|
||||||
|
command -v node >/dev/null 2>&1 || { echo "需要安裝 Node.js"; exit 1; }
|
||||||
|
command -v dotnet >/dev/null 2>&1 || { echo "需要安裝 .NET SDK"; exit 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2. 啟動後端 API (Port 5008)
|
||||||
|
start_backend() {
|
||||||
|
echo "🔧 啟動後端 API..."
|
||||||
|
cd backend/DramaLing.Api
|
||||||
|
dotnet restore
|
||||||
|
dotnet run &
|
||||||
|
BACKEND_PID=$!
|
||||||
|
echo "後端 PID: $BACKEND_PID"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 3. 啟動前端 (Port 3000)
|
||||||
|
start_frontend() {
|
||||||
|
echo "🎨 啟動前端..."
|
||||||
|
cd ../../frontend
|
||||||
|
npm install
|
||||||
|
npm run dev &
|
||||||
|
FRONTEND_PID=$!
|
||||||
|
echo "前端 PID: $FRONTEND_PID"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 4. 健康檢查
|
||||||
|
health_check() {
|
||||||
|
echo "🏥 執行健康檢查..."
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# 檢查後端
|
||||||
|
if curl -f http://localhost:5008/health >/dev/null 2>&1; then
|
||||||
|
echo "✅ 後端服務正常"
|
||||||
|
else
|
||||||
|
echo "❌ 後端服務異常"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 檢查前端
|
||||||
|
if curl -f http://localhost:3000 >/dev/null 2>&1; then
|
||||||
|
echo "✅ 前端服務正常"
|
||||||
|
else
|
||||||
|
echo "❌ 前端服務異常"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 執行啟動流程
|
||||||
|
check_prerequisites
|
||||||
|
start_backend
|
||||||
|
start_frontend
|
||||||
|
health_check
|
||||||
|
|
||||||
|
echo "🎉 開發環境啟動完成!"
|
||||||
|
echo "前端: http://localhost:3000"
|
||||||
|
echo "後端API: http://localhost:5008"
|
||||||
|
echo "API文檔: http://localhost:5008/swagger"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 **測試整合策略**
|
||||||
|
|
||||||
|
### **整合測試架構**
|
||||||
|
|
||||||
|
#### **API整合測試**
|
||||||
|
```csharp
|
||||||
|
[TestFixture]
|
||||||
|
public class AIAnalysisIntegrationTests : IClassFixture<WebApplicationFactory<Program>>
|
||||||
|
{
|
||||||
|
private readonly WebApplicationFactory<Program> _factory;
|
||||||
|
private readonly HttpClient _client;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_client = _factory.CreateClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task AnalyzeSentence_EndToEnd_ReturnsValidResponse()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var request = new
|
||||||
|
{
|
||||||
|
inputText = "She just join the team, so let's cut her some slack.",
|
||||||
|
analysisMode = "full"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await _client.PostAsJsonAsync("/api/ai/analyze-sentence", request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var result = await response.Content.ReadFromJsonAsync<AnalysisResponse>();
|
||||||
|
|
||||||
|
Assert.That(result.Success, Is.True);
|
||||||
|
Assert.That(result.Data.VocabularyAnalysis.Count, Is.GreaterThan(0));
|
||||||
|
Assert.That(result.Data.SentenceMeaning, Is.Not.Empty);
|
||||||
|
Assert.That(result.Data.Idioms.Count, Is.GreaterThan(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **前端E2E測試**
|
||||||
|
```typescript
|
||||||
|
// 使用 Playwright 或 Cypress
|
||||||
|
describe('AI Analysis E2E Flow', () => {
|
||||||
|
test('complete analysis workflow', async ({ page }) => {
|
||||||
|
// 1. 導航到分析頁面
|
||||||
|
await page.goto('http://localhost:3000/generate');
|
||||||
|
|
||||||
|
// 2. 輸入測試句子
|
||||||
|
await page.fill('[data-testid="text-input"]',
|
||||||
|
'She just join the team, so let\'s cut her some slack.');
|
||||||
|
|
||||||
|
// 3. 點擊分析按鈕
|
||||||
|
await page.click('[data-testid="analyze-button"]');
|
||||||
|
|
||||||
|
// 4. 等待分析完成
|
||||||
|
await page.waitForSelector('[data-testid="analysis-result"]', { timeout: 10000 });
|
||||||
|
|
||||||
|
// 5. 驗證結果
|
||||||
|
await expect(page.locator('[data-testid="grammar-correction"]')).toBeVisible();
|
||||||
|
await expect(page.locator('[data-testid="vocabulary-analysis"]')).toBeVisible();
|
||||||
|
await expect(page.locator('[data-testid="idioms-section"]')).toBeVisible();
|
||||||
|
await expect(page.locator('[data-testid="statistics-cards"]')).toBeVisible();
|
||||||
|
|
||||||
|
// 6. 測試詞彙點擊
|
||||||
|
await page.click('[data-testid="word-she"]');
|
||||||
|
await expect(page.locator('[data-testid="vocab-popup"]')).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### **性能測試整合**
|
||||||
|
|
||||||
|
#### **負載測試配置**
|
||||||
|
```yaml
|
||||||
|
# 使用 k6 或 JMeter
|
||||||
|
負載測試場景:
|
||||||
|
- 正常負載: 100 用戶,持續 10 分鐘
|
||||||
|
- 壓力測試: 500 用戶,持續 5 分鐘
|
||||||
|
- 尖峰測試: 1000 用戶,持續 2 分鐘
|
||||||
|
|
||||||
|
性能指標:
|
||||||
|
- 回應時間P95: < 5秒
|
||||||
|
- 錯誤率: < 1%
|
||||||
|
- 吞吐量: > 100 RPS
|
||||||
|
- 資源使用: CPU < 80%, Memory < 70%
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 **部署架構**
|
||||||
|
|
||||||
|
### **環境配置**
|
||||||
|
|
||||||
|
#### **開發環境 (Development)**
|
||||||
|
```yaml
|
||||||
|
基礎設施:
|
||||||
|
- 本地開發機器
|
||||||
|
- SQLite 資料庫
|
||||||
|
- In-Memory 快取
|
||||||
|
- Gemini API (測試金鑰)
|
||||||
|
|
||||||
|
配置特點:
|
||||||
|
- 詳細日誌輸出
|
||||||
|
- 熱重載支援
|
||||||
|
- Swagger API 文檔
|
||||||
|
- CORS 寬鬆政策
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **測試環境 (Staging)**
|
||||||
|
```yaml
|
||||||
|
基礎設施:
|
||||||
|
- 雲端虛擬機 或 Docker 容器
|
||||||
|
- PostgreSQL 資料庫
|
||||||
|
- Redis 快取
|
||||||
|
- Gemini API (測試金鑰)
|
||||||
|
|
||||||
|
配置特點:
|
||||||
|
- 生產環境模擬
|
||||||
|
- 效能監控啟用
|
||||||
|
- 自動化測試整合
|
||||||
|
- 安全掃描
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **生產環境 (Production)**
|
||||||
|
```yaml
|
||||||
|
基礎設施:
|
||||||
|
- Kubernetes 叢集 或 雲端服務
|
||||||
|
- PostgreSQL 高可用性叢集
|
||||||
|
- Redis 叢集
|
||||||
|
- Gemini API (生產金鑰)
|
||||||
|
- CDN 和負載均衡
|
||||||
|
|
||||||
|
配置特點:
|
||||||
|
- 高可用性 (99.9%+)
|
||||||
|
- 自動擴容
|
||||||
|
- 全面監控和告警
|
||||||
|
- 災難恢復機制
|
||||||
|
```
|
||||||
|
|
||||||
|
### **容器化部署**
|
||||||
|
|
||||||
|
#### **Docker Compose 配置**
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# 後端 API 服務
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ./backend/DramaLing.Api
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "5008:5008"
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- GEMINI_API_KEY=${GEMINI_API_KEY}
|
||||||
|
- ConnectionStrings__DefaultConnection=${DB_CONNECTION}
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
- redis
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:5008/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# 前端服務
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ./frontend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NEXT_PUBLIC_API_URL=http://backend:5008
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
|
||||||
|
# 資料庫服務
|
||||||
|
database:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=dramaling
|
||||||
|
- POSTGRES_USER=${DB_USER}
|
||||||
|
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
|
||||||
|
# 快取服務
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
redis_data:
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **Kubernetes 部署配置**
|
||||||
|
```yaml
|
||||||
|
# k8s-deployment.yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dramaling-backend
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: dramaling-backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: dramaling-backend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
image: dramaling/backend:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 5008
|
||||||
|
env:
|
||||||
|
- name: GEMINI_API_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: ai-secrets
|
||||||
|
key: gemini-api-key
|
||||||
|
- name: ConnectionStrings__DefaultConnection
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: app-config
|
||||||
|
key: db-connection
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "250m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 5008
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 30
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 5008
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **監控與可觀測性**
|
||||||
|
|
||||||
|
### **日誌整合**
|
||||||
|
|
||||||
|
#### **結構化日誌配置**
|
||||||
|
```json
|
||||||
|
// appsettings.Production.json
|
||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"Using": ["Serilog.Sinks.Console", "Serilog.Sinks.ApplicationInsights"],
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"System": "Warning",
|
||||||
|
"DramaLing": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"WriteTo": [
|
||||||
|
{
|
||||||
|
"Name": "Console",
|
||||||
|
"Args": {
|
||||||
|
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "ApplicationInsights",
|
||||||
|
"Args": {
|
||||||
|
"instrumentationKey": "{ApplicationInsights:InstrumentationKey}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **前端錯誤追蹤**
|
||||||
|
```typescript
|
||||||
|
// 錯誤邊界和監控
|
||||||
|
class ErrorBoundary extends React.Component {
|
||||||
|
componentDidCatch(error, errorInfo) {
|
||||||
|
// 發送錯誤到監控服務
|
||||||
|
console.error('React Error Boundary:', error, errorInfo);
|
||||||
|
|
||||||
|
// 可選:整合 Sentry 或其他錯誤追蹤服務
|
||||||
|
if (typeof window !== 'undefined' && window.gtag) {
|
||||||
|
window.gtag('event', 'exception', {
|
||||||
|
description: error.toString(),
|
||||||
|
fatal: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **健康檢查系統**
|
||||||
|
|
||||||
|
#### **深度健康檢查**
|
||||||
|
```csharp
|
||||||
|
public class SystemHealthCheck : IHealthCheck
|
||||||
|
{
|
||||||
|
private readonly IGeminiService _geminiService;
|
||||||
|
private readonly DramaLingDbContext _dbContext;
|
||||||
|
|
||||||
|
public async Task<HealthCheckResult> CheckHealthAsync(
|
||||||
|
HealthCheckContext context, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var checks = new Dictionary<string, HealthStatus>();
|
||||||
|
|
||||||
|
// 檢查資料庫連接
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _dbContext.Database.CanConnectAsync(cancellationToken);
|
||||||
|
checks["database"] = HealthStatus.Healthy;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
checks["database"] = HealthStatus.Unhealthy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查 AI 服務
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var isHealthy = await _geminiService.HealthCheckAsync();
|
||||||
|
checks["gemini_api"] = isHealthy ? HealthStatus.Healthy : HealthStatus.Degraded;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
checks["gemini_api"] = HealthStatus.Unhealthy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查記憶體使用
|
||||||
|
var memoryUsage = GC.GetTotalMemory(false);
|
||||||
|
checks["memory"] = memoryUsage < 500_000_000 ? HealthStatus.Healthy : HealthStatus.Degraded;
|
||||||
|
|
||||||
|
var overallStatus = checks.Values.All(s => s == HealthStatus.Healthy)
|
||||||
|
? HealthStatus.Healthy
|
||||||
|
: checks.Values.Any(s => s == HealthStatus.Unhealthy)
|
||||||
|
? HealthStatus.Unhealthy
|
||||||
|
: HealthStatus.Degraded;
|
||||||
|
|
||||||
|
return new HealthCheckResult(overallStatus,
|
||||||
|
description: $"System health: {string.Join(", ", checks.Select(c => $"{c.Key}:{c.Value}"))}",
|
||||||
|
data: checks.ToDictionary(c => c.Key, c => (object)c.Value.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 **安全整合**
|
||||||
|
|
||||||
|
### **HTTPS 配置**
|
||||||
|
```yaml
|
||||||
|
開發環境:
|
||||||
|
- HTTP: localhost:3000, localhost:5008
|
||||||
|
- 自簽證書: dotnet dev-certs https --trust
|
||||||
|
|
||||||
|
生產環境:
|
||||||
|
- HTTPS: 強制重定向
|
||||||
|
- TLS 1.3: 最低版本要求
|
||||||
|
- HSTS: 嚴格傳輸安全
|
||||||
|
- 證書: Let's Encrypt 或企業CA
|
||||||
|
```
|
||||||
|
|
||||||
|
### **CORS 政策**
|
||||||
|
```csharp
|
||||||
|
// 開發環境 CORS 配置
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("Development", policy =>
|
||||||
|
{
|
||||||
|
policy.WithOrigins("http://localhost:3000", "http://localhost:3001")
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowCredentials();
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddPolicy("Production", policy =>
|
||||||
|
{
|
||||||
|
policy.WithOrigins("https://dramaling.com", "https://app.dramaling.com")
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowCredentials();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 **監控整合**
|
||||||
|
|
||||||
|
### **應用程式監控**
|
||||||
|
|
||||||
|
#### **關鍵指標儀表板**
|
||||||
|
```yaml
|
||||||
|
業務指標:
|
||||||
|
- 每日分析次數
|
||||||
|
- 用戶活躍度
|
||||||
|
- 功能使用分佈
|
||||||
|
- AI分析成功率
|
||||||
|
|
||||||
|
技術指標:
|
||||||
|
- API回應時間分佈
|
||||||
|
- 資料庫查詢性能
|
||||||
|
- 記憶體和CPU使用
|
||||||
|
- 錯誤率和異常統計
|
||||||
|
|
||||||
|
用戶體驗指標:
|
||||||
|
- 頁面載入時間
|
||||||
|
- 首次內容繪製 (FCP)
|
||||||
|
- 最大內容繪製 (LCP)
|
||||||
|
- 累積佈局偏移 (CLS)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **告警配置**
|
||||||
|
```yaml
|
||||||
|
嚴重告警:
|
||||||
|
- API 錯誤率 > 5% (5分鐘內)
|
||||||
|
- 回應時間P95 > 10秒 (5分鐘內)
|
||||||
|
- 服務不可用 > 2分鐘
|
||||||
|
- 資料庫連接失敗
|
||||||
|
|
||||||
|
警告告警:
|
||||||
|
- CPU 使用率 > 80% (10分鐘內)
|
||||||
|
- 記憶體使用率 > 85% (10分鐘內)
|
||||||
|
- AI API 調用失敗率 > 10%
|
||||||
|
- 磁碟空間不足 < 10%
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 **故障排除指南**
|
||||||
|
|
||||||
|
### **常見問題和解決方案**
|
||||||
|
|
||||||
|
#### **連接問題**
|
||||||
|
```yaml
|
||||||
|
問題: CORS 錯誤
|
||||||
|
症狀: "Access to fetch blocked by CORS policy"
|
||||||
|
解決: 檢查後端 CORS 設定,確認前端域名在允許清單
|
||||||
|
|
||||||
|
問題: 連接被拒絕
|
||||||
|
症狀: "Connection refused" 或 "ECONNREFUSED"
|
||||||
|
解決: 確認後端服務正在運行,檢查埠號是否正確
|
||||||
|
|
||||||
|
問題: 超時錯誤
|
||||||
|
症狀: "Request timeout" 或響應超過 30 秒
|
||||||
|
解決: 檢查 AI API 金鑰,網路連接,增加超時設定
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **資料問題**
|
||||||
|
```yaml
|
||||||
|
問題: AI 回應格式錯誤
|
||||||
|
症狀: "Cannot read property 'vocabularyAnalysis' of undefined"
|
||||||
|
解決: 檢查 Gemini API 回應格式,更新錯誤處理邏輯
|
||||||
|
|
||||||
|
問題: 詞彙分析為空
|
||||||
|
症狀: 分析結果不包含詞彙資訊
|
||||||
|
解決: 檢查 AI Prompt 設計,確認輸入文本有效
|
||||||
|
|
||||||
|
問題: 統計數字不一致
|
||||||
|
症狀: 統計卡片數字與實際標記不符
|
||||||
|
解決: 檢查前端統計計算邏輯,確認分類算法正確
|
||||||
|
```
|
||||||
|
|
||||||
|
### **調試工具**
|
||||||
|
|
||||||
|
#### **開發調試指令**
|
||||||
|
```bash
|
||||||
|
# 檢查服務狀態
|
||||||
|
curl -I http://localhost:5008/health
|
||||||
|
curl -I http://localhost:3000
|
||||||
|
|
||||||
|
# 測試 API 端點
|
||||||
|
curl -X POST http://localhost:5008/api/ai/analyze-sentence \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"inputText":"Test sentence","analysisMode":"full"}'
|
||||||
|
|
||||||
|
# 檢查日誌
|
||||||
|
docker logs dramaling-backend
|
||||||
|
docker logs dramaling-frontend
|
||||||
|
|
||||||
|
# 檢查資源使用
|
||||||
|
docker stats
|
||||||
|
top -p $(pgrep dotnet)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **生產監控指令**
|
||||||
|
```bash
|
||||||
|
# 健康檢查
|
||||||
|
kubectl get pods -l app=dramaling
|
||||||
|
kubectl describe pod dramaling-backend-xxx
|
||||||
|
|
||||||
|
# 查看日誌
|
||||||
|
kubectl logs -f deployment/dramaling-backend
|
||||||
|
kubectl logs -f deployment/dramaling-frontend
|
||||||
|
|
||||||
|
# 性能監控
|
||||||
|
kubectl top pods
|
||||||
|
kubectl top nodes
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 **部署檢查清單**
|
||||||
|
|
||||||
|
### **部署前檢查**
|
||||||
|
- [ ] 所有測試通過 (單元、整合、E2E)
|
||||||
|
- [ ] 安全掃描無嚴重漏洞
|
||||||
|
- [ ] 性能基準測試達標
|
||||||
|
- [ ] 配置檔案正確設定
|
||||||
|
- [ ] 環境變數和金鑰配置完成
|
||||||
|
- [ ] 資料庫遷移腳本準備
|
||||||
|
- [ ] 監控和告警配置完成
|
||||||
|
- [ ] 回滾計劃準備
|
||||||
|
|
||||||
|
### **部署後驗證**
|
||||||
|
- [ ] 健康檢查端點回應正常
|
||||||
|
- [ ] API 功能端到端測試通過
|
||||||
|
- [ ] 前端頁面載入和功能正常
|
||||||
|
- [ ] 監控指標顯示正常
|
||||||
|
- [ ] 日誌記錄正確產生
|
||||||
|
- [ ] 告警機制測試正常
|
||||||
|
- [ ] 負載測試驗證性能
|
||||||
|
- [ ] 安全掃描確認無新漏洞
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 **CI/CD 流程**
|
||||||
|
|
||||||
|
### **持續整合流程**
|
||||||
|
```yaml
|
||||||
|
觸發條件:
|
||||||
|
- 主分支推送 (main)
|
||||||
|
- Pull Request 建立
|
||||||
|
- 標籤建立 (v*.*.*)
|
||||||
|
|
||||||
|
建置步驟:
|
||||||
|
1. 程式碼檢出
|
||||||
|
2. 依賴安裝
|
||||||
|
3. 靜態分析 (ESLint, SonarQube)
|
||||||
|
4. 單元測試執行
|
||||||
|
5. 測試覆蓋率檢查
|
||||||
|
6. 安全掃描
|
||||||
|
7. 建置 Docker 映像
|
||||||
|
8. 整合測試執行
|
||||||
|
|
||||||
|
部署條件:
|
||||||
|
- 所有測試通過
|
||||||
|
- 程式碼覆蓋率 > 80%
|
||||||
|
- 安全掃描通過
|
||||||
|
- 人工審核批准 (生產部署)
|
||||||
|
```
|
||||||
|
|
||||||
|
### **持續部署流程**
|
||||||
|
```yaml
|
||||||
|
測試環境自動部署:
|
||||||
|
- 主分支每次推送自動部署
|
||||||
|
- 自動執行煙霧測試
|
||||||
|
- 通知團隊部署狀態
|
||||||
|
|
||||||
|
生產環境部署:
|
||||||
|
- 手動觸發或定期發布
|
||||||
|
- 藍綠部署或滾動更新
|
||||||
|
- 自動回滾機制
|
||||||
|
- 部署後監控和驗證
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文件版本**: v2.0
|
||||||
|
**DevOps負責人**: DramaLing DevOps團隊
|
||||||
|
**最後更新**: 2025-01-25
|
||||||
|
**下次審查**: 2025-02-25
|
||||||
|
|
||||||
|
**關聯文件**:
|
||||||
|
- 《AI句子分析功能產品需求規格》- 產品需求和用戶故事
|
||||||
|
- 《AI分析API技術實現規格》- API設計和技術實現
|
||||||
|
- 《AI驅動產品後端技術架構指南》- 架構設計指導原則
|
||||||
Loading…
Reference in New Issue