Skip to main content

音频生成接口


一、同步生成接口​

接口信息​

  • 接口路径: /v1/text-to-speech
  • 请求方式: POST
  • 认证方式: Header 中的 X-API-Key
  • 响应方式: 同步返回,响应体为音频二进制数据

请求头​

参数名类型必填说明
X-API-Keystring是应用密钥

注意: X-API-Key 用于验证账户信息,进入 控制台 → 项目空间,选择对应项目,左侧导航进入「API Key 管理」即可创建/查看。

请求参数​

参数名类型必填说明
voice_idstring是音色 ID,例如:jingcheng、bochuan、zhining、nianan;请选择当前项目可用的音色
generate_textstring是需要转换的文本内容;长度按平台统一加权规则计算(中文汉字计 2,其他字符计 1),当前公开环境上限为 500 加权字符;支持在文本中使用 [laughs] 等模型标签
languagestring否系统音色可省略;个人音色不传时默认中文 zh,英文请传 en
text_normalizationboolean否默认 true;传 false 关闭文本归一化并按原文合成(仅标准 Luna 模型)
model_idstring否默认 lunatts-0813。
emotion_classstring否默认 default;当前标准 Luna 模型不处理此参数
speednumber否语速倍率,范围 0.6–1.2;不传或为 0 时默认 1.0,超出范围返回参数错误
audio_formatstring否不传、空值或 wav 返回 WAV;pcm / pcm_s16le 返回原始 PCM S16LE

文本归一化与标签​

以下用法适用于本页的同步和流式接口。

  • TN:text_normalization 默认 true,会对数字、日期等文本做归一化处理;如需按原文合成,请显式传 false。请传 JSON 布尔值,不要传字符串 "true" / "false"。
  • 标签:直接将下表中的标签写入 generate_text,保留英文拼写和半角方括号;不需要单独的 tags 参数,也不通过 emotion_class 传递。TN 与标签可以同时使用。
标签含义
[laughs]笑声
[chuckles]轻笑
[gasps]倒吸气
[sighs]叹气
[inhales]吸气
[breath]呼吸声
[exhale]呼气
[coughs]咳嗽
[clears throat]清嗓子
[sniffles]吸鼻子
[snorts]鼻哼声
[hisses]嘶声
[tsks]啧声
[groans]低吟声

例如,使用标签并开启 TN:

{
"voice_id": "qinyao",
"model_id": "lunatts-0813",
"generate_text": "[laughs] 今天是2026年9月8日,温度36度。",
"text_normalization": true
}

响应说明​

请求成功时,接口直接返回音频二进制数据。Content-Type 是客户端判断实际格式的唯一依据;不要仅根据请求参数或文件扩展名推断格式。

模型audio_format实际输出Content-Type
lunatts-0813不传、空值或 wavWAVaudio/wav
lunatts-0813pcm / pcm_s16le原始 PCM S16LEaudio/pcm

WAV / PCM 音频均为 24000 Hz、单声道、16-bit;原始 PCM 为 Signed Little-Endian,不含 WAV 文件头。

响应头如下:

响应头说明
Content-Type实际输出的 MIME 类型;客户端必须以此为准
X-Audio-Sample-Rate音频采样率(当前为 24000)
X-Audio-Channels音频声道数(当前为 1)
X-Audio-Bit-Depth音频位深(当前为 16)

鉴权、参数或余额等业务失败时,HTTP 状态码仍为 200,Content-Type 为 application/json,响应体包含 succeed: false、error_code 和 error_message。必须先区分 JSON 与音频,不能仅凭 HTTP 200 判断成功。

请求示例​

以下命令将响应头保存到 response-headers.txt,响应体保存到 response.bin。先检查 HTTP 状态和 Content-Type:只有 audio/wav 才可将文件命名为 audio.wav;若为 application/json,请读取错误字段。

# 使用 Luna-TTS
curl -X POST "https://api.vuilabs.cn/v1/text-to-speech" \
-H "X-API-Key: your-secret-key-here" \
-H "Content-Type: application/json" \
-d '{
"voice_id": "qinyao",
"generate_text": "你好,欢迎使用 Luna-TTS。",
"model_id": "lunatts-0813"
}' \
--dump-header response-headers.txt \
--output response.bin
# 默认返回 WAV 格式
curl -X POST "https://api.vuilabs.cn/v1/text-to-speech" \
-H "X-API-Key: your-secret-key-here" \
-H "Content-Type: application/json" \
-d '{
"voice_id": "jingcheng",
"generate_text": "你好,欢迎使用TTS服务。",
"model_id": "lunatts-0813",
"emotion_class": "default",
"speed": 1.0
}' \
--dump-header response-headers.txt \
--output response.bin

