Permalink to 音频音频

音频接口的响应形态如下:

路由形态
POST /v1/audio/speech同步——返回音频字节,或 JSON
POST /v1/audio/transcriptions同步——返回文本或 JSON
GET /v1/audio/transcriptions/:request_id只读——取回已保存的转写结果
POST /v1/audio/music异步——返回一个 Job

先确认可用模型

音频模型按部署逐个启用。写死模型名之前,先查一下这把 Key 能路由到哪些:

bash
curl -s https://hypit.ai/v1/models \
  -H "Authorization: Bearer $HYPIT_API_KEY" |
  jq -r '.data[] | select(.endpoints[] | test("audio|transcriptions")) | "\(.id)\t\(.endpoints)"'

Permalink to 语音合成语音合成

bash
curl https://hypit.ai/v1/audio/speech \
  -H "Authorization: Bearer $HYPIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "'"$MODEL"'", "input": "那只船翻过了堰。", "voice": "alloy"}' \
  --output speech.mp3

OpenAI SDK 的 client.audio.speech.* 可以直接打到这条路由。

Permalink to 请求体请求体

字段类型说明
modelstring必填
inputstring文本内容。text 是同义字段
promptstring自由描述,支持的模型上生效
lyricsstring歌词
voicestring具名音色
reference_idstring克隆音色 id
voice_descriptionstring用描述代替具名音色
response_formatstringmp3wavpcmopusflacaacoggformat 是同义字段
speedvolumeloudnessnumber取值范围由厂商定义
sample_ratebitrateintegermp3_bitratebitrate 的同义字段
duration_secondsnumbersecondsduration 是同义字段
ninteger1–8,默认 1
seedinteger
languagestring
instrumentalloopboolean
guidance_scaleprompt_influencenumber
reference_audiostring 数组http(s)data: URL
auto_generate_textboolean
outputstringbinary(默认)、b64_jsonurl

input/textpromptlyricsvoice_description 至少要有一个。inputlyrics 合计上限 4 万字符;整个 JSON 请求体上限 12 MiB。未建模的字段原样转发给上游。

Permalink to mimo-voicecloneMiMo VoiceClone

mimo-v2.5-tts-voiceclone 需要且只接受一个 MP3/WAV 声音样本。推荐放进 reference_audio;这里既可以给 http(s) URL,也可以给完整的 data URL,网关会按渠道需要抓取并 内联。直接使用 voice 时必须传 data URL(也兼容旧客户端传裸 base64):

json
{
  "model": "mimo-v2.5-tts-voiceclone",
  "input": "这段话会使用参考音频中的声音来朗读。",
  "reference_audio": ["data:audio/wav;base64,UklGRg..."],
  "response_format": "wav"
}

MiMo 要求 data URL 使用 data:audio/mpeg;base64,...data:audio/wav;base64,...,base64 部分最大 10 MiB。网关会按文件魔数校验,伪装 MIME 或其他音频容器会在请求上游之前返回 400。

Permalink to 响应响应

output 未设置或为 binary 时,响应是原始音频字节Content-Type 由嗅探得出(默认 audio/mpeg),并带 X-Content-Type-Options: nosniffContent-Disposition: inline; filename="job_….mp3"

outputb64_jsonurl 时,响应是 JSON:

json
{
  "object": "audio.speech",
  "created": 1787824589,
  "model": "…",
  "format": "mp3",
  "mime_type": "audio/mpeg",
  "b64_json": "SUQzBA…",
  "seconds": 3.4,
  "usage": { "characters": 28, "audio_seconds": 3.4 }
}

注意 output: "url" 在无法产生存储 URL 时会静默退回 b64_json,所以两个字段都要处理。音色设计类 请求返回 "object": "audio.voice_previews" 和一个 previews[] 数组,每项包含 {voice_id, name, description, b64_json|url, mime_type, format, seconds}

Permalink to 转写转写

bash
curl https://hypit.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $HYPIT_API_KEY" \
  -F model="$MODEL" \
  -F file=@interview.mp3 \
  -F response_format=verbose_json

OpenAI SDK 的 client.audio.transcriptions.* 可以直接打到这条路由。

接受 multipart/form-data application/json,其余 Content-Type 返回 400 unsupported_content_type

字段说明
model必填
file音频文件——仅 multipart
urlhttp(s) URL 代替文件。fileurl 必须且只能有一个
response_formatjson(默认)、textverbose_json
languageISO 语言码提示
prompt上下文提示
temperaturenumber
timestamp_granularities[]可重复:segment 和/或 word。不带方括号的写法也接受

限制:单个上传文件 100 MiB,整个 multipart 请求体 120 MiB,JSON 请求体 4 MiB。分片声明 的 Content-Type 会被忽略——我们嗅探字节,接受的容器为 WAV、FLAC、Ogg(Vorbis/Opus)、MP3、 ADTS AAC、M4A、MP4 和 WebM。无头的裸 PCM 会被拒绝。

response_format: "text" 返回 text/plain,正文就是转写结果本身。其余取值返回 JSON:

json
{
  "task": "transcribe",
  "language": "en",
  "duration": 92.4,
  "text": "…",
  "segments": [
    { "id": 0, "start": 0.0, "end": 3.2, "text": "…", "no_speech_prob": 0.01 }
  ],
  "words": [{ "word": "the", "start": 0.10, "end": 0.22 }],
  "usage": { "audio_seconds": 92.4 }
}

tasklanguagedurationsegmentswords 只在 verbose_json 下出现。usage 是我们加的, 在普通 json 形态下也有——OpenAI 那边是没有的。

Permalink to 取回已保存的转写结果取回已保存的转写结果

保存转写 POST 响应头中服务端生成的 X-Request-IdLocation。持久化预留成功后, Location 会指向以下只读接口;POST 随后因上游结果不明而报错时也可使用这个链接:

bash
curl https://hypit.ai/v1/audio/transcriptions/req_YOUR_SERVER_REQUEST_ID \
  -H "Authorization: Bearer $HYPIT_API_KEY"

使用原账号下当前有效的 API Key。OAuth 需要 user:jobs,只有 user:inference:audio 不够。 模型后来下架、Key 更换分组都不影响本账号历史结果;其他账号与不存在的 ID 一律返回相同的 404。 GET 不重新提交上游,也不重复扣费。

json
{
  "id": "req_YOUR_SERVER_REQUEST_ID",
  "object": "audio.transcription",
  "model": "your-model",
  "status": "completed",
  "settlement_state": "settled",
  "created_at": 1788900000,
  "completed_at": 1788900010,
  "expires_at": 1791492010,
  "result": {
    "text": "你好,世界。",
    "language": "zh",
    "duration": 4.5,
    "usage": { "audio_seconds": 4.5 }
  }
}

无论 POST 的 response_format 是什么,取回的 result 都是 JSON;上游提供时还包含 segmentswords。上游原始响应和输入 URL 不会暴露。

HTTPstatus含义
202pendingprocessing尚无可读结果;至少等待 Retry-After 指定的秒数再查询
200completed正文位于 result
200failed上游操作已明确失败
200unavailable处理已结束,但没有可靠的已保存正文
410expired正文保留期已结束

status 表示正文状态,settlement_state 独立表示结算状态。历史账单仍为 unknown 时, 已恢复正文可以是 completed。正常成功的 POST 在发送正文前保存结果;已受理的 Replicate 转写任务还可凭持久化的上游任务 ID 在进程重启后继续查询。并非所有供应商、所有错误都具备后台结果恢复能力。

