Skip to content
API 文档

音频处理总览

Grok 的语音能力分三块,前两个是普通 HTTP 接口,实时语音走 WebSocket:

能力请求格式返回独立页
文本转语音 (TTS)JSON音频二进制兼容层 · 原生透传
语音转文本 (STT)multipartJSON兼容层 · 原生透传
实时语音WebSocket事件流兼容层 · 原生透传

这一页是共享参考:音色清单、20 种语言、语音标签、输出格式、逐字符时间戳、发音替换、流式协议、计费方式。具体怎么调看上面的独立页。

路径对照 ​

能力原生字段 · 官方前缀原生字段 · 无前缀OpenAI 字段
TTSPOST /xai/v1/ttsPOST /v1/ttsPOST /v1/audio/speech
音色列表GET /xai/v1/tts/voicesGET /v1/tts/voices—
STTPOST /xai/v1/sttPOST /v1/sttPOST /v1/audio/transcriptions
流式 TTSWSS /xai/v1/ttsWSS /v1/tts—
流式 STTWSS /xai/v1/sttWSS /v1/stt—
实时语音WSS /xai/v1/realtimeWSS /v1/realtime同左
自定义音色/xai/v1/custom-voices/v1/custom-voices—

TTS / STT 其实有三条路径,别只记两条

  • /xai/v1/...:官方前缀,报错是 xAI 原文、状态码也是上游的。
  • /v1/tts、/v1/stt:字段名和 /xai/... 完全一样(text / voice_id / output_format),只是报错会被包成 OpenAI 信封。已有代码想少改路径、又想要统一错误格式时用它。
  • /v1/audio/speech、/v1/audio/transcriptions:OpenAI 字段名(input / voice / response_format),字段会被转换。

只有最后一条会转换字段名。 前两条走的是同一套 Grok 字段。

字段名只有 TTS 不一样

只有 TTS 的三组字段在两层叫法不同:input↔text、voice↔voice_id、response_format↔output_format.codec。

STT 和实时语音两层用的是同一套字段名,只是路径前缀不同。

TTS 参数详解 ​

参数类型必填说明
textstring是要合成的文本,最长 15,000 字符。支持语音标签
languagestring是BCP-47 语言码或 auto 自动识别。大小写不敏感
voice_idstring否音色 ID。不传默认 eve
speednumber否语速倍率,0.7–1.5,默认 1.0
output_formatobject否输出编码,见输出格式
with_timestampsboolean否为 true 时返回 JSON 信封,含 base64 音频 + 逐字符时间戳
text_normalizationboolean否为 true 时先把数字、缩写、符号转成口语形式再合成
optimize_streaming_latencyinteger否流式合成的延迟档位:0(默认,不做优化、音质最好)、1(首包更小、块边界有轻微音质损失)。官方指南另提到 2,需要更激进的首包优化时可试
replaceobject否发音替换表,见发音替换

音色 ​

说明
默认音色eve
内置音色至少 26 个,常用示例值:eve、ara、rex、leo。完整清单查下面的接口
大小写不敏感,eve / Eve / EVE 都能用
自定义音色用自己的参考音频克隆,见自定义音色

想知道当前可用的完整音色清单,直接查接口:

bash
curl https://api.wxiai.com/xai/v1/tts/voices \
  -H "Authorization: Bearer $WXIAI_API_KEY"

返回每个音色的 voice_id、name、language。也可以查单个:GET /xai/v1/tts/voices/{voice_id}。

音色 ID 是跨接口通用的

TTS 的 voice_id、实时语音的 session.voice、视频参考音的 voice_id 用的是同一套内置音色 ID。

支持的语言 ​

TTS 支持 20 种语言,language 必填。也能处理表外的其他语言,准确度会有波动。

语言代码语言代码
自动识别auto日语ja
英语en韩语ko
中文(简体)zh葡萄牙语(巴西)pt-BR
阿拉伯语(埃及)ar-EG葡萄牙语(葡萄牙)pt-PT
阿拉伯语(沙特)ar-SA俄语ru
阿拉伯语(阿联酋)ar-AE西班牙语(墨西哥)es-MX
孟加拉语bn西班牙语(西班牙)es-ES
法语fr土耳其语tr
德语de越南语vi
印地语hi
印尼语id
意大利语it

语音标签 ​

在 text 里插标签,就能得到笑声、停顿、耳语这类表达。两种写法:

内联标签 [tag] — 放在需要出现表情的位置:

类别标签
停顿[pause]、[long-pause]
笑与哭[laugh]、[chuckle]、[giggle]、[cry]
口腔音[tsk]、[tongue-click]、[lip-smack]、[hum-tune]
呼吸[breath]、[inhale]、[exhale]、[sigh]

