教程
如何通过 hiapi API 使用 qwen-audio-3.0-tts-plus:用 curl 和 Python 实现文本转语音
qwen-audio-3.0-tts-plus 是一个文本转语音模型,通过 hiapi 平台的统一异步任务队列访问——与图像和视频生成使用的是同一个 POST /v1/tasks 端点,而不是独立的音频 API。你提交文本,立即拿回一个 taskId,然后轮询或等待回调,获取可下载的音频文件 URL。本教程将带你完成一个在 curl 和 Python 中可用的请求(已针对实时 API 进行端到端验证),然后介绍你实际需要的生产模式:回调与轮询、幂等重试,以及需要处理的精确错误形态。
你将构建什么
一个脚本,将文本提交到 qwen-audio-3.0-tts-plus,等待任务完成,并下载生成的音频——另外还包括参数参考和错误处理模式,以便将该脚本转化为真正的集成。
前提条件:一个 hiapi API 密钥。从 hiapi 仪表板 获取——以下每个请求都使用 Authorization: Bearer sk-<your-key> 进行认证。
最小可用示例
curl
创建任务:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-audio-3.0-tts-plus",
"input": {
"text": "Welcome to hiapi, the unified API for AI models.",
"voice": "longanlingxin"
}
}'
{"code": 200, "data": {"taskId": "tk-hiapi-01KZ59B7ZJ7012PXB5J9GE1QE7"}, "message": "success"}
然后使用相同的 bearer 令牌轮询 GET /v1/tasks/<taskId>,直到 data.status 离开 "processing"。对于此模型,测试中大约花了 5 秒钟:
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-01KZ59B7ZJ7012PXB5J9GE1QE7 \
-H "Authorization: Bearer $HIAPI_KEY"
{
"code": 200,
"data": {
"taskId": "tk-hiapi-01KZ59B7ZJ7012PXB5J9GE1QE7",
"status": "success",
"model": "qwen-audio-3.0-tts-plus",
"storage": "temp",
"created": 1785810231,
"completed": 1785810236,
"output": [{"type": "audio", "url": "https://temp.hiapi.ai/.../01KZ59B7ZJ7012PXB5J9GE1QE7-0.mp3", "artifactId": "66654", "expireAt": 1786415036}]
},
"message": "success"
}
output[0].url 是一个真实可下载的 MP3(content-type: audio/mpeg——通过直接获取确认)。这是一个临时链接:当 storage 保持默认值 "temp" 时,expireAt 几乎正好在 created 之后 7 天,因此如果你需要长期保留音频,请下载字节并自行存储。
Python
import os
import time
import requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
headers = {"Authorization": f"Bearer {os.environ['HIAPI_KEY']}"}
resp = requests.post(
API_BASE,
headers={**headers, "Content-Type": "application/json"},
json={
"model": "qwen-audio-3.0-tts-plus",
"input": {
"text": "Welcome to hiapi, the unified API for AI models.",
"voice": "longanlingxin",
},
},
timeout=30,
)
resp.raise_for_status()
task_id = resp.json()["data"]["taskId"]
while True:
task = requests.get(f"{API_BASE}/{task_id}", headers=headers, timeout=30).json()["data"]
if task["status"] == "success":
audio_url = task["output"][0]["url"]
break
if task["status"] == "fail":
raise RuntimeError(task["error"])
time.sleep(2)
audio_bytes = requests.get(audio_url, timeout=60).content
with open("output.mp3", "wb") as f:
f.write(audio_bytes)
生产使用模式
完整的输入模式
input 对象只接受以下这些字段——API 对其他任何字段都会以 400 拒绝,因此不要从其他 TTS 提供商沿用参数名:
| 字段 | 是否必需 | 类型 / 值 |
|---|---|---|
text |
是 | 字符串 |
voice |
是 | "longanlingxin"、"longanlufeng" 之一(此模型目前只有两个音色可用) |
format |
否 | "pcm"、"wav"、"mp3"、"opus" 之一——省略时默认为 mp3 |
sample_rate |
否 | 8000、16000、22050、24000、44100、48000 之一 |
pitch |
否 | 数字,0.5–2 |
volume |
否 | 数字,0–100 |
上述每个边界和枚举值都来自 API 自身的验证错误——传入无效的 voice 或超出范围的 pitch,hiapi 都会准确告诉你允许的值:
{"code": 400, "data": null, "error_code": "INVALID_REQUEST", "message": "invalid input: voice: value must be one of 'longanlingxin', 'longanlufeng'"}
此模型没有 emotion、speed 或 SSML 风格的控制字段——携带这些字段的请求会以 "additional properties '...' not allowed" 失败。
回调 vs. 轮询
对于超出快速脚本范围的任何情况,跳过轮询,让 hiapi 推送结果。在任务创建请求中添加一个 callback 对象:
{
"model": "qwen-audio-3.0-tts-plus",
"callback": {"url": "https://example.com/hiapi/callback", "when": "final"},
"input": {"text": "Welcome to hiapi.", "voice": "longanlingxin"}
}
"final" 目前是 when 唯一支持的值——无论任务成功还是失败,hiapi 都会向你的 callback.url POST 一次,你从该负载中读取与轮询 GET /v1/tasks/<taskId> 相同的任务详情形态。完全省略 callback,改为自行轮询,如上述示例所示。
另外值得知道:任务输出默认为 storage: "temp"(文件大约存活一周,如上方 expireAt 值所示)。如果你需要音频长期可检索,请在任务上设置 "storage": "persistent"——持久存储按大小计费,因此对于一次性生成,下载并自行存储通常更便宜。
幂等性和重试
POST /v1/tasks 接受 Idempotency-Key 请求头(最多 255 字节)。在同一账户下使用相同密钥重试同一请求只会创建一次任务——重放会返回原始的 taskId,而不是第二次计费生成。用于在超时或 5xx 后重试,此时你确实不知道第一个请求是否已到达:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: tts-job-42" \
-d '{"model": "qwen-audio-3.0-tts-plus", "input": {"text": "...", "voice": "longanlingxin"}}'
错误处理
无效或未授权的密钥返回 HTTP 401,并带有 hiapi 的标准错误信封(直接对此模型验证):
{"error": {"code": "permission_denied", "message": "This API key cannot use the selected model...", "request_id": "...", "type": "hiapi_error"}}
错误的 input 负载返回 HTTP 400,带有 error_code: "INVALID_REQUEST" 和指明违规字段的 message,如上方模式部分所示——根据 error_code / error.code 分支,而不是根据人类可读的消息文本。如果任务达到终端 "fail" 状态而不是在创建时失败,任务详情响应会在 data.error(code + message)下携带相同形态,而不是顶层的 error 键。
相关阅读
- hiapi 仪表板 — 创建和管理 API 密钥。
- 创建任务文档 — 完整的
POST /v1/tasks契约,包括请求头、回调与幂等性。 - 获取任务详情文档 — 上方使用的轮询端点。
- hiapi 认证文档 —
Authorization请求头和密钥作用域在整个平台上的工作方式。 - hiapi 速率限制文档 —
429行为与Retry-After。 - hiapi 上的音频模型 — 浏览平台上的其他语音和音频模型。
- 此模型的当前价格见实时 价格页面,此处不再重复。
常见问题
音频生成与 hiapi 的图像/视频任务 API 不同吗?
不——相同的 POST /v1/tasks 队列、相同的创建后轮询或回调流程、相同的 output[0].url 形态。只有 output[0].type(此处为 "audio")和 input 模式因模型而异。
如果我不设置 format 会怎样?
你会得到一个 MP3——测试中省略它已确认。如果你需要 wav、pcm 或 opus,请显式设置 format。
我可以流式返回音频而不是等待任务完成吗? 不可以。此模型只暴露标准的创建/轮询/回调任务流程——其输入模式中没有流式参数,而且生成速度足够快(短文本只需几秒钟),每 1-2 秒轮询一次通常就足够了。
输出 URL 保持有效多久?
默认约 7 天(storage: "temp"),基于任务的 created 与 expireAt 时间戳之间的间隔。请及时下载音频,或者如果你需要更长期可检索,在任务上设置 "storage": "persistent"。
为什么我的请求失败并提示 "additional properties ... not allowed"?
模式是严格的——此模型只接受 text、voice、format、sample_rate、pitch 和 volume。来自其他 TTS API 的参数(如 emotion 或 speed)在此不被识别,将返回 400。
我在哪里找到当前价格? 在 价格页面——本教程有意不硬编码每字符或每请求成本,因为价格可能会变化。