1002 lines
27 KiB
Markdown
1002 lines
27 KiB
Markdown
# 🤖 DramaLing AI 功能 - 後端 API 完整文檔
|
||
|
||
**專案**: DramaLing 英語學習平台
|
||
**功能**: AI 智能分析與詞卡生成系統
|
||
**文檔版本**: v1.1
|
||
**最後更新**: 2025-01-18
|
||
|
||
---
|
||
|
||
## 📋 **功能概述**
|
||
|
||
DramaLing AI 功能包含兩大核心系統:
|
||
1. **句子分析系統**: 提供整句翻譯、語法修正和詞彙分析
|
||
2. **詞卡生成系統**: 透過 AI 分析文本自動生成學習詞卡
|
||
|
||
兩系統都整合 Google Gemini AI,提供高品質的英語學習分析。
|
||
|
||
### 🎯 **主要特點**
|
||
- ✅ **智能分析**: 使用 Google Gemini AI 進行文本分析
|
||
- ✅ **雙重模式**: 支援基本詞彙和智能萃取
|
||
- ✅ **完整資訊**: 包含音標、例句、同義詞、CEFR等級
|
||
- ✅ **安全驗證**: JWT認證和輸入驗證
|
||
- ✅ **錯誤處理**: 完善的例外處理和回退機制
|
||
- ✅ **批量操作**: 支援一次生成多張詞卡
|
||
|
||
---
|
||
|
||
## 📁 **核心檔案架構**
|
||
|
||
```
|
||
backend/DramaLing.Api/
|
||
├── Controllers/
|
||
│ └── AIController.cs # API 端點控制器
|
||
├── Services/
|
||
│ └── GeminiService.cs # AI 服務整合
|
||
├── Models/
|
||
│ └── Entities/
|
||
│ ├── Flashcard.cs # 詞卡資料模型
|
||
│ └── CardSet.cs # 詞卡集合模型
|
||
└── Data/
|
||
└── DramaLingDbContext.cs # 資料庫上下文
|
||
```
|
||
|
||
---
|
||
|
||
## 🔗 **API 端點列表**
|
||
|
||
## 🎯 **A. 句子分析系統**
|
||
|
||
### 1. **📝 句子分析 (整句意思生成)** `[AllowAnonymous]`
|
||
```http
|
||
POST /api/ai/analyze-sentence
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"inputText": "Hello world",
|
||
"forceRefresh": false,
|
||
"analysisMode": "full"
|
||
}
|
||
```
|
||
|
||
**功能**:
|
||
- ✅ **整句翻譯**: 自然流暢的繁體中文翻譯
|
||
- ✅ **詳細解釋**: 語法結構、詞彙特點、使用場景分析
|
||
- ✅ **語法修正**: 檢測並修正語法錯誤
|
||
- ✅ **詞彙分析**: 每個單字的詳細資訊
|
||
- ✅ **高價值標記**: 標記學習價值高的詞彙
|
||
|
||
**回應範例**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"analysisId": "a063fb12-b28f-4df8-af4f-eeb2d43fd9c4",
|
||
"inputText": "Hello world",
|
||
"grammarCorrection": {
|
||
"hasErrors": false,
|
||
"originalText": "Hello world",
|
||
"correctedText": "",
|
||
"corrections": []
|
||
},
|
||
"sentenceMeaning": {
|
||
"translation": "你好,世界",
|
||
"explanation": "這個句子是程式設計中最經典的入門程式碼,也是學習任何程式語言的第一個練習。語法結構非常簡單,主語是隱含的,謂語是 'Hello',賓語是 'world'。"
|
||
},
|
||
"finalAnalysisText": "Hello world",
|
||
"wordAnalysis": {
|
||
"Hello": {
|
||
"word": "Hello",
|
||
"translation": "你好",
|
||
"definition": "used as a greeting or to begin a phone conversation",
|
||
"partOfSpeech": "interjection",
|
||
"pronunciation": "/həˈloʊ/",
|
||
"isHighValue": true,
|
||
"difficultyLevel": "A1"
|
||
},
|
||
"world": {
|
||
"word": "world",
|
||
"translation": "世界",
|
||
"definition": "the earth, together with all of its countries and peoples",
|
||
"partOfSpeech": "noun",
|
||
"pronunciation": "/wɜːrld/",
|
||
"isHighValue": true,
|
||
"difficultyLevel": "A1"
|
||
}
|
||
},
|
||
"highValueWords": ["Hello", "world"],
|
||
"phrasesDetected": []
|
||
},
|
||
"message": "AI句子分析完成",
|
||
"cached": false,
|
||
"cacheHit": false,
|
||
"usingAI": true
|
||
}
|
||
```
|
||
|
||
**特點**:
|
||
- 🔄 **智能快取**: 24小時快取機制,提升回應速度
|
||
- 🛡️ **回退機制**: AI 失敗時使用本地分析
|
||
- 📊 **使用統計**: 記錄分析次數(目前已暫時關閉限制)
|
||
|
||
---
|
||
|
||
### 2. **🔍 互動式單字查詢** `[AllowAnonymous]`
|
||
```http
|
||
POST /api/ai/query-word
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"word": "beautiful",
|
||
"sentence": "The weather is beautiful today"
|
||
}
|
||
```
|
||
|
||
**功能**: 在句子語境中分析特定單字
|
||
**回應**: 包含詞彙詳細資訊和語境分析
|
||
|
||
---
|
||
|
||
## 🎯 **B. 詞卡生成系統**
|
||
|
||
### 3. **🧪 測試生成詞卡** `[AllowAnonymous]`
|
||
```http
|
||
POST /api/ai/test/generate
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"inputText": "要分析的英文文本",
|
||
"extractionType": "vocabulary",
|
||
"cardCount": 10
|
||
}
|
||
```
|
||
|
||
**特點**:
|
||
- 無需用戶認證
|
||
- 開發測試專用
|
||
- API Key 未配置時返回模擬資料
|
||
|
||
---
|
||
|
||
### 2. **🚀 正式生成詞卡** `[Authorize]`
|
||
```http
|
||
POST /api/ai/generate
|
||
Authorization: Bearer {jwt-token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"inputText": "The weather is beautiful today, and I'm planning to go hiking in the mountains.",
|
||
"extractionType": "vocabulary",
|
||
"cardCount": 5
|
||
}
|
||
```
|
||
|
||
**回應範例**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"taskId": "123e4567-e89b-12d3-a456-426614174000",
|
||
"status": "completed",
|
||
"generatedCards": [
|
||
{
|
||
"word": "beautiful",
|
||
"partOfSpeech": "adj.",
|
||
"pronunciation": "/ˈbjuːtɪfl/",
|
||
"translation": "美麗的",
|
||
"definition": "pleasing the senses or mind aesthetically",
|
||
"synonyms": ["lovely", "gorgeous"],
|
||
"example": "The weather is beautiful today",
|
||
"exampleTranslation": "今天天氣很美",
|
||
"difficultyLevel": "A2"
|
||
},
|
||
{
|
||
"word": "hiking",
|
||
"partOfSpeech": "n.",
|
||
"pronunciation": "/ˈhaɪkɪŋ/",
|
||
"translation": "登山健行",
|
||
"definition": "the activity of going for long walks in the countryside",
|
||
"synonyms": ["trekking", "walking"],
|
||
"example": "I'm planning to go hiking in the mountains",
|
||
"exampleTranslation": "我計劃去山裡健行",
|
||
"difficultyLevel": "B1"
|
||
}
|
||
]
|
||
},
|
||
"message": "Successfully generated 5 cards"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3. **💾 保存生成的詞卡** `[Authorize]`
|
||
```http
|
||
POST /api/ai/generate/{taskId}/save
|
||
Authorization: Bearer {jwt-token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"cardSetId": "456e7890-e89b-12d3-a456-426614174111",
|
||
"selectedCards": [
|
||
{
|
||
"word": "beautiful",
|
||
"translation": "美麗的",
|
||
"definition": "pleasing the senses or mind aesthetically",
|
||
"partOfSpeech": "adj.",
|
||
"pronunciation": "/ˈbjuːtɪfl/",
|
||
"example": "The weather is beautiful today",
|
||
"exampleTranslation": "今天天氣很美",
|
||
"difficultyLevel": "A2"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**回應範例**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"savedCount": 1,
|
||
"cardSetId": "456e7890-e89b-12d3-a456-426614174111",
|
||
"cardSetName": "我的詞卡集合",
|
||
"cards": [
|
||
{
|
||
"id": "789e1234-e89b-12d3-a456-426614174222",
|
||
"word": "beautiful",
|
||
"translation": "美麗的",
|
||
"definition": "pleasing the senses or mind aesthetically"
|
||
}
|
||
]
|
||
},
|
||
"message": "Successfully saved 1 cards to deck '我的詞卡集合'"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4. **💾 快速保存詞卡(測試用)** `[AllowAnonymous]`
|
||
```http
|
||
POST /api/ai/test/generate/save
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"selectedCards": [
|
||
{
|
||
"word": "example",
|
||
"translation": "例子",
|
||
"definition": "a thing characteristic of its kind",
|
||
"partOfSpeech": "n.",
|
||
"pronunciation": "/ɪɡˈzɑːmpl/",
|
||
"example": "This is an example sentence",
|
||
"exampleTranslation": "這是一個例句",
|
||
"difficultyLevel": "B1"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**特點**:
|
||
- 自動創建預設詞卡集合
|
||
- 測試環境專用
|
||
- 無需指定 CardSetId
|
||
|
||
---
|
||
|
||
### 5. **✅ 驗證詞卡內容** `[Authorize]`
|
||
```http
|
||
POST /api/ai/validate-card
|
||
Authorization: Bearer {jwt-token}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"flashcardId": "789e1234-e89b-12d3-a456-426614174222"
|
||
}
|
||
```
|
||
|
||
**用途**: 驗證已保存詞卡的內容準確性
|
||
|
||
---
|
||
|
||
## 📋 **請求參數詳細說明**
|
||
|
||
### **GenerateCardsRequest 參數**
|
||
| 參數 | 類型 | 必填 | 限制 | 說明 |
|
||
|------|------|------|------|------|
|
||
| `inputText` | string | ✅ | ≤ 5000 字元 | 要分析的英文文本 |
|
||
| `extractionType` | string | ✅ | "vocabulary" 或 "smart" | 萃取模式 |
|
||
| `cardCount` | int | ✅ | 1-20 | 要生成的詞卡數量 |
|
||
|
||
### **萃取模式說明**
|
||
- **`"vocabulary"`**: 基本詞彙萃取
|
||
- 重點:常用單字、動詞、形容詞等
|
||
- 適合:基礎學習者
|
||
|
||
- **`"smart"`**: 智能萃取
|
||
- 重點:片語、俚語、慣用語、搭配
|
||
- 適合:進階學習者
|
||
|
||
### **SaveCardsRequest 參數**
|
||
| 參數 | 類型 | 必填 | 說明 |
|
||
|------|------|------|------|
|
||
| `cardSetId` | Guid | ✅ | 目標詞卡集合 ID |
|
||
| `selectedCards` | Array | ✅ | 要保存的詞卡陣列 |
|
||
|
||
### **GeneratedCard 結構**
|
||
```typescript
|
||
interface GeneratedCard {
|
||
word: string; // 單字原型
|
||
partOfSpeech: string; // 詞性 (n./v./adj./adv.等)
|
||
pronunciation: string; // IPA 音標
|
||
translation: string; // 繁體中文翻譯
|
||
definition: string; // 英文定義
|
||
synonyms?: string[]; // 同義詞 (最多2個)
|
||
example: string; // 例句
|
||
exampleTranslation: string; // 例句中文翻譯
|
||
difficultyLevel: string; // CEFR 等級 (A1/A2/B1/B2/C1/C2)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🛡️ **安全與驗證機制**
|
||
|
||
### **輸入驗證**
|
||
```csharp
|
||
// 文本長度驗證
|
||
if (request.InputText.Length > 5000) {
|
||
return BadRequest("Input text must be less than 5000 characters");
|
||
}
|
||
|
||
// 萃取類型驗證
|
||
if (!new[] { "vocabulary", "smart" }.Contains(request.ExtractionType)) {
|
||
return BadRequest("Invalid extraction type");
|
||
}
|
||
|
||
// 詞卡數量驗證
|
||
if (request.CardCount < 1 || request.CardCount > 20) {
|
||
return BadRequest("Card count must be between 1 and 20");
|
||
}
|
||
```
|
||
|
||
### **認證機制**
|
||
```csharp
|
||
var userId = await _authService.GetUserIdFromTokenAsync(Request.Headers.Authorization);
|
||
if (userId == null) {
|
||
return Unauthorized(new { Success = false, Error = "Invalid token" });
|
||
}
|
||
```
|
||
|
||
### **使用限制**
|
||
- 🔄 **目前狀態**: 使用限制已暫時關閉 (`isPremium: true`)
|
||
- 📊 **配額檢查**: 支援每日配額限制(可配置)
|
||
- 🏷️ **用戶追蹤**: 基於 JWT token 識別用戶身份
|
||
|
||
---
|
||
|
||
## 🔄 **完整工作流程**
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant F as 前端
|
||
participant A as AIController
|
||
participant G as GeminiService
|
||
participant D as Database
|
||
|
||
F->>A: POST /api/ai/generate
|
||
A->>A: 驗證輸入參數
|
||
A->>A: 檢查用戶認證
|
||
A->>A: 檢查使用配額
|
||
A->>G: GenerateCardsAsync()
|
||
G->>G: 構建 AI Prompt
|
||
G->>G: 呼叫 Gemini API
|
||
G->>G: 解析 JSON 回應
|
||
G->>A: 返回生成的詞卡
|
||
A->>F: 返回詞卡結果
|
||
|
||
F->>A: POST /api/ai/generate/{taskId}/save
|
||
A->>A: 驗證用戶認證
|
||
A->>D: 檢查詞卡集合存在
|
||
A->>D: 批量保存詞卡
|
||
A->>D: 更新集合統計
|
||
A->>F: 返回保存結果
|
||
```
|
||
|
||
---
|
||
|
||
## 🤖 **AI 服務整合詳解**
|
||
|
||
### **句子分析 Prompt 模板**
|
||
```csharp
|
||
// 位置: GeminiService.cs AnalyzeSentenceAsync() 方法
|
||
var prompt = $@"
|
||
請分析以下英文句子,提供完整的分析:
|
||
|
||
句子:{inputText}
|
||
|
||
請按照以下JSON格式回應,不要包含任何其他文字:
|
||
|
||
{
|
||
""translation"": ""自然流暢的繁體中文翻譯"",
|
||
""explanation"": ""詳細解釋句子的語法結構、詞彙特點、使用場景和學習要點"",
|
||
""grammarCorrection"": {
|
||
""hasErrors"": false,
|
||
""originalText"": ""{inputText}"",
|
||
""correctedText"": null,
|
||
""corrections"": []
|
||
},
|
||
""highValueWords"": [""重要詞彙1"", ""重要詞彙2""],
|
||
""wordAnalysis"": {
|
||
""單字"": {
|
||
""translation"": ""中文翻譯"",
|
||
""definition"": ""英文定義"",
|
||
""partOfSpeech"": ""詞性"",
|
||
""pronunciation"": ""音標"",
|
||
""isHighValue"": true,
|
||
""difficultyLevel"": ""CEFR等級""
|
||
}
|
||
}
|
||
}
|
||
|
||
要求:
|
||
1. 翻譯要自然流暢,符合中文語法
|
||
2. 解釋要具體有用,不要空泛
|
||
3. 標記B1以上詞彙為高價值
|
||
4. 如有語法錯誤請指出並修正
|
||
5. 確保JSON格式正確
|
||
";
|
||
```
|
||
|
||
**關鍵欄位解釋**:
|
||
- **`translation`**: 這就是前端顯示的「整句翻譯」
|
||
- **`explanation`**: 這就是前端顯示的「詳細解釋」部分
|
||
- **前端組合**: `translation + ' ' + explanation` = 完整的「整句意思」
|
||
|
||
### **詞卡生成 Prompt 模板**
|
||
```csharp
|
||
private const string VocabularyExtractionPrompt = @"
|
||
從以下英文文本中萃取 {cardCount} 個最重要的詞彙,為每個詞彙生成詞卡資料。
|
||
|
||
輸入文本:
|
||
{inputText}
|
||
|
||
請按照以下 JSON 格式回應,不要包含任何其他文字或代碼塊標記:
|
||
|
||
{
|
||
""cards"": [
|
||
{
|
||
""word"": ""單字原型"",
|
||
""part_of_speech"": ""詞性(n./v./adj./adv.等)"",
|
||
""pronunciation"": ""IPA音標"",
|
||
""translation"": ""繁體中文翻譯"",
|
||
""definition"": ""英文定義(保持A1-A2程度)"",
|
||
""synonyms"": [""同義詞1"", ""同義詞2""],
|
||
""example"": ""例句(使用原文中的句子或生成新句子)"",
|
||
""example_translation"": ""例句中文翻譯"",
|
||
""difficulty_level"": ""CEFR等級(A1/A2/B1/B2/C1/C2)""
|
||
}
|
||
]
|
||
}
|
||
|
||
要求:
|
||
1. 選擇最有學習價值的詞彙
|
||
2. 定義要簡單易懂,適合英語學習者
|
||
3. 例句要實用且符合語境
|
||
4. 確保 JSON 格式正確
|
||
5. 同義詞最多2個,選擇常用的";
|
||
```
|
||
|
||
### **智能萃取 Prompt**
|
||
```csharp
|
||
private const string SmartExtractionPrompt = @"
|
||
分析以下英文文本,識別片語、俚語和常用表達,生成 {cardCount} 個學習卡片:
|
||
|
||
輸入文本:
|
||
{inputText}
|
||
|
||
重點關注:
|
||
1. 片語和俚語
|
||
2. 文化相關表達
|
||
3. 語境特定用法
|
||
4. 慣用語和搭配
|
||
|
||
請按照相同的 JSON 格式回應...";
|
||
```
|
||
|
||
### **錯誤處理與回退機制**
|
||
```csharp
|
||
try {
|
||
var generatedCards = await _geminiService.GenerateCardsAsync(
|
||
request.InputText,
|
||
request.ExtractionType,
|
||
request.CardCount
|
||
);
|
||
return Ok(successResponse);
|
||
}
|
||
catch (InvalidOperationException ex) when (ex.Message.Contains("API key")) {
|
||
_logger.LogWarning("Gemini API key not configured, using mock data");
|
||
|
||
// 返回模擬資料
|
||
var mockCards = GenerateMockCards(request.CardCount);
|
||
return Ok(mockResponse);
|
||
}
|
||
catch (Exception ex) {
|
||
_logger.LogError(ex, "Error in AI card generation");
|
||
return StatusCode(500, errorResponse);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 💾 **資料庫設計**
|
||
|
||
### **Flashcard 資料表結構**
|
||
```sql
|
||
CREATE TABLE Flashcards (
|
||
Id UNIQUEIDENTIFIER PRIMARY KEY,
|
||
UserId UNIQUEIDENTIFIER NOT NULL,
|
||
CardSetId UNIQUEIDENTIFIER NOT NULL,
|
||
Word NVARCHAR(100) NOT NULL,
|
||
Translation NVARCHAR(200) NOT NULL,
|
||
Definition NVARCHAR(500),
|
||
PartOfSpeech NVARCHAR(50),
|
||
Pronunciation NVARCHAR(100),
|
||
Example NVARCHAR(500),
|
||
ExampleTranslation NVARCHAR(500),
|
||
DifficultyLevel NVARCHAR(10),
|
||
CreatedAt DATETIME2 NOT NULL,
|
||
UpdatedAt DATETIME2 NOT NULL,
|
||
|
||
FOREIGN KEY (UserId) REFERENCES Users(Id),
|
||
FOREIGN KEY (CardSetId) REFERENCES CardSets(Id)
|
||
);
|
||
```
|
||
|
||
### **CardSet 資料表結構**
|
||
```sql
|
||
CREATE TABLE CardSets (
|
||
Id UNIQUEIDENTIFIER PRIMARY KEY,
|
||
UserId UNIQUEIDENTIFIER NOT NULL,
|
||
Name NVARCHAR(100) NOT NULL,
|
||
Description NVARCHAR(500),
|
||
Color NVARCHAR(20),
|
||
CardCount INT DEFAULT 0,
|
||
IsDefault BIT DEFAULT 0,
|
||
CreatedAt DATETIME2 NOT NULL,
|
||
UpdatedAt DATETIME2 NOT NULL,
|
||
|
||
FOREIGN KEY (UserId) REFERENCES Users(Id)
|
||
);
|
||
```
|
||
|
||
### **自動建立預設詞卡集合**
|
||
```csharp
|
||
var defaultCardSet = await _context.CardSets
|
||
.FirstOrDefaultAsync(cs => cs.IsDefault);
|
||
|
||
if (defaultCardSet == null) {
|
||
defaultCardSet = new CardSet {
|
||
Id = Guid.NewGuid(),
|
||
UserId = userId.Value,
|
||
Name = "AI 生成詞卡",
|
||
Description = "通過 AI 智能生成的詞卡集合",
|
||
Color = "#3B82F6",
|
||
IsDefault = true,
|
||
CreatedAt = DateTime.UtcNow,
|
||
UpdatedAt = DateTime.UtcNow
|
||
};
|
||
_context.CardSets.Add(defaultCardSet);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 **錯誤處理與狀態碼**
|
||
|
||
### **HTTP 狀態碼說明**
|
||
| 狀態碼 | 情境 | 說明 |
|
||
|--------|------|------|
|
||
| `200 OK` | 成功 | 詞卡生成/保存成功 |
|
||
| `400 Bad Request` | 輸入錯誤 | 參數驗證失敗 |
|
||
| `401 Unauthorized` | 認證失敗 | JWT Token 無效或過期 |
|
||
| `404 Not Found` | 資源不存在 | 詞卡集合或詞卡不存在 |
|
||
| `429 Too Many Requests` | 配額超限 | 超過每日生成限制 |
|
||
| `500 Internal Server Error` | 服務錯誤 | AI 服務或資料庫錯誤 |
|
||
|
||
### **標準錯誤回應格式**
|
||
```json
|
||
{
|
||
"success": false,
|
||
"error": "Input text is required",
|
||
"details": "The inputText field cannot be null or empty",
|
||
"timestamp": "2025-01-18T15:54:00Z",
|
||
"errorCode": "VALIDATION_ERROR"
|
||
}
|
||
```
|
||
|
||
### **常見錯誤類型**
|
||
```csharp
|
||
// 輸入驗證錯誤
|
||
return BadRequest(new {
|
||
Success = false,
|
||
Error = "Input text must be less than 5000 characters",
|
||
ErrorCode = "INPUT_TOO_LONG"
|
||
});
|
||
|
||
// 認證錯誤
|
||
return Unauthorized(new {
|
||
Success = false,
|
||
Error = "Invalid token",
|
||
ErrorCode = "AUTH_FAILED"
|
||
});
|
||
|
||
// 配額超限
|
||
return StatusCode(429, new {
|
||
Success = false,
|
||
Error = "Daily generation limit exceeded",
|
||
ErrorCode = "QUOTA_EXCEEDED",
|
||
ResetTime = DateTime.UtcNow.AddDays(1)
|
||
});
|
||
|
||
// AI 服務錯誤
|
||
return StatusCode(500, new {
|
||
Success = false,
|
||
Error = "AI service temporarily unavailable",
|
||
ErrorCode = "AI_SERVICE_ERROR"
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 **環境配置**
|
||
|
||
### **必要環境變數**
|
||
```bash
|
||
# AI 服務配置
|
||
export DRAMALING_GEMINI_API_KEY="your-gemini-api-key-here"
|
||
|
||
# 資料庫配置
|
||
export DRAMALING_DB_CONNECTION="Host=localhost;Database=dramaling;Username=postgres;Password=your-password"
|
||
|
||
# JWT 配置
|
||
export DRAMALING_JWT_SECRET="your-jwt-secret-key"
|
||
export DRAMALING_JWT_ISSUER="dramaling-api"
|
||
export DRAMALING_JWT_AUDIENCE="dramaling-frontend"
|
||
```
|
||
|
||
### **appsettings.json 配置範例**
|
||
```json
|
||
{
|
||
"ConnectionStrings": {
|
||
"DefaultConnection": "Data Source=dramaling_test.db"
|
||
},
|
||
"JwtSettings": {
|
||
"SecretKey": "${DRAMALING_JWT_SECRET}",
|
||
"Issuer": "${DRAMALING_JWT_ISSUER}",
|
||
"Audience": "${DRAMALING_JWT_AUDIENCE}",
|
||
"ExpirationMinutes": 60
|
||
},
|
||
"GeminiSettings": {
|
||
"ApiKey": "${DRAMALING_GEMINI_API_KEY}",
|
||
"Model": "gemini-pro",
|
||
"MaxTokens": 2048,
|
||
"Temperature": 0.7
|
||
},
|
||
"UsageLimits": {
|
||
"FreeUserDailyLimit": 10,
|
||
"PremiumUserDailyLimit": 100,
|
||
"MaxTextLength": 5000,
|
||
"MaxCardCount": 20
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 **測試範例**
|
||
|
||
### **使用 cURL 測試**
|
||
|
||
#### **A. 句子分析功能測試**
|
||
```bash
|
||
# 1. 測試句子分析 (整句意思生成) - 無需認證
|
||
curl -X POST http://localhost:5000/api/ai/analyze-sentence \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"inputText": "The weather is beautiful today and I am planning to go hiking.",
|
||
"forceRefresh": false,
|
||
"analysisMode": "full"
|
||
}' | jq '.data.sentenceMeaning'
|
||
|
||
# 2. 測試互動式單字查詢
|
||
curl -X POST http://localhost:5000/api/ai/query-word \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"word": "beautiful",
|
||
"sentence": "The weather is beautiful today"
|
||
}'
|
||
```
|
||
|
||
#### **B. 詞卡生成功能測試**
|
||
```bash
|
||
# 1. 測試生成詞卡 (無需認證)
|
||
curl -X POST http://localhost:5000/api/ai/test/generate \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"inputText": "The weather is beautiful today and I am planning to go hiking in the mountains.",
|
||
"extractionType": "vocabulary",
|
||
"cardCount": 5
|
||
}'
|
||
|
||
# 2. 正式生成詞卡 (需要認證)
|
||
curl -X POST http://localhost:5000/api/ai/generate \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer your-jwt-token-here" \
|
||
-d '{
|
||
"inputText": "Learning English through movies and TV shows is an effective method.",
|
||
"extractionType": "smart",
|
||
"cardCount": 8
|
||
}'
|
||
|
||
# 3. 保存詞卡
|
||
curl -X POST http://localhost:5000/api/ai/test/generate/save \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"selectedCards": [
|
||
{
|
||
"word": "effective",
|
||
"translation": "有效的",
|
||
"definition": "successful in producing a desired result",
|
||
"partOfSpeech": "adj.",
|
||
"pronunciation": "/ɪˈfektɪv/",
|
||
"example": "This is an effective method",
|
||
"exampleTranslation": "這是一個有效的方法",
|
||
"difficultyLevel": "B2"
|
||
}
|
||
]
|
||
}'
|
||
```
|
||
|
||
### **前端 JavaScript 整合範例**
|
||
|
||
#### **A. 句子分析功能**
|
||
```javascript
|
||
// 分析句子獲得整句意思
|
||
async function analyzeSentence(text, forceRefresh = false) {
|
||
try {
|
||
const response = await fetch('/api/ai/analyze-sentence', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
inputText: text,
|
||
forceRefresh: forceRefresh,
|
||
analysisMode: 'full'
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
// 取得整句意思
|
||
const sentenceMeaning = result.data.sentenceMeaning;
|
||
console.log('翻譯:', sentenceMeaning.translation);
|
||
console.log('解釋:', sentenceMeaning.explanation);
|
||
|
||
// 取得詞彙分析
|
||
console.log('詞彙分析:', result.data.wordAnalysis);
|
||
console.log('高價值詞彙:', result.data.highValueWords);
|
||
|
||
return result.data;
|
||
} else {
|
||
throw new Error(result.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error analyzing sentence:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
// 查詢特定單字
|
||
async function queryWord(word, sentence) {
|
||
try {
|
||
const response = await fetch('/api/ai/query-word', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
word: word,
|
||
sentence: sentence
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
return result.data;
|
||
} catch (error) {
|
||
console.error('Error querying word:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### **B. 詞卡生成功能**
|
||
```javascript
|
||
// 生成詞卡
|
||
async function generateCards(text, type = 'vocabulary', count = 10) {
|
||
try {
|
||
const response = await fetch('/api/ai/generate', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||
},
|
||
body: JSON.stringify({
|
||
inputText: text,
|
||
extractionType: type,
|
||
cardCount: count
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
console.log('Generated cards:', result.data.generatedCards);
|
||
return result.data;
|
||
} else {
|
||
throw new Error(result.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error generating cards:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
// 保存詞卡
|
||
async function saveCards(taskId, cardSetId, selectedCards) {
|
||
try {
|
||
const response = await fetch(`/api/ai/generate/${taskId}/save`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||
},
|
||
body: JSON.stringify({
|
||
cardSetId: cardSetId,
|
||
selectedCards: selectedCards
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
console.log('Cards saved successfully:', result.data);
|
||
return result.data;
|
||
} else {
|
||
throw new Error(result.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error saving cards:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
// 使用範例
|
||
(async () => {
|
||
try {
|
||
// 生成詞卡
|
||
const generateResult = await generateCards(
|
||
"Artificial intelligence is transforming the way we learn languages.",
|
||
"smart",
|
||
6
|
||
);
|
||
|
||
// 保存選中的詞卡
|
||
const selectedCards = generateResult.generatedCards.slice(0, 3); // 選前3張
|
||
await saveCards(
|
||
generateResult.taskId,
|
||
'your-card-set-id',
|
||
selectedCards
|
||
);
|
||
|
||
console.log('Process completed successfully!');
|
||
} catch (error) {
|
||
console.error('Process failed:', error);
|
||
}
|
||
})();
|
||
```
|
||
|
||
---
|
||
|
||
## 📈 **效能與最佳實踐**
|
||
|
||
### **效能考量**
|
||
- 🚀 **快取策略**: 相同文本的分析結果可以快取
|
||
- ⚡ **非同步處理**: 長文本分析採用背景處理
|
||
- 🔄 **批量操作**: 一次保存多張詞卡減少資料庫操作
|
||
- 📊 **資源限制**: 限制同時處理的請求數量
|
||
|
||
### **最佳實踐**
|
||
```csharp
|
||
// 1. 使用交易確保資料一致性
|
||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||
try {
|
||
_context.Flashcards.AddRange(flashcardsToSave);
|
||
defaultCardSet.CardCount += flashcardsToSave.Count;
|
||
await _context.SaveChangesAsync();
|
||
await transaction.CommitAsync();
|
||
} catch {
|
||
await transaction.RollbackAsync();
|
||
throw;
|
||
}
|
||
|
||
// 2. 分頁處理大量結果
|
||
var cards = await _context.Flashcards
|
||
.Where(f => f.UserId == userId)
|
||
.OrderBy(f => f.CreatedAt)
|
||
.Skip(pageIndex * pageSize)
|
||
.Take(pageSize)
|
||
.ToListAsync();
|
||
|
||
// 3. 使用索引優化查詢
|
||
[Index(nameof(UserId), nameof(CreatedAt))]
|
||
public class Flashcard { /* ... */ }
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 **部署注意事項**
|
||
|
||
### **生產環境配置**
|
||
1. **安全性**:
|
||
- 使用 HTTPS 通訊
|
||
- 定期輪換 JWT Secret
|
||
- 實施 Rate Limiting
|
||
- 加密敏感資料
|
||
|
||
2. **監控**:
|
||
- API 回應時間監控
|
||
- 錯誤率追蹤
|
||
- 使用量統計
|
||
- AI 服務可用性監控
|
||
|
||
3. **擴展性**:
|
||
- 考慮使用佇列系統處理大量請求
|
||
- 資料庫連接池配置
|
||
- 負載平衡配置
|
||
- CDN 快取靜態資源
|
||
|
||
### **部署檢查清單**
|
||
- [ ] 環境變數正確設定
|
||
- [ ] 資料庫遷移完成
|
||
- [ ] AI API 金鑰有效
|
||
- [ ] JWT 配置正確
|
||
- [ ] CORS 設定完成
|
||
- [ ] 監控系統運行
|
||
- [ ] 備份策略實施
|
||
- [ ] 日誌記錄配置
|
||
|
||
---
|
||
|
||
## 📞 **支援與維護**
|
||
|
||
### **常見問題**
|
||
1. **Q: AI 生成的詞卡質量如何保證?**
|
||
A: 使用精心設計的 Prompt 模板,並提供詞卡驗證功能
|
||
|
||
2. **Q: 如何處理 AI 服務不可用的情況?**
|
||
A: 實施回退機制,返回預設模擬資料確保服務可用性
|
||
|
||
3. **Q: 支援哪些語言和難度等級?**
|
||
A: 目前專注於英語學習,支援 CEFR A1-C2 等級
|
||
|
||
### **技術支援**
|
||
- 📧 **開發團隊**: dev@dramaling.com
|
||
- 📚 **文檔庫**: `/docs/api/`
|
||
- 🐛 **問題回報**: GitHub Issues
|
||
- 💬 **即時支援**: Slack #dramaling-dev
|
||
|
||
---
|
||
|
||
**© 2025 DramaLing Team. All rights reserved.** |