api_v2_guide.md 11 KB

语音合成坊 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 创建语音识别任务

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"
  }
}

1.2 查询识别任务

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"
  }
}

1.3 获取识别任务列表

GET /api/v2/audio/asr?page=1&page_size=20&status=SUCCEEDED
Authorization: Bearer {token}

2. 语音合成 (TTS)

2.1 创建语音合成任务

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"
  }
}

2.2 查询合成任务

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"
  }
}

2.3 获取合成任务列表

GET /api/v2/audio/synthesis?page=1&page_size=20
Authorization: Bearer {token}

3. 声音克隆

3.1 创建声音克隆任务

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"
  }
}

3.2 查询克隆任务

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"
  }
}

3.3 获取克隆任务列表

GET /api/v2/audio/voice-clone?page=1&page_size=20
Authorization: Bearer {token}

4. 长文本转音频

4.1 创建长文本转音频任务

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"
  }
}

4.2 查询长文本任务(带进度)

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"
  }
}

4.3 获取长文本任务列表

GET /api/v2/audio/long-text?page=1&page_size=20
Authorization: Bearer {token}

5. 任务管理

5.1 查询任务状态(通用)

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"
  }
}

5.2 取消任务

POST /api/v2/audio/tasks/{task_id}/cancel
Authorization: Bearer {token}

5.3 删除任务

DELETE /api/v2/audio/tasks/{task_id}
Authorization: Bearer {token}

5.4 批量删除任务

POST /api/v2/audio/tasks/batch-delete
Content-Type: application/json
Authorization: Bearer {token}

{
  "task_ids": ["task_1", "task_2", "task_3"]
}

5.5 获取任务统计

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"
  }
}

前端轮询示例

JavaScript/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 示例

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
}

最佳实践

  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