该 API 提供基于 WebSocket 的实时文本到语音(Text-to-Speech, TTS)合成功能,支持增量式文本输入和流式音频输出。单次请求支持的最大文本长度为 10000 字符,适用于实时对话、在线客服、语音交互等场景。
WebSocket TTS 通信遵循以下流程:
1. 客户端建立 WebSocket 连接
↓
2. 服务端返回 connected_success 事件
↓
3. 客户端发送 task_start 事件(包含音色、音频格式等配置)
↓
4. 服务端返回 task_started 事件
↓
5. 客户端发送 task_continue 事件(发送待合成文本)
↓
6. 服务端返回音频数据(可多次发送 task_continue)
↓
7. 客户端发送 task_finish 事件
↓
8. 服务端返回 task_finished 事件并关闭连接发送此事件正式开始合成任务。当服务端返回 task_started 事件时,标志着任务已成功开始。只有在接收到该事件后,才能向服务器发送 task_continue 或 task_finish 事件。
| 参数名 | 必填 | 说明 | 示例 |
|---|---|---|---|
| Authorization | 是 | 鉴权 Token。格式:Bearer API_KEY | Bearer sk-123456… |
| Content-Type | 是 | 内容类型。固定为 application/json | application/json |
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| event | string | 是 | 无 | 固定值:task_start |
| model | string | 是 | 无 | 模型名称,固定为 SenseAudio-TTS-1.0 |
| voice_setting | object | 是 | 无 | 声音设置 |
| voice_setting.voice_id | string | 是 | 无 | 主音色名称 |
| voice_setting.speed | float | 否 | 1.0 | 语速,取值范围 [0.5, 2.0] |
| voice_setting.vol | float | 否 | 1.0 | 音量,取值范围 (0, 10] |
| voice_setting.pitch | int | 否 | 0 | 音调,取值范围 [-12, 12],0 表示保持原始音调 |
| audio_setting | object | 否 | 无 | 音频格式设置 |
| audio_setting.sample_rate | int | 否 | 32000 | 音频采样率,取值范围 [8000, 16000, 22050, 24000, 32000, 44100] |
| audio_setting.bitrate | int | 否 | 128000 | 音频码率,取值范围 [32000, 64000, 128000, 256000] |
| audio_setting.format | string | 否 | mp3 | 输出格式:mp3、wav、pcm、flac |
| audio_setting.channel | int | 否 | 2 | 音频声道,1:单声道,2:双声道 |
{
"event": "task_start",
"model": "SenseAudio-TTS-1.0",
"voice_setting": {
"voice_id": "girl_banxia",
"speed": 1,
"vol": 1,
"pitch": 0
},
"audio_setting": {
"sample_rate": 32000,
"bitrate": 128000,
"format": "mp3",
"channel": 1
}
}| 参数名 | 类型 | 说明 |
|---|---|---|
| session_id | string | 会话 ID |
| event | string | 事件类型 |
| trace_id | string | 链路追踪 ID |
| base_resp | object | 请求状态信息 |
| base_resp.status_code | int64 | 状态码 |
| base_resp.status_msg | string | 状态详情 |
{
"session_id": "69c20e38c8761996a85d57881fe4d817",
"event": "task_started",
"trace_id": "69c20e38c8761996a85d57881fe4d817",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}当收到服务端返回的 task_started 事件后,任务正式开始,可通过发送 task_continue 事件发送要合成的文本。支持顺序发送多个 task_continue 事件,实现分段文本合成。
| 参数名 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| event | string | 是 | 固定值:task_continue | |
| text | string | 是 | 合成文本内容(支持中英文)<break time=500>详解见下方停顿符说明 | |
| dictionary | array | 否 | 多音字配置列表。详见下表(仅克隆音色使用、模型必须为SenseAudio-TTS-1.5) | [{“original”: “好干净”,“replacement”: “[hao4]干净”}] |
<break> 用于在语音合成中插入停顿。
<break time=500>示例:
你好<break time=500>欢迎使用我们的服务| 参数名 | 类型 | 必填 | 描述 | 默认值 | 示例 |
|---|---|---|---|---|---|
| original | string | 是 | 原始文本。 | 无 | 铺床铺地,量米量酒杯 |
| replacement | int | 是 | 多音字配置。 | 无 | 铺床铺[di4],[liang2]米[liang4]酒杯 |
{
"event": "task_continue",
"text": "人生就像一场马拉松,重要的不是跑得多快"
}| 参数名 | 类型 | 说明 |
|---|---|---|
| session_id | string | 会话 ID |
| event | string | 事件类型 |
| trace_id | string | 链路追踪 ID |
| is_final | bool | 该请求返回是否完结 |
| base_resp | object | 请求状态信息 |
| base_resp.status_code | int64 | 状态码 |
| base_resp.status_msg | string | 状态详情 |
| data | object | 返回的合成数据对象(可能为 null) |
| data.audio | string | 合成后的音频数据(hex 编码) |
| data.status | int64 | 音频流状态:1 表示合成中,2 表示合成结束 |
| extra_info | object | 音频附加信息(流式返回时只有最后一个 chunk 会返回) |
| extra_info.audio_length | int64 | 音频时长(毫秒) |
| extra_info.audio_sample_rate | int64 | 音频采样率 |
| extra_info.audio_size | int64 | 音频文件大小(字节) |
| extra_info.bitrate | int64 | 音频比特率 |
| extra_info.audio_format | string | 音频格式,取值范围 [mp3, pcm, flac, wav] |
| extra_info.audio_channel | int | 音频声道数,1:单声道,2:双声道 |
| extra_info.word_count | int64 | 字数统计(按 grapheme cluster 统计,排除纯空白/标点/控制符) |
| extra_info.character_count | int64 | 字符数统计(按 Unicode 码点统计) |
{
"session_id": "69c20e38c8761996a85d57881fe4d817",
"event": "task_continue",
"trace_id": "69c20e38c8761996a85d57881fe4d817",
"is_final": false,
"data": {
"audio": "hex编码的音频数据...",
"status": 1
},
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}服务端收到此事件后,会等待当前队列中所有合成任务完成后,关闭 WebSocket 连接并结束任务。
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | string | 是 | 固定值:task_finish |
{
"event": "task_finish"
}| 参数名 | 类型 | 说明 |
|---|---|---|
| session_id | string | 会话 ID |
| event | string | 事件类型 |
| trace_id | string | 链路追踪 ID |
| base_resp | object | 请求状态信息 |
| base_resp.status_code | int64 | 状态码 |
| base_resp.status_msg | string | 状态详情 |
{
"session_id": "69c20e38c8761996a85d57881fe4d817",
"event": "task_finished",
"trace_id": "69c20e38c8761996a85d57881fe4d817",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}初次请求接口时,表示 WebSocket 连接建立成功。
{
"session_id": "xxxx",
"event": "connected_success",
"trace_id": "xxx",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}标志任务已成功开始,客户端可以开始发送 task_continue 事件。
{
"session_id": "xxxx",
"event": "task_started",
"trace_id": "xxxxx",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}标志任务已结束,WebSocket 连接即将关闭。
{
"session_id": "xxxx",
"event": "task_finished",
"trace_id": "xxxx",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}标志任务失败,包含错误信息。
{
"session_id": "xxxx",
"event": "task_failed",
"trace_id": "xxxxx",
"base_resp": {
"status_code": 1004,
"status_msg": "具体错误信息"
}
}const fs = require('fs')
const WebSocket = require('ws')
const WS_URL = 'wss://api.senseaudio.cn/ws/v1/t2a_v2'
const API_KEY = process.env.SENSEAUDIO_API_KEY
if (!API_KEY) {
throw new Error('Missing env: SENSEAUDIO_API_KEY')
}
// 这里以“把所有分片写入文件”为例。若要边播边放,可将 audioBuffer 推入播放器/解码器。
const output = fs.createWriteStream('output.mp3')
const ws = new WebSocket(WS_URL, {
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
})
ws.on('open', () => {
console.log('WebSocket 连接已建立')
})
ws.on('message', (data) => {
const response = JSON.parse(data.toString())
console.log('收到服务端事件:', response.event)
if (response.event === 'connected_success') {
ws.send(
JSON.stringify({
event: 'task_start',
model: 'SenseAudio-TTS-1.0',
voice_setting: {
voice_id: 'female_jiaomei',
speed: 1.0,
vol: 1.0,
pitch: 0,
},
audio_setting: {
sample_rate: 32000,
bitrate: 128000,
format: 'mp3',
channel: 1,
},
})
)
return
}
if (response.event === 'task_started') {
ws.send(
JSON.stringify({
event: 'task_continue',
text: '道可道,非常道。名可名,非常名。无名天地之始,有名万物之母。',
})
)
ws.send(
JSON.stringify({
event: 'task_continue',
text: '故常无欲,以观其妙;常有欲,以观其徼。',
})
)
ws.send(JSON.stringify({ event: 'task_finish' }))
return
}
if (response?.data?.audio) {
const audioBuffer = Buffer.from(response.data.audio, 'hex')
output.write(audioBuffer)
}
if (response.event === 'task_finished') {
output.end()
ws.close()
}
if (response.event === 'task_failed') {
console.error('任务失败:', response?.base_resp?.status_msg)
output.end()
ws.close()
}
})
ws.on('error', (err) => {
console.error('WebSocket 错误:', err)
})
ws.on('close', () => {
console.log('WebSocket 连接已关闭')
})| 参数 | 取值范围 | 默认值 | 说明 |
|---|---|---|---|
| 语速 | [0.5, 2.0] | 1.0 | 数值越大语速越快 |
| 音量 | [0, 10] | 1.0 | 数值越大音量越大 |
| 音调 | [-12, 12] | 0 | 正值提高,负值降低 |
| 采样率 | 8000, 16000, 22050, 24000, 32000, 44100 (Hz) | 32000 | 推荐 32000 |
| 码率 | 32000, 64000, 128000, 256000 (bps) | 128000 | 仅 MP3 格式 |
| 声道 | 1 (单声道), 2 (双声道) | 2 | - |
| 状态码 | 说明 | 解决方案 |
|---|---|---|
| 0 | 成功 | - |
| 1001 | 参数错误 | 检查请求参数格式和取值范围 |
| 1002 | 模型不存在 | 确认模型名称是否正确 |
| 1003 | 音色不存在 | 确认音色 ID 是否正确 |
| 1004 | 文本内容违规 | 检查文本内容是否符合规范 |
| 1005 | 文本长度超限 | 控制单次文本长度在限制内 |
| 2001 | 服务内部错误 | 稍后重试或联系技术支持 |
| 2002 | 合成队列已满 | 稍后重试 |
| 3001 | 连接已超时 | 重新建立连接 |
音频数据格式:
连接超时机制:
事件发送顺序:
内容检测:
如需技术支持或有任何问题,请联系: