0fcb77b991
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Successful in 1m6s
CI Build & Deploy Pipeline / Build Staging Web Image (push) Successful in 1m49s
CI Build & Deploy Pipeline / Build Production API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Production (push) Has been skipped
CI Build & Deploy Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Validate Code Quality And Tests (push) Successful in 3m1s
CI/CD Pipeline / Unit Tests (push) Successful in 3m20s
CI/CD Pipeline / Integration Tests (push) Successful in 1m29s
CI Build & Deploy Pipeline / Build Staging API Image (push) Successful in 7m4s
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Successful in 7m54s
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 45s
CI Build & Deploy Pipeline / Staging E2E Tests (push) Failing after 2m50s
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Successful in 3m28s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
146 lines
3.9 KiB
TypeScript
146 lines
3.9 KiB
TypeScript
/**
|
||
* 配音相关 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<UnifiedVoiceListResponse> => {
|
||
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<UnifiedVoiceListResponse>(`/voices${qs ? `?${qs}` : ""}`)
|
||
return response.data
|
||
}
|
||
|
||
/** 获取预设音色列表(无需鉴权) */
|
||
export const fetchPresetVoices = async (): Promise<PresetVoiceListResponse> => {
|
||
const response = await apiClient.get<PresetVoiceListResponse>("/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<VoiceItem[]> => {
|
||
const response = await apiClient.get("/voices/legacy")
|
||
return response.data.items || response.data || []
|
||
}
|
||
|
||
/** 创建配音 */
|
||
export const createVoice = async (data: CreateVoiceRequest): Promise<VoiceItem> => {
|
||
const response = await apiClient.post("/voices", data)
|
||
return response.data
|
||
}
|
||
|
||
/** 更新配音 */
|
||
export const updateVoice = async (
|
||
voiceId: string,
|
||
data: Partial<CreateVoiceRequest>,
|
||
): Promise<VoiceItem> => {
|
||
const response = await apiClient.put(`/voices/${voiceId}`, data)
|
||
return response.data
|
||
}
|
||
|
||
/** 删除配音 */
|
||
export const deleteVoice = async (voiceId: string): Promise<void> => {
|
||
await apiClient.delete(`/voices/${voiceId}`)
|
||
}
|
||
|
||
/** AI 生成配音 */
|
||
export const generateAIVoice = async (data: {
|
||
text: string
|
||
voice_type?: string
|
||
speed?: number
|
||
}): Promise<VoiceItem> => {
|
||
const response = await apiClient.post("/voices/generate", data)
|
||
return response.data
|
||
}
|