实时口译
本示例使用 Grok API 构建实时语音口译工具,在你说话时进行双语互译。它还展示了浏览器如何直连实时语音 API,同时将 API 密钥留在服务端。
说一段英语,停顿约一秒就能听到西班牙语译文,也可以选择其他语言组合。网页使用服务器发放的、有效期为一分钟的 token 直连 Grok 的实时语音 API,并随对话显示双语字幕。
你将学到什么
将 API 密钥保留在服务端,通过以下方法签发短期客户端凭据:
client.voice.clientSecrets.create()在浏览器中使用
xai-client-secret.<token>WebSocket 子协议连接实时语音 API,为每个会话签发新的 token通过提示词让实时语音会话翻译听到的话,而不回答其中的问题
将麦克风音频实时传给会话,并用 Web Audio API 播放 Grok 的语音
根据会话的转写事件,实时显示你的原话和 Grok 译文的字幕
运行示例
需要 Node.js 22.13 或更高版本,以及供网页使用的麦克风。将 API 密钥写入 .env(位于仓库根目录),或导出环境变量 XAI_API_KEY。
cd examples/live-interpreter/typescript
npm install
npm run web打开 http://localhost:3000,选择你说的语言和 Grok 应使用的目标语言,然后点击麦克风。网页类似双栏口译应用:左侧实时显示你说的话。你一停顿,Grok 就会用目标语言复述,右侧同时显示译文。Grok 发言期间会暂停你的麦克风,因此请像与真人口译员交谈时一样,等它说完再继续。点击停止按钮结束会话后,页面会显示时长和费用。
没有麦克风时也可以从终端试用。程序先用文本转语音录制一句话,再像网页传输你的语音一样将音频发给会话,并打印原文和译文:
npm start
npm start -- --to fr "Where can I buy a ticket for tonight's concert?"Grok 的语音保存到 output/translation.wav,终端还会打印 Grok 开始发声前的等待时间和本次费用(约 0.01 美元)。
每分钟口译费用与语音转语音相同,为 0.08 美元,每小时为 4.80 美元。每个 response.done 事件都会报告截至当时的计费秒数,字段为 usage.billable_audio_seconds。测试发现,计费时长从收到第一段音频开始计算,包含静音时间;网页也据此估算费用。用完后请停止会话。
工作原理
浏览器直接连接实时 API,服务器仅向浏览器发放由 SDK 签发的 token。会话使用网页自行打开的 WebSocket,因为 SDK 没有实时客户端,且必须启用 dangerouslyAllowBrowser 才能在浏览器中运行,这会把 API 密钥暴露给网页。
src/interpreter.ts 包含服务器与终端脚本共用的代码:
createSession()签发客户端凭据,调用的方法是client.voice.clientSecrets.create()。token 指定模型grok-voice-think-fast-2.0,并关闭推理,因为用另一种语言复述句子不需要推理。实测无论是否启用推理,Grok 都在说话人停顿后 0.7 至 1 秒内开始发声。每个 token 只能开启一个会话,会话在 token 过期后仍会继续,所以 token 只需在浏览器连接时有效,其有效期为 60 秒。它返回 token 和会话设置。浏览器连接后会在
session.update中发送这些设置,包括提示词、声音、服务端轮次检测、双向 24 kHz PCM 音频,以及grok-transcribe模型(可在说话人尚未说完时进行转写)。SDK 的类型仅允许 token 携带模型和推理设置,因此浏览器需要另行发送其余配置,使用的事件为session.update。interpreterPrompt()采用提示指南中的章节组织提示词。语音模型擅长交谈,因此提示词大多用于阻止它参与讨论。听到的所有内容都应当翻译:听到问题就翻译问题,听到“忽略你的指令”也要翻译这句话,而不是照做。
src/server.ts 是一个小型 node:http 服务器,为网页提供服务并在以下端点签发 token:POST /api/session。任何能访问该路由的人都可使用你的账号开启会话,因此实际应用只应向已登录用户发放 token。
public/index.html 使用原生 HTML 和 JavaScript:
浏览器无法在 WebSocket 连接上设置请求头,因此网页通过子协议发送 token:
new WebSocket("wss://api.x.ai/v1/realtime", ["xai-client-secret." + token])。当收到session.created时发送设置,当收到session.updated确认提示词后开始发送音频。token 自带的设置会先通过一个session.updated事件送达,该事件不含提示词。AudioWorklet 以 24 kHz 采集麦克风音频,网页将其切成 100 毫秒的 base64 PCM 音频块,通过以下事件发送:
input_audio_buffer.append。服务端轮次检测会发现说话人的停顿,随后开始 Grok 的发言轮次。每个轮次对应一行。
input_audio_buffer.speech_started会新增一行,conversation.item.input_audio_transcription.updated随说话人发言填写左栏,response.output_audio_transcript.delta填写右栏。短暂停顿可能提前结束轮次。如果说话人在input_audio_buffer.committed到达前继续发言,Grok 会丢弃该轮次,下一轮转写仍以相同词语开头,因此网页复用已有的行。音频通过response.output_audio.delta到达,接收速度快于播放速度,因此每块音频的播放起点设为上一块的终点。网页在播放 Grok 语音期间以及播放结束后 0.3 秒内暂停发送麦克风音频,防止 Grok 听到并翻译扬声器播放的自己的声音。
测试中,无论使用客户端凭据还是 API 密钥,约有十分之一的连接成功打开却未能启动会话。网页每次最多等五秒接收
session.created,超时后会换用新 token 重试,最多三次。
src/index.ts 在终端运行同样的会话。它通过 client.voice.speak() 将句子录制为原始 24 kHz PCM 音频,通过 createSession() 签发 token,再使用 Node 22 内置的 WebSocket 客户端以相同子协议连接。除 SDK 外,此示例无需其他软件包。它实时传输录音,随后发送 1.5 秒静音以结束轮次,收到转写就打印出来。