手把手教你接入阿里云 Qwen TTS,让 AI 帮你「开口说话」
🎙️ 从 API 申请到代码落地,一篇搞定 AI 语音合成
📖 前言
最近在搞一个需要语音合成的小项目,调研了一圈市面上的 TTS 服务:
| 服务 | 优点 | 缺点 |
|---|---|---|
| OpenAI TTS | 效果顶级 | 贵、中文一般、需要梯子 |
| Azure Speech | 稳定、音色多 | 配置复杂、计费不透明 |
| 讯飞语音 | 老牌、稳定 | 中规中矩、克隆能力弱 |
| 百度语音 | 便宜 | 效果一般 |
| Qwen TTS | 中文自然、支持克隆、SSML 完善 | 文档稍乱(所以写了这篇) |
最后选了 阿里云 Qwen TTS(CosyVoice),跑了一段时间感觉还不错,这里把完整的接入流程和踩坑经验分享出来。
本文你将学到:
- ✅ 如何申请 API Key
- ✅ TTS 接口怎么调
- ✅ 预置音色 & 克隆自己的声音
- ✅ 用 SSML 让语音有情感变化
- ✅ cURL / Node.js 代码模板(直接复制能跑)
废话不多说,直接开整 👇
目录
什么是 Qwen TTS
Qwen TTS 是阿里云通义千问(Qwen)推出的语音合成服务,基于 CosyVoice 模型,能够将文本转换为自然流畅的语音。
核心特点
| 特性 | 说明 |
|---|---|
| 多音色支持 | 提供丰富的预置音色,涵盖男声、女声、不同语言和风格 |
| 音色克隆 | 支持上传音频样本,克隆自定义音色 |
| SSML 支持 | 支持语音合成标记语言,精细控制语速、停顿、情感等 |
| 流式输出 | 支持 WebSocket 流式返回音频,适合实时场景 |
| 高质量音频 | 支持多种采样率(8k-48k)和格式(mp3/wav/pcm) |
可用模型
| 模型名称 | 说明 |
|---|---|
cosyvoice-v3-plus | 推荐使用,支持音色克隆,效果最佳 |
cosyvoice-v3-flash | 快速版本,响应更快,适合对延迟敏感的场景 |
获取 API Key
步骤 1:注册/登录阿里云
访问 阿里云官网,注册或登录你的账号。
步骤 2:开通百炼服务
- 进入 阿里云百炼控制台
- 首次使用需要开通服务(免费开通)
- 新用户通常有免费额度可用
步骤 3:创建 API Key
- 在百炼控制台左侧菜单找到 API-KEY 管理
- 点击 创建新的 API-KEY
- 复制并妥善保存你的 API Key
⚠️ 安全提示:API Key 是敏感信息,请勿在客户端代码或公开仓库中暴露。
API 接口说明
Qwen TTS 提供两种调用方式:
1. HTTP API(简单场景)
适合一次性合成短文本。
Endpoint:
POST https://dashscope.aliyuncs.com/api/v1/services/aigc/text2audio/text-to-audio
Headers:
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
2. WebSocket API(流式/长文本)
适合实时流式输出或长文本合成。
Endpoint:
wss://dashscope.aliyuncs.com/api-ws/v1/inference/
核心参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | string | 是 | 模型名称,如 cosyvoice-v3-plus |
text | string | 是 | 要合成的文本内容 |
voice | string | 是 | 音色 ID(预置或克隆) |
format | string | 否 | 音频格式:mp3(默认)、wav、pcm |
sample_rate | int | 否 | 采样率:8000、16000、22050(默认)、24000、44100、48000 |
volume | int | 否 | 音量:0-100,默认 50 |
rate | float | 否 | 语速:0.5-2.0,默认 1.0 |
pitch | float | 否 | 音调:0.5-2.0,默认 1.0 |
enable_ssml | bool | 否 | 是否启用 SSML 解析,默认 false |
获取 Voice ID
方式一:使用预置音色
阿里云提供了丰富的预置音色,无需额外配置即可使用。
常用预置音色示例:
| Voice ID | 描述 |
|---|---|
longxiaochun | 龙小淳,女声,温柔知性 |
longxiaoxia | 龙小夏,女声,活泼可爱 |
longyuan | 龙媛,女声,亲切自然 |
longwan | 龙湾,男声,沉稳大气 |
longjielidou | 龙杰力豆,男声,阳光活力 |
完整音色列表请参考:CosyVoice 音色列表
方式二:克隆自定义音色
如果预置音色不满足需求,可以上传音频样本克隆专属音色。
克隆步骤:
-
准备音频样本
- 格式:MP3 或 WAV
- 时长:建议 10-30 秒
- 质量:清晰的人声,避免背景噪音
-
调用克隆 API
# 1. 上传音频获取 URL(或使用已有的公网音频 URL)
# 2. 创建克隆音色
curl -X POST "https://dashscope.aliyuncs.com/api/v1/services/audio/tts/customization" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "cosyvoice-v3-plus",
"action": "create",
"prefix": "myvoice",
"url": "https://your-audio-url.com/sample.mp3"
}'
-
获取 Voice ID
- 克隆成功后会返回
voice_id - 格式类似:
cosyvoice-v3-plus-voice-xxxxxxxxxxxx - 该 ID 可永久使用
- 克隆成功后会返回
-
查询克隆状态
curl -X POST "https://dashscope.aliyuncs.com/api/v1/services/audio/tts/customization" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "cosyvoice-v3-plus",
"action": "query",
"voice_id": "YOUR_VOICE_ID"
}'
状态说明:
DEPLOYING:处理中,请等待OK:已就绪,可以使用UNDEPLOYED:处理失败
代码示例
cURL 示例
HTTP API(同步)
curl -X POST "https://dashscope.aliyuncs.com/api/v1/services/aigc/text2audio/text-to-audio" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "cosyvoice-v3-plus",
"input": {
"text": "你好,欢迎使用阿里云语音合成服务。"
},
"parameters": {
"voice": "longxiaochun",
"format": "mp3",
"sample_rate": 22050,
"volume": 50,
"rate": 1.0,
"pitch": 1.0
}
}' \
--output output.mp3
Node.js 示例
WebSocket 流式合成
const WebSocket = require('ws');
const fs = require('fs');
const { v4: uuidv4 } = require('uuid');
const API_KEY = 'YOUR_API_KEY';
/**
* 使用 WebSocket 流式合成语音
* @param {string} text - 要合成的文本
* @param {string} voiceId - 音色 ID
* @param {string} outputPath - 输出文件路径
* @param {Object} options - 可选参数
*/
async function synthesize(text, voiceId, outputPath, options = {}) {
const {
model = 'cosyvoice-v3-plus',
format = 'mp3',
sampleRate = 22050,
volume = 50,
rate = 1.0,
pitch = 1.0
} = options;
const taskId = uuidv4();
return new Promise((resolve, reject) => {
const ws = new WebSocket('wss://dashscope.aliyuncs.com/api-ws/v1/inference/', {
headers: {
'Authorization': `bearer ${API_KEY}`
}
});
const fileStream = fs.createWriteStream(outputPath);
ws.on('open', () => {
console.log('WebSocket 连接成功');
// 发送任务请求
const runTaskMessage = {
header: {
action: 'run-task',
task_id: taskId,
streaming: 'duplex'
},
payload: {
task_group: 'audio',
task: 'tts',
function: 'SpeechSynthesizer',
model: model,
parameters: {
text_type: 'PlainText',
voice: voiceId,
format: format,
sample_rate: sampleRate,
volume: volume,
rate: rate,
pitch: pitch
},
input: {}
}
};
ws.send(JSON.stringify(runTaskMessage));
});
ws.on('message', (data, isBinary) => {
if (isBinary) {
// 二进制数据是音频流
fileStream.write(data);
} else {
const message = JSON.parse(data.toString());
const event = message.header?.event;
switch (event) {
case 'task-started':
console.log('任务已启动,发送文本...');
// 发送文本内容
ws.send(JSON.stringify({
header: {
action: 'continue-task',
task_id: taskId,
streaming: 'duplex'
},
payload: {
input: { text: text }
}
}));
// 发送结束信号
setTimeout(() => {
ws.send(JSON.stringify({
header: {
action: 'finish-task',
task_id: taskId,
streaming: 'duplex'
},
payload: { input: {} }
}));
}, 100);
break;
case 'task-finished':
console.log('语音合成完成');
fileStream.end(() => {
ws.close();
resolve(outputPath);
});
break;
case 'task-failed':
const error = message.header?.error_message || '未知错误';
console.error('合成失败:', error);
fileStream.end();
ws.close();
reject(new Error(error));
break;
}
}
});
ws.on('error', (error) => {
console.error('WebSocket 错误:', error.message);
fileStream.end();
reject(error);
});
});
}
// 使用示例
synthesize(
'你好,这是一段测试语音。',
'longxiaochun', // 或使用克隆的 voice_id
'./output.mp3'
).then(path => {
console.log('输出文件:', path);
}).catch(err => {
console.error('错误:', err.message);
});
HTTP API 简单调用
const https = require('https');
const fs = require('fs');
const API_KEY = 'YOUR_API_KEY';
async function textToSpeech(text, voiceId, outputPath) {
const requestBody = JSON.stringify({
model: 'cosyvoice-v3-plus',
input: { text },
parameters: {
voice: voiceId,
format: 'mp3',
sample_rate: 22050
}
});
const options = {
hostname: 'dashscope.aliyuncs.com',
path: '/api/v1/services/aigc/text2audio/text-to-audio',
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(requestBody)
}
};
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
const fileStream = fs.createWriteStream(outputPath);
res.pipe(fileStream);
fileStream.on('finish', () => {
fileStream.close();
resolve(outputPath);
});
});
req.on('error', reject);
req.write(requestBody);
req.end();
});
}
// 使用示例
textToSpeech('你好世界', 'longxiaochun', './hello.mp3');
SSML 情感表达
想让合成的语音更有感染力?SSML(语音合成标记语言)可以帮你实现丰富的情感变化。
什么是 SSML
SSML(Speech Synthesis Markup Language)是一种 XML 格式的标记语言,用于精细控制语音合成的各种细节:
- 语速 (
rate):控制说话快慢 - 音调 (
pitch):控制声音高低 - 音量 (
volume):控制声音大小 - 停顿 (
<break>):在特定位置添加停顿 - 音效 (
effect):添加机器人、萝莉、回声等特效
基本语法
所有 SSML 内容必须包裹在 <speak> 标签中:
<speak rate="1.0" pitch="1.0" volume="50">
你的文本内容
</speak>
情绪参数预设
通过调整 rate、pitch、volume 三个参数的组合,可以表达不同的情绪:
| 情绪 | rate | pitch | volume | 特点描述 |
|---|---|---|---|---|
| 😊 开心/兴奋 | 1.15 | 1.1 | 65 | 语速快、音调高、音量大 |
| 😢 悲伤/失落 | 0.85 | 0.9 | 40 | 语速慢、音调低、音量小 |
| 😠 生气/愤怒 | 1.2 | 1.05 | 75 | 语速快、音调略高、音量大 |
| 🥰 温柔/安慰 | 0.9 | 1.05 | 45 | 语速慢、音调略高、音量轻柔 |
| 😲 惊讶/震惊 | 1.1 | 1.15 | 60 | 语速略快、音调明显升高 |
| 😟 担忧/紧张 | 0.95 | 0.95 | 50 | 语速略慢、音调略低 |
| 🤔 疑惑/困惑 | 0.9 | 1.0 | 50 | 语速慢、正常音调 |
| 💪 自信/坚定 | 1.0 | 1.0 | 65 | 正常语速、音量大 |
停顿控制
使用 <break> 标签添加停顿,让语音更自然:
| 场景 | 推荐时长 |
|---|---|
| 逗号/顿号后 | 50-100ms |
| 句号后 | 300-500ms |
| 思考/犹豫 | 200-400ms |
| 戏剧性停顿 | 500-1000ms |
| 段落间 | 1-2s |
实用示例
示例 1:开心地打招呼
<speak rate="1.15" pitch="1.1" volume="65">
哇!<break time="200ms"/>好久不见!<break time="300ms"/>
最近过得怎么样?
</speak>
示例 2:悲伤的告别
<speak rate="0.85" pitch="0.9" volume="40">
好吧...<break time="500ms"/>
我知道了。<break time="400ms"/>
那就...<break time="300ms"/>再见吧。
</speak>
示例 3:愤怒的质问
<speak rate="1.2" pitch="1.05" volume="75">
不行!<break time="200ms"/>
绝对不行!<break time="300ms"/>
你到底在想什么?
</speak>
示例 4:温柔的安慰
<speak rate="0.9" pitch="1.05" volume="45">
别担心,<break time="400ms"/>
一切都会好起来的。<break time="500ms"/>
我会一直陪着你。
</speak>
示例 5:情绪转换(从疑惑到惊喜)
<speak>
<speak rate="0.9" pitch="1.0" volume="50">
这是什么?<break time="400ms"/>
</speak>
<speak rate="1.15" pitch="1.15" volume="65">
哇!<break time="200ms"/>是我一直想要的礼物!
</speak>
</speak>
示例 6:讲故事(多情绪切换)
<speak rate="1.0" pitch="1.0" volume="50">
从前有一座山,<break time="300ms"/>山里有一座庙。
<break time="500ms"/>
<speak rate="0.9" pitch="0.95" volume="45">
老和尚对小和尚说...<break time="600ms"/>
</speak>
<speak rate="1.1" pitch="1.1" volume="60">
"小和尚!<break time="200ms"/>去打水!"
</speak>
</speak>
用 AI 生成 SSML
手动编写 SSML 比较繁琐,推荐使用 AI 工具(如 ChatGPT、Claude、通义千问等)自动转换。
Prompt 模板
将以下 Prompt 发送给 AI,即可将普通文本转换为带情感的 SSML:
请将以下文本转换为 Qwen TTS 的 SSML 格式。要求:
1. 根据语境添加适当的情感参数(rate/pitch/volume)
2. 在合适的位置添加停顿(<break>)
3. 情绪变化处使用嵌套的 <speak> 标签
4. 参考情绪参数:
- 开心:rate=1.15, pitch=1.1, volume=65
- 悲伤:rate=0.85, pitch=0.9, volume=40
- 生气:rate=1.2, pitch=1.05, volume=75
- 温柔:rate=0.9, pitch=1.05, volume=45
需要转换的文本:
"""
[在这里粘贴你的文本]
"""
转换示例
原始文本:
你怎么才来?我等了你好久!算了算了,看你这么辛苦,我就不怪你了。走吧,我们去吃饭。
AI 转换后的 SSML:
<speak>
<speak rate="1.15" pitch="1.05" volume="70">
你怎么才来?<break time="200ms"/>
我等了你好久!
</speak>
<break time="500ms"/>
<speak rate="0.95" pitch="1.0" volume="50">
算了算了,<break time="300ms"/>
看你这么辛苦,<break time="200ms"/>我就不怪你了。
</speak>
<break time="400ms"/>
<speak rate="1.1" pitch="1.1" volume="60">
走吧,<break time="200ms"/>我们去吃饭!
</speak>
</speak>
API 调用注意事项
使用 SSML 时,需要在 API 参数中启用:
parameters: {
voice: 'your_voice_id',
format: 'mp3',
enable_ssml: true // 必须设为 true
}
特殊字符转义:
| 字符 | 转义写法 |
|---|---|
" | " |
' | ' |
& | & |
< | < |
> | > |
常见问题
Q: 如何选择合适的模型?
| 场景 | 推荐模型 |
|---|---|
| 音色克隆 | cosyvoice-v3-plus |
| 追求低延迟 | cosyvoice-v3-flash |
| 高质量要求 | cosyvoice-v3-plus |
Q: 支持哪些音频格式?
| 格式 | 说明 |
|---|---|
mp3 | 通用格式,体积小,推荐使用 |
wav | 无损格式,体积较大 |
pcm | 原始音频数据,需自行处理 |
Q: 如何调整语音效果?
- 语速:调整
rate参数(0.5-2.0),值越大越快 - 音调:调整
pitch参数(0.5-2.0),值越大越高 - 音量:调整
volume参数(0-100)
Q: 长文本如何处理?
- 建议使用 WebSocket 流式 API
- 可将长文本分段处理,然后拼接音频
- 注意单次请求的文本长度限制(通常 5000 字符)
Q: 克隆音色的音频要求?
- 时长:10-30 秒效果最佳
- 格式:MP3 或 WAV
- 质量:清晰人声,无背景音乐/噪音
- 内容:自然说话,语速适中
参考链接
最后更新:2026 年 2 月