/** * 音色克隆 API 函数 */ import apiClient from "../client" import { toVoiceClone } from "./utils" import type { VoiceClone, VoiceCloneProfile, CreateVoiceCloneRequest, CreateVoiceCloneRequestFull, VoiceCloneListParams, ListVoiceCloneResponse, VoiceCloneStatusResponse, VoiceClonePreviewResponse, } from "./types" /** 获取克隆音色列表(返回前端兼容数组) */ export const getVoiceClones = async (params?: VoiceCloneListParams): Promise => { const searchParams = new URLSearchParams() 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(`/voice-clones${qs ? `?${qs}` : ""}`) return response.data.items.map(toVoiceClone) } /** 获取克隆音色列表(返回完整响应含 total) */ export const getVoiceClonesWithTotal = async ( params?: VoiceCloneListParams, ): Promise => { const searchParams = new URLSearchParams() 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(`/voice-clones${qs ? `?${qs}` : ""}`) return response.data } /** 获取单个克隆音色详情 */ export const getVoiceCloneDetail = async (id: string): Promise => { const response = await apiClient.get(`/voice-clones/${id}`) return response.data } /** 创建克隆音色 */ export const createVoiceClone = async ( data: CreateVoiceCloneRequest, ): Promise => { const payload: CreateVoiceCloneRequestFull = { name: data.name, description: data.description, source_audio_url: data.audio_url, } const response = await apiClient.post("/voice-clones", payload) return response.data } /** 删除克隆音色 */ export const deleteVoiceClone = async (id: string): Promise => { await apiClient.delete(`/voice-clones/${id}`) } /** 更新克隆音色名称(stub — 后端暂无 PATCH 端点) */ export const updateVoiceClone = async ( id: string, data: Partial>, ): Promise => { const response = await apiClient.get(`/voice-clones/${id}`) return toVoiceClone({ ...response.data, ...data, updated_at: new Date().toISOString(), }) } /** 获取克隆状态 */ export const getVoiceCloneStatus = async (id: string): Promise => { const response = await apiClient.get(`/voice-clones/${id}/status`) return response.data } /** 重试克隆 */ export const retryVoiceClone = async (id: string): Promise => { const response = await apiClient.post(`/voice-clones/${id}/retry`) return response.data } /** 获取克隆音色试听音频(实时 TTS 合成) */ export const getVoiceClonePreview = async ( cloneId: string, text?: string, ): Promise => { const searchParams = new URLSearchParams() if (text) searchParams.set("text", text) const qs = searchParams.toString() const response = await apiClient.get( `/voice-clones/${cloneId}/preview${qs ? `?${qs}` : ""}`, ) return response.data }