# 语音合成坊 V2 API 使用指南 ## 概述 V2版本采用统一的异步架构,所有任务通过 `task_id` 追踪状态。客户端需要实现轮询机制来获取任务结果。 ## 基础信息 - **Base URL**: `/api/v2/audio` - **认证方式**: Bearer Token 或 API Key - **响应格式**: JSON (统一使用 ApiResponse 包装) ## 异步任务流程 ``` 1. 创建任务 → 返回 task_id 2. 轮询查询 → 检查任务状态 3. 获取结果 → status = SUCCEEDED 时获取结果 ``` ### 任务状态 - `PENDING` - 等待处理 - `PROCESSING` - 处理中 - `SUCCEEDED` - 成功完成 - `FAILED` - 失败 ## API 端点 ### 1. 语音识别 (ASR) #### 1.1 创建语音识别任务 ```http POST /api/v2/audio/asr/recognize Content-Type: application/json Authorization: Bearer {token} { "model": "paraformer-v2", "file_url": "https://example.com/audio.mp3" } ``` **响应**: ```json { "code": 200, "message": "success", "data": { "task_id": "task_xxx", "status": "PENDING", "created_at": "2026-01-09T10:00:00" } } ``` #### 1.2 查询识别任务 ```http GET /api/v2/audio/asr/{task_id} Authorization: Bearer {token} ``` **响应(成功)**: ```json { "code": 200, "message": "success", "data": { "task_id": "task_xxx", "status": "SUCCEEDED", "result_text": "识别的文本内容", "duration": 120.5, "bill": "0.012", "completed_at": "2026-01-09T10:01:00" } } ``` #### 1.3 获取识别任务列表 ```http GET /api/v2/audio/asr?page=1&page_size=20&status=SUCCEEDED Authorization: Bearer {token} ``` ### 2. 语音合成 (TTS) #### 2.1 创建语音合成任务 ```http POST /api/v2/audio/synthesis Content-Type: application/json Authorization: Bearer {token} { "model": "cosyvoice-v1", "voice": "longxiaochun", "text": "你好,这是测试文本", "format": "mp3" } ``` **响应**: ```json { "code": 200, "message": "success", "data": { "task_id": "task_yyy", "status": "PENDING", "created_at": "2026-01-09T10:00:00" } } ``` #### 2.2 查询合成任务 ```http GET /api/v2/audio/synthesis/{task_id} Authorization: Bearer {token} ``` **响应(成功)**: ```json { "code": 200, "message": "success", "data": { "task_id": "task_yyy", "status": "SUCCEEDED", "audio_url": "https://example.com/output.mp3", "duration": 5.2, "characters": 12, "bill": "0.024", "completed_at": "2026-01-09T10:00:30" } } ``` #### 2.3 获取合成任务列表 ```http GET /api/v2/audio/synthesis?page=1&page_size=20 Authorization: Bearer {token} ``` ### 3. 声音克隆 #### 3.1 创建声音克隆任务 ```http POST /api/v2/audio/voice-clone Content-Type: application/json Authorization: Bearer {token} { "target_model": "cosyvoice-v1", "prefix": "user123", "voice_name": "我的声音", "audio_url": "https://example.com/voice_sample.mp3" } ``` **响应**: ```json { "code": 200, "message": "success", "data": { "task_id": "task_zzz", "status": "PENDING", "created_at": "2026-01-09T10:00:00" } } ``` #### 3.2 查询克隆任务 ```http GET /api/v2/audio/voice-clone/{task_id} Authorization: Bearer {token} ``` **响应(成功)**: ```json { "code": 200, "message": "success", "data": { "task_id": "task_zzz", "status": "SUCCEEDED", "voice_id": "voice_abc123", "voice_name": "我的声音", "bill": "1.00", "completed_at": "2026-01-09T10:05:00" } } ``` #### 3.3 获取克隆任务列表 ```http GET /api/v2/audio/voice-clone?page=1&page_size=20 Authorization: Bearer {token} ``` ### 4. 长文本转音频 #### 4.1 创建长文本转音频任务 ```http POST /api/v2/audio/long-text Content-Type: application/json Authorization: Bearer {token} { "model": "cosyvoice-v1", "voice": "longxiaochun", "text": "这是一段很长的文本...", "format": "mp3" } ``` **响应**: ```json { "code": 200, "message": "success", "data": { "task_id": "uuid_xxx", "status": "PENDING", "segment_count": 5, "progress": 0, "created_at": "2026-01-09T10:00:00" } } ``` #### 4.2 查询长文本任务(带进度) ```http GET /api/v2/audio/long-text/{task_id} Authorization: Bearer {token} ``` **响应(处理中)**: ```json { "code": 200, "message": "success", "data": { "task_id": "uuid_xxx", "status": "PROCESSING", "progress": 60, "segment_count": 5, "segments": [ {"index": 0, "status": "SUCCEEDED", "audio_url": "..."}, {"index": 1, "status": "SUCCEEDED", "audio_url": "..."}, {"index": 2, "status": "SUCCEEDED", "audio_url": "..."}, {"index": 3, "status": "PROCESSING"}, {"index": 4, "status": "PENDING"} ] } } ``` **响应(成功)**: ```json { "code": 200, "message": "success", "data": { "task_id": "uuid_xxx", "status": "SUCCEEDED", "progress": 100, "audio_url": "https://example.com/merged_audio.mp3", "duration": 300.5, "bill": "0.50", "completed_at": "2026-01-09T10:10:00" } } ``` #### 4.3 获取长文本任务列表 ```http GET /api/v2/audio/long-text?page=1&page_size=20 Authorization: Bearer {token} ``` ### 5. 任务管理 #### 5.1 查询任务状态(通用) ```http GET /api/v2/audio/tasks/{task_id}/status Authorization: Bearer {token} ``` **响应**: ```json { "code": 200, "message": "success", "data": { "task_id": "task_xxx", "task_type": "asr_recognition", "status": "SUCCEEDED", "created_at": "2026-01-09T10:00:00", "updated_at": "2026-01-09T10:01:00", "completed_at": "2026-01-09T10:01:00" } } ``` #### 5.2 取消任务 ```http POST /api/v2/audio/tasks/{task_id}/cancel Authorization: Bearer {token} ``` #### 5.3 删除任务 ```http DELETE /api/v2/audio/tasks/{task_id} Authorization: Bearer {token} ``` #### 5.4 批量删除任务 ```http POST /api/v2/audio/tasks/batch-delete Content-Type: application/json Authorization: Bearer {token} { "task_ids": ["task_1", "task_2", "task_3"] } ``` #### 5.5 获取任务统计 ```http GET /api/v2/audio/tasks/statistics Authorization: Bearer {token} ``` **响应**: ```json { "code": 200, "message": "success", "data": { "total_tasks": 100, "pending_tasks": 5, "processing_tasks": 3, "succeeded_tasks": 85, "failed_tasks": 7, "total_bill": "12.50" } } ``` ## 前端轮询示例 ### JavaScript/TypeScript ```typescript // 创建任务 async function createASRTask(fileUrl: string) { const response = await fetch('/api/v2/audio/asr/recognize', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ model: 'paraformer-v2', file_url: fileUrl }) }); const result = await response.json(); return result.data.task_id; } // 轮询查询任务状态 async function pollTaskStatus(taskId: string, maxAttempts = 60) { for (let i = 0; i < maxAttempts; i++) { const response = await fetch(`/api/v2/audio/asr/${taskId}`, { headers: { 'Authorization': `Bearer ${token}` } }); const result = await response.json(); const task = result.data; if (task.status === 'SUCCEEDED') { return task; // 成功,返回结果 } else if (task.status === 'FAILED') { throw new Error(task.error_message || '任务失败'); } // 等待2秒后继续轮询 await new Promise(resolve => setTimeout(resolve, 2000)); } throw new Error('任务超时'); } // 完整流程 async function recognizeAudio(fileUrl: string) { try { // 1. 创建任务 const taskId = await createASRTask(fileUrl); console.log('任务已创建:', taskId); // 2. 轮询查询 const result = await pollTaskStatus(taskId); console.log('识别结果:', result.result_text); return result; } catch (error) { console.error('识别失败:', error); throw error; } } ``` ### React Hook 示例 ```typescript import { useState, useEffect } from 'react'; function useAsyncTask(taskId: string | null) { const [task, setTask] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { if (!taskId) return; let cancelled = false; setLoading(true); const poll = async () => { try { const response = await fetch(`/api/v2/audio/tasks/${taskId}/status`, { headers: { 'Authorization': `Bearer ${token}` } }); const result = await response.json(); const taskData = result.data; if (cancelled) return; setTask(taskData); if (taskData.status === 'SUCCEEDED' || taskData.status === 'FAILED') { setLoading(false); } else { // 继续轮询 setTimeout(poll, 2000); } } catch (err) { if (!cancelled) { setError(err); setLoading(false); } } }; poll(); return () => { cancelled = true; }; }, [taskId]); return { task, loading, error }; } ``` ## 错误处理 ### 常见错误码 - `400` - 请求参数错误 - `401` - 未授权(token无效或过期) - `404` - 任务不存在 - `500` - 服务器内部错误 ### 错误响应格式 ```json { "code": 400, "message": "参数错误: file_url 不能为空", "data": null } ``` ## 最佳实践 1. **轮询间隔**: 建议2-5秒,避免过于频繁 2. **超时处理**: 设置最大轮询次数(如60次 = 2分钟) 3. **错误重试**: 网络错误可重试,业务错误不重试 4. **任务清理**: 完成的任务定期清理,避免数据堆积 5. **进度显示**: 长文本任务使用 progress 字段显示进度条 6. **并发控制**: 限制同时创建的任务数量 ## 迁移指南(V1 → V2) ### 主要变化 1. **同步 → 异步**: 所有接口改为异步模式 2. **立即返回 → 轮询查询**: 需要实现轮询机制 3. **路径变化**: `/api/audio/*` → `/api/v2/audio/*` ### 迁移步骤 1. 更新API路径 2. 实现轮询逻辑 3. 更新UI显示(添加加载状态) 4. 测试异步流程 5. 逐步切换到V2端点 ## 性能优化建议 1. **WebSocket**: 考虑使用WebSocket替代轮询(未来版本) 2. **缓存**: 缓存已完成任务的结果 3. **批量查询**: 使用任务列表接口批量查询状态 4. **CDN**: 音频文件使用CDN加速 ## 监控指标 - 任务创建速率 - 任务完成率 - 平均处理时间 - 失败率和失败原因 - API响应时间 ## 技术支持 如有问题,请查看: - 技术文档: `backend/docs/audio_v2_tables.md` - 开发进度: `memory-bank/development-progress.md`