OpenAI 实时转录

2026-11-06 12:39 更新

Go示例在转录会话配置完成后发送24 kHz单声道PCM16、提交语音轮次,并以item_id匹配该提交项目的最终转录;不同轮次的完成事件可能乱序。 应用需要从麦克风、通话或其他实时音频流获取文字,而不需要助手语音回答时,使用实时转录。推荐模型会随讲话到达返回转录增量,并在应用提交每个音频轮次后返回最终转录。

从 gpt-live-transcribe 开始。音频已录制完成时使用文件转录,工作流比较见转录概览。

创建转录会话

服务端使用标准 API 密钥通过 WebSocket 转录时,连接 wss://api.openai.com/v1/realtime?intent=transcription。认证头见 WebSocket 指南,但 URL 中不要提供 model。该指南带模型的 URL 创建的是对话会话,不能接受下面的转录更新。

连接打开后,发送 type: "transcription" 的 session.update,在会话配置选择 gpt-live-transcribe。浏览器音频见 WebRTC。

来源示例 1(json):字段名、事件类型和示意值保留原样,含义见相邻正文;片段中的省略号不表示完整可运行程序。

{
  "type": "session.update",
  "session": {
    "type": "transcription",
    "audio": {
      "input": {
        "format": {
          "type": "audio/pcm",
          "rate": 24000
        },
        "transcription": {
          "model": "gpt-live-transcribe"
        },
        "turn_detection": null
      }
    }
  }
}

示例使用 24 kHz PCM。gpt-live-transcribe 转录会话中,省略 audio.input.turn_detection 或设为 null;模型不支持 server_vad 或 semantic_vad。完整配置见 Realtime 会话参考。

流式发送音频

通过 input_audio_buffer.append 发送音频块:

来源示例 2(javascript):

// [中文] 示例 2:流式发送音频;以下保留本语言原始示例。
// [中文] 本段构造的事件类型:input_audio_buffer.append;不要将构造载荷等同于收到成功确认。
// [中文] 沿原示例执行这些方法:ws.send;异步调用及事件接收顺序保留。
ws.send(
  JSON.stringify({
    type: "input_audio_buffer.append",
    audio: base64Pcm16,
  })
);

在每个音频轮次结束时发送 input_audio_buffer.commit,取得最终转录:

来源示例 3(javascript):

// [中文] 示例 3:流式发送音频;以下保留本语言原始示例。
// [中文] 本段构造的事件类型:input_audio_buffer.commit;不要将构造载荷等同于收到成功确认。
// [中文] 沿原示例执行这些方法:ws.send;异步调用及事件接收顺序保留。
ws.send(
  JSON.stringify({
    type: "input_audio_buffer.commit",
  })
);

使用客户端 VAD 检测讲话结束,然后发送 input_audio_buffer.commit。

处理转录事件

监听增量转录和完成事件:

来源示例 4(javascript):

程序文字译释107:最终转录文字。

// [中文] 示例 4:处理转录事件;以下保留本语言原始示例。
// [中文] 沿原示例执行这些方法:ws.on;异步调用及事件接收顺序保留。
ws.on("message", (data) => {
  const event = JSON.parse(data);

  if (event.type === "conversation.item.input_audio_transcription.delta") {
    process.stdout.write(event.delta);
  }

  if (event.type === "conversation.item.input_audio_transcription.completed") {
    console.log("\nFinal transcript:", event.transcript);
  }
});

增量事件包含新获得的转录文字:

来源示例 5(json):字段名、事件类型和示意值保留原样,含义见相邻正文;片段中的省略号不表示完整可运行程序。

{
  "type": "conversation.item.input_audio_transcription.delta",
  "item_id": "item_003",
  "content_index": 0,
  "delta": "Hello,"
}

完成事件包含已提交项目的最终转录:

来源示例 6(json):

程序文字译释108:你好,你怎么样?

{
  "type": "conversation.item.input_audio_transcription.completed",
  "item_id": "item_003",
  "content_index": 0,
  "transcript": "Hello, how are you?"
}

// [中文] 按会话配置发送输入音频并处理提交或转录事件;音频字节格式必须匹配配置,不能仅修改参数而不转换采样数据。
// [中文] 本段为配置或调用片段,需结合外层程序与已建立连接使用;不作为独立完整程序宣称编译通过。
func transcribeTurn(ctx context.Context, conn *realtime.RealtimeConnection, audio []byte) error {
    for start := 0; start < len(audio); start += 9600 {
        end := min(start+9600, len(audio))
        if err := conn.Send(ctx, realtime.RealtimeClientEventParamOfInputAudioBufferAppend(base64.StdEncoding.EncodeToString(audio[start:end]))); err != nil {
            return err
        }
    }
    if err := conn.Send(ctx, realtime.RealtimeClientEventUnionParam{
        OfInputAudioBufferCommit: &realtime.InputAudioBufferCommitEventParam{},
    }); err != nil {
        return err
    }
    // Match the final transcript to the committed item, not event arrival order.
    var itemID string
    for {
        event, err := conn.Recv(ctx)
        if err != nil {
            return err
        }
        switch event.Type {
        case "input_audio_buffer.committed":
            itemID = event.OfInputAudioBufferCommittedEvent.ItemID
        case "conversation.item.input_audio_transcription.delta":
            delta := event.OfConversationItemInputAudioTranscriptionDeltaEvent
            if itemID != "" && delta.ItemID == itemID {
                fmt.Fprintf(os.Stderr, "Partial transcript (%s): %s\n", delta.ItemID, delta.Delta)
            }
        case "conversation.item.input_audio_transcription.completed":
            completed := event.OfConversationItemInputAudioTranscriptionCompletedEvent
            if itemID == "" || completed.ItemID != itemID {
                continue
            }
            fmt.Println("Final transcript:", completed.Transcript)
            return nil
        case "conversation.item.input_audio_transcription.failed":
            if itemID != "" && event.OfConversationItemInputAudioTranscriptionFailedEvent.ItemID == itemID {
                return fmt.Errorf("transcription failed")
            }
        case "error":
            return fmt.Errorf("Realtime API error: %s", event.OfRealtimeErrorEvent.Error.Message)
        }
    }
}

