diff --git a/docs/cosyvoice-copy.md b/docs/cosyvoice-copy.md deleted file mode 100644 index 898d996d39..0000000000 --- a/docs/cosyvoice-copy.md +++ /dev/null @@ -1,129 +0,0 @@ -# 阿里云CosyVoice声音复刻API说明文档 -## 一、接口概述 -CosyVoice声音复刻API依托大模型技术,仅需10~20秒清晰音频,即可快速生成高度拟真的定制音色(`voice_id`),支持`cosyvoice-v1`和`cosyvoice-v2`模型(v2效果更优)。复刻服务免费,使用复刻音色进行语音合成时按字符计费。 - -核心功能:音色的创建、查询、更新、删除,生成的`voice_id`可直接用于CosyVoice语音合成接口。 - -## 二、前提条件 -1. 开通CosyVoice服务,获取API Key(推荐配置到环境变量,避免硬编码)。 -2. 安装最新版DashScope SDK(Java/Python),其他语言需调用RESTful API。 -3. 准备公网可访问的音频URL(推荐上传至阿里云OSS,支持WAV/MP3/M4A格式)。 - -## 三、核心接口详情(支持Java/Python SDK + RESTful API) -### 1. 创建音色(生成voice_id) -#### 功能描述 -上传10~20秒音频,生成专属`voice_id`,用于后续语音合成。 -#### 请求参数 -| 参数名 | 类型 | 是否必填 | 说明 | -|--------------|--------|----------|----------------------------------------------------------------------| -| target_model | string | 是 | 复刻模型,支持`cosyvoice-v1`/`cosyvoice-v2` | -| prefix | string | 是 | 音色自定义前缀,仅允许数字和小写字母,长度<10字符 | -| url | string | 是 | 音频文件公网URL,需满足格式要求(采样率≥16kHz、文件≤10MB、含≥5秒连续语音) | -#### 响应参数 -| 参数名 | 类型 | 说明 | -|----------|--------|--------------------------| -| voice_id | string | 定制音色ID,用于语音合成 | -| request_id| string | 任务唯一标识,用于排查问题 | -#### 示例代码(Python SDK) -```python -import os -import dashscope -from dashscope.audio.tts_v2 import VoiceEnrollmentService - -dashscope.api_key = os.getenv('DASHSCOPE_API_KEY') -service = VoiceEnrollmentService() -# 调用创建接口 -voice_id = service.create_voice(target_model="cosyvoice-v2", prefix="test", url="音频公网URL") -print(f"生成的voice_id: {voice_id}") -``` - -### 2. 查询所有音色 -#### 功能描述 -查询账号下已创建的所有音色,支持按前缀筛选和分页。 -#### 请求参数 -| 参数名 | 类型 | 是否必填 | 说明 | -|------------|--------|----------|-------------------------------| -| prefix | string | 否 | 音色前缀,为空则返回所有音色 | -| page_index | int | 否 | 页码索引,默认0 | -| page_size | int | 否 | 每页条数,默认10 | -#### 响应参数 -| 参数名 | 类型 | 说明 | -|--------------|--------|----------------------------------------------------------------------| -| voice_list | array | 音色列表,含每个音色的`voice_id`、创建时间(gmt_create)、状态(status) | -| status | string | 音色状态:DEPLOYING(审核中)/OK(可用)/UNDEPLOYED(审核失败) | -| request_id | string | 任务唯一标识 | - -### 3. 查询指定音色 -#### 功能描述 -查询单个`voice_id`的详细信息(状态、原始音频URL等)。 -#### 请求参数 -| 参数名 | 类型 | 是否必填 | 说明 | -|----------|--------|----------|--------------------| -| voice_id | string | 是 | 需查询的音色ID | -#### 响应参数 -| 参数名 | 类型 | 说明 | -|----------------|--------|----------------------------------------------------------------------| -| voice_id | string | 音色ID | -| resource_link | string | 复刻所用音频的公网URL | -| target_model | string | 复刻时使用的模型 | -| status | string | 音色状态(DEPLOYING/OK/UNDEPLOYED) | -| gmt_create | string | 音色创建时间 | - -### 4. 更新音色 -#### 功能描述 -使用新的音频URL更新已有`voice_id`的音色。 -#### 请求参数 -| 参数名 | 类型 | 是否必填 | 说明 | -|----------|--------|----------|----------------------------------------------------------------------| -| voice_id | string | 是 | 需更新的音色ID | -| url | string | 是 | 新的音频公网URL(需满足格式要求) | -#### 响应参数 -| 参数名 | 类型 | 说明 | -|------------|--------|--------------------| -| request_id | string | 任务唯一标识 | - -### 5. 删除音色 -#### 功能描述 -删除无需使用的`voice_id`,释放配额(账号最多保留1000个音色)。 -#### 请求参数 -| 参数名 | 类型 | 是否必填 | 说明 | -|----------|--------|----------|--------------------| -| voice_id | string | 是 | 需删除的音色ID | -#### 响应参数 -| 参数名 | 类型 | 说明 | -|------------|--------|--------------------| -| request_id | string | 任务唯一标识 | - -## 四、音频文件要求 -1. 格式:支持WAV(16bit)、MP3、M4A。 -2. 采样率:≥16000Hz。 -3. 时长:10~20秒(建议不超过60秒),含至少一段≥5秒的连续语音。 -4. 大小:≤10MB。 -5. 质量:语音清晰、无杂音,朗读连贯。 - -## 五、使用流程(复刻→合成) -1. 调用「创建音色」接口,传入音频URL,获取`voice_id`。 -2. 调用CosyVoice语音合成接口,将`voice_id`作为`voice`参数传入,即可使用定制音色合成语音。 -3. (可选)通过「查询指定音色」接口确认`status`为`OK`后再使用。 - -## 六、关键限制 -1. 配额限制:每个主账号最多保留1000个复刻音色,删除后释放配额。 -2. 并发限制:复刻接口总并发≤10 RPS(v1+v2合计),语音合成接口并发≤3 RPS。 -3. 模型匹配:v1版本`voice_id`仅用于v1合成,v2版本`voice_id`仅用于v2合成,不可混用。 -4. 有效期:超过1年未使用的音色将自动下线。 - -## 七、常见错误码及解决方案 -| 错误码 | 说明 | 解决方案 | -|-------------------------|---------------------------------------|------------------------------------------------------------------| -| Throttling.AllocationQuota | 音色数量达限额 | 删除无用音色或提交工单申请扩容 | -| Audio.AudioShortError | 音频有效时长过短 | 重新录制10~20秒连续语音 | -| InvalidApiKey | API Key无效 | 检查API Key是否正确,无多余空格或缺失字符 | -| Model.AccessDenied | 模型访问权限不足 | 使用“默认业务空间”下的API Key调用 | -| BadRequest.UnsupportedFileFormat | 音频格式不支持 | 转换为WAV/MP3/M4A格式,确认文件实际编码与后缀一致 | -| Audio.FileSizeExceed | 音频文件超过10MB | 压缩文件大小或截取有效片段 | - -## 八、注意事项 -1. 版权要求:需对复刻音频的所有权及合法使用权负责,遵守服务协议。 -2. 音频URL:确保公网可访问,推荐使用阿里云OSS生成临时访问链接(避免长期公开泄露)。 -3. 升级建议:v1音色可使用原始音频重新复刻为v2版本,获得更优效果。 -4. 合成调节:使用`voice_id`合成语音时,可通过`volume`(音量)、`speechRate`(语速)等参数调节输出效果。 diff --git a/docs/cosyvoice-generate.md b/docs/cosyvoice-generate.md deleted file mode 100644 index 18406d9473..0000000000 --- a/docs/cosyvoice-generate.md +++ /dev/null @@ -1,271 +0,0 @@ -# 阿里云CosyVoice Java SDK 调用模板(参数+示例) -## 一、前提条件 -1. 开通CosyVoice服务,获取API Key(建议配置到环境变量,避免硬编码)。 -2. 安装最新版DashScope SDK(支持2.20.3+版本,SSML功能需此版本及以上)。 -3. 模型与音色需匹配(如v2模型对应v2音色,v3模型对应v3音色)。 - -## 二、核心参数汇总 -| 参数名 | 类型 | 是否必填 | 默认值 | 取值范围/说明 | -|--------------|------------|----------|-------------------------|------------------------------------------------------------------------------| -| model | String | 是 | - | cosyvoice-v1/v2/v3/v3-plus(v3系列需申请邀测) | -| voice | String | 是 | - | 对应模型的音色(如v2:longxiaochun_v2;v3:longhuohuo_v3,详见文档音色列表) | -| format | enum | 否 | 因音色而异(默认MP3 22050Hz) | 支持WAV/MP3/PCM/OGG_OPUS,如PCM_22050HZ_MONO_16BIT、MP3_24000HZ_MONO_256KBPS | -| volume | int | 否 | 50 | 0~100(音量大小) | -| speechRate | float | 否 | 1.0 | 0.5~2.0(语速,1.0为默认,约4字/秒) | -| pitchRate | float | 否 | 1.0 | 0.5~2.0(语调) | -| bit_rate | int | 否 | 32 | 6~510kbps(仅opus格式支持,v1模型不支持) | -| seed | int | 否 | 0 | 0~65535(随机数种子,仅v3/v3-plus支持) | -| style | int | 否 | 0 | ≥0整数(风格调整,仅v3/v3-plus支持) | -| languageHints| List | 否 | - | 仅v3/v3-plus支持,单次配置1个语种("zh"/"en") | -| instruction | String | 否 | - | 仅v3/v3-plus支持,格式:"你说话的情感是<情感值>"(如"Happy"/"Angry") | - -## 三、四种核心调用方式模板 -### 1. 同步调用(阻塞式,适合短文本) -```java -import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam; -import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer; -import java.io.File; -import java.io.FileOutputStream; -import java.nio.ByteBuffer; - -public class SyncCallTemplate { - // 配置参数(根据需求修改) - private static final String MODEL = "cosyvoice-v3"; // 模型 - private static final String VOICE = "longhuohuo_v3"; // 音色 - private static final String TEXT = "今天天气真好,适合出门散步!"; // ≤2000字符 - private static final String OUTPUT_FILE = "output.mp3"; // 输出文件 - - public static void main(String[] args) { - // 1. 构建请求参数 - SpeechSynthesisParam param = SpeechSynthesisParam.builder() - // .apiKey("your-api-key") // 未配置环境变量时打开 - .model(MODEL) - .voice(VOICE) - .volume(60) // 可选:调整音量 - .speechRate(1.1f) // 可选:调整语速 - .build(); - - // 2. 初始化合成器(同步调用传null) - SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); - ByteBuffer audioData = null; - - try { - // 3. 阻塞调用,获取完整音频 - audioData = synthesizer.call(TEXT); - // 4. 保存音频到本地 - if (audioData != null) { - try (FileOutputStream fos = new FileOutputStream(new File(OUTPUT_FILE))) { - fos.write(audioData.array()); - } - System.out.println("合成成功!输出文件:" + OUTPUT_FILE); - System.out.println("RequestId:" + synthesizer.getLastRequestId()); - System.out.println("首包延迟:" + synthesizer.getFirstPackageDelay() + "ms"); - } - } catch (Exception e) { - System.err.println("合成失败:" + e.getMessage()); - } finally { - // 5. 关闭WebSocket连接 - synthesizer.getDuplexApi().close(1000, "任务结束"); - } - } -} -``` - -### 2. 异步调用(非阻塞,短文本实时接收) -```java -import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult; -import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam; -import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer; -import com.alibaba.dashscope.common.ResultCallback; -import java.util.concurrent.CountDownLatch; - -public class AsyncCallTemplate { - private static final String MODEL = "cosyvoice-v2"; - private static final String VOICE = "longxiaochun_v2"; - private static final String TEXT = "欢迎使用阿里云CosyVoice语音合成服务!"; // ≤2000字符 - - public static void main(String[] args) throws InterruptedException { - CountDownLatch latch = new CountDownLatch(1); - - // 1. 配置回调(实时接收音频) - ResultCallback callback = new ResultCallback() { - @Override - public void onEvent(SpeechSynthesisResult result) { - // 接收音频分片(可实时播放或写入文件) - if (result.getAudioFrame() != null) { - System.out.println("收到音频分片,大小:" + result.getAudioFrame().capacity() + "字节"); - // 此处可添加音频处理逻辑(如流式播放、追加写入文件) - } - // 查看计费字符数(最终以最后一次为准) - if (result.getUsage() != null) { - System.out.println("当前计费字符数:" + result.getUsage().getCharacters()); - } - } - - @Override - public void onComplete() { - System.out.println("合成完成!"); - latch.countDown(); - } - - @Override - public void onError(Exception e) { - System.err.println("合成失败:" + e.getMessage()); - latch.countDown(); - } - }; - - // 2. 构建参数并初始化合成器 - SpeechSynthesisParam param = SpeechSynthesisParam.builder() - // .apiKey("your-api-key") - .model(MODEL) - .voice(VOICE) - .format(SpeechSynthesisAudioFormat.MP3_16000HZ_MONO_128KBPS) // 可选配置格式 - .build(); - SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback); - - try { - // 3. 非阻塞调用 - synthesizer.call(TEXT); - latch.await(); // 等待合成完成 - System.out.println("RequestId:" + synthesizer.getLastRequestId()); - } catch (Exception e) { - System.err.println("调用异常:" + e.getMessage()); - } finally { - synthesizer.getDuplexApi().close(1000, "任务结束"); - } - } -} -``` - -### 3. 流式调用(分段传文本,适合长文本) -```java -import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult; -import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat; -import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam; -import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer; -import com.alibaba.dashscope.common.ResultCallback; - -public class StreamingCallTemplate { - // 分段文本(每段≤2000字符,累计≤20万字符) - private static final String[] TEXT_SEGMENTS = { - "流式语音合成适合长文本场景,", - "可以分段发送文本,", - "服务端实时返回音频,", - "减少等待时间。" - }; - private static final String MODEL = "cosyvoice-v3"; - private static final String VOICE = "longchuanshu_v3"; - - public static void main(String[] args) { - // 1. 配置回调 - ResultCallback callback = new ResultCallback() { - @Override - public void onEvent(SpeechSynthesisResult result) { - if (result.getAudioFrame() != null) { - System.out.println("收到流式音频分片"); - // 处理音频(如实时播放、写入缓冲文件) - } - } - - @Override - public void onComplete() { - System.out.println("流式合成全部完成!"); - } - - @Override - public void onError(Exception e) { - System.err.println("流式合成失败:" + e.getMessage()); - } - }; - - // 2. 构建参数 - SpeechSynthesisParam param = SpeechSynthesisParam.builder() - // .apiKey("your-api-key") - .model(MODEL) - .voice(VOICE) - .format(SpeechSynthesisAudioFormat.PCM_22050HZ_MONO_16BIT) - .speechRate(0.9f) - .build(); - SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback); - - try { - // 3. 分段发送文本(间隔≤23秒) - for (String segment : TEXT_SEGMENTS) { - synthesizer.streamingCall(segment); - Thread.sleep(500); // 模拟文本输入间隔 - } - // 4. 必须调用:结束流式合成(触发剩余文本合成) - synthesizer.streamingComplete(); - System.out.println("RequestId:" + synthesizer.getLastRequestId()); - } catch (Exception e) { - System.err.println("调用异常:" + e.getMessage()); - } finally { - synthesizer.getDuplexApi().close(1000, "任务结束"); - } - } -} -``` - -### 4. Flowable调用(响应式编程,支持流式输入输出) -```java -import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam; -import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer; -import com.alibaba.dashscope.exception.NoApiKeyException; -import io.reactivex.Flowable; -import io.reactivex.BackpressureStrategy; - -public class FlowableCallTemplate { - private static final String MODEL = "cosyvoice-v2"; - private static final String VOICE = "longyingtian_v2"; - private static final String[] TEXT_ARRAY = {"响应式编程模式,", "支持流式输入输出,", "适合高并发场景。"}; - - public static void main(String[] args) throws NoApiKeyException { - // 1. 模拟流式文本输入 - Flowable textStream = Flowable.create(emitter -> { - new Thread(() -> { - for (String text : TEXT_ARRAY) { - emitter.onNext(text); - try { - Thread.sleep(800); - } catch (InterruptedException e) { - emitter.onError(e); - } - } - emitter.onComplete(); - }).start(); - }, BackpressureStrategy.BUFFER); - - // 2. 构建参数 - SpeechSynthesisParam param = SpeechSynthesisParam.builder() - // .apiKey("your-api-key") - .model(MODEL) - .voice(VOICE) - .volume(70) - .build(); - SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); - - try { - // 3. 流式调用并处理结果 - synthesizer.streamingCallAsFlowable(textStream) - .blockingForEach(result -> { - if (result.getAudioFrame() != null) { - System.out.println("Flowable收到音频,大小:" + result.getAudioFrame().capacity() + "字节"); - // 处理音频逻辑 - } - }); - System.out.println("Flowable合成完成!RequestId:" + synthesizer.getLastRequestId()); - } finally { - synthesizer.getDuplexApi().close(1000, "任务结束"); - } - } -} -``` - -## 四、核心注意事项 -1. 文本长度限制:非流式单次≤2000字符,流式累计≤20万字符(含SSML标签)。 -2. 字符计算规则:汉字=2字符,英文/数字/标点/空格=1字符。 -3. 流式调用必须调用`streamingComplete()`,否则结尾文本无法合成。 -4. 每次调用`call()`前需重新初始化`SpeechSynthesizer`实例。 -5. 音频格式需与播放器兼容(如MP3/OPUS支持流式播放,推荐使用ffmpeg、AudioFormat等工具)。 - diff --git a/docs/cosyvoice-ram-config.md b/docs/cosyvoice-ram-config.md deleted file mode 100644 index 6a520b2865..0000000000 --- a/docs/cosyvoice-ram-config.md +++ /dev/null @@ -1,156 +0,0 @@ -# CosyVoice访问OSS配置指南 - -## 问题说明 -CosyVoice复刻服务需要访问OSS存储的音频文件,但默认情况下CosyVoice没有访问用户OSS的权限。 - -## 解决方案:配置RAM权限 - -### 1. 创建RAM角色 -在阿里云RAM控制台创建角色,允许CosyVoice服务访问OSS: - -```json -{ - "Version": "1", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "oss:GetObject", - "oss:HeadObject" - ], - "Resource": [ - "acs:oss:*:*:{bucket-name}/*" - ] - } - ] -} -``` - -**参数说明:** -- `{bucket-name}`:替换为你的OSS存储桶名称 - -### 2. 配置信任策略 -为RAM角色添加信任策略,允许DashScope服务扮演该角色: - -```json -{ - "Version": "1", - "Statement": [ - { - "Effect": "Allow", - "Principal": { - "Service": [ - "dashscope.aliyuncs.com" - ] - }, - "Action": "sts:AssumeRole" - } - ] -} -``` - -### 3. 授权步骤(控制台操作) - -**步骤1:创建自定义权限策略** -1. 登录阿里云控制台 → 访问控制(RAM) → 权限管理 → 权限策略 -2. 点击"创建策略" -3. 选择"脚本配置" -4. 粘贴上述JSON权限策略 -5. 策略名称:`CosyVoice-OSS-Access` -6. 点击"确定" - -**步骤2:创建RAM角色** -1. RAM → 身份管理 → 角色 → 创建角色 -2. 选择"阿里云服务" → "DashScope" -3. 输入角色名称:`CosyVoice-OSS-Role` -4. 完成创建 - -**步骤3:授权角色访问OSS** -1. 在角色详情页面,点击"添加权限" -2. 搜索并添加: - - `AliyunOSSReadOnlyAccess`(阿里云OSS只读权限) - - `CosyVoice-OSS-Access`(自定义权限) -3. 点击"确定" - -**步骤4:获取ARN** -在角色详情页面,复制"ARN": -``` -acs:ram::{你的AccountID}:role/CosyVoice-OSS-Role -``` - -### 4. 配置application.yaml - -在 `yudao-server/src/main/resources/application.yaml` 中添加: - -```yaml -yudao: - cosyvoice: - # ... 其他配置 - # RAM角色ARN(用于授权CosyVoice访问OSS) - ram-role-arn: "acs:ram::{AccountID}:role/CosyVoice-OSS-Role" -``` - -### 5. 修改OSS访问方式 - -在 `CosyVoiceClient.buildClonePayload()` 中,添加授权信息: - -```java -// 在请求头中添加Authorization -Request httpRequest = new Request.Builder() - .url(properties.getVoiceEnrollmentUrl()) - .addHeader("Authorization", "Bearer " + properties.getApiKey()) - .addHeader("Content-Type", "application/json") - // 添加STS临时凭证(需要先调用AssumeRole获取临时凭证) - .addHeader("x-acs-security-token", "{security-token}") - .post(RequestBody.create(payload.getBytes(StandardCharsets.UTF_8), JSON)) - .build(); -``` - -### 6. 获取STS临时凭证(Java代码) - -```java -import com.aliyun.sts20150401.Client; -import com.aliyun.sts20150401.models.AssumeRoleRequest; -import com.aliyun.sts20150401.models.AssumeRoleResponse; - -public String getSecurityToken() { - // 需要配置RAM角色ARN和访问密钥 - AssumeRoleRequest request = new AssumeRoleRequest() - .setRoleArn(properties.getRamRoleArn()) - .setRoleSessionName("cosyvoice-session"); - - AssumeRoleResponse response = client.assumeRole(request); - return response.body.credentials.securityToken; -} -``` - -### 7. 完整实现思路 - -1. **本地开发**:使用STS临时凭证 -2. **生产环境**: - - 方案A:配置RAM角色,让CosyVoice直接访问OSS - - 方案B:将音频文件上传到CosyVoice可访问的公共OSS存储桶 - -## 替代方案:使用公共OSS存储桶 - -如果RAM权限配置复杂,可以: - -1. 创建公共可读的OSS存储桶 -2. 将音频文件上传到该存储桶 -3. 使用公共URL进行复刻 - -**注意**:公共存储桶存在安全风险,仅用于测试! - -## 验证配置 - -配置完成后,重新测试语音复刻功能: - -1. 查看日志中的请求URL是否可公网访问 -2. 查看是否还有"url error"错误 -3. 查看复刻是否成功返回voice_id - -## 参考资料 - -- [阿里云RAM权限管理](https://help.aliyun.com/zh/ram/instance/role/parameter-overview) -- [STS临时凭证](https://help.aliyun.com/zh/acs/STS/usage-scenarios/usage-scenarios) -- [CosyVoice错误代码](https://help.aliyun.com/zh/model-studio/error-code#error-url)