包裹标签 <tag>文字</tag> — 改变一段文字的念法,开闭标签要配对:

类别标签
音量与力度<soft>、<loud>、<build-intensity>、<decrease-intensity>
音高与速度<higher-pitch>、<lower-pitch>、<slow>、<fast>
声音风格<whisper>、<sing-song>、<singing>、<emphasis>

例子:

text
于是我走进去,[pause] 它就在那儿。[laugh] 我真的不敢相信!
<whisper>这件事一直是个秘密。</whisper> 挺酷的吧?

输出格式 ​

output_format 由三个字段组成,不传就是 MP3 / 24000 Hz / 128000 bps。

codec(必填,只填这一个也能用):

值Content-Type适合
mp3audio/mpeg通用,兼容性最好。默认
wavaudio/wav无损,适合后期剪辑
pcmaudio/pcm裸音频,适合实时处理管线
mulawaudio/basic电话(G.711 μ-law)
alawaudio/alaw电话(G.711 A-law)

sample_rate:8000(电话)、16000(宽带)、22050、24000(默认)、44100(CD)、48000(专业)

bit_rate(只对 MP3 生效):32000、64000、96000、128000(默认)、192000

json
// 高保真 MP3
"output_format": { "codec": "mp3", "sample_rate": 44100, "bit_rate": 192000 }

// 电话线路(μ-law)
"output_format": { "codec": "mulaw", "sample_rate": 8000 }

逐字符时间戳 ​

传 with_timestamps: true 后,返回从音频二进制流变成 JSON 信封:

json
{
  "audio": "<base64 音频>",
  "content_type": "audio/mpeg",
  "duration": 0.92,
  "audio_timestamps": {
    "graph_chars": ["H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d", "."],
    "graph_times": [
      [0.00, 0.06], [0.06, 0.12], [0.12, 0.18], [0.18, 0.24],
      [0.24, 0.34], [0.34, 0.40], [0.40, 0.48], [0.48, 0.54],
      [0.54, 0.62], [0.62, 0.68], [0.68, 0.78], [0.78, 0.92]
    ]
  }
}

graph_chars[i] 和 graph_times[i] 按下标一一对应,每个元素是 [开始秒, 结束秒]。做字幕、卡拉OK 高亮、口型同步都用它。

graph_chars 两个数组长度永远相等,按下标一一对应。但要注意两件事:

  1. 用了 replace 时,graph_chars 描述的是「念出来的文本」,里面是替换后的字符,不是你说发送的原文。
  2. 开了 text_normalization 时,一个符号可能被读成好几个词,但时间只会记在它的第一个字符上。

所以按下标遍历 graph_chars,不要用下标去切你发送的原始文本。

发音替换 ​

replace 是一张「原词 → 念法」的映射表,在合成之前替换,所以只影响音频,你发出去的文本和计费字符数都不变。

json
{
  "text": "欢迎致电 Acme Mobile,nginx 已启动。",
  "voice_id": "eve",
  "language": "zh",
  "replace": {
    "Acme Mobile": "Acme Mobull",
    "nginx": "/ˈɛndʒɪn ˈɛks/"
  }
}
规则值
匹配方式不区分大小写,按整词匹配,最长匹配优先
值的两种写法拼读重写("Acme Mobull")或 IPA 音标(/ˈɛndʒɪn ˈɛks/,两侧斜杠不会被念出来)
key 允许的字符只有字母、数字、撇号、空格
上限最多 200 条;key ≤ 100 字符,value ≤ 128 字符
替换后的文本上限60,000 字符

自定义音色 ​

用一段参考音频克隆音色,之后在 voice_id 里直接使用。创建接口用 multipart/form-data,不是 JSON。

bash
curl -X POST https://api.wxiai.com/xai/v1/custom-voices \
  -H "Authorization: Bearer $WXIAI_API_KEY" \
  -F "name=Friendly Narrator" \
  -F "language=en" \
  -F "gender=female" \
  -F "tone=warm" \
  -F "use_case=narration" \
  -F "file=@reference.wav;type=audio/wav"

成功返回 201 和新音色对象,voice_id 是 8 位小写字母数字:

json
{
  "voice_id": "nlbqfwie",
  "name": "Friendly Narrator",
  "language": "en",
  "created_at": "2026-04-26T18:56:34.872993+00:00"
}
表单字段必填说明
file是参考音频,最长 120 秒(建议 90 秒以上)
name否显示名
description否自由描述
gender否male / female / neutral
accent否自由文本,如 British
age否young / middle-aged / old
language否en 或 en-US、zh-CN(地区码要大写)
use_case否conversational / narration / characters / educational / advertisement / social_media / entertainment
tone否warm / casual / professional / friendly / authoritative / expressive / calm