不同讲话轮次的完成事件不保证按顺序到达。使用 item_id 将转录事件匹配到已提交输入项。

添加转录上下文

音频包含专业词汇或预计会出现多种语言时,可以补充上下文。在已有会话中再发送 session.update,即可更改转录配置。

来源示例 7(json):

程序文字译释109:一段涉及高级套餐及账户AC-42的客服通话。

程序文字译释110:高级套餐。

{
  "type": "session.update",
  "session": {
    "type": "transcription",
    "audio": {
      "input": {
        "format": {
          "type": "audio/pcm",
          "rate": 24000
        },
        "transcription": {
          "model": "gpt-live-transcribe",
          "prompt": "A customer support call about a premium plan and account AC-42.",
          "keywords": ["premium plan", "AC-42", "billing"],
          "languages": ["en", "fr"],
          "delay": "low"
        },
        "turn_detection": null
      }
    }
  }
}

  • prompt:描述录音及其场景。
  • keywords:提供可能出现的产品名、缩写或其他字面术语。
  • languages:指定预计的输入语言。

支持的语言代码格式包括:

  • ISO 639-1,如 en、es、fr。
  • 部分 ISO 639-3,如 eng、spa、yue、cmn。
  • zh 地区语言代码,如 zh-cn、zh-tw、zh-hk。

Realtime API 会拒绝不支持或格式错误的语言代码。

关键词是提示,不是强制输出。每个关键词保持一行,不含 <、>、回车或换行。关键词包含这些字符,或 prompt 超出模型长度限制时,会话更新会被拒绝。

gpt-live-transcribe 使用 languages,而不是单数 language 字段,不要同时发送两者。

转录已提交轮次

只有明确需要提交音频轮次之后才开始转录,或需要输出检测到的语言时,才在 Realtime 会话使用 gpt-transcribe。这种专用工作流要求 WebSocket 连接。

gpt-transcribe 无论在 Realtime API 会话中做输入转录,还是在专用转录会话中运行,都会自动把较早已转录轮次作为上下文。

来源示例 8(json):字段名、事件类型和示意值保留原样,含义见相邻正文;片段中的省略号不表示完整可运行程序。

{
  "type": "session.update",
  "session": {
    "type": "transcription",
    "audio": {
      "input": {
        "format": {
          "type": "audio/pcm",
          "rate": 24000
        },
        "transcription": {
          "model": "gpt-transcribe"
        },
        "turn_detection": null
      }
    }
  }
}

追加音频并发送 input_audio_buffer.commit,模型随后可在最终完成事件之前发出转录增量。完成事件还包含检测到的语言:

来源示例 9(json):字段名、事件类型和示意值保留原样,含义见相邻正文;片段中的省略号不表示完整可运行程序。

{
  "type": "conversation.item.input_audio_transcription.completed",
  "item_id": "item_003",
  "content_index": 0,
  "transcript": "Bonjour, pouvez-vous m'entendre ?",
  "languages": [{ "code": "fr" }]
}

gpt-transcribe 无法可靠预测语言时,languages 是空数组。gpt-live-transcribe 不返回检测语言预测。

调整延迟与准确性

流式转录需要在延迟与质量间权衡。较低延迟设置可更早产生部分文字;较高设置让模型发出文字前获得更多音频上下文,可能改善词错误率。

从 audio.input.transcription.delay 开始,使用实际音频测试。可参考以下起点:

  • minimal:最敏感于延迟的交互。
  • low:低延迟实时字幕。
  • medium:平衡延迟与准确性。
  • high:准确性比立即显示更重要。
  • xhigh:能容忍最多等待时间,以获得更多上下文。

实际毫秒延迟随模型配置变化,应用代表性音频做基准测试,不要假定每级对应固定时间。

不要只根据合成音频选设置。测试实际麦克风、电话音频、口音、背景噪声、语码切换、领域词汇和长会话。

处理置信度、时间戳与说话人标签

gpt-live-transcribe 不返回词级时间戳、说话人标签或转录置信度。需要时间戳或说话人标签时,使用兼容的文件转录模型,或增加应用级回退方案。

生产检查清单

  • 调参前确定目标延迟和准确性阈值。
  • 使用真实生产音频测试,而不只是干净样本。
  • 逐一测试目标语言。
  • 评估集中加入数字、日期、货币、电子邮箱、产品名与领域术语。
  • 除词错误率外,分别追踪空转录、截断和延迟。
  • 决定后续增量纠正较早文字时,界面如何修订部分文本。
  • 用 item_id 排序并协调最终转录。
  • 为不支持的时间戳、说话人标签或置信度字段保留回退路径。

相关指南

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号