ci: Prettier纳入两层防御体系 (#520)
CI Build & Deploy Pipeline / Staging E2E Tests (push) Failing after 2m50s
CI Build & Deploy Pipeline / Production Browser E2E (push) Failing after 1437h19m24s
CI Build & Deploy Pipeline / Build Production Web Image (push) Failing after 1437h19m26s
CI Build & Deploy Pipeline / Deploy Production (push) Failing after 1437h19m25s
CI Build & Deploy Pipeline / Build Production API Image (push) Failing after 1437h19m26s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 1437h21m16s
CI Build & Deploy Pipeline / Build Staging API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (push) Failing after 1437h51m29s
CI/CD Pipeline / Validate Code Quality And Tests (push) Has been skipped
CI/CD Pipeline / Unit Tests (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped

Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
This commit was merged in pull request #520.
This commit is contained in:
2026-07-18 18:08:19 +08:00
committed by auto-approve-bot
parent 1ee779a566
commit 0fcb77b991
145 changed files with 10310 additions and 12869 deletions
+81 -87
View File
@@ -4,148 +4,142 @@
*
* 任务 3.11:新增统一音色 API(对接后端 3.04),保留旧接口向后兼容
*/
import apiClient from "./client";
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;
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;
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[];
voice_id: string
name: string
description: string
gender: string
language: string
preview_url: string | null
tags: string[]
}
/** 预设音色列表响应 */
export interface PresetVoiceListResponse {
items: PresetVoiceItem[];
total: number;
items: PresetVoiceItem[]
total: number
}
/** 统一列表查询参数 */
export interface UnifiedVoiceListParams {
type?: "preset" | "clone";
status?: string;
skip?: number;
limit?: number;
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;
};
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;
};
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;
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;
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 || [];
};
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 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;
};
const response = await apiClient.put(`/voices/${voiceId}`, data)
return response.data
}
/** 删除配音 */
export const deleteVoice = async (voiceId: string): Promise<void> => {
await apiClient.delete(`/voices/${voiceId}`);
};
await apiClient.delete(`/voices/${voiceId}`)
}
/** AI 生成配音 */
export const generateAIVoice = async (data: {
text: string;
voice_type?: string;
speed?: number;
text: string
voice_type?: string
speed?: number
}): Promise<VoiceItem> => {
const response = await apiClient.post("/voices/generate", data);
return response.data;
};
const response = await apiClient.post("/voices/generate", data)
return response.data
}