/** * 配音相关 API * Phase 1 新增:全局配音库 * * 任务 3.11:新增统一音色 API(对接后端 3.04),保留旧接口向后兼容 */ import apiClient from "./client" /* ── 统一音色 API(后端 3.04) ─────────────────────────── */ /** 统一音色条目(preset + clone 混合) */ export interface UnifiedVoiceItem { id: string type: "preset" | "clone" name: string description: string gender: string language: string voice_id: string voice_provider: string audio_url: string | null preview_url: string | null duration: number | null file_size: number | null status: string tags: string[] user_id: string | null project_id: string | null voice_clone_profile_id: string | null created_at: string | null updated_at: string | null } /** 统一音色列表响应 */ export interface UnifiedVoiceListResponse { items: UnifiedVoiceItem[] total: number preset_count: number clone_count: number } /** 预设音色条目 */ export interface PresetVoiceItem { voice_id: string name: string description: string gender: string language: string preview_url: string | null tags: string[] } /** 预设音色列表响应 */ export interface PresetVoiceListResponse { items: PresetVoiceItem[] total: number } /** 统一列表查询参数 */ export interface UnifiedVoiceListParams { type?: "preset" | "clone" status?: string skip?: number limit?: number } /** 获取统一音色列表(推荐) */ export const fetchVoices = async ( params?: UnifiedVoiceListParams, ): Promise => { const searchParams = new URLSearchParams() if (params?.type) searchParams.set("type", params.type) if (params?.status) searchParams.set("status", params.status) if (params?.skip !== undefined) searchParams.set("skip", String(params.skip)) if (params?.limit !== undefined) searchParams.set("limit", String(params.limit)) const qs = searchParams.toString() const response = await apiClient.get(`/voices${qs ? `?${qs}` : ""}`) return response.data } /** 获取预设音色列表(无需鉴权) */ export const fetchPresetVoices = async (): Promise => { const response = await apiClient.get("/voices/presets") return response.data } /* ── 向后兼容(旧接口) ────────────────────────────────── */ /** 配音条目(旧) */ export interface VoiceItem { id: string name: string text: string voice_type?: string duration_seconds?: number storage_key?: string audio_url?: string status?: string is_favorite?: boolean created_at?: string updated_at?: string } /** 创建配音请求(旧) */ export interface CreateVoiceRequest { name: string text: string voice_type?: string } /** 获取当前用户的所有配音(旧 → /voices/legacy) */ export const getVoices = async (): Promise => { const response = await apiClient.get("/voices/legacy") return response.data.items || response.data || [] } /** 创建配音 */ export const createVoice = async (data: CreateVoiceRequest): Promise => { const response = await apiClient.post("/voices", data) return response.data } /** 更新配音 */ export const updateVoice = async ( voiceId: string, data: Partial, ): Promise => { const response = await apiClient.put(`/voices/${voiceId}`, data) return response.data } /** 删除配音 */ export const deleteVoice = async (voiceId: string): Promise => { await apiClient.delete(`/voices/${voiceId}`) } /** AI 生成配音 */ export const generateAIVoice = async (data: { text: string voice_type?: string speed?: number }): Promise => { const response = await apiClient.post("/voices/generate", data) return response.data }