You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

3.9 KiB

Changelog: 音色选择对话框 API 集成

日期: 2026-02-10
类型: 功能增强
模块: 前端 - 音色选择

变更概述

VoiceSelectionDialog 组件从使用 Mock 数据改为对接真实的 ElevenLabs API,支持动态加载中文音色列表,并添加完整的加载状态、错误处理和缓存机制。

技术实现

1. 类型定义 (client/src/types/voice.ts)

  • 定义 ElevenLabsVoice 接口(API 原始响应)
  • 定义 VoicesResponse 接口(API 响应包装)
  • 保留 Voice 接口(组件内部使用)
  • 实现 adaptVoice() 适配器函数(API → 组件类型转换)
  • 实现 isChineseVoice() 筛选函数(检查 labels.languageverified_languages

2. API 服务层 (client/src/services/api/ai.ts)

async getVoices(): Promise<VoicesResponse> {
  const response = await apiClient.get('/ai/voices');
  const chineseVoices = response.voices.filter(isChineseVoice);
  return { voices: chineseVoices };
}
  • 新增 getVoices() 方法
  • 自动筛选支持中文的音色(zh 语言标识)

3. React Query Hook (client/src/hooks/api/useVoices.ts)

export function useVoices() {
  return useQuery({
    queryKey: ['voices', 'chinese'],
    queryFn: async () => {
      const response = await aiApi.getVoices();
      return response.voices.map(adaptVoice);
    },
    staleTime: 5 * 60 * 1000,  // 5 分钟缓存
    gcTime: 10 * 60 * 1000,     // 10 分钟垃圾回收
    retry: 2,
    refetchOnWindowFocus: false,
  });
}
  • 使用 TanStack Query 管理数据获取
  • 自动缓存 5 分钟
  • 失败自动重试 2 次
  • 返回 { data, isLoading, isError, error, refetch }

4. 组件改造 (VoiceSelectionDialog.tsx)

新增状态处理

  • 加载状态:显示 Spinner + "加载音色列表中..."
  • 错误状态:显示错误图标 + 错误信息 + "重试"按钮
  • 空状态:显示"暂无可用音色"
  • 成功状态:渲染音色列表

类型适配

  • 支持 gender: 'male' | 'female' | 'neutral'(新增中性选项)
  • 使用 voice.id 替代 voice.voice_id
  • 使用 voice.previewUrl 替代 voice.preview_url

数据流

用户打开对话框
  ↓
useVoices() 触发
  ↓
检查缓存(5 分钟内)
  ↓ 无缓存
aiApi.getVoices()
  ↓
GET /api/v1/ai/voices
  ↓
筛选中文音色(isChineseVoice)
  ↓
类型适配(adaptVoice)
  ↓
组件渲染

筛选逻辑

音色被认为支持中文,当满足以下任一条件:

  1. voice.labels.language === 'zh'
  2. voice.verified_languages 数组中包含 language === 'zh' 的项

缓存策略

  • staleTime: 5 分钟(数据在 5 分钟内被视为新鲜)
  • gcTime: 10 分钟(未使用的缓存 10 分钟后清理)
  • refetchOnWindowFocus: false(窗口聚焦不重新请求)
  • retry: 2 次(失败自动重试)

影响范围

新增文件

  • client/src/types/voice.ts
  • client/src/hooks/api/useVoices.ts

修改文件

  • client/src/services/api/ai.ts
  • client/src/components/features/preview/dialogs/VoiceSelectionDialog.tsx

保留文件

  • client/src/mocks/voices.ts(保留用于开发/测试)

后续优化建议

  1. 性能优化:考虑虚拟滚动(音色列表超过 50 个时)
  2. 搜索功能:添加音色名称/标签搜索
  3. 分类筛选:按性别、年龄、用途分类
  4. 预加载:在用户可能打开对话框前预加载数据
  5. 错误细化:区分网络错误、服务器错误、权限错误

测试建议

  • 正常加载:验证音色列表正确显示
  • 加载状态:网络延迟时显示 Spinner
  • 错误处理:断网时显示错误提示
  • 重试功能:点击"重试"按钮重新请求
  • 缓存验证:5 分钟内重新打开不发起请求
  • 音色筛选:仅显示中文音色
  • 音频播放:点击播放按钮正常播放预览