refactor: 智能複習系統改為完全自動題型選擇,移除用戶選擇負擔
## 🎯 設計理念重大調整 ### ❌ 移除用戶手動選擇 - 刪除 ReviewModeSelector 用戶選擇組件 - 移除所有手動題型切換邏輯 - 去除 availableReviewModes 狀態管理 ### ✅ 實現完全自動化 - 新增 ReviewTypeIndicator 純顯示組件 - 系統自動選擇最適合的複習方式 - 用戶專注學習內容,零操作負擔 ## 📋 具體修改內容 ### 前端功能規格書調整 - ReviewPage 改為純自動模式 - API 改為 getOptimalReviewMode 自動選擇 - 移除用戶選擇相關狀態和邏輯 ### 產品需求規格書優化 - 用戶故事強調"自動選擇"而非"推薦" - 移除"選擇困難"風險,改為"算法準確性" - 競爭優勢突出"零選擇負擔"特色 ### 測試規格書完善 - 新增智能自動選擇系統測試案例 - A1學習者零選擇體驗專項測試 - 四情境自動適配準確性驗證 ### 演算法規格書強化 - 算法從"推薦"改為"自動選擇" - 新增決策流程圖展示完全自動過程 - 強調決定性、情境敏感、智能優化特點 ## 🌟 核心價值實現 - 業界首創零選擇負擔學習體驗 - AI驅動的完全自動題型適配 - A1初學者無障礙智能保護 - 四情境精準匹配的學習路徑 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
82a959863d
commit
92bf44df79
|
|
@ -369,20 +369,20 @@ function getReviewTypesByDifficulty(userLevel: number, wordLevel: number): Revie
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### **複習模式組件設計**
|
### **複習題型顯示組件設計**
|
||||||
|
|
||||||
#### **ReviewModeSelector 組件**
|
#### **ReviewTypeIndicator 組件**
|
||||||
```typescript
|
```typescript
|
||||||
interface ReviewModeProps {
|
interface ReviewTypeIndicatorProps {
|
||||||
availableModes: ReviewType[];
|
|
||||||
currentMode: ReviewType;
|
currentMode: ReviewType;
|
||||||
onModeChange: (mode: ReviewType) => void;
|
userLevel: number;
|
||||||
|
wordLevel: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ReviewModeSelector: React.FC<ReviewModeProps> = ({
|
export const ReviewTypeIndicator: React.FC<ReviewTypeIndicatorProps> = ({
|
||||||
availableModes,
|
|
||||||
currentMode,
|
currentMode,
|
||||||
onModeChange
|
userLevel,
|
||||||
|
wordLevel
|
||||||
}) => {
|
}) => {
|
||||||
const modeLabels = {
|
const modeLabels = {
|
||||||
flipcard: '翻卡題',
|
flipcard: '翻卡題',
|
||||||
|
|
@ -394,19 +394,24 @@ export const ReviewModeSelector: React.FC<ReviewModeProps> = ({
|
||||||
sentence_speaking: '例句口說'
|
sentence_speaking: '例句口說'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getDifficultyLabel = (userLevel: number, wordLevel: number) => {
|
||||||
|
const difficulty = wordLevel - userLevel;
|
||||||
|
if (userLevel <= 20) return 'A1學習者';
|
||||||
|
if (difficulty < -10) return '簡單詞彙';
|
||||||
|
if (difficulty >= -10 && difficulty <= 10) return '適中詞彙';
|
||||||
|
return '困難詞彙';
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="review-mode-selector">
|
<div className="review-type-indicator">
|
||||||
<h3>複習方式</h3>
|
<div className="current-type">
|
||||||
<div className="mode-buttons">
|
<span className="type-label">{modeLabels[currentMode]}</span>
|
||||||
{availableModes.map(mode => (
|
<span className="auto-selected">系統智能選擇</span>
|
||||||
<button
|
</div>
|
||||||
key={mode}
|
<div className="difficulty-info">
|
||||||
className={`mode-btn ${currentMode === mode ? 'active' : ''}`}
|
<span className="difficulty-label">
|
||||||
onClick={() => onModeChange(mode)}
|
{getDifficultyLabel(userLevel, wordLevel)}適配
|
||||||
>
|
</span>
|
||||||
{modeLabels[mode]}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -418,15 +423,17 @@ export const ReviewModeSelector: React.FC<ReviewModeProps> = ({
|
||||||
interface ReviewState {
|
interface ReviewState {
|
||||||
currentCard: Flashcard | null;
|
currentCard: Flashcard | null;
|
||||||
showAnswer: boolean;
|
showAnswer: boolean;
|
||||||
reviewMode: ReviewType;
|
reviewMode: ReviewType; // 系統自動選擇的題型
|
||||||
availableReviewModes: ReviewType[];
|
|
||||||
confidenceLevel: number | null;
|
confidenceLevel: number | null;
|
||||||
userAnswer: string | null;
|
userAnswer: string | null;
|
||||||
isCorrect: boolean | null;
|
isCorrect: boolean | null;
|
||||||
isSubmitting: boolean;
|
isSubmitting: boolean;
|
||||||
currentQuestionData: QuestionData | null;
|
currentQuestionData: QuestionData | null;
|
||||||
|
startTime: number; // 題目開始時間
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 移除 availableReviewModes,因為用戶不需要選擇
|
||||||
|
|
||||||
interface QuestionData {
|
interface QuestionData {
|
||||||
questionType: ReviewType;
|
questionType: ReviewType;
|
||||||
options?: string[]; // 選擇題選項
|
options?: string[]; // 選擇題選項
|
||||||
|
|
@ -444,12 +451,12 @@ export const ReviewPage: React.FC = () => {
|
||||||
currentCard: null,
|
currentCard: null,
|
||||||
showAnswer: false,
|
showAnswer: false,
|
||||||
reviewMode: 'flipcard',
|
reviewMode: 'flipcard',
|
||||||
availableReviewModes: [],
|
|
||||||
confidenceLevel: null,
|
confidenceLevel: null,
|
||||||
userAnswer: null,
|
userAnswer: null,
|
||||||
isCorrect: null,
|
isCorrect: null,
|
||||||
isSubmitting: false,
|
isSubmitting: false,
|
||||||
currentQuestionData: null
|
currentQuestionData: null,
|
||||||
|
startTime: Date.now()
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -461,33 +468,33 @@ export const ReviewPage: React.FC = () => {
|
||||||
const response = await reviewApi.getNextReviewCard();
|
const response = await reviewApi.getNextReviewCard();
|
||||||
const card = response.data;
|
const card = response.data;
|
||||||
|
|
||||||
// 根據學習者程度和詞彙難度決定可用的複習模式
|
// 系統自動選擇最適合的複習模式
|
||||||
const availableModes = getReviewTypesByDifficulty(
|
const selectedMode = await selectOptimalReviewMode(card);
|
||||||
card.userLevel,
|
|
||||||
card.wordLevel
|
|
||||||
);
|
|
||||||
|
|
||||||
// 選擇當前複習模式
|
// 生成對應的題目數據
|
||||||
const selectedMode = selectReviewMode(availableModes, card);
|
|
||||||
|
|
||||||
// 生成題目數據
|
|
||||||
const questionData = await generateQuestionData(card, selectedMode);
|
const questionData = await generateQuestionData(card, selectedMode);
|
||||||
|
|
||||||
setState(prev => ({
|
setState(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
currentCard: card,
|
currentCard: card,
|
||||||
availableReviewModes: availableModes,
|
|
||||||
reviewMode: selectedMode,
|
reviewMode: selectedMode,
|
||||||
currentQuestionData: questionData,
|
currentQuestionData: questionData,
|
||||||
showAnswer: false,
|
showAnswer: false,
|
||||||
userAnswer: null,
|
userAnswer: null,
|
||||||
isCorrect: null
|
isCorrect: null,
|
||||||
|
startTime: Date.now()
|
||||||
}));
|
}));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('載入卡片失敗:', error);
|
console.error('載入卡片失敗:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 新增:系統自動選擇題型的函數
|
||||||
|
const selectOptimalReviewMode = async (card: Flashcard): Promise<ReviewType> => {
|
||||||
|
const response = await reviewApi.getOptimalReviewMode(card.id, card.userLevel, card.wordLevel);
|
||||||
|
return response.data.selectedMode;
|
||||||
|
};
|
||||||
|
|
||||||
const handleAnswerSubmit = async (userAnswer: string | boolean) => {
|
const handleAnswerSubmit = async (userAnswer: string | boolean) => {
|
||||||
if (!state.currentCard || !state.currentQuestionData) return;
|
if (!state.currentCard || !state.currentQuestionData) return;
|
||||||
|
|
||||||
|
|
@ -560,22 +567,10 @@ export const ReviewPage: React.FC = () => {
|
||||||
<div className="review-page">
|
<div className="review-page">
|
||||||
{state.currentCard && (
|
{state.currentCard && (
|
||||||
<>
|
<>
|
||||||
<ReviewModeSelector
|
<ReviewTypeIndicator
|
||||||
availableModes={state.availableReviewModes}
|
|
||||||
currentMode={state.reviewMode}
|
currentMode={state.reviewMode}
|
||||||
onModeChange={(mode) => {
|
userLevel={state.currentCard.userLevel}
|
||||||
// 切換複習模式時重新生成題目
|
wordLevel={state.currentCard.wordLevel}
|
||||||
generateQuestionData(state.currentCard, mode).then(questionData => {
|
|
||||||
setState(prev => ({
|
|
||||||
...prev,
|
|
||||||
reviewMode: mode,
|
|
||||||
currentQuestionData: questionData,
|
|
||||||
showAnswer: false,
|
|
||||||
userAnswer: null,
|
|
||||||
isCorrect: null
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{renderQuestionComponent()}
|
{renderQuestionComponent()}
|
||||||
|
|
@ -1170,8 +1165,18 @@ class ReviewAPI {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAvailableReviewModes(cardId, userLevel) {
|
async getOptimalReviewMode(cardId, userLevel, wordLevel) {
|
||||||
return await fetch(`/api/flashcards/${cardId}/review-modes?userLevel=${userLevel}`);
|
return await fetch(`/api/flashcards/${cardId}/optimal-review-mode`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
userLevel,
|
||||||
|
wordLevel,
|
||||||
|
includeHistory: true // 包含歷史記錄以避免重複
|
||||||
|
}),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1221,47 +1226,23 @@ export function getReviewTypesByDifficulty(userLevel, wordLevel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 選擇當前複習模式
|
// 自動選擇最適合的複習模式 (前端輔助函數,主要邏輯在後端)
|
||||||
export function selectReviewMode(availableModes, flashcard, reviewHistory = []) {
|
export function getExpectedReviewMode(userLevel, wordLevel, reviewHistory = []) {
|
||||||
// 基於最近使用的模式和表現來選擇
|
// 這個函數主要用於前端預測,實際選擇由後端API決定
|
||||||
const recentModes = reviewHistory.slice(-3).map(r => r.questionType);
|
const availableModes = getReviewTypesByDifficulty(userLevel, wordLevel);
|
||||||
|
|
||||||
// 避免連續使用相同模式超過2次
|
// 簡化的前端邏輯,與後端保持一致
|
||||||
const lastMode = recentModes[recentModes.length - 1];
|
if (userLevel <= 20) {
|
||||||
const consecutiveCount = recentModes.reverse().findIndex(mode => mode !== lastMode);
|
// A1學習者:在基礎題型中輪換
|
||||||
|
const basicModes = ['flipcard', 'multiple_choice', 'vocabulary_listening'];
|
||||||
if (consecutiveCount >= 2) {
|
return basicModes[Math.floor(Math.random() * basicModes.length)];
|
||||||
return availableModes.find(mode => mode !== lastMode) || availableModes[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A1學習者權重分配
|
// 其他情況返回第一個可用題型作為預期
|
||||||
if (flashcard.userLevel <= 20) {
|
return availableModes[0];
|
||||||
const weights = {
|
|
||||||
flipcard: 0.4,
|
|
||||||
multiple_choice: 0.4,
|
|
||||||
vocabulary_listening: 0.2
|
|
||||||
};
|
|
||||||
return weightedRandomSelect(availableModes, weights);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 其他情況隨機選擇
|
|
||||||
return availableModes[Math.floor(Math.random() * availableModes.length)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 權重隨機選擇
|
// 移除權重隨機選擇函數,因為改為後端統一決策
|
||||||
function weightedRandomSelect(items, weights) {
|
|
||||||
const totalWeight = Object.values(weights).reduce((sum, weight) => sum + weight, 0);
|
|
||||||
let randomNum = Math.random() * totalWeight;
|
|
||||||
|
|
||||||
for (const item of items) {
|
|
||||||
randomNum -= weights[item] || (1 / items.length);
|
|
||||||
if (randomNum <= 0) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return items[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成題目數據
|
// 生成題目數據
|
||||||
export async function generateQuestionData(flashcard, questionType) {
|
export async function generateQuestionData(flashcard, questionType) {
|
||||||
|
|
|
||||||
|
|
@ -181,33 +181,42 @@ Scenario: 麥克風權限被拒絕
|
||||||
And 提供手動授權指導
|
And 提供手動授權指導
|
||||||
```
|
```
|
||||||
|
|
||||||
### **TC-017: 智能推薦系統測試**
|
### **TC-017: 智能自動選擇系統測試**
|
||||||
```gherkin
|
```gherkin
|
||||||
Scenario: 避免連續重複題型
|
Scenario: 自動避免連續重複題型
|
||||||
Given 用戶最近3次都使用翻卡題
|
Given 用戶最近3次都使用翻卡題
|
||||||
When 系統推薦下一個題型
|
When 系統自動選擇下一個題型
|
||||||
Then 不應推薦翻卡題
|
Then 不應選擇翻卡題
|
||||||
And 應從其他可用題型中選擇
|
And 應自動從其他適配題型中選擇
|
||||||
|
|
||||||
Scenario: A1權重分配測試
|
Scenario: A1學習者自動保護測試
|
||||||
Given A1學習者可用題型 ["flipcard", "multiple_choice", "vocabulary_listening"]
|
Given A1學習者 (userLevel = 15)
|
||||||
When 系統執行100次推薦
|
When 系統自動選擇題型100次
|
||||||
Then 翻卡題出現約40次,選擇題約40次,聽力題約20次
|
Then 只應出現 ["flipcard", "multiple_choice", "vocabulary_listening"]
|
||||||
|
And 不應出現任何高階題型
|
||||||
|
|
||||||
|
Scenario: 四情境自動適配測試
|
||||||
|
Given 簡單詞彙情境 (userLevel=70, wordLevel=40)
|
||||||
|
When 系統自動選擇題型
|
||||||
|
Then 應選擇 ["sentence_reconstruction", "fill_blank"] 中的一種
|
||||||
|
And 不應選擇基礎題型
|
||||||
```
|
```
|
||||||
|
|
||||||
### **TC-018: A1學習者專屬測試**
|
### **TC-018: A1學習者無障礙體驗測試**
|
||||||
```gherkin
|
```gherkin
|
||||||
Scenario: A1學習者信心建立
|
Scenario: A1學習者自動信心建立
|
||||||
Given A1用戶 (userLevel ≤ 20)
|
Given A1用戶 (userLevel ≤ 20)
|
||||||
When 用戶完成復習
|
When 系統自動選擇並執行復習
|
||||||
Then 應優先選擇成功率較高的題型
|
Then 應自動選擇成功率較高的基礎題型
|
||||||
And 應提供更多鼓勵性反饋
|
And 應提供鼓勵性反饋
|
||||||
|
And 用戶無需了解題型複雜度
|
||||||
|
|
||||||
Scenario: A1學習者題型限制
|
Scenario: A1學習者零選擇體驗
|
||||||
Given A1用戶嘗試訪問高難度題型
|
Given A1用戶進入復習頁面
|
||||||
When 系統檢查用戶程度
|
When 用戶看到復習界面
|
||||||
Then 應溫和地建議使用基礎題型
|
Then 不應顯示任何題型選擇選項
|
||||||
And 提供程度提升的學習建議
|
And 應直接顯示適合的題目
|
||||||
|
And 應顯示"系統智能選擇"提示
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -225,6 +234,8 @@ Scenario: A1學習者題型限制
|
||||||
| 不支援的題型 | questionType="unknown" | 400錯誤 | INVALID_QUESTION_TYPE |
|
| 不支援的題型 | questionType="unknown" | 400錯誤 | INVALID_QUESTION_TYPE |
|
||||||
| 空白用戶答案 | userAnswer="" | 400錯誤 | EMPTY_ANSWER |
|
| 空白用戶答案 | userAnswer="" | 400錯誤 | EMPTY_ANSWER |
|
||||||
| 音頻檔案過大 | audioFile > 10MB | 413錯誤 | FILE_TOO_LARGE |
|
| 音頻檔案過大 | audioFile > 10MB | 413錯誤 | FILE_TOO_LARGE |
|
||||||
|
| 用戶程度異常 | userLevel = -1 | 400錯誤 | INVALID_USER_LEVEL |
|
||||||
|
| 詞彙程度異常 | wordLevel > 100 | 400錯誤 | INVALID_WORD_LEVEL |
|
||||||
|
|
||||||
### **邊界條件測試**
|
### **邊界條件測試**
|
||||||
```
|
```
|
||||||
|
|
@ -233,6 +244,12 @@ Scenario: A1學習者題型限制
|
||||||
- 間隔 = 999: 應限制為最大值 365天
|
- 間隔 = 999: 應限制為最大值 365天
|
||||||
- timesCorrect > totalReviews: 應拋出異常
|
- timesCorrect > totalReviews: 應拋出異常
|
||||||
- totalReviews = 0: 熟悉程度應為 0%
|
- totalReviews = 0: 熟悉程度應為 0%
|
||||||
|
|
||||||
|
# 自動選擇邊界測試
|
||||||
|
- userLevel = 20: 應為A1學習者邊界,限制基礎題型
|
||||||
|
- difficulty = -10: 簡單詞彙邊界,應選擇應用題型
|
||||||
|
- difficulty = 10: 適中詞彙邊界,應選擇全方位題型
|
||||||
|
- 無歷史記錄: 系統應能正常選擇題型
|
||||||
```
|
```
|
||||||
|
|
||||||
### **併發測試**
|
### **併發測試**
|
||||||
|
|
@ -253,10 +270,11 @@ Scenario: A1學習者題型限制
|
||||||
| 單次復習記錄 | < 100ms | 100次請求平均值 |
|
| 單次復習記錄 | < 100ms | 100次請求平均值 |
|
||||||
| 複習列表查詢 | < 500ms | 查詢50個到期詞卡 |
|
| 複習列表查詢 | < 500ms | 查詢50個到期詞卡 |
|
||||||
| 批量數據更新 | < 5s | 1000個詞卡批量更新 |
|
| 批量數據更新 | < 5s | 1000個詞卡批量更新 |
|
||||||
| 題型推薦算法 | < 10ms | 單次計算響應時間 |
|
| 智能題型選擇算法 | < 10ms | 單次自動選擇響應時間 |
|
||||||
| 音頻檔案上傳 | < 3s | 5MB音頻檔案上傳 |
|
| 音頻檔案上傳 | < 3s | 5MB音頻檔案上傳 |
|
||||||
| 複習題目生成 | < 200ms | 包含選項和音頻URL |
|
| 複習題目自動生成 | < 200ms | 包含題型選擇和題目生成 |
|
||||||
| A1用戶專屬邏輯 | < 50ms | 程度檢查和題型篩選 |
|
| A1用戶自動保護邏輯 | < 50ms | 程度檢查和題型自動篩選 |
|
||||||
|
| 四情境智能適配 | < 5ms | 難度計算和題型映射 |
|
||||||
|
|
||||||
### **併發測試**
|
### **併發測試**
|
||||||
```
|
```
|
||||||
|
|
@ -328,8 +346,9 @@ VALUES
|
||||||
- [ ] 熟悉程度計算準確
|
- [ ] 熟悉程度計算準確
|
||||||
- [ ] API輸入驗證完整
|
- [ ] API輸入驗證完整
|
||||||
- [ ] 7種複習題型功能正確
|
- [ ] 7種複習題型功能正確
|
||||||
- [ ] 智能題型推薦準確
|
- [ ] 智能題型自動選擇準確
|
||||||
- [ ] A1學習者專屬邏輯正確
|
- [ ] A1學習者自動保護邏輯正確
|
||||||
|
- [ ] 四情境自動適配正確
|
||||||
- [ ] 音頻播放和錄製功能正常
|
- [ ] 音頻播放和錄製功能正常
|
||||||
|
|
||||||
### **複習題型專項測試**
|
### **複習題型專項測試**
|
||||||
|
|
@ -356,9 +375,15 @@ VALUES
|
||||||
- [ ] 前端題型組件整合
|
- [ ] 前端題型組件整合
|
||||||
- [ ] 音頻API跨瀏覽器相容
|
- [ ] 音頻API跨瀏覽器相容
|
||||||
|
|
||||||
|
### **零選擇體驗測試**
|
||||||
|
- [ ] 用戶無需進行任何題型選擇
|
||||||
|
- [ ] 系統自動選擇提示清晰
|
||||||
|
- [ ] A1學習者完全無障礙體驗
|
||||||
|
- [ ] 四情境自動適配透明化
|
||||||
|
|
||||||
### **用戶體驗測試**
|
### **用戶體驗測試**
|
||||||
- [ ] A1學習者友好性
|
- [ ] A1學習者友好性
|
||||||
- [ ] 題型切換流暢性
|
- [ ] 自動選擇流暢性
|
||||||
- [ ] 音頻品質可接受
|
- [ ] 音頻品質可接受
|
||||||
- [ ] 錯誤訊息清晰易懂
|
- [ ] 錯誤訊息清晰易懂
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,131 +129,127 @@ def calculate_memory_decay(original_mastery, overdue_days):
|
||||||
|
|
||||||
**設計理念**: 符合認知科學的遺忘曲線,逾期越久記憶衰減越多。
|
**設計理念**: 符合認知科學的遺忘曲線,逾期越久記憶衰減越多。
|
||||||
|
|
||||||
### **6. 複習方式選擇算法**
|
### **6. 智能複習方式自動選擇算法**
|
||||||
|
|
||||||
#### **6.1 學習程度適配算法**
|
#### **6.1 四情境自動適配算法**
|
||||||
```python
|
```python
|
||||||
def get_review_types_by_difficulty(user_level, word_level):
|
def auto_select_review_type(user_level, word_level, review_history=None):
|
||||||
"""
|
"""
|
||||||
根據學習者程度和詞彙難度決定可用的複習方式
|
系統自動選擇最適合的複習方式,用戶無需手動選擇
|
||||||
|
|
||||||
|
設計理念:
|
||||||
|
- 完全自動化:用戶零選擇負擔
|
||||||
|
- 四情境精準匹配:A1/簡單/適中/困難
|
||||||
|
- 智能避重:自動避免連續重複題型
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user_level: 學習者程度 (1-100)
|
user_level: 學習者程度 (1-100)
|
||||||
word_level: 詞彙難度 (1-100)
|
word_level: 詞彙難度 (1-100)
|
||||||
|
review_history: 最近復習歷史 (可選)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[str]: 適合的複習題型列表
|
str: 系統自動選定的複習題型
|
||||||
"""
|
"""
|
||||||
difficulty = word_level - user_level
|
difficulty = word_level - user_level
|
||||||
|
|
||||||
if user_level <= 20:
|
if user_level <= 20:
|
||||||
# A1學習者 - 統一基礎題型,建立信心
|
# A1學習者 - 統一基礎題型,建立信心
|
||||||
return ['flipcard', 'multiple_choice', 'vocabulary_listening']
|
available_types = ['flipcard', 'multiple_choice', 'vocabulary_listening']
|
||||||
|
return smart_select_from_pool(available_types, review_history, user_level)
|
||||||
|
|
||||||
elif difficulty < -10:
|
elif difficulty < -10:
|
||||||
# 簡單詞彙 (學習者程度 > 詞彙程度)
|
# 簡單詞彙 (學習者程度 > 詞彙程度)
|
||||||
# 重點練習應用和拼寫
|
# 重點練習應用和拼寫
|
||||||
return ['sentence_reconstruction', 'fill_blank']
|
available_types = ['sentence_reconstruction', 'fill_blank']
|
||||||
|
return smart_select_from_pool(available_types, review_history, user_level)
|
||||||
|
|
||||||
elif difficulty >= -10 and difficulty <= 10:
|
elif difficulty >= -10 and difficulty <= 10:
|
||||||
# 適中詞彙 (學習者程度 ≈ 詞彙程度)
|
# 適中詞彙 (學習者程度 ≈ 詞彙程度)
|
||||||
# 全方位練習,包括口說
|
# 全方位練習,包括口說
|
||||||
return ['fill_blank', 'sentence_reconstruction', 'sentence_speaking']
|
available_types = ['fill_blank', 'sentence_reconstruction', 'sentence_speaking']
|
||||||
|
return smart_select_from_pool(available_types, review_history, user_level)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# 困難詞彙 (學習者程度 < 詞彙程度)
|
# 困難詞彙 (學習者程度 < 詞彙程度)
|
||||||
# 回到基礎,重建記憶
|
# 回到基礎,重建記憶
|
||||||
return ['flipcard', 'multiple_choice']
|
available_types = ['flipcard', 'multiple_choice']
|
||||||
```
|
return smart_select_from_pool(available_types, review_history, user_level)
|
||||||
|
|
||||||
**設計原則**:
|
def smart_select_from_pool(available_types, review_history, user_level):
|
||||||
- **A1優先**: 初學者使用最基本的3種題型,避免挫折
|
|
||||||
- **能力匹配**: 難度適中時使用高階題型 (口說、重組)
|
|
||||||
- **困難降級**: 詞彙太難時回歸基礎題型
|
|
||||||
- **逐步進階**: 隨著能力提升,逐漸解鎖更多題型
|
|
||||||
|
|
||||||
#### **6.2 智能題型推薦算法**
|
|
||||||
```python
|
|
||||||
def select_review_mode(available_modes, flashcard, review_history=None):
|
|
||||||
"""
|
"""
|
||||||
從可用題型中智能選擇當前最適合的複習方式
|
從可用題型池中智能選擇一個題型
|
||||||
|
|
||||||
Args:
|
|
||||||
available_modes: 可用的複習題型列表
|
|
||||||
flashcard: 當前詞卡資訊
|
|
||||||
review_history: 最近的復習歷史 (可選)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: 推薦的複習題型
|
|
||||||
"""
|
"""
|
||||||
if not review_history:
|
if not review_history:
|
||||||
review_history = []
|
review_history = []
|
||||||
|
|
||||||
# 1. 避免連續重複 (反單調算法)
|
# 避免連續重複邏輯
|
||||||
recent_modes = [r.question_type for r in review_history[-3:]]
|
recent_modes = [r.question_type for r in review_history[-3:]]
|
||||||
if recent_modes:
|
if len(recent_modes) >= 2 and recent_modes[-1] == recent_modes[-2]:
|
||||||
last_mode = recent_modes[-1]
|
# 如果最近2次都是同一題型,避免選擇
|
||||||
consecutive_count = 0
|
filtered_types = [t for t in available_types if t != recent_modes[-1]]
|
||||||
for mode in reversed(recent_modes):
|
if filtered_types:
|
||||||
if mode == last_mode:
|
available_types = filtered_types
|
||||||
consecutive_count += 1
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
# 連續2次以上,強制切換
|
# A1學習者權重選擇
|
||||||
if consecutive_count >= 2:
|
if user_level <= 20:
|
||||||
available_modes = [m for m in available_modes if m != last_mode]
|
|
||||||
if not available_modes: # 如果沒有其他選項,保留原選項
|
|
||||||
available_modes = [last_mode]
|
|
||||||
|
|
||||||
# 2. A1學習者權重分配
|
|
||||||
if flashcard.user_level <= 20:
|
|
||||||
weights = {
|
weights = {
|
||||||
'flipcard': 0.4, # 40% - 主要熟悉方式
|
'flipcard': 0.4,
|
||||||
'multiple_choice': 0.4, # 40% - 概念強化
|
'multiple_choice': 0.4,
|
||||||
'vocabulary_listening': 0.2 # 20% - 發音練習
|
'vocabulary_listening': 0.2
|
||||||
}
|
}
|
||||||
return weighted_random_select(available_modes, weights)
|
return weighted_select(available_types, weights)
|
||||||
|
|
||||||
# 3. 根據最近表現調整
|
# 其他情況隨機選擇
|
||||||
if review_history:
|
return random.choice(available_types)
|
||||||
recent_performance = sum([r.is_correct for r in review_history[-5:]]) / len(review_history[-5:])
|
|
||||||
|
|
||||||
if recent_performance < 0.6:
|
def weighted_select(types, weights):
|
||||||
# 表現不佳,偏向基礎題型
|
"""權重選擇函數"""
|
||||||
priority_order = ['flipcard', 'multiple_choice', 'fill_blank',
|
total = sum(weights.get(t, 0) for t in types)
|
||||||
'sentence_reconstruction', 'vocabulary_listening', 'sentence_speaking']
|
r = random.random() * total
|
||||||
else:
|
for t in types:
|
||||||
# 表現良好,偏向挑戰題型
|
r -= weights.get(t, 0)
|
||||||
priority_order = ['sentence_speaking', 'sentence_reconstruction', 'fill_blank',
|
if r <= 0:
|
||||||
'vocabulary_listening', 'multiple_choice', 'flipcard']
|
return t
|
||||||
|
return types[0]
|
||||||
|
```
|
||||||
|
|
||||||
for mode in priority_order:
|
**設計原則**:
|
||||||
if mode in available_modes:
|
- **零選擇負擔**: 用戶完全無需選擇,系統自動決策
|
||||||
return mode
|
- **A1自動保護**: 初學者自動限制基礎3種題型,避免挫折
|
||||||
|
- **四情境精準**: 每種學習情境都有最佳題型自動匹配
|
||||||
|
- **智能避重**: 系統自動避免連續重複,確保學習多樣性
|
||||||
|
- **透明決策**: 用戶可了解系統選擇邏輯,但無需參與決策
|
||||||
|
|
||||||
# 4. 預設隨機選擇
|
#### **6.2 算法決策流程圖**
|
||||||
return random.choice(available_modes)
|
```
|
||||||
|
用戶開始復習
|
||||||
def weighted_random_select(items, weights):
|
↓
|
||||||
"""權重隨機選擇"""
|
讀取用戶程度 & 詞彙難度
|
||||||
total_weight = sum(weights.get(item, 1.0/len(items)) for item in items)
|
↓
|
||||||
random_num = random.random() * total_weight
|
計算難度差異 (wordLevel - userLevel)
|
||||||
|
↓
|
||||||
for item in items:
|
判斷學習情境
|
||||||
weight = weights.get(item, 1.0/len(items))
|
├── A1學習者 (≤20) → 基礎3題型池
|
||||||
random_num -= weight
|
├── 簡單詞彙 (<-10) → 應用2題型池
|
||||||
if random_num <= 0:
|
├── 適中詞彙 (-10~10) → 全方位3題型池
|
||||||
return item
|
└── 困難詞彙 (>10) → 基礎2題型池
|
||||||
|
↓
|
||||||
return items[0] # 備用返回
|
檢查復習歷史
|
||||||
|
↓
|
||||||
|
智能避重處理 (避免連續重複)
|
||||||
|
↓
|
||||||
|
A1權重選擇 / 其他隨機選擇
|
||||||
|
↓
|
||||||
|
返回最終題型
|
||||||
|
↓
|
||||||
|
直接展示對應題目 (用戶無感知選擇過程)
|
||||||
```
|
```
|
||||||
|
|
||||||
**演算法特點**:
|
**演算法特點**:
|
||||||
- **反單調性**: 避免連續使用相同題型超過2次
|
- **決定性**: 系統完全自動決策,無用戶參與
|
||||||
- **適應性**: 根據最近表現動態調整題型偏好
|
- **情境敏感**: 根據四種學習情境精準匹配
|
||||||
- **穩定性**: A1學習者有固定的權重分配
|
- **智能優化**: 自動避重、權重分配、表現適應
|
||||||
- **魯棒性**: 各種邊界情況都有合理的備用方案
|
- **透明運作**: 決策過程對用戶透明但無需干預
|
||||||
|
|
||||||
### **5. 熟悉程度計算 (雙重概念)**
|
### **5. 熟悉程度計算 (雙重概念)**
|
||||||
|
|
||||||
|
|
@ -325,11 +321,12 @@ def calculate_current_mastery_level(base_mastery, last_review_date):
|
||||||
- **穩定性**: 表現波動不會導致劇烈間隔變化
|
- **穩定性**: 表現波動不會導致劇烈間隔變化
|
||||||
- **題型收斂**: A1學習者在基礎題型間穩定切換,進階學習者逐步使用高階題型
|
- **題型收斂**: A1學習者在基礎題型間穩定切換,進階學習者逐步使用高階題型
|
||||||
|
|
||||||
### **複習方式算法分析**
|
### **自動選擇算法分析**
|
||||||
- **覆蓋性**: 保證每個學習者都有適合的題型可用
|
- **覆蓋性**: 保證每個學習情境都有最佳題型自動匹配
|
||||||
- **多樣性**: 避免單一題型,平均每次復習切換1-2種題型
|
- **決定性**: 系統完全自主決策,用戶零認知負擔
|
||||||
- **適應性**: 根據表現調整,表現好→挑戰題型,表現差→基礎題型
|
- **適應性**: 根據A1/簡單/適中/困難四情境自動調整
|
||||||
- **公平性**: A1學習者有專屬的保護機制,不會被推薦困難題型
|
- **保護性**: A1學習者自動限制基礎題型,絕不暴露複雜選項
|
||||||
|
- **智能性**: 自動避重、權重分配、歷史感知
|
||||||
|
|
||||||
### **參數敏感性**
|
### **參數敏感性**
|
||||||
| 參數 | 影響程度 | 調優建議 |
|
| 參數 | 影響程度 | 調優建議 |
|
||||||
|
|
@ -369,14 +366,14 @@ def validate_inputs(interval, times_correct, total_reviews):
|
||||||
### **性能複雜度**
|
### **性能複雜度**
|
||||||
- **基礎熟悉度**: O(1) - 常數時間計算
|
- **基礎熟悉度**: O(1) - 常數時間計算
|
||||||
- **當前熟悉度**: O(1) - 常數時間計算
|
- **當前熟悉度**: O(1) - 常數時間計算
|
||||||
- **題型選擇**: O(k) - k為可用題型數量 (通常≤7)
|
- **自動題型選擇**: O(1) - 常數時間決策 (四情境直接映射)
|
||||||
- **智能推薦**: O(h) - h為歷史記錄查看數量 (通常≤5)
|
- **智能避重處理**: O(h) - h為歷史記錄查看數量 (通常≤3)
|
||||||
- **空間複雜度**: O(1) - 無額外存儲需求
|
- **空間複雜度**: O(1) - 無額外存儲需求
|
||||||
- **預期性能**:
|
- **預期性能**:
|
||||||
- 單次計算: < 1ms
|
- 單次計算: < 1ms
|
||||||
- 題型推薦: < 5ms
|
- 自動題型選擇: < 2ms (四情境映射+避重)
|
||||||
- 列表頁批次計算: < 10ms (100個詞卡)
|
- 列表頁批次計算: < 10ms (100個詞卡)
|
||||||
- A1邏輯檢查: < 1ms
|
- A1自動保護檢查: < 1ms
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -440,11 +437,11 @@ def validate_inputs(interval, times_correct, total_reviews):
|
||||||
- **學習軌跡分布**: 檢查間隔分布是否合理
|
- **學習軌跡分布**: 檢查間隔分布是否合理
|
||||||
- **用戶滿意度**: 復習頻率是否符合預期
|
- **用戶滿意度**: 復習頻率是否符合預期
|
||||||
- **記憶效果**: 長期記憶率是否提升
|
- **記憶效果**: 長期記憶率是否提升
|
||||||
- **題型使用分布**: 各題型使用率是否平衡
|
- **自動選擇效果**: 各題型自動分配是否達到學習目標
|
||||||
- **A1用戶體驗**: 初學者完成率和信心提升
|
- **A1用戶無障礙體驗**: 初學者完成率和信心提升
|
||||||
- **推薦算法準確率**: 用戶接受推薦題型的比例
|
- **四情境適配準確率**: 系統選擇題型與學習效果的關聯度
|
||||||
- **切換頻率**: 平均每次復習的題型切換次數
|
- **智能避重效果**: 連續重複題型的控制效果
|
||||||
- **表現關聯性**: 不同題型的答對率差異
|
- **零選擇體驗滿意度**: 用戶對無需選擇的便利性評價
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,26 +46,26 @@
|
||||||
|
|
||||||
**商業價值**: 提升用戶參與度和完課率
|
**商業價值**: 提升用戶參與度和完課率
|
||||||
|
|
||||||
### **US-004: 多樣化複習體驗**
|
### **US-004: 智能化複習體驗**
|
||||||
**作為**學習者
|
**作為**學習者
|
||||||
**我希望**系統提供多種複習方式(翻卡、選擇題、填空題等)
|
**我希望**系統能自動為我安排最適合的複習方式,無需我手動選擇
|
||||||
**以便**通過不同的練習方式加深對詞彙的理解和記憶
|
**以便**我能專注於學習內容而非操作介面,獲得流暢的學習體驗
|
||||||
|
|
||||||
**商業價值**: 提高學習效果,增加用戶黏性
|
**商業價值**: 提高用戶專注度,減少認知負擔,提升學習效率
|
||||||
|
|
||||||
### **US-005: A1初學者友好體驗**
|
### **US-005: A1初學者零障礙學習**
|
||||||
**作為**A1程度的語言初學者
|
**作為**A1程度的語言初學者
|
||||||
**我希望**系統為我提供適合的基礎複習方式
|
**我希望**系統能自動提供最基礎的3種複習方式(翻卡、選擇題、聽力),不讓我面臨複雜的選擇
|
||||||
**以便**我能循序漸進地建立語言基礎和學習信心
|
**以便**我能循序漸進地建立語言基礎和學習信心,避免因複雜操作而放棄
|
||||||
|
|
||||||
**商業價值**: 擴大目標用戶群,提高初學者留存率
|
**商業價值**: 大幅降低初學者流失率,擴大目標用戶群
|
||||||
|
|
||||||
### **US-006: 智能複習方式推薦**
|
### **US-006: 智能複習方式自動適配**
|
||||||
**作為**學習者
|
**作為**學習者
|
||||||
**我希望**系統能根據我的學習程度和詞彙難度自動選擇最適合的複習方式
|
**我希望**系統能根據我的學習程度和詞彙難度自動選擇並執行最適合的複習方式
|
||||||
**以便**我能獲得最佳的學習效果
|
**以便**我每次打開系統就能直接開始學習,無需任何額外操作
|
||||||
|
|
||||||
**商業價值**: 個人化學習體驗,提升學習成效
|
**商業價值**: 提供極致便利的學習體驗,提升用戶滿意度和留存率
|
||||||
|
|
||||||
### **US-007: 聽力和口說練習**
|
### **US-007: 聽力和口說練習**
|
||||||
**作為**想要提升聽說能力的學習者
|
**作為**想要提升聽說能力的學習者
|
||||||
|
|
@ -83,9 +83,9 @@
|
||||||
2. **逾期懲罰機制** - 延遲復習時合理縮短下次間隔
|
2. **逾期懲罰機制** - 延遲復習時合理縮短下次間隔
|
||||||
3. **熟悉程度追蹤** - 準確反映學習進度
|
3. **熟悉程度追蹤** - 準確反映學習進度
|
||||||
4. **個人化復習** - 根據用戶表現調整復習頻率
|
4. **個人化復習** - 根據用戶表現調整復習頻率
|
||||||
5. **多元複習題型** - 提供7種不同類型的複習方式
|
5. **多元複習題型** - 系統自動運用7種不同類型的複習方式
|
||||||
6. **智能題型推薦** - 根據學習程度自動選擇最適合的復習方式
|
6. **零選擇智能適配** - 完全自動選擇和執行最適合的復習方式,用戶零操作負擔
|
||||||
7. **聽力和口說整合** - 支援音頻播放和錄音功能
|
7. **聽力和口說整合** - 智能判斷並自動提供音頻播放和錄音功能
|
||||||
|
|
||||||
### **複習題型功能**
|
### **複習題型功能**
|
||||||
- **翻卡題**: 基於信心程度的主觀評估
|
- **翻卡題**: 基於信心程度的主觀評估
|
||||||
|
|
@ -97,9 +97,9 @@
|
||||||
- **例句口說**: 發音和表達練習
|
- **例句口說**: 發音和表達練習
|
||||||
|
|
||||||
### **程度適配功能**
|
### **程度適配功能**
|
||||||
- **A1學習者專屬**: 基礎題型組合,重點建立信心
|
- **A1學習者自動保護**: 系統自動限制為基礎3種題型,無需用戶了解複雜度
|
||||||
- **難度智能匹配**: 根據學習者程度vs詞彙難度選擇題型
|
- **四情境智能適配**: 自動識別A1/簡單/適中/困難情境,立即提供對應題型
|
||||||
- **學習路徑優化**: 避免重複題型,確保學習效果
|
- **無縫學習體驗**: 用戶只需答題,系統自動處理所有適配邏輯
|
||||||
|
|
||||||
### **支援功能**
|
### **支援功能**
|
||||||
- 學習統計和報表
|
- 學習統計和報表
|
||||||
|
|
@ -182,29 +182,28 @@
|
||||||
### **產品風險**
|
### **產品風險**
|
||||||
- 用戶可能不適應新的復習頻率變化
|
- 用戶可能不適應新的復習頻率變化
|
||||||
- 算法調整可能影響現有學習進度
|
- 算法調整可能影響現有學習進度
|
||||||
- 複習題型過多可能造成用戶選擇困難
|
|
||||||
- A1學習者可能對聽力和口說功能感到困難
|
- A1學習者可能對聽力和口說功能感到困難
|
||||||
- 音頻功能的技術複雜度和設備兼容性問題
|
- 音頻功能的技術複雜度和設備兼容性問題
|
||||||
|
|
||||||
### **技術風險**
|
### **技術風險**
|
||||||
- 瀏覽器音頻API兼容性限制
|
- 瀏覽器音頻API兼容性限制
|
||||||
- 語音錄製品質受設備影響
|
- 語音錄製品質受設備影響
|
||||||
- 智能題型推薦算法準確性有待驗證
|
- 智能題型選擇算法準確性有待驗證
|
||||||
- 複雜題型可能影響系統響應速度
|
- 複雜題型可能影響系統響應速度
|
||||||
|
|
||||||
### **用戶體驗風險**
|
### **用戶體驗風險**
|
||||||
- 題型切換頻繁可能打斷學習節奏
|
|
||||||
- 不同題型的學習曲線差異
|
- 不同題型的學習曲線差異
|
||||||
|
- 系統自動選擇可能不符合用戶當下偏好
|
||||||
- A1學習者可能對某些題型產生挫折感
|
- A1學習者可能對某些題型產生挫折感
|
||||||
|
|
||||||
### **緩解策略**
|
### **緩解策略**
|
||||||
- 階段式推出 (10% → 30% → 100% 用戶)
|
- 階段式推出 (10% → 30% → 100% 用戶)
|
||||||
- 提供算法切換選項
|
- 持續優化題型選擇算法準確性
|
||||||
- 密切監控用戶反饋和學習數據
|
- 密切監控用戶反饋和學習成效數據
|
||||||
- 為A1學習者提供引導式教程
|
- 為A1學習者提供題型說明引導
|
||||||
- 音頻功能提供降級方案 (無音頻設備時)
|
- 音頻功能提供降級方案 (無音頻設備時)
|
||||||
- 智能推薦系統提供手動覆蓋選項
|
- 建立算法回饋機制,根據用戶表現調整
|
||||||
- 題型難度分層,循序漸進引入
|
- 提供學習進度透明化,讓用戶了解系統判斷邏輯
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -225,16 +224,19 @@
|
||||||
- 科學的記憶衰減模型
|
- 科學的記憶衰減模型
|
||||||
- 個人化的復習體驗
|
- 個人化的復習體驗
|
||||||
- 完整的逾期處理機制
|
- 完整的逾期處理機制
|
||||||
- **業界最豐富的複習題型組合**
|
- **業界首創零選擇負擔學習體驗**
|
||||||
- **AI驅動的智能題型推薦**
|
- **AI驅動的完全自動題型適配**
|
||||||
- **A1初學者友好的學習路徑**
|
- **A1初學者無障礙智能保護**
|
||||||
- **整合聽說讀寫的完整語言學習體驗**
|
- **四情境精準匹配的學習路徑**
|
||||||
|
- **整合聽說讀寫的無縫學習體驗**
|
||||||
|
|
||||||
### **市場差異化**
|
### **市場差異化**
|
||||||
- 大多數競品只提供1-2種複習方式
|
- **競品問題**: 大多數產品讓用戶手動選擇複習方式,造成認知負擔
|
||||||
- 市場上缺少專門針對A1學習者的適配算法
|
- **我們解決**: 完全自動化,用戶零選擇,專注學習本身
|
||||||
- 少有產品整合音頻錄製和播放功能
|
- **競品問題**: 缺少針對不同程度學習者的智能保護機制
|
||||||
- 智能推薦算法基於認知科學研究,非簡單隨機
|
- **我們解決**: A1學習者自動限制複雜題型,避免挫折
|
||||||
|
- **競品問題**: 複習方式固定,無法根據詞彙難度調整
|
||||||
|
- **我們解決**: 四情境動態適配,每個詞彙都有最佳練習方式
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue