8d86707e2e
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 2m9s
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 1532h16m16s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1532h16m17s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 1532h16m20s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 1532h16m20s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1532h16m18s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 1532h16m21s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 1532h16m19s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 1532h16m21s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 1532h16m20s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 1532h47m58s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 1532h47m59s
- GeneratePage.tsx: 3处防御性错误提取函数添加 eslint-disable 注释 (safeExtract/extractString/safeExtractErr),移除 as Record<string, unknown> 断言 - TemplateLibrary.tsx: formatConfig 使用 ConfigDisplayFields 接口替代 Record 断言 - VoiceLibrary.tsx: buildVoiceMetadata 返回 VoiceUploadMetadata 接口 - VoiceMaterialLibrary.tsx: buildMetadata 返回 VoiceAssetMetadata 接口 - editPlans.ts: EditPlanConfig 去除索引签名,补充所有生成时字段 - assets.ts: AssetItem.metadata 使用 AssetMetadata 具体类型 - products.ts: GenerateFromTemplateRequest.config 改为 EditPlanConfig - tts.ts/voiceClone.ts: metadata 参数使用具体接口 - editingPlanner.ts: ValidationWarningDetails 替代 Record<string, unknown> - client.ts: 防御性错误提取添加 eslint-disable 注释 TypeScript 编译零错误,代码库中零 Record<string, unknown> 残留
204 lines
5.1 KiB
TypeScript
204 lines
5.1 KiB
TypeScript
/**
|
||
* TTS 语音合成 API
|
||
* 对接后端 /api/v1/tts/* 端点
|
||
*
|
||
* 任务 3.14 新增
|
||
*/
|
||
import apiClient from "./client";
|
||
|
||
/* ── 类型定义 ──────────────────────────────────── */
|
||
|
||
/** TTS 元数据(合成时附带的扩展信息) */
|
||
export interface TTSMetadata {
|
||
/** 语音时长(秒) */
|
||
duration?: number;
|
||
/** 采样率(Hz) */
|
||
sample_rate?: number;
|
||
/** 语言 */
|
||
language?: string;
|
||
/** 其他扩展字段 */
|
||
[key: string]: unknown;
|
||
}
|
||
|
||
/** 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?: TTSMetadata;
|
||
}
|
||
|
||
/** 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_: TTSMetadata | 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}`);
|
||
};
|
||
|
||
/* ── 音色列表 ──────────────────────────────────── */
|
||
|
||
/** TTS 音色 */
|
||
export interface TTSVoice {
|
||
id: string;
|
||
name: string;
|
||
/** 音色分类标签:male/female/young/service/news/emotion */
|
||
category?: string;
|
||
/** 语言 */
|
||
language?: string;
|
||
/** 试听 URL */
|
||
preview_url?: string;
|
||
/** 描述 */
|
||
description?: string;
|
||
}
|
||
|
||
/** 获取 TTS 音色列表 */
|
||
export const getTtsVoices = async (): Promise<TTSVoice[]> => {
|
||
const response = await apiClient.get<TTSVoice[]>("/tts/voices");
|
||
return response.data;
|
||
};
|
||
|
||
/* ── TTS 试听 ──────────────────────────────────── */
|
||
|
||
/** TTS 试听请求参数 */
|
||
export interface TTSPreviewRequest {
|
||
text: string;
|
||
voice_id: string;
|
||
speed?: number;
|
||
pitch?: number;
|
||
}
|
||
|
||
/** TTS 试听响应 */
|
||
export interface TTSPreviewResponse {
|
||
audio_url: string;
|
||
duration?: number;
|
||
}
|
||
|
||
/** TTS 试听 */
|
||
export const previewTts = async (
|
||
data: TTSPreviewRequest,
|
||
): Promise<TTSPreviewResponse> => {
|
||
const response = await apiClient.post<TTSPreviewResponse>(
|
||
"/tts/preview",
|
||
data,
|
||
);
|
||
return response.data;
|
||
};
|