d1c83de698
CI/CD Pipeline / Deploy Staging (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Failing after 47h32m26s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 47h32m26s
- 合成完成后显示「存为素材」按钮,点击弹出保存弹窗
- 弹窗支持改名称、选标签(预设标签 + 自定义新增)
- 保存成功后提示「去素材库查看」可跳转配音素材库
- 新增 saveTtsToLibrary API 对接后端 POST /tts/jobs/{id}/save-to-library
143 lines
3.7 KiB
TypeScript
143 lines
3.7 KiB
TypeScript
/**
|
|
* TTS 语音合成 API
|
|
* 对接后端 /api/v1/tts/* 端点
|
|
*
|
|
* 任务 3.14 新增
|
|
*/
|
|
import apiClient from "./client";
|
|
|
|
/* ── 类型定义 ──────────────────────────────────── */
|
|
|
|
/** TTS 合成请求参数 */
|
|
export interface TTSSynthesizeRequest {
|
|
text: string;
|
|
voice_id?: string;
|
|
output_name?: string;
|
|
language?: string;
|
|
speed?: number;
|
|
voice_model?: string;
|
|
voice_clone_profile_id?: string;
|
|
format?: string;
|
|
metadata?: Record<string, unknown>;
|
|
}
|
|
|
|
/** TTS 合成创建响应 */
|
|
export interface TTSSynthesizeResponse {
|
|
job_id: string;
|
|
status: string;
|
|
message: string;
|
|
}
|
|
|
|
/** TTS 任务详情 */
|
|
export interface TTSJob {
|
|
id: string;
|
|
user_id: string;
|
|
project_id: string | null;
|
|
text: string;
|
|
voice_id: string | null;
|
|
voice_model: string | null;
|
|
voice_clone_profile_id: string | null;
|
|
language: string;
|
|
speed: number;
|
|
output_name: string | null;
|
|
output_audio_url: string | null;
|
|
output_format: string;
|
|
duration_seconds: number | null;
|
|
file_size_bytes: number | null;
|
|
sample_rate: number | null;
|
|
status: string;
|
|
error_message: string | null;
|
|
retry_count: number;
|
|
max_retries: number;
|
|
metadata_: Record<string, unknown> | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
/** TTS 任务状态(轻量轮询用) */
|
|
export interface TTSJobStatus {
|
|
id: string;
|
|
status: string;
|
|
output_audio_url: string | null;
|
|
error_message: string | null;
|
|
duration_seconds: number | null;
|
|
retry_count: number;
|
|
}
|
|
|
|
/** TTS 任务列表响应 */
|
|
export interface TTSJobListResponse {
|
|
items: TTSJob[];
|
|
total: number;
|
|
skip: number;
|
|
limit: number;
|
|
}
|
|
|
|
/** TTS 任务列表查询参数 */
|
|
export interface TTSJobListParams {
|
|
status?: string;
|
|
skip?: number;
|
|
limit?: number;
|
|
}
|
|
|
|
/* ── API 函数 ──────────────────────────────────── */
|
|
|
|
/** 创建 TTS 合成任务 */
|
|
export const synthesizeSpeech = async (
|
|
data: TTSSynthesizeRequest,
|
|
): Promise<TTSSynthesizeResponse> => {
|
|
const response = await apiClient.post<TTSSynthesizeResponse>(
|
|
"/tts/synthesize",
|
|
data,
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
/** 获取 TTS 任务详情 */
|
|
export const getTTSJob = async (jobId: string): Promise<TTSJob> => {
|
|
const response = await apiClient.get<TTSJob>(`/tts/jobs/${jobId}`);
|
|
return response.data;
|
|
};
|
|
|
|
/** 获取 TTS 任务状态(轻量轮询) */
|
|
export const getTTSJobStatus = async (jobId: string): Promise<TTSJobStatus> => {
|
|
const response = await apiClient.get<TTSJobStatus>(
|
|
`/tts/jobs/${jobId}/status`,
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
/** 获取 TTS 任务列表 */
|
|
export const getTTSJobs = async (
|
|
params?: TTSJobListParams,
|
|
): Promise<TTSJobListResponse> => {
|
|
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<TTSJobListResponse>(
|
|
`/tts/jobs${qs ? `?${qs}` : ""}`,
|
|
);
|
|
return response.data;
|
|
};
|
|
|
|
/** 存为素材请求参数 */
|
|
export interface SaveTtsToLibraryRequest {
|
|
name?: string;
|
|
tag_ids?: string[];
|
|
}
|
|
|
|
/** 将 TTS 合成结果保存到配音素材库 */
|
|
export const saveTtsToLibrary = async (
|
|
jobId: string,
|
|
data?: SaveTtsToLibraryRequest,
|
|
): Promise<void> => {
|
|
await apiClient.post(`/tts/jobs/${jobId}/save-to-library`, data ?? {});
|
|
};
|
|
|
|
/** 删除 TTS 任务 */
|
|
export const deleteTTSJob = async (jobId: string): Promise<void> => {
|
|
await apiClient.delete(`/tts/jobs/${jobId}`);
|
|
};
|