调用示例​

Python

import requests

response = requests.post(
"https://api.vuilabs.cn/v1/text-to-speech",
headers={"X-API-Key": "your-secret-key-here"},
json={
"voice_id": "jingcheng",
"generate_text": "你好,欢迎使用TTS服务。",
"model_id": "lunatts-0813",
"emotion_class": "default",
"speed": 1.0,
}
)

content_type = response.headers.get("Content-Type", "").split(";")[0].strip().lower()
if content_type == "application/json":
result = response.json()
raise RuntimeError(f"{result['error_code']}: {result['error_message']}")
response.raise_for_status()
if content_type != "audio/wav":
raise RuntimeError(f"非预期的响应类型: {content_type}")

if not response.content:
raise RuntimeError("音频响应为空")
with open("audio.wav", "wb") as f:
f.write(response.content)

Node.js

const fs = require("fs");
const https = require("https");

const body = JSON.stringify({
voice_id: "jingcheng",
generate_text: "你好,欢迎使用TTS服务。",
model_id: "lunatts-0813",
emotion_class: "default",
speed: 1.0,
});

const req = https.request(
{
hostname: "api.vuilabs.cn",
path: "/v1/text-to-speech",
method: "POST",
headers: {
"X-API-Key": "your-secret-key-here",
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body),
},
},
(res) => {
const contentType = (res.headers["content-type"] || "").split(";")[0].trim().toLowerCase();
if (res.statusCode === 200 && contentType === "audio/wav") {
const file = fs.createWriteStream("audio.wav");
res.on("error", (error) => file.destroy(error));
file.on("error", (error) => {
console.error("音频保存失败:", error.message);
process.exitCode = 1;
});
res.pipe(file);
} else {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
if (contentType === "application/json") {
try {
const result = JSON.parse(data);
console.error(`${result.error_code}: ${result.error_message}`);
} catch {
console.error("无法解析 JSON 错误响应");
}
} else {
console.error(`HTTP ${res.statusCode}: 非预期的响应类型 ${contentType}`);
}
process.exitCode = 1;
});
}
}
);

req.on("error", (error) => {
console.error("请求失败:", error.message);
process.exitCode = 1;
});
req.write(body);
req.end();

二、流式生成接口​

接口信息​

  • 接口路径: /v1/text-to-speech/stream
  • 请求方式: POST
  • 认证方式: Header 中的 X-API-Key
  • 响应方式: HTTP Chunked Transfer 流式返回音频,默认 WAV,可指定 PCM;实际格式以响应 Content-Type 为准。

当前模型完成合成后,由网关流式传输音频,不保证首字节延迟低于同步接口。

请求头​

参数名类型必填说明
X-API-Keystring是应用密钥

请求参数​

参数名类型必填说明
voice_idstring是音色 ID,例如:jingcheng、bochuan、zhining、nianan;请选择当前项目可用的音色
generate_textstring是需要转换的文本内容;长度按平台统一加权规则计算(中文汉字计 2,其他字符计 1),当前公开环境上限为 500 加权字符;支持在文本中使用 [laughs] 等模型标签
languagestring否系统音色可省略;个人音色不传时默认中文 zh,英文请传 en
text_normalizationboolean否默认 true;传 false 关闭文本归一化并按原文合成(仅标准 Luna 模型)
model_idstring否默认 lunatts-0813。
emotion_classstring否默认 default;当前标准 Luna 模型不处理此参数
speednumber否语速倍率,范围 0.6–1.2;不传或为 0 时默认 1.0,其他非零值超出范围返回参数错误
audio_formatstring否不传、空值或 wav 返回 WAV;pcm / pcm_s16le 返回原始 PCM S16LE

TN 与标签用法见文本归一化与标签。

响应说明​

请求成功后,接口以 HTTP Chunked Transfer 方式持续返回音频数据块,直到传输完成。确认 HTTP 200 且 Content-Type 为音频后,请持续读取至连接结束,并确认接收到的音频非空。HTTP 200 也可能是 JSON 业务错误,不能直接开始保存音频。

模型audio_format实际输出Content-Type
lunatts-0813不传、空值或 wavWAV 字节流audio/wav
lunatts-0813pcm / pcm_s16le原始 PCM S16LE 字节流audio/pcm

默认返回 WAV;需要原始 PCM S16LE 时请传 audio_format: "pcm"。两种格式均为 24000 Hz、单声道、16-bit,请按响应格式保存和播放。

响应头说明
Content-Type实际输出的 MIME 类型;客户端必须以此为准
X-Audio-Sample-Rate音频采样率(当前为 24000)
X-Audio-Channels音频声道数(当前为 1)
X-Audio-Bit-Depth音频位深(当前为 16)
X-Accel-Bufferingno,音频数据实时返回,不缓冲

注意:参数错误或认证失败时,接口仍返回 HTTP 200 和 JSON 错误信息(succeed: false)。音频传输开始后,若发生错误,连接会中断,已接收的音频可能不完整;请处理读取错误并检查音频完整性。

请求示例​

响应头和响应体分别保存;按上文方式确认音频类型后再使用 response.bin,JSON 错误体不能作为 WAV 播放。

# 使用 Luna-TTS 流式生成:返回 WAV 字节流
curl -X POST "https://api.vuilabs.cn/v1/text-to-speech/stream" \
-H "X-API-Key: your-secret-key-here" \
-H "Content-Type: application/json" \
-d '{
"voice_id": "qinyao",
"generate_text": "你好,这是 Luna-TTS 流式生成。",
"model_id": "lunatts-0813",
"audio_format": "wav"
}' \
--dump-header response-headers.txt \
--output response.bin

调用示例​

Python(流式写入 WAV 文件)

import requests

response = requests.post(
"https://api.vuilabs.cn/v1/text-to-speech/stream",
headers={"X-API-Key": "your-secret-key-here"},
json={
"voice_id": "jingcheng",
"generate_text": "你好,欢迎使用TTS服务。",
"model_id": "lunatts-0813",
"emotion_class": "default",
"speed": 1.0,
"audio_format": "wav"
},
stream=True
)

content_type = response.headers.get("Content-Type", "").split(";")[0].strip().lower()
if content_type == "application/json":
result = response.json()
raise RuntimeError(f"{result['error_code']}: {result['error_message']}")
response.raise_for_status()
if content_type != "audio/wav":
raise RuntimeError(f"非预期的响应类型: {content_type}")

with open("audio.wav", "wb") as f:
for chunk in response.iter_content(chunk_size=4096):
f.write(chunk)

Node.js(流式写入 WAV 文件)

const fs = require("fs");
const https = require("https");

const body = JSON.stringify({
voice_id: "jingcheng",
generate_text: "你好,欢迎使用TTS服务。",
model_id: "lunatts-0813",
emotion_class: "default",
speed: 1.0,
audio_format: "wav",
});

const req = https.request(
{
hostname: "api.vuilabs.cn",
path: "/v1/text-to-speech/stream",
method: "POST",
headers: {
"X-API-Key": "your-secret-key-here",
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body),
},
},
(res) => {
const contentType = (res.headers["content-type"] || "").split(";")[0].trim().toLowerCase();
if (res.statusCode === 200 && contentType === "audio/wav") {
const file = fs.createWriteStream("audio.wav");
res.on("error", (error) => file.destroy(error));
file.on("error", (error) => {
console.error("音频保存失败:", error.message);
process.exitCode = 1;
});
res.pipe(file);
} else {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
if (contentType === "application/json") {
try {
const result = JSON.parse(data);
console.error(`${result.error_code}: ${result.error_message}`);
} catch {
console.error("无法解析 JSON 错误响应");
}
} else {
console.error(`HTTP ${res.statusCode}: 非预期的响应类型 ${contentType}`);
}
process.exitCode = 1;
});
}
}
);

req.on("error", (error) => {
console.error("请求失败:", error.message);
process.exitCode = 1;
});
req.write(body);
req.end();

三、错误响应​

请求失败时,响应体为 JSON 格式:

{
"error_code": 20003,
"error_message": "余额不足",
"succeed": false,
"data": null
}

同步和流式接口在开始返回音频前,业务失败时 HTTP 状态码仍为 200,Content-Type 为 application/json。例如无效 Key 返回 error_code: 10003、error_message: "未授权"、succeed: false。请读取这些字段,不要以 HTTP 状态码代替业务判断。

错误码说明​

error_code说明
10001 / 10013参数错误(如 generate_text 缺失或超过字符上限、voice_id 缺失、model_id 不受支持或非零 speed 不在 0.6–1.2 范围等)
10003API Key 无效或未授权
10005 / 10014请求频率或连接数超限
20003余额不足
10006请求超时
20002服务暂时不可用
10000服务异常

四、计费说明​

具体计费规则、价格和免费额度请参见 产品计费。