dramaling-vocab-learning/note/VOICE_FEATURES_SPECIFICATIO...

19 KiB
Raw Blame History

DramaLing 語音功能規格書

TTS 語音發音 & 語音辨識系統


📋 專案概況

文件版本: 1.0 建立日期: 2025-09-19 最後更新: 2025-09-19 負責人: DramaLing 開發團隊

功能目標

基於現有 DramaLing 詞彙學習平台,整合 TTS (文字轉語音) 和語音辨識功能,提供完整的語音學習體驗,包括發音播放、口說練習與評分。


🎯 核心功能需求

1. TTS 語音發音系統

1.1 基礎發音功能

  • 目標詞彙發音

    • 支援美式/英式發音切換
    • 高品質音頻輸出 (16kHz 以上)
    • 響應時間 < 500ms
    • 支援 IPA 音標同步顯示
  • 例句發音

    • 完整例句語音播放
    • 重點詞彙高亮顯示
    • 語速調整 (0.5x - 2.0x)
    • 自動斷句處理

1.2 進階播放功能

  • 智能播放模式

    • 單詞→例句→重複循環
    • 自動暫停間隔可調 (1-5秒)
    • 背景學習模式
    • 睡前學習模式 (漸弱音量)
  • 個人化設定

    • 預設語音類型選擇
    • 播放速度記憶
    • 音量控制
    • 靜音模式支援

1.3 學習模式整合

  • 翻卡模式

    • 點擊播放按鈕發音
    • 自動播放開關
    • 正面/背面分別播放
  • 測驗模式

    • 聽力測驗音頻播放
    • 題目語音朗讀
    • 正確答案發音確認

2. 語音辨識與口說練習

2.1 發音練習功能

  • 單詞發音練習

    • 錄音與標準發音比對
    • 音素級別評分 (0-100分)
    • 錯誤音素標記與建議
    • 重複練習直到達標
  • 例句朗讀練習

    • 完整句子發音評估
    • 流暢度評分
    • 語調評估
    • 語速分析

2.2 智能評分系統

  • 多維度評分

    • 準確度 (Accuracy): 音素正確性
    • 流暢度 (Fluency): 語速與停頓
    • 完整度 (Completeness): 內容完整性
    • 音調 (Prosody): 語調與重音
  • 評分標準

    • A級 (90-100分): 接近母語水準
    • B級 (80-89分): 良好,輕微口音
    • C級 (70-79分): 可理解,需改進
    • D級 (60-69分): 困難理解
    • F級 (0-59分): 需大幅改進

2.3 漸進式學習

  • 難度等級

    • 初級: 單音節詞彙
    • 中級: 多音節詞彙與短句
    • 高級: 複雜句型與連讀
  • 個人化調整

    • 根據 CEFR 等級調整標準
    • 學習進度追蹤
    • 弱點分析與強化練習

🏗️ 技術架構設計

3. 前端架構

3.1 UI 組件設計

// AudioPlayer 組件
interface AudioPlayerProps {
  text: string
  audioUrl?: string
  accent: 'us' | 'uk'
  speed: number
  autoPlay: boolean
  onPlayStart?: () => void
  onPlayEnd?: () => void
}

// VoiceRecorder 組件
interface VoiceRecorderProps {
  targetText: string
  onRecordingComplete: (audioBlob: Blob) => void
  onScoreReceived: (score: PronunciationScore) => void
  maxDuration: number
}

// PronunciationScore 類型
interface PronunciationScore {
  overall: number
  accuracy: number
  fluency: number
  completeness: number
  prosody: number
  phonemes: PhonemeScore[]
}

3.2 狀態管理

// Zustand Store
interface AudioStore {
  // TTS 狀態
  isPlaying: boolean
  currentAudio: HTMLAudioElement | null
  playbackSpeed: number
  preferredAccent: 'us' | 'uk'

  // 語音辨識狀態
  isRecording: boolean
  recordingData: Blob | null
  lastScore: PronunciationScore | null

  // 操作方法
  playTTS: (text: string, accent?: 'us' | 'uk') => Promise<void>
  stopAudio: () => void
  startRecording: () => void
  stopRecording: () => Promise<Blob>
  evaluatePronunciation: (audio: Blob, text: string) => Promise<PronunciationScore>
}

4. 後端 API 設計

4.1 TTS API 端點

// Controllers/AudioController.cs
[ApiController]
[Route("api/[controller]")]
public class AudioController : ControllerBase
{
    [HttpPost("tts")]
    public async Task<IActionResult> GenerateAudio([FromBody] TTSRequest request)
    {
        // 生成語音檔案
        // 回傳音檔 URL 或 Base64
    }

    [HttpGet("tts/cache/{hash}")]
    public async Task<IActionResult> GetCachedAudio(string hash)
    {
        // 回傳快取的音檔
    }
}

// DTOs
public class TTSRequest
{
    public string Text { get; set; }
    public string Accent { get; set; } // "us" or "uk"
    public float Speed { get; set; } = 1.0f
    public string Voice { get; set; }
}

4.2 語音評估 API

[HttpPost("pronunciation/evaluate")]
public async Task<IActionResult> EvaluatePronunciation([FromForm] PronunciationRequest request)
{
    // 處理音檔上傳
    // 調用語音評估服務
    // 回傳評分結果
}

public class PronunciationRequest
{
    public IFormFile AudioFile { get; set; }
    public string TargetText { get; set; }
    public string UserLevel { get; set; } // CEFR level
}

public class PronunciationResponse
{
    public int OverallScore { get; set; }
    public float Accuracy { get; set; }
    public float Fluency { get; set; }
    public float Completeness { get; set; }
    public float Prosody { get; set; }
    public List<PhonemeScore> PhonemeScores { get; set; }
    public List<string> Suggestions { get; set; }
}

5. 第三方服務整合

5.1 TTS 服務選型

主要選擇: Azure Cognitive Services Speech

  • 優點: 高品質、多語言、價格合理
  • 語音選項:
    • 美式: en-US-AriaNeural, en-US-GuyNeural
    • 英式: en-GB-SoniaNeural, en-GB-RyanNeural
  • SSML 支援: 語速、音調、停頓控制
  • 成本: $4/百萬字符

備用選擇: Google Cloud Text-to-Speech

  • 優點: 自然度高、WaveNet 技術
  • 成本: $4-16/百萬字符

5.2 語音辨識服務

主要選擇: Azure Speech Services Pronunciation Assessment

  • 功能: 音素級評分、流暢度分析
  • 支援格式: WAV, MP3, OGG
  • 評分維度: 準確度、流暢度、完整度、韻律
  • 成本: $1/小時音頻

技術整合範例:

public class AzureSpeechService
{
    private readonly SpeechConfig _speechConfig;

    public async Task<string> GenerateAudioAsync(string text, string voice)
    {
        using var synthesizer = new SpeechSynthesizer(_speechConfig);
        var ssml = CreateSSML(text, voice);
        var result = await synthesizer.SpeakSsmlAsync(ssml);

        // 存儲到 Azure Blob Storage
        return await SaveAudioToStorage(result.AudioData);
    }

    public async Task<PronunciationScore> EvaluateAsync(byte[] audioData, string referenceText)
    {
        var pronunciationConfig = new PronunciationAssessmentConfig(
            referenceText,
            PronunciationAssessmentGradingSystem.FivePoint,
            PronunciationAssessmentGranularity.Phoneme);

        // 執行評估...
    }
}

💾 數據存儲設計

6. 數據庫架構

6.1 音頻快取表

CREATE TABLE audio_cache (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    text_hash VARCHAR(64) UNIQUE NOT NULL, -- 文字內容的 SHA-256
    text_content TEXT NOT NULL,
    accent VARCHAR(2) NOT NULL, -- 'us' or 'uk'
    voice_id VARCHAR(50) NOT NULL,
    audio_url TEXT NOT NULL,
    file_size INTEGER,
    duration_ms INTEGER,
    created_at TIMESTAMP DEFAULT NOW(),
    last_accessed TIMESTAMP DEFAULT NOW(),
    access_count INTEGER DEFAULT 1,

    INDEX idx_text_hash (text_hash),
    INDEX idx_last_accessed (last_accessed)
);

