V2版本采用统一的异步架构,所有任务通过 task_id 追踪状态。客户端需要实现轮询机制来获取任务结果。
/api/v2/audio1. 创建任务 → 返回 task_id
2. 轮询查询 → 检查任务状态
3. 获取结果 → status = SUCCEEDED 时获取结果
PENDING - 等待处理PROCESSING - 处理中SUCCEEDED - 成功完成FAILED - 失败POST /api/v2/audio/asr/recognize
Content-Type: application/json
Authorization: Bearer {token}
{
"model": "paraformer-v2",
"file_url": "https://example.com/audio.mp3"
}
响应:
{
"code": 200,
"message": "success",
"data": {
"task_id": "task_xxx",
"status": "PENDING",
"created_at": "2026-01-09T10:00:00"
}
}
GET /api/v2/audio/asr/{task_id}
Authorization: Bearer {token}
响应(成功):
{
"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"
}
}
GET /api/v2/audio/asr?page=1&page_size=20&status=SUCCEEDED
Authorization: Bearer {token}
POST /api/v2/audio/synthesis
Content-Type: application/json
Authorization: Bearer {token}
{
"model": "cosyvoice-v1",
"voice": "longxiaochun",
"text": "你好,这是测试文本",
"format": "mp3"
}
响应:
{
"code": 200,
"message": "success",
"data": {
"task_id": "task_yyy",
"status": "PENDING",
"created_at": "2026-01-09T10:00:00"
}
}
GET /api/v2/audio/synthesis/{task_id}
Authorization: Bearer {token}
响应(成功):
{
"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"
}
}
GET /api/v2/audio/synthesis?page=1&page_size=20
Authorization: Bearer {token}
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"
}
响应:
{
"code": 200,
"message": "success",
"data": {
"task_id": "task_zzz",
"status": "PENDING",
"created_at": "2026-01-09T10:00:00"
}
}
GET /api/v2/audio/voice-clone/{task_id}
Authorization: Bearer {token}
响应(成功):
{
"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"
}
}
GET /api/v2/audio/voice-clone?page=1&page_size=20
Authorization: Bearer {token}
POST /api/v2/audio/long-text
Content-Type: application/json
Authorization: Bearer {token}
{
"model": "cosyvoice-v1",
"voice": "longxiaochun",
"text": "这是一段很长的文本...",
"format": "mp3"
}
响应:
{
"code": 200,
"message": "success",
"data": {
"task_id": "uuid_xxx",
"status": "PENDING",
"segment_count": 5,
"progress": 0,
"created_at": "2026-01-09T10:00:00"
}
}
GET /api/v2/audio/long-text/{task_id}
Authorization: Bearer {token}
响应(处理中):
{
"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"}
]
}
}
响应(成功):
{
"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"
}
}
GET /api/v2/audio/long-text?page=1&page_size=20
Authorization: Bearer {token}
GET /api/v2/audio/tasks/{task_id}/status
Authorization: Bearer {token}
响应:
{
"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"
}
}
POST /api/v2/audio/tasks/{task_id}/cancel
Authorization: Bearer {token}
DELETE /api/v2/audio/tasks/{task_id}
Authorization: Bearer {token}
POST /api/v2/audio/tasks/batch-delete
Content-Type: application/json
Authorization: Bearer {token}
{
"task_ids": ["task_1", "task_2", "task_3"]
}
GET /api/v2/audio/tasks/statistics
Authorization: Bearer {token}
响应:
{
"code": 200,
"message": "success",
"data": {
"total_tasks": 100,
"pending_tasks": 5,
"processing_tasks": 3,
"succeeded_tasks": 85,
"failed_tasks": 7,
"total_bill": "12.50"
}
}
// 创建任务
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;
}
}
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 - 服务器内部错误{
"code": 400,
"message": "参数错误: file_url 不能为空",
"data": null
}
/api/audio/* → /api/v2/audio/*如有问题,请查看:
backend/docs/audio_v2_tables.mdmemory-bank/development-progress.md