正文沿用部署的存储保留期:默认 30 天,从首次保存正文算起;负数配置表示永久保留。 到期删除正文,但保留财务记录。响应标记 Cache-Control: private, no-store。 保存后的公开结果沿用上游缓冲响应的 32 MiB 上限,超限明确拒绝,不静默截断。 已确认超限且无法交付时返回 502,退还客户预留,正文标记 unavailable,客户结算为零。 普通客户端断线或 GET 缺正文不能作为退款依据。

此接口要求服务端生成的请求 ID。若断线发生在响应头送达之前,客户端无法通过此接口发现该 ID。 客户端传入的 X-Request-Id 不是幂等键;再次 POST 会创建新请求,并可能再次收费。 这次结果取回扩展不提供 POST 幂等保证。

Permalink to 音乐音乐

POST /v1/audio/music 是异步的。它接受与 /v1/audio/speech 完全相同的请求体——同样的字段、 同样的同义写法、同样的校验、同样的 12 MiB 上限——返回 202 Accepted 和一个 kindaudio 的 Job。

bash
curl https://hypit.ai/v1/audio/music \
  -H "Authorization: Bearer $HYPIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "'"$MODEL"'",
    "prompt": "慢速 lo-fi 钢琴,窗外下雨",
    "lyrics": "",
    "instrumental": true,
    "duration_seconds": 60
  }'

这里真正起作用的字段是 promptlyricsinstrumentalduration_secondsvoicereference_idreference_audiolanguageseednoutput 会被解析和校验,但没有任何 效果:Job 的产物一律通过 assets 接口交付。

之后的轮询与取产物流程和异步任务完全一样。另有两个别名指向同一个 handler:

bash
curl https://hypit.ai/v1/audio/music/$JOB_ID \
  -H "Authorization: Bearer $HYPIT_API_KEY"

curl -L -o track.mp3 https://hypit.ai/v1/audio/music/$JOB_ID/content \
  -H "Authorization: Bearer $HYPIT_API_KEY"

Permalink to sdk-示例SDK 示例

python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["HYPIT_API_KEY"],
    base_url=os.environ.get("HYPIT_BASE_URL", "https://hypit.ai/v1"),
)

with client.audio.speech.with_streaming_response.create(
    model=os.environ["MODEL"],
    voice="alloy",
    input="那只船翻过了堰。",
) as response:
    response.stream_to_file("speech.mp3")

with open("interview.mp3", "rb") as f:
    print(client.audio.transcriptions.create(model=os.environ["MODEL"], file=f).text)
js
import { createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.HYPIT_API_KEY,
  baseURL: process.env.HYPIT_BASE_URL ?? "https://hypit.ai/v1",
});

const speech = await client.audio.speech.create({
  model: process.env.MODEL,
  voice: "alloy",
  input: "那只船翻过了堰。",
});
Readable.fromWeb(speech.body).pipe(createWriteStream("speech.mp3"));

Permalink to 这三条路由特有的错误这三条路由特有的错误

状态code路由含义
400missing_model全部model 必填
400missing_input合成、音乐没有文本、prompt、歌词或音色描述
413text_too_long合成、音乐超过 4 万字符
400invalid_n合成、音乐n 必须在 1–8 之间
400invalid_duration合成、音乐时长不能为负
400invalid_response_format合成、音乐不在七种音频格式之内
400invalid_output合成、音乐不是 binaryb64_jsonurl
413voice_sample_too_large合成MiMo VoiceClone 的 base64 样本超过 10 MiB
400unsupported_content_type转写既不是 JSON 也不是 multipart
400missing_file / ambiguous_input转写fileurl 必须且只能有一个
400invalid_response_format转写不是 jsontextverbose_json
400invalid_timestamp_granularity转写不是 segmentword
400invalid_temperature转写不是数字
400unsupported_audio_format转写字节内容不是可识别的容器
400empty_file / unreadable_file转写分片里没有可用内容
413file_too_large转写超过 100 MiB
413body_too_large全部超过该路由的请求体上限
502empty_audio_response / empty_transcription_response合成、转写上游没有返回可用内容