实时翻译让您能够将源音频流式传输到专用的翻译会话,并在说话者仍在讲话时接收翻译后的音频和转写文本增量。它适用于实时口译、多语言通话、广播、会议、课程和视频聊天室。
如果您的应用需要翻译人类说话的内容,请使用 gpt-realtime-translate。如果您需要能够回答问题、调用工具和管理对话的助手,请改用 gpt-realtime-2.1,并搭配标准 Realtime 会话。
翻译会话有何不同
实时翻译会话与语音智能体会话采用不同的架构:
| 语音智能体会话 | 翻译会话 |
|---|---|
连接到 /v1/realtime。 | 连接到 /v1/realtime/translations。 |
| 模型充当助手。 | 模型充当口译员。 |
| 使用对话和响应生命周期。 | 根据传入的音频持续进行流式输出。 |
| 可能调用工具并生成助手轮次。 | 生成翻译后的音频和转写文本增量。 |
您可以调用 response.create。 | 您不需要调用 response.create。 |
音频流本身就会触发翻译。请持续追加音频,包括短语之间的静音,并在输出事件到达时处理这些事件。
选择传输方式
当浏览器采集或播放音频时,请使用 WebRTC。WebRTC 以媒体轨道的形式发送源音频,并以远程音频轨道的形式接收翻译后的语音,因此您无需手动重采样或播放 PCM 音频块。
如果您的服务器已经在接收原始音频,例如使用 Twilio Media Streams、SIP 媒体、广播输入流或媒体工作进程,请使用 WebSocket。使用 WebSocket 时,请发送经过 base64 编码的 24 kHz PCM16 音频,并自行播放返回的音频增量。
创建浏览器 WebRTC 会话
对于浏览器应用,请在服务器上创建短期有效的客户端密钥。不要在浏览器中暴露您的标准 API 密钥。
app.post("/session", async (req, res) => {
const language = req.body.targetLanguage ?? "es";
const response = await fetch(
"https://api.openai.com/v1/realtime/translations/client_secrets",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
"Content-Type": "application/json",
"OpenAI-Safety-Identifier": "hashed-user-id",
},
body: JSON.stringify({
session: {
model: "gpt-realtime-translate",
audio: {
output: { language },
},
},
}),
}
);
res.status(response.status).json(await response.json());
});在浏览器中采集音频、创建对等连接,并将 SDP offer 通过 POST 请求发送到翻译通话端点:
const { value: clientSecret } = await fetch("/session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ targetLanguage: "es" }),
}).then((response) => response.json());
const sourceStream = await navigator.mediaDevices.getUserMedia({
audio: true,
});
const pc = new RTCPeerConnection();
pc.addTrack(sourceStream.getAudioTracks()[0], sourceStream);
const translatedAudio = new Audio();
translatedAudio.autoplay = true;
pc.ontrack = ({ streams }) => {
translatedAudio.srcObject = streams[0];
};
const events = pc.createDataChannel("oai-events");
events.onmessage = ({ data }) => {
const event = JSON.parse(data);
if (event.type === "session.output_transcript.delta") {
subtitles.textContent += event.delta;
}
};
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
const sdpResponse = await fetch(
"https://api.openai.com/v1/realtime/translations/calls",
{
method: "POST",
headers: {
Authorization: `Bearer ${clientSecret}`,
"Content-Type": "application/sdp",
},
body: offer.sdp,
}
);
if (!sdpResponse.ok) {
throw new Error(await sdpResponse.text());
}
await pc.setRemoteDescription({
type: "answer",
sdp: await sdpResponse.text(),
});创建 WebSocket 会话
连接到专用的翻译端点,并在 URL 中选择模型:
运行此示例前,请为 Node.js 安装 ws,为 Python 安装 websocket-client,或为 Ruby 安装 async-websocket(gem install async-websocket)。
import WebSocket from "ws";
const ws = new WebSocket(
"wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
{
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
"OpenAI-Safety-Identifier": "hashed-user-id",
},
}
);如果您使用 Ruby,请将以下配置和音频追加代码片段插入 Async::WebSocket::Client.connect 代码块内,放在检查会话是否已创建的代码之后、代码块结束之前。在发送音频和接收翻译事件期间,请保持连接打开。
套接字连接建立后,配置目标语言:
ws.on("open", () => {
ws.send(
JSON.stringify({
type: "session.update",
session: {
audio: {
output: {
language: "es",
},
},
},
})
);
});然后持续追加音频:
ws.send(
JSON.stringify({
type: "session.input_audio_buffer.append",
audio: base64Pcm16,
})
);监听翻译后的音频和转写文本:
ws.on("message", (data) => {
const event = JSON.parse(data.toString());
if (event.type === "session.output_audio.delta") {
playPcm16(event.delta);
}
if (event.type === "session.output_transcript.delta") {
process.stdout.write(event.delta);
}
if (event.type === "session.input_transcript.delta") {
updateSourceTranscript(event.delta);
}
});关闭 WebSocket 会话
源音频流结束时,请在关闭 WebSocket 之前发送 session.close 事件。此事件会通知服务处理完待处理的输入音频,输出所有剩余的翻译音频和转写文本,然后发送 session.closed 事件。只有翻译会话支持 session.close 事件。
发送 session.close 后,请停止追加音频,并在正常的接收循环中继续读取事件,直到收到 session.closed。立即关闭套接字可能会导致会话中尚未发送完毕的翻译输出丢失。
let translationSessionClosing = false;
function closeTranslationSession() {
if (translationSessionClosing) {
return;
}
translationSessionClosing = true;
ws.send(
JSON.stringify({
type: "session.close",
})
);
}
ws.on("message", (data) => {
const event = JSON.parse(data.toString());
if (event.type === "session.output_audio.delta") {
playPcm16(event.delta);
}
if (event.type === "session.output_transcript.delta") {
process.stdout.write(event.delta);
}
if (event.type === "session.input_transcript.delta") {
updateSourceTranscript(event.delta);
}
if (event.type === "session.closed") {
ws.close();
}
});
// Call this when the source stream ends.
closeTranslationSession();构建随听翻译功能
当您需要将一位说话者或一路音频流的内容翻译为音频并提供给听众时,请使用随听翻译。适用场景包括直播、会议演讲、网络研讨会、财报电话会议、讲座和视频。
典型架构如下:
source audio -> translation session -> translated audio + subtitles
为每种目标语言创建一个翻译会话。如果同一份英语源音频需要西班牙语和法语输出,请分别创建一个英语到西班牙语的会话和一个英语到法语的会话。
对于浏览器随听翻译应用,请使用 getDisplayMedia() 采集标签页音频,通过 WebRTC 发送,并播放远程翻译音频轨道。对于生产环境中的广播,请在服务器媒体工作进程中运行翻译,并向听众发布翻译后的音频轨道或字幕。
构建对话翻译功能
当两名或更多参与者使用不同语言交流时,请使用对话翻译。适用场景包括客服通话、销售通话、辅导和视频聊天室。
请将各参与者的音频轨道保持独立。将不同说话者的音频混合到同一条流中,会使说话者身份、各说话者的字幕以及重叠语音更难处理。
对于双人通话,为每个翻译方向创建一个翻译会话:
Caller A audio -> translate into Caller B language -> play to Caller B
Caller B audio -> translate into Caller A language -> play to Caller A
对于群组房间,会话数量取决于活跃发言者和目标语言:
translation sessions ~= active source speaker tracks x distinct target languages
对于小型房间,每位听众都可以在浏览器端为需要翻译的远程发言者创建辅助翻译组件。对于较大的房间,使用服务端参与者或媒体工作进程,对每位源发言者的音频仅订阅一次,为每种目标语言创建一个翻译会话,并重新发布翻译后的音轨。
测试质量和延迟
使用真实音频并结合双语审查来测试翻译。自动化指标能提供帮助,但无法发现用户会注意到的所有错误。
测试以下各项:
- 语言对的翻译质量;
- 名称、数字、日期、货币和电话号码;
- 特定领域的术语;
- 语言切换和混合语言对话;
- 口音、快速讲话和重叠语音;
- 首段翻译音频的延迟;
- 话语结束后的延迟;
- 字幕显示时机;
- 声音一致性;
- 重连行为。
如果您的用例要求准确翻译名称或领域术语,请在上线前建立一套标准测试集,并人工审查失败案例。
生产环境检查清单
- 浏览器端媒体选择 WebRTC,服务端媒体选择 WebSocket。
- 使用专用的
/v1/realtime/translations端点。 - 持续传输音频流,包括短语之间的静音。
- 关闭 WebSocket 会话之前,使用
session.close并等待session.closed。 - 进行对话翻译时,保持各发言者的音轨独立。
- 为每种输出语言使用一个会话。
- 在有帮助的情况下,同时显示源语言和目标语言的转录文本。
- 提供原始音频、翻译音频、字幕、静音和音量的控制选项。
- 显示正在重连、延迟和不可用状态。
- 将延迟与翻译质量分开跟踪。
相关指南
比较语音智能体会话、翻译会话和转录会话。
将浏览器端媒体连接到实时会话。
通过服务端媒体流水线传输原始音频流。
以流式方式输出实时音频的转录文本增量。