6.2 發音評估記錄

CREATE TABLE pronunciation_assessments (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    flashcard_id UUID REFERENCES flashcards(id) ON DELETE CASCADE,
    target_text TEXT NOT NULL,
    audio_url TEXT,

    -- 評分結果
    overall_score INTEGER NOT NULL,
    accuracy_score DECIMAL(5,2),
    fluency_score DECIMAL(5,2),
    completeness_score DECIMAL(5,2),
    prosody_score DECIMAL(5,2),

    -- 詳細分析
    phoneme_scores JSONB, -- 音素級評分
    suggestions TEXT[],

    -- 學習情境
    study_session_id UUID REFERENCES study_sessions(id),
    practice_mode VARCHAR(20), -- 'word', 'sentence', 'conversation'

    created_at TIMESTAMP DEFAULT NOW(),

    INDEX idx_user_flashcard (user_id, flashcard_id),
    INDEX idx_session (study_session_id)
);

6.3 語音設定表

CREATE TABLE user_audio_preferences (
    user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,

    -- TTS 偏好
    preferred_accent VARCHAR(2) DEFAULT 'us',
    preferred_voice_male VARCHAR(50),
    preferred_voice_female VARCHAR(50),
    default_speed DECIMAL(3,1) DEFAULT 1.0,
    auto_play_enabled BOOLEAN DEFAULT false,

    -- 語音練習偏好
    pronunciation_difficulty VARCHAR(20) DEFAULT 'medium', -- 'easy', 'medium', 'strict'
    target_score_threshold INTEGER DEFAULT 80,
    enable_detailed_feedback BOOLEAN DEFAULT true,

    updated_at TIMESTAMP DEFAULT NOW()
);

🎨 用戶體驗設計

7. 界面設計規範

7.1 TTS 播放控制

// AudioControls 組件設計
const AudioControls = ({ text, accent, onPlay, onStop }) => (
  <div className="flex items-center gap-3 p-3 bg-gray-50 rounded-lg">
    {/* 播放按鈕 */}
    <button
      onClick={isPlaying ? onStop : onPlay}
      className="flex items-center justify-center w-10 h-10 bg-blue-600 text-white rounded-full hover:bg-blue-700 transition-colors"
    >
      {isPlaying ? <PauseIcon /> : <PlayIcon />}
    </button>

    {/* 語言切換 */}
    <div className="flex gap-1">
      <AccentButton accent="us" active={accent === 'us'} />
      <AccentButton accent="uk" active={accent === 'uk'} />
    </div>

    {/* 速度控制 */}
    <SpeedSlider
      value={speed}
      onChange={setSpeed}
      min={0.5}
      max={2.0}
      step={0.1}
    />

    {/* 音標顯示 */}
    <span className="text-sm text-gray-600 font-mono">
      {pronunciation}
    </span>
  </div>
);

7.2 語音錄製界面

const VoiceRecorder = ({ targetText, onScoreReceived }) => {
  const [isRecording, setIsRecording] = useState(false);
  const [recordingTime, setRecordingTime] = useState(0);
  const [lastScore, setLastScore] = useState(null);

  return (
    <div className="voice-recorder p-6 border-2 border-dashed border-gray-300 rounded-xl">
      {/* 目標文字顯示 */}
      <div className="text-center mb-6">
        <h3 className="text-lg font-semibold mb-2">請朗讀以下內容</h3>
        <p className="text-2xl font-medium text-gray-800 p-4 bg-blue-50 rounded-lg">
          {targetText}
        </p>
      </div>

      {/* 錄音控制 */}
      <div className="flex flex-col items-center gap-4">
        <button
          onClick={isRecording ? stopRecording : startRecording}
          className={`w-20 h-20 rounded-full flex items-center justify-center transition-all ${
            isRecording
              ? 'bg-red-500 hover:bg-red-600 animate-pulse'
              : 'bg-blue-500 hover:bg-blue-600'
          } text-white`}
        >
          {isRecording ? <StopIcon size={32} /> : <MicIcon size={32} />}
        </button>

        {/* 錄音時間 */}
        {isRecording && (
          <div className="text-sm text-gray-600">
            錄音中... {formatTime(recordingTime)}
          </div>
        )}

        {/* 評分結果 */}
        {lastScore && (
          <ScoreDisplay score={lastScore} />
        )}
      </div>
    </div>
  );
};

7.3 評分結果展示

const ScoreDisplay = ({ score }) => (
  <div className="score-display w-full max-w-md mx-auto">
    {/* 總分 */}
    <div className="text-center mb-4">
      <div className={`text-4xl font-bold ${getScoreColor(score.overall)}`}>
        {score.overall}
      </div>
      <div className="text-sm text-gray-600">總體評分</div>
    </div>

    {/* 詳細評分 */}
    <div className="grid grid-cols-2 gap-3 mb-4">
      <ScoreItem label="準確度" value={score.accuracy} />
      <ScoreItem label="流暢度" value={score.fluency} />
      <ScoreItem label="完整度" value={score.completeness} />
      <ScoreItem label="音調" value={score.prosody} />
    </div>

    {/* 改進建議 */}
    {score.suggestions.length > 0 && (
      <div className="suggestions">
        <h4 className="font-semibold mb-2">💡 改進建議</h4>
        <ul className="text-sm text-gray-700 space-y-1">
          {score.suggestions.map((suggestion, index) => (
            <li key={index} className="flex items-start gap-2">
              <span className="text-blue-500"></span>
              {suggestion}
            </li>
          ))}
        </ul>
      </div>
    )}
  </div>
);

📊 效能與優化

8. 快取策略

8.1 TTS 快取機制

  • 本地快取: 瀏覽器 localStorage 存儲常用音頻 URL
  • 服務端快取: Redis 快取 TTS 請求結果 (24小時)
  • CDN 分發: 音頻檔案透過 CDN 加速分發
  • 預載策略: 學習模式開始前預載下一批詞彙音頻

8.2 音頻檔案管理

public class AudioCacheService
{
    public async Task<string> GetOrCreateAudioAsync(string text, string accent)
    {
        var cacheKey = GenerateCacheKey(text, accent);

        // 檢查快取
        var cachedUrl = await _cache.GetStringAsync(cacheKey);
        if (!string.IsNullOrEmpty(cachedUrl))
        {
            await UpdateAccessTime(cacheKey);
            return cachedUrl;
        }

        // 生成新音頻
        var audioUrl = await _ttsService.GenerateAsync(text, accent);

        // 存入快取
        await _cache.SetStringAsync(cacheKey, audioUrl, TimeSpan.FromDays(7));

        return audioUrl;
    }

    private string GenerateCacheKey(string text, string accent)
    {
        var combined = $"{text}|{accent}";
        using var sha256 = SHA256.Create();
        var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(combined));
        return Convert.ToHexString(hash);
    }
}

9. 效能指標

9.1 TTS 效能目標

  • 首次生成延遲: < 3秒
  • 快取命中延遲: < 500ms
  • 音頻檔案大小: < 1MB (30秒內容)
  • 快取命中率: > 85%

9.2 語音辨識效能

  • 錄音上傳: < 2秒 (10秒音頻)
  • 評估回應: < 5秒
  • 準確度: > 90% (與人工評估對比)

💰 成本分析

10. 服務成本估算

10.1 TTS 成本 (基於 Azure Speech)

  • 定價: $4 USD/百萬字符
  • 月估算:
    • 100 活躍用戶 × 50 詞/天 × 30天 = 150,000 詞/月
    • 平均 8 字符/詞 = 1,200,000 字符/月
    • 月成本: $4.8 USD

10.2 語音評估成本

  • 定價: $1 USD/小時音頻
  • 月估算:
    • 100 用戶 × 10分鐘練習/天 × 30天 = 500小時/月
    • 月成本: $500 USD

