OpenAI 实时翻译
Python连接示例还需要安装sounddevice和websocket-client。Go应在发送音频时并发运行listen;收到session.closed后关闭传输。 实时翻译允许把源音频流发送到专用翻译会话,在讲话者仍说话时接收翻译音频和转录增量。适用于实时口译、多语言通话、广播、会议、课程及视频房间。
应用需要翻译人类讲话时,使用 gpt-realtime-translate。如果需要回答问题、调用工具、管理对话的助手,应在标准 Realtime 会话使用 gpt-realtime-2.1。
翻译会话有何不同
实时翻译与语音智能体使用不同架构:
| 语音智能体会话 | 翻译会话 |
|---|---|
连接 /v1/realtime。 |
连接 /v1/realtime/translations。 |
| 模型充当助手。 | 模型充当口译员。 |
| 使用对话与响应生命周期。 | 持续处理传入音频流。 |
| 可以调用工具并生成助手轮次。 | 生成翻译音频和转录增量。 |
可调用 response.create。 |
不调用 response.create。 |
翻译由音频流本身启动。持续追加音频,包括话语之间的静音,并在输出事件到达时处理。
选择传输方式
浏览器采集或播放音频时使用 WebRTC。源音频通过媒体轨道发送,翻译语音通过远端音轨接收,无需手动重采样或播放 PCM 块。
服务器已接收原始音频时,例如 Twilio Media Streams、SIP 媒体、广播输入或媒体工作进程,使用 WebSockets。此时发送 Base64 编码的 24 kHz PCM16 音频,并自行播放返回的音频增量。
创建浏览器 WebRTC 会话
浏览器应用应在服务器创建短期客户端密钥,不要向浏览器暴露标准 API 密钥。
创建翻译客户端密钥:
来源示例 1(javascript):
// [中文] 示例 1:创建浏览器 WebRTC 会话;以下保留本语言原始示例。
// [中文] 原代码明确设置的模型值:gpt-realtime-translate;各值的作用按其所在配置对象区分。
// [中文] 本段涉及的 HTTP 端点:/v1/realtime/translations/client_secrets;认证和请求体保持原示例形式。
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 提交到翻译通话端点:
连接浏览器翻译通话:
来源示例 2(javascript):
// [中文] 示例 2:创建浏览器 WebRTC 会话;以下保留本语言原始示例。
// [中文] 本段涉及的 HTTP 端点:/v1/realtime/translations/calls;认证和请求体保持原示例形式。
// [中文] 沿原示例执行这些方法:pc.addTrack、pc.createDataChannel、pc.createOffer、pc.setLocalDescription、pc.setRemoteDescription;异步调用及事件接收顺序保留。
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)。Java 添加 Maven 依赖 com.openai:openai-java:4.75.1。
Java 示例分别展示连接、语言配置与音频输入,不是完整翻译工作流。Java SDK 支持接收事件和结束会话,但本指南未提供这些步骤的 Java 示例;完整流程请跟随 Node.js 或 Python 示例。
连接翻译会话:
来源示例 3(javascript):
// [中文] 示例 3:创建 WebSocket 会话;以下保留本语言原始示例。
// [中文] 在可信服务器连接专用 translations 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",
},
}
);
来源示例 4(python):
## [中文] 示例 4:创建 WebSocket 会话;以下保留本语言原始示例。
## [中文] 沿原示例执行这些方法:ws.connect;异步调用及事件接收顺序保留。
import os
import websocket
ws = websocket.WebSocket()
ws.connect(
"wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
header=[
f"Authorization: Bearer {os.environ['OPENAI_API_KEY']}",
"OpenAI-Safety-Identifier: hashed-user-id",
],
)
// [中文] 用本语言客户端连接指定WebSocket端点,区分Live与Realtime的凭证、URL和事件;应用继续负责音频收发与会话生命周期。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
client := openai.NewClient()
session, err := client.Realtime.ConnectTranslation(ctx, "gpt-realtime-translate", realtime.TranslationConnectionOptions{}, option.WithHeader("OpenAI-Safety-Identifier", "hashed-user-id"))
if err != nil {
return err
}
defer session.Abort()
created, err := session.Recv(ctx)
if err != nil {
return err
}
fmt.Println(created.Type)
if created.Type != "session.created" {
return fmt.Errorf("expected session.created, got %s", created.Type)
}
来源示例 5(java):
程序文字译释111:已连接翻译会话。
// [中文] 示例 5:创建 WebSocket 会话;以下保留本语言原始示例。
// [中文] 原代码明确设置的模型值:gpt-realtime-translate;各值的作用按其所在配置对象区分。
// [中文] 沿原示例执行这些方法:connection.receive;异步调用及事件接收顺序保留。
import com.openai.client.okhttp.OkHttpClient;
import com.openai.core.ClientOptions;
import com.openai.helpers.TranslationConnection;
import com.openai.helpers.TranslationWebSocketOptions;
import com.openai.models.realtime.*;
var http = OkHttpClient.builder().build();
var options =
ClientOptions.builder()
.fromEnv()
.httpClient(http)
.putHeader("OpenAI-Safety-Identifier", "hashed-user-id")
.build();
try (http;
var connection =
TranslationConnection.connect(
options,
TranslationWebSocketOptions.builder()
.model("gpt-realtime-translate")
.sendTimeout(java.time.Duration.ofSeconds(30))
.build())) {
while (true) {
var event = connection.receive();
if (event.error().isPresent())
throw new IllegalStateException(event.error().orElseThrow().toString());
if (event.sessionCreated().isPresent()) {
System.out.println("Connected to translation session.");
System.out.println(event);
break;
}
}
}
来源示例 6(ruby):
程序文字译释112:会话创建前连接已关闭。
程序文字译释113:原本预期session.created,实际收到所示事件。
## [中文] 示例 6:创建 WebSocket 会话;以下保留本语言原始示例。
## [中文] 在异步上下文中连接翻译端点,并用环境变量中的服务端密钥认证。
## [中文] 读取第一条消息,确认类型为 session.created;无消息或类型不符即抛错。
## [中文] 离开连接块会关闭连接;应把后续配置、收发音频及 session.close/等待 session.closed 的流程放在块内,不能创建后立即退出。
require "async"
require "async/http/endpoint"
require "async/websocket/client"
require "json"
endpoint = Async::HTTP::Endpoint.parse("wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate", timeout: 10, alpn_protocols: ["http/1.1"])
headers = {
"Authorization" => "Bearer #{ENV.fetch("OPENAI_API_KEY")}",
"OpenAI-Safety-Identifier" => "hashed-user-id"
}
Sync do |task|
task.with_timeout(120) do
Async::WebSocket::Client.connect(endpoint, headers: headers) do |connection|
message = connection.read or raise "Connection closed before session creation"
event = JSON.parse(message.to_str)
raise "Expected session.created: #{event}" unless event["type"] == "session.created"
puts(event.fetch("type"))
end
end
end
Ruby 的配置和音频追加片段,应放在 Async::WebSocket::Client.connect 块内,位于会话创建检查之后、块结束之前。发送音频和接收翻译事件期间保持连接打开。
Java 连接示例在 try 块结束时关闭套接字。后续配置和音频输入示例要求仍打开的 TranslationConnection;收发音频期间保持连接,离开块前按关闭 WebSocket 会话完成会话并排空事件,直到 session.closed。
套接字打开后配置目标语言:
来源示例 7(javascript):
// [中文] 示例 7:创建 WebSocket 会话;以下保留本语言原始示例。
// [中文] 本段构造的事件类型:session.update;不要将构造载荷等同于收到成功确认。
// [中文] 沿原示例执行这些方法:ws.on、ws.send;异步调用及事件接收顺序保留。
ws.on("open", () => {
ws.send(
JSON.stringify({
type: "session.update",
session: {
audio: {
output: {
language: "es",
},
},
},
})
);
});
来源示例 8(python):
## [中文] 示例 8:创建 WebSocket 会话;以下保留本语言原始示例。
## [中文] 本段构造的事件类型:session.update;不要将构造载荷等同于收到成功确认。
## [中文] 沿原示例执行这些方法:ws.send;异步调用及事件接收顺序保留。
import json
ws.send(
json.dumps(
{
"type": "session.update",
"session": {
"audio": {
"output": {
"language": "es",
},
},
},
}
)
)
// [中文] 用本语言客户端连接指定WebSocket端点,区分Live与Realtime的凭证、URL和事件;应用继续负责音频收发与会话生命周期。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
if err := session.Send(ctx, realtime.RealtimeTranslationClientEventParamOfSessionUpdate(realtime.RealtimeTranslationSessionUpdateRequestParam{
Audio: realtime.RealtimeTranslationSessionUpdateRequestAudioParam{
Output: realtime.RealtimeTranslationSessionUpdateRequestAudioOutputParam{
Language: openai.String("es"),
},
},
})); err != nil {
return err
}
来源示例 9(java):
// [中文] 示例 9:创建 WebSocket 会话;以下保留本语言原始示例。
// [中文] 沿原示例执行这些方法:connection.send;异步调用及事件接收顺序保留。
import com.openai.client.okhttp.OkHttpClient;
import com.openai.core.ClientOptions;
import com.openai.helpers.TranslationConnection;
import com.openai.helpers.TranslationWebSocketOptions;
import com.openai.models.realtime.*;
connection.send(
RealtimeTranslationClientEvent.ofSessionUpdate(
RealtimeTranslationSessionUpdateEvent.builder()
.session(
RealtimeTranslationSessionUpdateRequest.builder()
.audio(
RealtimeTranslationSessionUpdateRequest.Audio.builder()
.output(
RealtimeTranslationSessionUpdateRequest.Audio.Output.builder()
.language("es")
.build())
.build())
.build())
.build()));
来源示例 10(ruby):
## [中文] 示例 10:创建 WebSocket 会话;以下保留本语言原始示例。
## [中文] 本段构造的事件类型:session.update;不要将构造载荷等同于收到成功确认。
## [中文] 沿原示例执行这些方法:connection.write;异步调用及事件接收顺序保留。
connection.write(JSON.generate(type: "session.update", session: { audio: { output: { language: "es" } } }))
connection.flush
然后连续追加源音频:
来源示例 11(javascript):
// [中文] 示例 11:创建 WebSocket 会话;以下保留本语言原始示例。
// [中文] 本段构造的事件类型:session.input_audio_buffer.append;不要将构造载荷等同于收到成功确认。
// [中文] 沿原示例执行这些方法:ws.send;异步调用及事件接收顺序保留。
ws.send(
JSON.stringify({
type: "session.input_audio_buffer.append",
audio: base64Pcm16,
})
);
来源示例 12(python):
## [中文] 示例 12:创建 WebSocket 会话;以下保留本语言原始示例。
## [中文] 本段构造的事件类型:session.input_audio_buffer.append;不要将构造载荷等同于收到成功确认。
## [中文] 沿原示例执行这些方法:ws.send;异步调用及事件接收顺序保留。
ws.send(
json.dumps(
{
"type": "session.input_audio_buffer.append",
"audio": base64_pcm16,
}
)
)
// [中文] 用本语言客户端连接指定WebSocket端点,区分Live与Realtime的凭证、URL和事件;应用继续负责音频收发与会话生命周期。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
// audio contains mono PCM16 samples at 24 kHz.
for start := 0; start < len(audio); start += 4800 {
end := min(start+4800, len(audio))
if err := session.Send(ctx, realtime.RealtimeTranslationClientEventParamOfSessionInputAudioBufferAppend(base64.StdEncoding.EncodeToString(audio[start:end]))); err != nil {
return err
}
}
来源示例 13(java):
// [中文] 示例 13:创建 WebSocket 会话;以下保留本语言原始示例。
// [中文] 沿原示例执行这些方法:connection.send;异步调用及事件接收顺序保留。
// [中文] 需要发送的原始字节先编码为 Base64;编码不会替代重采样或改变编解码格式。
import com.openai.client.okhttp.OkHttpClient;
import com.openai.core.ClientOptions;
import com.openai.helpers.TranslationConnection;
import com.openai.helpers.TranslationWebSocketOptions;
import com.openai.models.realtime.*;
import java.util.Base64;
// Call for each PCM16, 24 kHz, mono chunk supplied by your audio source.
static void appendAudio(TranslationConnection connection, byte[] pcmAudio) {
String base64Pcm16 = Base64.getEncoder().encodeToString(pcmAudio);
connection.send(
RealtimeTranslationClientEvent.ofSessionInputAudioBufferAppend(
RealtimeTranslationInputAudioBufferAppendEvent.builder().audio(base64Pcm16).build()));
}
来源示例 14(ruby):
## [中文] 示例 14:创建 WebSocket 会话;以下保留本语言原始示例。
## [中文] 本段构造的事件类型:session.input_audio_buffer.append;不要将构造载荷等同于收到成功确认。
## [中文] 沿原示例执行这些方法:connection.write;异步调用及事件接收顺序保留。
## [中文] 需要发送的原始字节先编码为 Base64;编码不会替代重采样或改变编解码格式。
require "base64"
File.open("speech.pcm", "rb") do |audio|
while (chunk = audio.read(4_800))
connection.write(JSON.generate(type: "session.input_audio_buffer.append", audio: Base64.strict_encode64(chunk)))
connection.flush
end
end
监听翻译音频与转录:
来源示例 15(javascript):
// [中文] 示例 15:创建 WebSocket 会话;以下保留本语言原始示例。
// [中文] 沿原示例执行这些方法:ws.on;异步调用及事件接收顺序保留。
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);
}
});
来源示例 16(python):
## [中文] 请求正常关闭并等待session.closed或对应终结状态;发送关闭事件不等同于已收到最终用量或释放所有资源。
import base64
import json
from concurrent.futures import ThreadPoolExecutor
from contextlib import suppress
from queue import SimpleQueue
import sounddevice as sd
audio_queue = SimpleQueue()
def play_audio():
try:
# Closing the stream waits for PortAudio's pending buffers to finish.
with sd.RawOutputStream(samplerate=24000, channels=1, dtype="int16") as stream:
while (pcm := audio_queue.get()) is not None:
stream.write(pcm)
except Exception:
# The receiver may have already closed the socket.
with suppress(OSError):
ws.abort() # Wake recv() so the receiver can report the playback failure.
raise
with ThreadPoolExecutor(max_workers=1) as executor:
playback = executor.submit(play_audio)
try:
while True:
event = json.loads(ws.recv())
if playback.done():
playback.result() # Report a playback failure on the receiver.
if event["type"] == "session.output_audio.delta":
audio_queue.put(base64.b64decode(event["delta"]))
if event["type"] in (
"session.output_transcript.delta",
"session.input_transcript.delta",
):
print(event["delta"], end="", flush=True)
if event["type"] == "error":
raise RuntimeError(f"Translation error: {event['error']['code']}")
if event["type"] == "session.closed":
break
finally:
ws.close()
audio_queue.put(None)
playback.result()
关闭 WebSocket 会话
源音频流结束时,在关闭 WebSocket 之前发送 session.close。该事件让服务刷新待处理输入音频、发出剩余翻译音频和转录,再发送 session.closed。这里的 session.close 事件仅由翻译会话支持。
发送 session.close 后停止追加音频,在正常接收循环中继续读取,直到 session.closed。立即关闭套接字可能丢失仍在排出的翻译输出。
关闭翻译会话:
来源示例 17(javascript):
// [中文] 请求正常关闭并等待session.closed或对应终结状态;发送关闭事件不等同于已收到最终用量或释放所有资源。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
// Run this listener while another goroutine sends audio into the session.
func listen(ctx context.Context, session *realtime.TranslationSession) error {
for {
event, err := session.Recv(ctx)
if err != nil {
return err
}
switch event.Type {
case "error":
return fmt.Errorf("translation error: %s", event.OfRealtimeErrorEvent.Error.Message)
case "session.output_transcript.delta":
fmt.Print(event.OfRealtimeTranslationOutputTranscriptDeltaEvent.Delta)
case "session.output_audio.delta":
pcm, err := base64.StdEncoding.DecodeString(event.OfRealtimeTranslationOutputAudioDeltaEvent.Delta)
if err != nil {
return err
}
// Feed pcm into your application's 24 kHz audio player.
fmt.Fprintln(log.Writer(), "Received audio bytes:", len(pcm))
case "session.closed":
return session.Close()
}
}
}
来源示例 18(python):
// [中文] 请求正常关闭并等待session.closed或对应终结状态;发送关闭事件不等同于已收到最终用量或释放所有资源。
let translationSessionClosing = false;
let gotTranslationClosed = false;
let drainDeadline;
ws.on("close", () => {
clearTimeout(drainDeadline);
if (!gotTranslationClosed) {
console.error("Translation disconnected before final session.closed");
process.exitCode = 1;
}
});
function closeTranslationSession() {
if (translationSessionClosing) {
return;
}
translationSessionClosing = true;
// Adjust this deadline for your application's finalization requirements.
drainDeadline = setTimeout(() => {
console.error("Translation finalization timed out");
process.exitCode = 1;
ws.close();
}, 15_000);
ws.send(JSON.stringify({ type: "session.close" }));
}
// Use this in place of the earlier output handler, so audio plays only once.
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 === "error") {
clearTimeout(drainDeadline);
console.error("Translation error", event.error?.code);
process.exitCode = 1;
ws.close();
}
if (event.type === "session.closed") {
clearTimeout(drainDeadline);
gotTranslationClosed = true;
ws.close();
}
});
// Call this when the source stream ends.
closeTranslationSession();
## [中文] 请求正常关闭并等待session.closed或对应终结状态;发送关闭事件不等同于已收到最终用量或释放所有资源。
import base64
import json
import time
from concurrent.futures import ThreadPoolExecutor
from contextlib import suppress
from queue import SimpleQueue
import sounddevice as sd
audio_queue = SimpleQueue()
def play_audio():
try:
# Closing the stream waits for PortAudio's pending buffers to finish.
with sd.RawOutputStream(samplerate=24000, channels=1, dtype="int16") as stream:
while (pcm := audio_queue.get()) is not None:
stream.write(pcm)
except Exception:
# The receiver may have already closed the socket.
with suppress(OSError):
ws.abort() # Wake recv() so the receiver can report the playback failure.
raise
translation_session_closing = False
def close_translation_session():
global translation_session_closing
if translation_session_closing:
return
translation_session_closing = True
ws.send(json.dumps({"type": "session.close"}))
with ThreadPoolExecutor(max_workers=1) as executor:
playback = executor.submit(play_audio)
try:
# Call this when the source stream ends.
close_translation_session()
# Adjust this deadline for your application's finalization requirements.
drain_deadline = time.monotonic() + 15.0
while True:
remaining = drain_deadline - time.monotonic()
if remaining <= 0:
raise TimeoutError("Translation finalization timed out")
ws.settimeout(remaining)
data = ws.recv()
if not data:
raise RuntimeError("Translation disconnected before session.closed")
event = json.loads(data)
if playback.done():
playback.result() # Report a playback failure on the receiver.
if event["type"] == "error":
raise RuntimeError(f"Translation error: {event['error']['code']}")
if event["type"] == "session.output_audio.delta":
audio_queue.put(base64.b64decode(event["delta"]))
if event["type"] in (
"session.output_transcript.delta",
"session.input_transcript.delta",
):
print(event["delta"], end="", flush=True)
if event["type"] == "session.closed":
break
finally:
# The server deadline covers receiving events, not local playback.
ws.close()
audio_queue.put(None)
playback.result()
// [中文] 请求正常关闭并等待session.closed或对应终结状态;发送关闭事件不等同于已收到最终用量或释放所有资源。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
// Stop sending audio first. The listener closes the transport after session.closed.
if err := session.Send(ctx, realtime.RealtimeTranslationClientEventUnionParam{
OfSessionClose: &realtime.RealtimeTranslationSessionCloseEventParam{},
}); err != nil {
return err
}
构建伴随收听翻译
一个源讲话者或音频流需要为听众提供翻译音频时,使用伴随收听翻译,例如直播、会议演讲、网络研讨会、财报电话会、讲座和视频。
典型架构如下:
来源示例 19(text):
本例中文译文与说明:
源音频 → 翻译会话 → 翻译音频与字幕。
source audio -> translation session -> translated audio + subtitles
每种目标语言创建一个翻译会话。同一个英语源需要西班牙语和法语输出时,分别创建英译西和英译法会话。
浏览器伴随收听应用通过 getDisplayMedia() 采集标签页音频,经 WebRTC 发送并播放远端翻译音轨。生产广播可在服务端媒体工作进程中翻译,再把翻译音轨或字幕发布给听众。
构建对话翻译
两位或更多参与者跨语言交流时,使用对话翻译,如客服、销售、辅导和视频房间。
保持参与者音轨分离。混入同一流会使讲话者身份、字幕和重叠讲话更难处理。
两人通话时,每个方向各创建一个翻译会话:
来源示例 20(text):
本例中文译文与说明:
来电者 A 的音频 → 翻译成 B 的语言 → 播放给 B。
来电者 B 的音频 → 翻译成 A 的语言 → 播放给 A。
Caller A audio -> translate into Caller B language -> play to Caller B
Caller B audio -> translate into Caller A language -> play to Caller A
群组房间的会话数量取决于活动讲话者与目标语言:
来源示例 21(text):
本例中文译文与说明:
翻译会话数约等于:活动源讲话者音轨数 × 不同目标语言数。
translation sessions ~= active source speaker tracks x distinct target languages
小房间中,各听众可为需要翻译的远端讲话者创建浏览器侧翻译辅助会话。较大房间应使用服务端参与者或媒体工作进程,每个源讲话者只订阅一次,为各目标语言建立翻译会话,再重新发布翻译轨道。
测试质量与延迟
使用真实音频和双语审阅测试翻译。自动指标有帮助,但无法发现用户会注意到的所有错误。
测试应包括:
- 各语言对的质量。
- 姓名、数字、日期、货币与电话号码。
- 领域专用术语。
- 语码切换与混合语言对话。
- 口音、快速讲话与重叠讲话。
- 首段翻译音频延迟。
- 话语结束时的延迟。
- 字幕时序。
- 声音一致性。
- 重连行为。
场景依赖精确姓名或领域术语时,上线前建立人工校验的标准集,并人工审查失败案例。
生产检查清单
- 浏览器媒体选 WebRTC,服务端媒体选 WebSockets。
- 使用专用
/v1/realtime/translations端点。 - 连续传输音频,包括语句间静音。
- WebSocket 用
session.close并等到session.closed后再关闭。 - 对话翻译保持各讲话者音轨分离。
- 每种输出语言使用一个会话。
- 有帮助时同时显示原文与译文转录。
- 提供原始音频、翻译音频、字幕、静音与音量控制。
- 显示重连中、延迟和不可用状态。
- 延迟与翻译质量分别追踪。
相关指南
- Realtime 与音频概览:比较语音智能体、翻译与转录会话。
- WebRTC 连接:将浏览器媒体连接到实时会话。
- WebSocket 连接:在服务端媒体流水线传输原始音频。
- 实时转录:从实时音频流获取转录增量。

TRAE-AI编程


更多建议: