切换日光/暗黑模式
Grok 的语音能力分三块,前两个是普通 HTTP 接口,实时语音走 WebSocket:
| 能力 | 请求格式 | 返回 | 独立页 |
|---|---|---|---|
| 文本转语音 (TTS) | JSON | 音频二进制 | 兼容层 · 原生透传 |
| 语音转文本 (STT) | multipart | JSON | 兼容层 · 原生透传 |
| 实时语音 | WebSocket | 事件流 | 兼容层 · 原生透传 |
这一页是共享参考:音色清单、20 种语言、语音标签、输出格式、逐字符时间戳、发音替换、流式协议、计费方式。具体怎么调看上面的独立页。
路径对照
| 能力 | 原生字段 · 官方前缀 | 原生字段 · 无前缀 | OpenAI 字段 |
|---|---|---|---|
| TTS | POST /xai/v1/tts | POST /v1/tts | POST /v1/audio/speech |
| 音色列表 | GET /xai/v1/tts/voices | GET /v1/tts/voices | — |
| STT | POST /xai/v1/stt | POST /v1/stt | POST /v1/audio/transcriptions |
| 流式 TTS | WSS /xai/v1/tts | WSS /v1/tts | — |
| 流式 STT | WSS /xai/v1/stt | WSS /v1/stt | — |
| 实时语音 | WSS /xai/v1/realtime | WSS /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 参数详解
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
text | string | 是 | 要合成的文本,最长 15,000 字符。支持语音标签 |
language | string | 是 | BCP-47 语言码或 auto 自动识别。大小写不敏感 |
voice_id | string | 否 | 音色 ID。不传默认 eve |
speed | number | 否 | 语速倍率,0.7–1.5,默认 1.0 |
output_format | object | 否 | 输出编码,见输出格式 |
with_timestamps | boolean | 否 | 为 true 时返回 JSON 信封,含 base64 音频 + 逐字符时间戳 |
text_normalization | boolean | 否 | 为 true 时先把数字、缩写、符号转成口语形式再合成 |
optimize_streaming_latency | integer | 否 | 流式合成的延迟档位:0(默认,不做优化、音质最好)、1(首包更小、块边界有轻微音质损失)。官方指南另提到 2,需要更激进的首包优化时可试 |
replace | object | 否 | 发音替换表,见发音替换 |
音色
| 说明 | |
|---|---|
| 默认音色 | 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 | 适合 |
|---|---|---|
mp3 | audio/mpeg | 通用,兼容性最好。默认 |
wav | audio/wav | 无损,适合后期剪辑 |
pcm | audio/pcm | 裸音频,适合实时处理管线 |
mulaw | audio/basic | 电话(G.711 μ-law) |
alaw | audio/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两个数组长度永远相等,按下标一一对应。但要注意两件事:
- 用了
replace时,graph_chars描述的是「念出来的文本」,里面是替换后的字符,不是你说发送的原文。- 开了
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} |
两个前提
POST /v1/custom-voices需要 Enterprise 套餐才能走 API 创建;控制台里可以免费建,每个团队最多 30 个。- 自定义音色只属于你的团队,不会出现在
GET /v1/tts/voices内置音色列表里,只能从GET /v1/custom-voices查。
流式语音合成 (WebSocket)
想让音频边生成边播放,连 wss://api.wxiai.com/xai/v1/tts。
连接参数(放 URL query)
注意流式用 codec 这个扁平字段,不是 HTTP 版本的 output_format.codec。
| 参数 | 默认 | 说明 |
|---|---|---|
voice | eve | 音色 ID |
language | — | 必填,和 HTTP 版本一样 |
codec | mp3 | mp3 / wav / pcm / mulaw / alaw(ulaw 是 mulaw 的别名) |
sample_rate | 24000 | 采样率 |
bit_rate | 128000 | 码率,仅 mp3 生效 |
speed | 1.0 | 语速,0.7–1.5 |
optimize_streaming_latency | 0 | 延迟档位,0 / 1 |
text_normalization | false | 是否先做文本规范化 |
with_timestamps | false | 是否随音频分片返回时间戳 |
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.delta | base64 音频分片。开了 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 条 |
| 连接许可 TTL | 600 秒 |
一连接可以合成多段
audio.done 之后连接不会断,直接再发一组 text.delta → text.done 就能合成下一段,适合对话式 UI。
STT 参数详解
请求格式是 multipart/form-data,不是 JSON。file 和 url 至少给一个。
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
file | file | — | 音频文件,最大 500 MB。与 url 二选一,且必须是 multipart 最后一个字段 |
url | string | — | 音频地址,服务端下载后转写。与 file 二选一 |
language | string | — | 语言码。只有配 format=true 时才起作用(用于文本格式化) |
format | boolean | false | 开启反向文本规范化:把口语数字/货币转成书面形式("one hundred dollars" → "$100")。需要同时传 language |
diarize | boolean | false | 说话人分离。开启后每个词会带 speaker 字段 |
multichannel | boolean | false | 逐声道独立转写,结果放在 channels 数组里 |
channels | integer | — | 声道数(2–8)。仅裸音频需要,容器格式自动识别 |
audio_format | string | — | 裸音频格式提示:pcm / mulaw / alaw。容器格式别传这个字段 |
sample_rate | integer | — | 采样率,仅裸音频需要 |
keyterm | string | — | Grok 专有。关键词偏置,重复传多个,最多 100 个、每个 ≤ 50 字符 |
filler_words | boolean | false | Grok 专有。为 true 时保留 "uh"、"um" 这类填充词 |
vad_threshold | number | 0.5 | Grok 专有。语音活动门限(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 值 | 说明 |
|---|---|---|
| PCM | pcm | 有符号 16 位小端(2 字节/采样) |
| µ-law | mulaw | G.711 µ-law(1 字节/采样) |
| A-law | alaw | G.711 A-law(1 字节/采样) |
上限:单文件 500 MB;单声道、立体声或最多 8 声道(需 multichannel=true)。
流式语音识别 (WebSocket)
连 wss://api.wxiai.com/xai/v1/stt,配置全放在 URL query 里,音频用裸二进制帧发送(不是 base64)。
| Query 参数 | 默认 | 说明 |
|---|---|---|
sample_rate | 16000 | 采样率。encoding=opus 时忽略 |
encoding | pcm | pcm / mulaw / alaw / opus |
interim_results | false | 为 true 时每 ~500 ms 发一次中间结果(is_final=false) |
endpointing | 400 | 判定一句结束所需的静音时长(ms),范围 0–5000 |
language | — | 语言码,用于文本格式化 |
diarize | — | 说话人分离 |
filler_words | false | 是否保留填充词 |
multichannel / channels | false / 1 | 多声道转写,最多 8 声道(不支持 encoding=opus) |
keyterm | — | 关键词偏置,最多 100 个 |
smart_turn | — | 智能断句置信度门限(0.0–1.0) |
smart_turn_timeout | — | 强制断句的最大静音时长(ms),范围 1–5000 |
vad_threshold | 0.08 | 语音活动门限(0.0–1.0) |
你发过去:二进制帧(裸音频,按实时节奏切片)、{"type": "finalize"}(立刻结束当前这句)、{"type": "finalize", "channel": 0}(多声道场景)、{"type": "audio.done"}(音频发完)。
服务端发回来:transcript.created(就绪,收到再发音频)、transcript.partial、transcript.done、error。
transcript.partial 用两个布尔量表达三种状态:
is_final | speech_final | 含义 |
|---|---|---|
false | false | 中间结果,文字还会变(仅 interim_results=true 时) |
true | false | 分块结束,这段文字已定稿(约 3 秒语音) |
true | true | 整句结束,说话人停下了 |
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 秒以上。