10.3 存儲成本 (Azure Blob Storage)

  • 音頻存儲: $0.02/GB/月
  • 估算: 10,000 音頻檔 × 100KB = 1GB
  • 月成本: $0.02 USD

10.4 成本優化策略

  1. 智能快取: 減少重複 TTS 請求 80%
  2. 音頻壓縮: 使用 MP3 格式降低存儲成本
  3. 免費層級: 提供基礎 TTS付費解鎖語音評估
  4. 批量處理: 合併短文本降低 API 調用次數

🚀 開發實施計劃

11. 開發階段

第一階段: TTS 基礎功能 (1週)

  • Azure Speech Services 整合
  • 基礎 TTS API 開發
  • 前端音頻播放組件
  • 美式/英式發音切換
  • 快取機制實現

第二階段: 進階 TTS 功能 (1週)

  • 語速調整功能
  • 自動播放模式
  • 音頻預載優化
  • 個人化設定
  • 學習模式整合

第三階段: 語音辨識基礎 (1週)

  • 瀏覽器錄音功能
  • 音頻上傳與處理
  • Azure 語音評估整合
  • 基礎評分顯示

第四階段: 口說練習完善 (1週)

  • 詳細評分分析
  • 音素級反饋
  • 改進建議系統
  • 練習記錄與追蹤
  • UI/UX 優化

12. 技術債務與風險

12.1 已知限制

  • 瀏覽器相容性: Safari 對 Web Audio API 支援限制
  • 移動端挑戰: iOS Safari 錄音權限問題
  • 網路依賴: 離線模式無法使用語音功能
  • 成本控制: 需嚴格監控 API 使用量

12.2 緩解措施

  1. 降級機制: API 配額用盡時顯示音標
  2. 錯誤處理: 網路問題時提供友善提示
  3. 權限管理: 明確的麥克風權限引導
  4. 監控告警: 成本異常時自動通知

📋 驗收標準

13. 功能測試

13.1 TTS 測試案例

  • 單詞發音播放正常
  • 例句發音完整清晰
  • 美式/英式發音切換有效
  • 語速調整範圍 0.5x-2.0x
  • 快取機制減少 80% 重複請求
  • 離線快取音頻可正常播放

13.2 語音辨識測試

  • 錄音功能在主流瀏覽器正常
  • 音頻品質滿足評估需求
  • 評分結果與人工評估差異 < 10%
  • 5秒內回傳評估結果
  • 音素級錯誤標記準確

13.3 效能測試

  • TTS 首次請求 < 3秒
  • 快取命中 < 500ms
  • 音頻檔案 < 1MB (30秒)
  • 99% 服務可用性
  • 1000 併發用戶支援

📚 附錄

14. API 文檔範例

14.1 TTS API

POST /api/audio/tts
Content-Type: application/json

{
  "text": "Hello, world!",
  "accent": "us",
  "speed": 1.0,
  "voice": "aria"
}

Response:
{
  "audioUrl": "https://cdn.dramaling.com/audio/abc123.mp3",
  "duration": 2.5,
  "cacheHit": false
}

14.2 語音評估 API

POST /api/audio/pronunciation/evaluate
Content-Type: multipart/form-data

audio: [audio file]
targetText: "Hello, world!"
userLevel: "B1"

Response:
{
  "overallScore": 85,
  "accuracy": 88.5,
  "fluency": 82.0,
  "completeness": 90.0,
  "prosody": 80.0,
  "phonemeScores": [
    {"phoneme": "/h/", "score": 95},
    {"phoneme": "/ɛ/", "score": 75, "suggestion": "嘴形需要更開"}
  ],
  "suggestions": [
    "注意 'world' 的 /r/ 音",
    "整體語調可以更自然"
  ]
}

15. 相關資源

15.1 技術文檔

15.2 設計參考


文件結束

本規格書涵蓋 DramaLing 語音功能的完整設計與實施計劃。如有任何問題或建議,請聯繫開發團隊。