参考音频建议:.wav(无压缩 PCM)、24 kHz、16 bit、单声道。MP3 / FLAC / OGG / Opus / M4A / AAC / MKV / MP4 也能收,但有损格式的压缩痕迹会被克隆进音色。

管理接口:

操作请求
列表GET /xai/v1/custom-voices,limit 默认 100、范围 1–1000,分页用 pagination_token
详情GET /xai/v1/custom-voices/{voice_id}
改元数据PATCH /xai/v1/custom-voices/{voice_id}
下载参考音频GET /xai/v1/custom-voices/{voice_id}/audio
删除DELETE /xai/v1/custom-voices/{voice_id}

两个前提

  1. POST /v1/custom-voices 需要 Enterprise 套餐才能走 API 创建;控制台里可以免费建,每个团队最多 30 个。
  2. 自定义音色只属于你的团队,不会出现在 GET /v1/tts/voices 内置音色列表里,只能从 GET /v1/custom-voices 查。

流式语音合成 (WebSocket) ​

想让音频边生成边播放,连 wss://api.wxiai.com/xai/v1/tts。

连接参数(放 URL query) ​

注意流式用 codec 这个扁平字段,不是 HTTP 版本的 output_format.codec。

参数默认说明
voiceeve音色 ID
language—必填,和 HTTP 版本一样
codecmp3mp3 / wav / pcm / mulaw / alaw(ulaw 是 mulaw 的别名)
sample_rate24000采样率
bit_rate128000码率,仅 mp3 生效
speed1.0语速,0.7–1.5
optimize_streaming_latency0延迟档位,0 / 1
text_normalizationfalse是否先做文本规范化
with_timestampsfalse是否随音频分片返回时间戳

voice / language / codec / sample_rate 非法时,服务端会在握手升级之前直接返回 400 / 404,不会建立连接。

你发过去的是 JSON 文本帧 ​

json
{"type": "text.delta", "delta": "这里是第一段文字。"}
{"type": "text.delta", "delta": "接着是第二段。"}
{"type": "text.done"}
事件说明
text.delta一段待合成文本,单条上限 15,000 字符
text.done本段说完,服务端把剩余音频生成完并回 audio.done
text.clear取消当前这段,丢弃已缓冲内容,服务端回 audio.clear
session.update更新本次连接的 replace 映射表,下一段生效

服务端发回来的是:

事件说明
audio.deltabase64 音频分片。开了 with_timestamps 时还带本片的 audio_timestamps 和 audio_duration
audio.done本段音频发完,带一个 trace_id 便于排查
audio.clear确认当前段已取消,连接可以继续用
session.updated确认 session.update,回显当前生效的 replace
error出错,message 里是原因
限制值
总文本长度无上限(分段发即可),超过 15,000 字符必须用这个接口
单条 text.delta≤ 15,000 字符
并发连接每团队 50 条
连接许可 TTL600 秒

一连接可以合成多段

audio.done 之后连接不会断,直接再发一组 text.delta → text.done 就能合成下一段,适合对话式 UI。

STT 参数详解 ​

请求格式是 multipart/form-data,不是 JSON。file 和 url 至少给一个。

参数类型默认说明
filefile—音频文件,最大 500 MB。与 url 二选一,且必须是 multipart 最后一个字段
urlstring—音频地址,服务端下载后转写。与 file 二选一
languagestring—语言码。只有配 format=true 时才起作用(用于文本格式化)
formatbooleanfalse开启反向文本规范化:把口语数字/货币转成书面形式("one hundred dollars" → "$100")。需要同时传 language
diarizebooleanfalse说话人分离。开启后每个词会带 speaker 字段
multichannelbooleanfalse逐声道独立转写,结果放在 channels 数组里
channelsinteger—声道数(2–8)。仅裸音频需要,容器格式自动识别
audio_formatstring—裸音频格式提示:pcm / mulaw / alaw。容器格式别传这个字段
sample_rateinteger—采样率,仅裸音频需要
keytermstring—Grok 专有。关键词偏置,重复传多个,最多 100 个、每个 ≤ 50 字符
filler_wordsbooleanfalseGrok 专有。为 true 时保留 "uh"、"um" 这类填充词
vad_thresholdnumber0.5Grok 专有。语音活动门限(0.0–1.0)。调低更适应轻声/噪声;0 关闭门限

三个 Grok 专有参数只在原生层可用

keyterm、filler_words、vad_threshold 走 OpenAI 兼容层(/v1/audio/transcriptions)不会生效——兼容层只转发 OpenAI 也有的那组字段。

需要它们请走 音生文 STT(原生透传)。

file 必须是最后一个字段

其余字段要写在 file 前面——流式上传时,排在 file 之后的字段可能被忽略。

STT 返回 ​

json
{
  "text": "The balance is $167,983.15.",
  "language": "en",
  "duration": 3.45,
  "words": [
    { "text": "The", "start": 0.24, "end": 0.48 },
    { "text": "balance", "start": 0.48, "end": 0.96 }
  ]
}
字段说明
text完整转写文本
language识别到的语言(BCP-47,如 en、es-mx)
duration音频时长(秒,保留 2 位小数)
words词级时间戳。开了 diarize 时每个词多一个 speaker(整数)
channels逐声道结果。开了 multichannel 时才有,每项含 index、text、words

支持的音频格式 ​

容器格式(自动识别,不要传 audio_format):.wav、.mp3、.ogg、.opus、.flac、.aac、.mp4、.m4a、.mkv

裸格式(必须同时传 audio_format 和 sample_rate):

格式audio_format 值说明
PCMpcm有符号 16 位小端(2 字节/采样)
µ-lawmulawG.711 µ-law(1 字节/采样)
A-lawalawG.711 A-law(1 字节/采样)

上限:单文件 500 MB;单声道、立体声或最多 8 声道(需 multichannel=true)。

流式语音识别 (WebSocket) ​

连 wss://api.wxiai.com/xai/v1/stt,配置全放在 URL query 里,音频用裸二进制帧发送(不是 base64)。

Query 参数默认说明
sample_rate16000采样率。encoding=opus 时忽略
encodingpcmpcm / mulaw / alaw / opus
interim_resultsfalse为 true 时每 ~500 ms 发一次中间结果(is_final=false)
endpointing400判定一句结束所需的静音时长(ms),范围 0–5000
language—语言码,用于文本格式化
diarize—说话人分离
filler_wordsfalse是否保留填充词
multichannel / channelsfalse / 1多声道转写,最多 8 声道(不支持 encoding=opus)
keyterm—关键词偏置,最多 100 个
smart_turn—智能断句置信度门限(0.0–1.0)
smart_turn_timeout—强制断句的最大静音时长(ms),范围 1–5000
vad_threshold0.08语音活动门限(0.0–1.0)

你发过去:二进制帧(裸音频,按实时节奏切片)、{"type": "finalize"}(立刻结束当前这句)、{"type": "finalize", "channel": 0}(多声道场景)、{"type": "audio.done"}(音频发完)。

服务端发回来:transcript.created(就绪,收到再发音频)、transcript.partial、transcript.done、error。

transcript.partial 用两个布尔量表达三种状态:

is_finalspeech_final含义
falsefalse中间结果,文字还会变(仅 interim_results=true 时)
truefalse分块结束,这段文字已定稿(约 3 秒语音)
truetrue整句结束,说话人停下了

Smart Turn:别把人打断在半句 ​

开了 smart_turn=<门限> 后,服务端在每个静音点用一个小模型判断「他说完了吗」:

  • 置信度高于门限 → 正常发 speech_final=true
  • 置信度低于门限 → 降级为分块结束(is_final=true、speech_final=false),文字定稿但这句话继续
门限效果
0.5均衡,能抓住大多数自然停顿
0.7保守,适合口述和连续数字
0.9很保守,只在非常确定时才断句

开了 Smart Turn 后断句时机完全交给模型,建议同时设 smart_turn_timeout(如 3000),否则用户走开后会话可能一直挂着不结束。

text
wss://api.wxiai.com/xai/v1/stt?sample_rate=16000&encoding=pcm&interim_results=true&smart_turn=0.7&smart_turn_timeout=3000

计费方式(和文本不一样) ​

能力计费维度说明
语音合成 (TTS)按字符数文本越长越贵,和音频时长无关
语音识别 (STT)按音频秒数音频越长越贵,和识别出的字数无关
实时语音按分钟双向音频都计费,见实时语音总览

具体单价见 https://api.wxiai.com/models。

TTS 省钱要点

因为按字符数计费,先把文本精简再合成比合成后再处理音频划算得多。长文本如果只是要试听,先截一小段。

容易踩的坑 ​

  • TTS 字段名混用:在 /xai/v1/tts 上传 input,或在 /v1/audio/speech 上传 text,都会报字段缺失。
  • language 是必填的:TTS 不传 language 会直接报参数错误。不想指定就用 auto。
  • STT 用了 JSON:STT 只接受 multipart/form-data。
  • file 没放最后:写在 file 后面的字段可能被丢掉。
  • 把 TTS 的返回当 JSON 解析:返回的是音频二进制流(除非传了 with_timestamps)。
  • 超时按文本接口设:长音频转写、大段文本合成都可能超过 30 秒,客户端超时调到 120 秒以上。

相关页 ​

基于 Apache-2.0 许可发布