文档 · 语音合成
一个音色,而且一直是那个音色
语音合成只有一个别名 auto/tts,走 POST /v1/audio/speech。它背后有两个模型,切换条件只有一个:当前模型在上游被下线了。响应慢不换,被限流也不换。下面先讲它返回什么——和你想的可能不一样。
怎么调
curl https://tokenexchage.com/v1/audio/speech \
-H "Authorization: Bearer sk-你的key" \
-H "Content-Type: application/json" \
-d '{"model":"auto/tts","input":"把这句话读出来。","voice":"zhimao"}'
返回的是 JSON,不是音频:
{
"object": "audio.speech",
"url": "https://dashscope-result-….oss-cn-beijing.aliyuncs.com/…",
"expires_at": "2026-09-28T12:40:00Z",
"format": "wav"
}
趁 url 还没过期把它拉下来,或者转存到你自己控制的地方。那是对象存储的临时链接,不是永久 CDN 地址。
import requests
r = requests.post(
"https://tokenexchage.com/v1/audio/speech",
headers={"Authorization": "Bearer sk-你的key"},
json={"model": "auto/tts",
"input": "把这句话读出来。",
"voice": "zhimao"},
).json()
audio = requests.get(r["url"]).content
open("out." + (r["format"] or "wav"), "wb").write(audio)
为什么不套 OpenAI 的形状
OpenAI 的 /v1/audio/speech 是在同一个连接上把音频字节流吐回来。我们不这么做,原因值得说清楚。
别名背后的模型返回的是一个临时地址。真要给你字节流,网关就得自己把音频拉下来再吐出去——意味着每一秒生成的音频都要在本机过两遍。对一个免费开放的功能,这笔带宽花得毫无意义。
所以形状是混合的:保持 JSON,把地址提到顶层,把格式标出来。这是整套接口里唯一一处我们明知偏离 OpenAI 契约的地方,写成文档而不是糊过去。
如果你现在的代码就是在调 OpenAI 的语音接口,需要改的只有一处:从返回值里读 url,而不是消费流。请求路径、鉴权头、model / input / voice 三个字段,全都不变。
别名会做什么、不会做什么
| 上游发生什么 | 你会得到 |
|---|---|
| 模型被下线(404 / 410) | 列表里的下一个模型接手 |
| 超时 | 报错。还是同一个模型 |
| 被限流 | 报错。还是同一个模型 |
| 上游 5xx | 报错。还是同一个模型 |
换 TTS 模型不会让输出「变差一点」——它会变成另一样东西。音色不同,节奏不同。如果你在做一套四十集的音频,中途静默换人不是次品,是一整套得重做。
模型退役是唯一一种「换掉比失败好」的情况,因为不换就什么都没有。所以只有这一种情况会往下走。
这条规则适用于这里所有非对话别名。它和池化路由的做法正好相反,也是向量那个别名只有一个候选的原因。
参数
| 字段 | 必填 | 说明 |
|---|---|---|
model | 是 | 写 auto/tts;也可以直接写具体模型名 |
input | 是 | 要读出来的文字 |
voice | 否 | 默认 zhimao |
请求体上限 25 MB,超了在任何上游调用之前就返 413。Content-Type: multipart/form-data 也收,和 JSON 走同一个处理函数。
其他能力
同一套命名,一个能力一个别名,都在 /v1/models 里: