OpenAI API - Realtime 实时


实时 API(Beta)

使用实时 API 构建低延迟、多模态的体验。

https://platform.openai.com/docs/guides/realtime


The OpenAI 实时 API 允许低延迟、多模态交互,包括语音到语音的对话体验和实时转录。
此API与原生的多模态模型(如 GPT-4oGPT-4o mini)兼容,提供实时文本和音频处理、函数调用和语音生成等功能,以及最新的转录模型 GPT-4o TranscribeGPT-4o mini Transcribe


使用实时API入门

您可以通过两种方式连接到实时API:

  • 使用 WebRTC,它非常适合客户端应用程序(例如,一个网页应用)
  • 使用 WebSockets,这对于服务器到服务器的应用程序非常出色(例如,如果你的后端或你正在为电话构建语音代理)

开始探索下面的示例和合作伙伴集成,或者学习如何使用最适合您用例的方法连接到实时API。


示例应用

查看以下示例应用之一,以查看实时API的实际应用。


实时控制台
要快速开始,下载并配置实时控制台演示。查看事件来回流动,并检查它们的内容。学习如何通过函数调用执行自定义逻辑。
https://github.com/openai/openai-realtime-console


实时太阳系演示
一个使用WebRTC集成的实时API演示,通过功能调用通过语音导航太阳系。
https://github.com/openai/openai-realtime-solar-system


Twilio 集成演示
一个结合Realtime API和Twilio构建AI电话助手的演示。
https://github.com/openai/openai-realtime-twilio-demo


实时 API 代理演示
A 演示实时 API 语音代理之间的交接以及推理模型验证。
https://github.com/openai/openai-realtime-agents


合作伙伴集成

查看这些合作伙伴集成,它们在前端应用程序和电话用例中使用实时API。

LiveKit集成指南

如何使用实时API与LiveKit的WebRTC基础设施。

https://docs.livekit.io/agents/openai/overview/


Twilio集成指南
使用 Twilio 强大的语音 API 构建实时应用程序。
https://www.twilio.com/en-us/blog/twilio-openai-realtime-api-launch-integration


Agora 集成快速入门
如何将 Agora 的实时音频通信功能与 Realtime API 集成。
https://docs.agora.io/en/open-ai-integration/get-started/quickstart


Pipecat集成指南
创建使用 OpenAI 音频模型和 Pipecat 协奏框架的语音代理。
https://docs.pipecat.ai/guides/features/openai-audio-models-and-apis


客户端工具调用
使用 Cloudflare Workers 构建,一个展示客户端工具调用的示例应用程序。也请查看YouTube 上的教程
https://github.com/craigsdennis/talk-to-javascript-openai-workers


用例

Realtime API 最常见的用例是构建实时、语音到语音、对话式的体验。这对于构建 语音代理 和其他带语音功能的应用程序来说非常出色。

Realtime API 还可以独立用于转录和轮次检测用例。客户端可以流式传输音频,当检测到语音时,Realtime API 会生成流式转录。

这两个用例都受益于内置的 语音活动检测 (VAD),可以自动检测用户何时完成说话。这有助于无缝处理对话轮次,或者逐句分析转录。

在专门的指南中了解更多关于这些用例的信息。

实时语音到语音

学习如何使用 Realtime API 进行流式语音到语音对话。

https://platform.openai.com/docs/guides/realtime-conversations


实时转录

学习如何使用 Realtime API 进行仅转录的用例。

https://platform.openai.com/docs/guides/realtime-transcription


根据您的用例(对话或转录),您应该以不同的方式初始化会话。使用下面的切换器查看每种情况的详细信息。


通过 WebRTC 连接

WebRTC 是一套强大的标准接口,用于构建实时应用。OpenAI 实时 API 支持通过 WebRTC 服务器间连接连接到实时模型。按照以下指南了解如何配置 WebRTC 连接到实时 API。


概述

在您希望从不受信任的客户端(如网页浏览器)通过网络连接到实时模型的情况下,我们建议使用 WebRTC 连接方法。WebRTC 更适合处理可变连接状态,并提供了一系列方便的 API 用于捕获用户音频输入和播放来自模型的远程音频流。

从浏览器连接到实时 API 应该使用一个临时 API 密钥,通过 OpenAI REST API 生成。初始化 WebRTC 连接的过程如下(假设客户端是网页浏览器):

  1. 浏览器向开发者控制的服务器发送请求,以创建一个临时 API 密钥。
  2. 开发者的服务器使用一个 标准 API 密钥OpenAI REST API 请求一个临时密钥,并将这个新密钥返回给浏览器。请注意,临时密钥目前在被颁发后一分钟内过期。
  3. 浏览器使用临时密钥直接通过 WebRTC 互连 验证与 OpenAI 实时 API 的会话。

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/9ea9d21944c442618b959bec231bd3de.png =500xx)


虽然从技术上讲,可以使用 标准API密钥 来验证客户端WebRTC会话,但 这种做法是危险且不安全的,因为它会泄露您的密钥。标准API密钥可以访问您的完整OpenAI API账户,并且应该仅在安全的服务器端环境中使用。我们建议在可能的情况下,在客户端应用程序中使用临时密钥。


连接详情

通过 WebRTC 连接需要以下连接信息:

URLhttps://api.openai.com/v1/realtime
查询参数model 要连接的实时 模型 ID,例如 gpt-4o-realtime-preview-2024-12-17
头部Authorization: Bearer EPHEMERAL_KEY 用临时 API 密钥替换 EPHEMERAL_KEY - 有关如何生成一个的详细信息见下文。

以下示例展示了如何初始化一个 WebRTC 会话(包括用于发送和接收实时 API 事件的 数据通道)。它假设您已经获取了一个临时 API 密钥(用于此目的的示例服务器代码可以在 下一节 中找到)。

async function init() {
  // Get an ephemeral key from your server - see server code below
  const tokenResponse = await fetch("/session");
  const data = await tokenResponse.json();
  const EPHEMERAL_KEY = data.client_secret.value;

  // Create a peer connection
  const pc = new RTCPeerConnection();

  // Set up to play remote audio from the model
  const audioEl = document.createElement("audio");
  audioEl.autoplay = true;
  pc.ontrack = e => audioEl.srcObject = e.streams[0];

  // Add local audio track for microphone input in the browser
  const ms = await navigator.mediaDevices.getUserMedia({
    audio: true
  });
  pc.addTrack(ms.getTracks()[0]);

  // Set up data channel for sending and receiving events
  const dc = pc.createDataChannel("oai-events");
  dc.addEventListener("message", (e) => {
    // Realtime server events appear here!
    console.log(e);
  });

  // Start the session using the Session Description Protocol (SDP)
  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);

  const baseUrl = "https://api.openai.com/v1/realtime";
  const model = "gpt-4o-realtime-preview-2024-12-17";
  const sdpResponse = await fetch(`${baseUrl}?model=${model}`, {
    method: "POST",
    body: offer.sdp,
    headers: {
      Authorization: `Bearer ${EPHEMERAL_KEY}`,
      "Content-Type": "application/sdp"
    },
  });

  const answer = {
    type: "answer",
    sdp: await sdpResponse.text(),
  };
  await pc.setRemoteDescription(answer);
}

init();

WebRTC API 提供了丰富的控件来处理媒体流和输入设备。有关在 WebRTC 上构建用户界面的更多指导,请参阅 MDN 上的文档


创建一个临时token

要创建一个用于客户端的临时token ,您需要构建一个小的服务器端应用程序(或集成现有的一个)来通过 OpenAI REST API 请求一个临时密钥。您将使用一个 标准 API 密钥 在您的后端服务器上对这次请求进行身份验证。

以下是一个简单的 Node.js express 服务器示例,它使用 REST API 签发一个临时 API 密钥:

import express from "express";

const app = express();

// An endpoint which would work with the client code above - it returns
// the contents of a REST API request to this protected endpoint
app.get("/session", async (req, res) => {
  const r = await fetch("https://api.openai.com/v1/realtime/sessions", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "gpt-4o-realtime-preview-2024-12-17",
      voice: "verse",
    }),
  });
  const data = await r.json();

  // Send back the JSON we received from the OpenAI REST API
  res.send(data);
});

app.listen(3000);

您可以在任何可以发送和接收HTTP请求的平台创建一个类似这样的服务器端点。只需确保您只在服务器上使用标准的OpenAI API密钥,而不是在浏览器中。


发送和接收事件

要了解如何通过WebRTC数据通道发送和接收事件,请参阅实时对话指南


使用 WebSockets 连接

WebSockets 是一个广泛支持的实时数据传输 API,也是连接到 OpenAI 实时 API 在服务器到服务器应用中的绝佳选择。对于浏览器和移动客户端,我们建议通过 WebRTC 进行连接。


概述

在与 Realtime 的服务器到服务器集成中,您的后端系统将通过 WebSocket 直接连接到 Realtime API。您可以使用 标准 API 密钥 来验证此连接,因为token 只能在您的安全后端服务器上可用。


在这里插入图片描述


如果您选择通过客户端设备上的 WebSocket 连接到 Realtime API,则 WebSocket 连接也可以使用临时客户端令牌进行身份验证(如上文 WebRTC 部分所示)。

标准 OpenAI API 令牌应仅用于安全的服务器端环境


连接详情

语音到语音转录

通过WebSocket连接需要以下连接信息:

URLwss://api.openai.com/v1/realtime
查询参数model 要连接的实时 模型ID,例如 gpt-4o-realtime-preview-2024-12-17
头部Authorization: Bearer YOUR_API_KEYYOUR_API_KEY 替换为服务器上的 标准API密钥,或在非安全客户端上的 临时token (注意,对于此用例,建议使用WebRTC)。OpenAI-Beta: realtime=v1 在测试期间,此头部是必需的。

以下是一些使用这些连接详情初始化WebSocket连接到实时API的示例。

ws模块(Node.js)websocket-client(Python)WebSocket(浏览器)

使用ws模块(Node.js)进行连接

import WebSocket from "ws";

const url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-12-17";
const ws = new WebSocket(url, {
  headers: {
    "Authorization": "Bearer " + process.env.OPENAI_API_KEY,
    "OpenAI-Beta": "realtime=v1",
  },
});

ws.on("open", function open() {
  console.log("Connected to server.");
});

ws.on("message", function incoming(message) {
  console.log(JSON.parse(message.toString()));
});

实时对话Beta

了解如何管理实时语音到语音对话。

https://platform.openai.com/docs/guides/realtime-conversations


一旦通过WebRTCWebSocket连接到实时API,您就可以调用实时模型(例如gpt-4o-realtime-preview)进行语音到语音的对话。这样做需要您发送客户端事件来启动操作,并监听服务器事件以响应实时API采取的操作。
本指南将介绍使用模型功能(如音频和文本生成以及功能调用)所需的事件流程,以及如何考虑实时会话的状态。
如果您不需要与模型进行对话,即您不期望任何响应,您可以使用实时 API 的 转录模式


实时语音到语音会话

实时会话是模型与连接客户端之间的有状态交互。会话的关键组件包括:

  • 会话对象,它控制交互的参数,如使用的模型、生成输出的声音以及其他配置。
  • 对话,它表示当前会话期间产生的用户输入项和模型输出项。
  • 响应,这是模型生成的音频或文本项,被添加到对话中。

输入音频缓冲区和WebSockets

如果您使用WebRTC,发送和接收模型音频所需的媒体处理的大部分工作都由WebRTC API辅助完成。

如果您使用WebSockets进行音频传输,您需要手动与输入音频缓冲区进行交互,通过发送音频到服务器,这些音频以JSON事件的形式发送,并使用base64编码。

所有这些组件共同构成了一个实时会话。您将使用客户端事件来更新会话的状态,并监听服务器事件以响应会话中的状态变化。


在这里插入图片描述


会话生命周期事件

通过 WebRTCWebSockets 初始化会话后,服务器将发送一个 session.created 事件,表示会话已准备好。在客户端,您可以使用 session.update 事件更新当前会话配置。大多数会话属性可以在任何时间更新,但模型在会话中响应音频一次后,用于音频输出的 voice 无法更新。实时会话的最大时长为 30分钟

以下示例展示了使用 session.update 客户端事件更新会话。有关在这些通道上发送客户端事件的更多信息,请参阅 WebRTCWebSocket 指南。

更新此会话中模型使用的系统指令

event = {
    "type": "session.update",
    "session": {
        "instructions": "Never use the word 'moist' in your responses!"
    }
}
ws.send(json.dumps(event))

当会话被更新后,服务器将发出一个 session.updated(https://platform.openai.com/docs/api-reference/realtime-server-events/session/updated) 事件,包含会话的新状态。

相关客户端事件相关服务器事件
session.updatesession.createdsession.updated

文本输入和输出

要使用实时模型生成文本,您可以向当前对话中添加文本输入,要求模型生成响应,并监听表示模型响应进度的服务器发送事件。为了生成文本,会话必须配置为使用 text 模式(默认情况下是这样)。

使用 conversation.item.create 客户端事件创建一个新的文本对话项。这类似于在 Chat Completions 中发送一个用户消息(提示)

创建一个包含用户输入的对话项

event = {
    "type": "conversation.item.create",
    "item": {
        "type": "message",
        "role": "user",
        "content": [
            {
                "type": "input_text",
                "text": "What Prince album sold the most copies?",
            }
        ]
    }
}
ws.send(json.dumps(event))

在将用户消息添加到对话后,发送 response.create 事件 以从模型中启动响应。如果当前会话启用了音频和文本,则模型将以音频和文本内容进行响应。如果您只想生成文本,可以在发送 response.create 客户端事件时指定,如下所示。
生成纯文本响应

event = {
    "type": "response.create",
    "response": {
        "modalities": [ "text" ]
    }
}
ws.send(json.dumps(event))

当响应完全完成后,服务器将发出response.done事件。此事件将包含模型生成的完整文本,如下所示。
监听 response.done 以查看最终结果

def on_message(ws, message):
    server_event = json.loads(message)
    if server_event.type == "response.done":
        print(server_event.response.output[0])

在模型响应生成过程中,服务器将在处理过程中发出一系列生命周期事件。您可以监听这些事件,例如response.text.delta,以在响应生成时向用户提供实时反馈。服务器发出的所有事件列表如下,在相关服务器事件部分。它们按照事件发出的顺序提供,以及与文本生成相关的客户端事件。

相关客户端事件相关服务器事件
conversation.item.create
response.create
conversation.item.created
response.created
response.output_item.added
response.content_part.added
response.text.delta
response.text.done
response.content_part.done
response.output_item.done
response.done
rate_limits.updated

音频输入和输出

Realtime API 最强大的功能之一是与模型进行语音到语音的交互,无需中间的文本到语音或语音到文本步骤。这使语音界面的延迟更低,并给模型提供了更多关于语音输入的语调和语气的数据来处理。


语音选项

实时会话可以配置为在生成音频输出时使用几个内置语音之一。您可以在会话创建时(或在 response.create 上)设置 voice 来控制模型的声音。当前语音选项有 alloyashballadcoralechosageshimmerverse。一旦模型在一个会话中发出音频,该会话的 voice 就不能修改。


使用 WebRTC 处理音频

如果您使用 WebRTC 连接到实时 API,实时 API 正在充当您的客户端的 peer connection。模型输出的音频以 remote media stream 的形式发送到您的客户端。模型输入的音频通过音频设备(getUserMedia)收集,并将媒体流作为轨道添加到 peer connection。

来自 WebRTC 连接指南 的示例代码展示了使用浏览器 API 配置本地和远程音频的基本示例:

// Create a peer connection
const pc = new RTCPeerConnection();

// Set up to play remote audio from the model
const audioEl = document.createElement("audio");
audioEl.autoplay = true;
pc.ontrack = e => audioEl.srcObject = e.streams[0];

// Add local audio track for microphone input in the browser
const ms = await navigator.mediaDevices.getUserMedia({
  audio: true
});
pc.addTrack(ms.getTracks()[0]);

上面的代码片段可以启用与实时API的简单交互,但还有更多可以做的事情。有关不同类型用户界面的更多示例,请查看WebRTC samples存储库。这些样本的实时演示也可以在这里找到
使用 媒体捕获和流 浏览器中的功能,您可以实现诸如静音和取消静音麦克风、选择收集输入的设备等功能。


WebRTC 中的客户端和服务器音频事件

默认情况下,WebRTC 客户端在发送音频输入之前不需要向实时 API 发送任何客户端事件。一旦将本地音频轨道添加到对等连接中,您的用户就可以开始说话了!

然而,当音频在客户端和服务器之间通过对等连接来回传输时,WebRTC 客户端仍然会接收到许多由服务器发送的生命周期事件。例如:

  • 当输入通过本地媒体轨道发送时,您将从服务器接收到 input_audio_buffer.speech_started 事件。
  • 当本地音频输入停止时,您将接收到 input_audio_buffer.speech_stopped 事件。
  • 您将接收到 正在进行中的音频转录的 delta 事件
  • 当模型转录并完成发送响应时,您将接收到 response.done 事件。

操作 WebRTC API 以获取媒体流可能为您提供所需的所有控制。然而,有时可能需要使用更底层的接口来处理音频输入和输出。有关更多信息以及用于细粒度音频输入处理所需的事件列表,请参阅下方的 WebSockets 部分。


使用 WebSockets 处理音频

在通过 WebSocket 发送和接收音频时,您需要做更多的工作来从客户端发送媒体,并从服务器接收媒体。以下是一个表格,描述了在 WebSocket 会话期间的事件流程,这些事件对于通过 WebSocket 发送和接收音频是必要的。

以下事件按生命周期顺序给出,尽管某些事件(如 delta 事件)可能同时发生。

生命周期阶段客户端事件服务器事件
会话初始化session.updatesession.created
session.updated
用户音频输入conversation.item.create (发送整个音频消息)
input_audio_buffer.append (分块流式传输音频)
input_audio_buffer.commit (当 VAD 禁用时使用)
response.create (当 VAD 禁用时使用)
input_audio_buffer.speech_started
input_audio_buffer.speech_stopped
input_audio_buffer.committed
服务器音频输出input_audio_buffer.clear
(当 VAD 禁用时使用)
conversation.item.created
response.created
response.output_item.created
response.content_part.added
response.audio.delta
response.audio_transcript.delta
response.text.delta
response.audio.done
response.audio_transcript.done
response.text.done
response.content_part.done
response.output_item.done
response.done
rate_limits.updated

将音频输入流式传输到服务器

要将音频输入流式传输到服务器,您可以使用客户端事件 input_audio_buffer.append。此事件要求您通过套接字将 Base64 编码的音频字节块 发送到实时 API。每个块的大小不能超过 15 MB。

输入块格式可以配置为整个会话或每个响应。


将音频输入字节追加到对话中

import base64
import json
import struct
import soundfile as sf
from websocket import create_connection

# ... create websocket-client named ws ...

def float_to_16bit_pcm(float32_array):
    clipped = [max(-1.0, min(1.0, x)) for x in float32_array]
    pcm16 = b''.join(struct.pack('<h', int(x * 32767)) for x in clipped)
    return pcm16

def base64_encode_audio(float32_array):
    pcm_bytes = float_to_16bit_pcm(float32_array)
    encoded = base64.b64encode(pcm_bytes).decode('ascii')
    return encoded

files = [
    './path/to/sample1.wav',
    './path/to/sample2.wav',
    './path/to/sample3.wav'
]

for filename in files:
    data, samplerate = sf.read(filename, dtype='float32')  
    channel_data = data[:, 0] if data.ndim > 1 else data
    base64_chunk = base64_encode_audio(channel_data)
    
    # Send the client event
    event = {
        "type": "input_audio_buffer.append",
        "audio": base64_chunk
    }
    ws.send(json.dumps(event))

发送完整音频消息

也可以创建包含完整音频录音的对话消息。使用 conversation.item.create 客户端事件来创建包含 input_audio 内容的消息。

创建包含完整音频输入的对话项目

fullAudio = "<a base64-encoded string of audio bytes>"

event = {
    "type": "conversation.item.create",
    "item": {
        "type": "message",
        "role": "user",
        "content": [
            {
                "type": "input_audio",
                "audio": fullAudio,
            }
        ],
    },
}

ws.send(json.dumps(event))

使用WebSocket处理音频输出

要在客户端设备(如网页浏览器)上播放输出音频,我们建议使用WebRTC而不是WebSocket。WebRTC在发送媒体到客户端设备时,即使在不确定的网络条件下,也会更加稳健。

但是,要使用WebSocket在服务器到服务器的应用程序中处理音频输出,您需要监听包含从模型中编码的音频数据块的Base64编码的response.audio.delta事件。您可能需要缓冲这些块并将它们写入文件,或者立即将它们流式传输到另一个源,例如与Twilio的电话通话

请注意,response.audio.doneresponse.done事件实际上不会包含音频数据 - 只包含音频内容转录。要获取实际的字节,您需要监听response.audio.delta事件。

输出块格式可以配置为整个会话或每个响应。

  • 会话:在session.update中的session.output_audio_format session.update
  • 响应:在response.create中的response.output_audio_format response.create

监听response.audio.delta事件

def on_message(ws, message):
    server_event = json.loads(message)
    if server_event.type == "response.audio.delta":
        # Access Base64-encoded audio chunks:
        # print(server_event.delta)

语音活动检测

默认情况下,实时会话已启用 语音活动检测 (VAD),这意味着 API 将确定用户何时开始或停止说话,并自动响应。

了解更多关于如何配置 VAD 的信息,请参阅我们的 语音活动检测 指南。


禁用 VAD

可以通过将 turn_detection 设置为 null 并使用 session.update 客户端事件来禁用 VAD。这在需要精细控制音频输入的接口中非常有用,例如 push to talk 接口。

当 VAD 被禁用时,客户端将需要手动发出一些额外的客户端事件来触发音频响应:

  • 手动发送 input_audio_buffer.commit,这将为新对话创建一个新的用户输入项。
  • 手动发送 response.create 以触发模型生成的音频响应。
  • 在开始新的用户输入之前发送 input_audio_buffer.clear

保持VAD模式,但禁用自动响应

如果您想保持VAD模式开启,但只想保留手动决定何时生成响应的能力,您可以将 turn_detection.interrupt_responseturn_detection.create_response 设置为 false,使用 session.update会话更新)客户端事件。这将保留VAD的所有行为,但不会自动创建新的响应。客户端可以使用 response.create创建响应)事件手动触发这些操作。

这在用于内容审核或输入验证或RAG模式时可能很有用,在这些模式中,您更愿意在交互的延迟与对输入的控制之间进行权衡。


在默认对话之外创建响应

默认情况下,在会话期间生成的所有响应都会添加到会话的对话状态(即“默认对话”)中。然而,您可能希望在不属于会话默认对话的上下文中生成模型响应,或者希望同时生成多个响应。您还可能希望对模型在生成响应时考虑的对话项有更精细的控制(例如,仅考虑最后 N 个回合)。

通过在创建响应时将 response.conversation 字段设置为字符串 none,可以使用 response.create 客户端事件生成不属于默认对话状态的“场外”响应。

在创建场外响应时,您可能还希望有一种方式来识别哪些服务器发送的事件与该响应相关。您可以为模型响应提供 metadata,这有助于您识别为该客户端发送的事件生成的哪个响应。

创建一个场外模型响应

prompt = """
Analyze the conversation so far. If it is related to support, output
"support". If it is related to sales, output "sales".
"""

event = {
    "type": "response.create",
    "response": {
        # Setting to "none" indicates the response is out of band,
        # and will not be added to the default conversation
        "conversation": "none",

        # Set metadata to help identify responses sent back from the model
        "metadata": { "topic": "classification" },

        # Set any other available response fields
        "modalities": [ "text" ],
        "instructions": prompt,
    },
}

ws.send(json.dumps(event))

现在,当您监听 response.done 服务器事件时,您可以识别出您的非带外响应的结果。
创建一个带外模型响应

def on_message(ws, message):
    server_event = json.loads(message)
    topic = ""

    # See if metadata is present
    try:
        topic = server_event.response.metadata.topic
    except AttributeError:
        print("topic not set")
    
    if server_event.type == "response.done" and topic == "classification":
        # this server event pertained to our OOB model response
        print(server_event.response.output[0])

为响应创建自定义上下文

您还可以创建一个自定义上下文,该模型将使用该上下文在默认/当前对话之外生成响应。这可以通过使用 response.create 客户端事件上的 input 数组来完成。查看文档。您可以使用新的输入,或者通过 ID 引用对话中的现有输入项。

监听具有自定义上下文的出站模型响应

event = {
    "type": "response.create",
    "response": {
        "conversation": "none",
        "metadata": { "topic": "pizza" },
        "modalities": [ "text" ],

        # Create a custom input array for this request with whatever 
        # context is appropriate
        "input": [
            # potentially include existing conversation items:
            {
                "type": "item_reference",
                "id": "some_conversation_item_id"
            },

            # include new content as well
            {
                "type": "message",
                "role": "user",
                "content": [
                    {
                        "type": "input_text",
                        "text": "Is it okay to put pineapple on pizza?",
                    }
                ],
            }
        ],
    },
}

ws.send(json.dumps(event))

使用无上下文创建响应

您还可以将响应插入到默认对话中,忽略所有其他指令和上下文。通过将 input 设置为空数组来实现。

将无上下文模型响应插入到默认对话中

prompt = """
Say exactly the following:
I'm a little teapot, short and stout! 
This is my handle, this is my spout!
"""

event = {
    "type": "response.create",
    "response": {
        # An empty input array removes all prior context
        "input": [],
        "instructions": prompt,
    },
}

ws.send(json.dumps(event))

函数调用

实时模型也支持函数调用,这使您能够执行自定义代码以扩展模型的功能。以下是它在高层次上的工作原理:

  1. 更新会话创建响应时,您可以指定模型可以调用的可用函数列表。
  2. 如果在处理输入时,模型确定它应该进行函数调用,它将向对话中添加代表函数调用参数的项目。
  3. 当客户端检测到包含函数调用参数的对话项目时,它将使用这些参数执行自定义代码。
  4. 当自定义代码执行完毕后,客户端将创建新的对话项目,其中包含函数调用的输出,并要求模型进行响应。

让我们通过添加一个可调用的函数来展示这将在实践中如何工作,该函数将为模型的用户提供今天的星座运势。我们将展示需要发送的客户端事件对象的形状,以及服务器将相应地发出什么。


配置可调用的函数

首先,我们必须为模型提供一个基于用户输入它可以调用的函数选择。可用的函数可以在会话级别或单个响应级别进行配置。

以下是一个配置占星术生成函数的 session.update 客户端事件负载示例,该函数接受单个参数(需要生成占星术的星座):

session.update

{
  "type": "session.update",
  "session": {
    "tools": [
      {
        "type": "function",
        "name": "generate_horoscope",
        "description": "Give today's horoscope for an astrological sign.",
        "parameters": {
          "type": "object",
          "properties": {
            "sign": {
              "type": "string",
              "description": "The sign for the horoscope.",
              "enum": [
                "Aries",
                "Taurus",
                "Gemini",
                "Cancer",
                "Leo",
                "Virgo",
                "Libra",
                "Scorpio",
                "Sagittarius",
                "Capricorn",
                "Aquarius",
                "Pisces"
              ]
            }
          },
          "required": ["sign"]
        }
      }
    ],
    "tool_choice": "auto",
  }
}

函数和参数的 description 字段有助于模型选择是否调用该函数以及每个参数应包含哪些数据。如果模型接收到指示用户想要他们的星座运势的输入,它将使用 sign 参数调用此函数。


检测模型何时想要调用函数

根据模型接收到的输入,模型可能会决定调用一个函数以生成最佳响应。假设我们的应用程序添加了以下对话项并尝试生成响应:

conversation.item.create

{
  "type": "conversation.item.create",
  "item": {
    "type": "message",
    "role": "user",
    "content": [
      {
        "type": "input_text",
        "text": "What is my horoscope? I am an aquarius."
      }
    ]
  }
}

随后是一个客户端事件以生成响应:
response.create

{
  "type": "response.create"
}

而不是立即返回文本或音频响应,模型将生成一个包含应传递给开发者应用程序中函数的参数的响应。您可以使用response.function_call_arguments.delta服务器事件来监听函数调用参数的实时更新,但response.done也将包含我们调用函数所需的完整数据。
response.done

{
  "type": "response.done",
  "event_id": "event_AeqLA8iR6FK20L4XZs2P6",
  "response": {
    "object": "realtime.response",
    "id": "resp_AeqL8XwMUOri9OhcQJIu9",
    "status": "completed",
    "status_details": null,
    "output": [
      {
        "object": "realtime.item",
        "id": "item_AeqL8gmRWDn9bIsUM2T35",
        "type": "function_call",
        "status": "completed",
        "name": "generate_horoscope",
        "call_id": "call_sHlR7iaFwQ2YQOqm",
        "arguments": "{\"sign\":\"Aquarius\"}"
      }
    ],
    "usage": {
      "total_tokens": 541,
      "input_tokens": 521,
      "output_tokens": 20,
      "input_token_details": {
        "text_tokens": 292,
        "audio_tokens": 229,
        "cached_tokens": 0,
        "cached_tokens_details": { "text_tokens": 0, "audio_tokens": 0 }
      },
      "output_token_details": {
        "text_tokens": 20,
        "audio_tokens": 0
      }
    },
    "metadata": null
  }
}

在服务器发出的 JSON 中,我们可以检测到模型想要调用一个自定义函数:

属性函数调用目的
response.output[0].type当设置为 function_call 时,表示此响应包含对命名函数调用的参数。
response.output[0].name调用的配置函数的名称,在此例中为 generate_horoscope
response.output[0].arguments包含函数参数的 JSON 字符串。在我们的例子中,"{\"sign\":\"Aquarius\"}"
response.output[0].call_id一个为此次函数调用生成的ID - 您需要此ID将函数调用结果返回到模型中
鉴于这些信息,我们可以在我们的应用程序中执行代码以生成星座运势,然后将其信息反馈给模型,以便它可以生成响应。

向模型提供函数调用的结果

在接收到模型返回的函数调用参数后,您的应用程序可以执行满足函数调用的代码。这可以是您想要做任何事情,比如与外部API通信或访问数据库。

一旦您准备好向模型提供您自定义代码的结果,您可以通过 conversation.item.create 客户端事件创建一个新的对话项来包含该结果。

conversation.item.create

{
  "type": "conversation.item.create",
  "item": {
    "type": "function_call_output",
    "call_id": "call_sHlR7iaFwQ2YQOqm",
    "output": "{\"horoscope\": \"You will soon meet a new friend.\"}"
  }
}
  • 对话项类型是 function_call_output
  • item.call_id 是我们在上面的 response.done 事件中得到的相同 ID
  • item.output 是一个包含我们函数调用结果的 JSON 字符串

一旦我们添加了包含我们的函数调用结果的对话项,我们再次从客户端发出 response.create 事件。这将触发使用函数调用数据的一个模型响应。

response.create

{
  "type": "response.create"
}

错误处理

当服务器在会话期间遇到错误条件时,会触发一个名为 error事件。偶尔,这些错误可以追溯到由您的应用程序发出的客户端事件。

与 HTTP 请求和响应不同,其中响应隐式地与客户端的请求相关联,我们需要使用客户端事件上的 event_id 属性来确定其中一个事件何时在服务器上触发了错误条件。以下代码展示了这种技术,其中客户端尝试发出一个不支持的事件类型。

const event = {
  event_id: "my_awesome_event",
  type: "scooby.dooby.doo",
};

dataChannel.send(JSON.stringify(event));

此客户端发送的失败事件将触发以下错误事件:

{
  "type": "invalid_request_error",
  "code": "invalid_value",
  "message": "Invalid value: 'scooby.dooby.doo' ...",
  "param": "type",
  "event_id": "my_awesome_event"
}

实时转录Beta

学习如何使用实时API进行实时音频转录。

https://platform.openai.com/docs/guides/realtime-transcription


您可以使用实时API进行仅转录的使用场景,无论是从麦克风输入还是从文件输入。例如,您可以使用它实时生成字幕或转录。在仅转录模式下,模型将不会生成响应。
如果您想让模型生成响应,您可以使用实时 API 在 语音到语音对话模式 中。


实时转录会话

要使用实时API进行转录,您需要创建一个转录会话,通过 WebSocketsWebRTC 连接。

与常规实时API会话进行对话不同,转录会话通常不包含来自模型的响应。

转录会话对象也与常规实时API会话不同:

{
  object: "realtime.transcription_session",
  id: string,
  input_audio_format: string,
  input_audio_transcription: [{
    model: string,
    prompt: string,
    language: string
  }],
  turn_detection: {
    type: "server_vad",
    threshold: float,
    prefix_padding_ms: integer,
    silence_duration_ms: integer,
  } | null,
  input_audio_noise_reduction: {
    type: "near_field" | "far_field"
  },
  include: list[string] | null
}

一些转录会话支持的附加属性包括:

  • input_audio_transcription.model: 要使用的转录模型,目前支持 gpt-4o-transcribegpt-4o-mini-transcribewhisper-1
  • input_audio_transcription.prompt: 用于转录的提示,用于指导模型(例如:“期待与科技相关的词语”)
  • input_audio_transcription.language: 用于转录的语言,理想情况下采用 ISO-639-1 格式(例如 “en”, “fr”…)以提高准确性和延迟
  • input_audio_noise_reduction:用于转录的降噪配置
  • include: 要包含在转录事件中的属性列表

可能的输入音频格式值为:pcm16(默认)、g711_ulawg711_alaw
您可以在API参考中找到有关转录会话对象的更多信息。


处理转录

当使用实时API进行转录时,您可以监听 conversation.item.input_audio_transcription.deltaconversation.item.input_audio_transcription.completed 事件。

对于 whisper-1delta 事件将包含完整的回合转录,与 completed 事件相同。对于 gpt-4o-transcribegpt-4o-mini-transcribedelta 事件将包含增量转录,这些转录将随着从模型中流出来进行。

以下是一个转录 delta 事件的示例:

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

以下是示例转录完成事件:

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

请注意,来自不同说话轮次的完成事件之间的顺序不保证。您应使用 item_id 将这些事件与 input_audio_buffer.committed 事件匹配,并使用 input_audio_buffer.committed.previous_item_id 来处理顺序。
要将音频数据发送到转录会话,您可以使用 input_audio_buffer.append 事件。
您有 2 个选项:

  • 使用流式麦克风输入
  • 从wav文件中流式传输数据

语音活动检测

实时API支持自动语音活动检测(VAD)。默认启用,VAD将控制何时提交输入音频缓冲区,因此何时开始转录。

有关配置VAD的更多信息,请参阅我们的语音活动检测指南。

您还可以通过将turn_detection属性设置为null来禁用VAD,并控制何时在您端提交输入音频。


额外配置


噪声降低

您可以使用 input_audio_noise_reduction 属性来配置如何处理音频流中的噪声降低。

可能的值有:

  • near_field:使用近场噪声降低。
  • far_field:使用远场噪声降低。
  • null:禁用噪声降低。

默认值是 near_field,您可以通过将属性设置为 null 来禁用噪声降低。


使用 logprobs

您可以使用 include 属性来在转录事件中包含 logprobs,使用 item.input_audio_transcription.logprobs

这些 logprobs 可以用来计算转录的置信度得分。

{
  "type": "transcription_session.update",
  "input_audio_format": "pcm16",
  "input_audio_transcription": {
    "model": "gpt-4o-transcribe",
    "prompt": "",
    "language": ""
  },
  "turn_detection": {
    "type": "server_vad",
    "threshold": 0.5,
    "prefix_padding_ms": 300,
    "silence_duration_ms": 500,
  },
  "input_audio_noise_reduction": {
    "type": "near_field"
  },
  "include": [ 
    "item.input_audio_transcription.logprobs",
  ],
}

语音活动检测 (VAD)Beta

了解 Realtime API 中的自动语音活动检测。

https://platform.openai.com/docs/guides/realtime-vad


语音活动检测(VAD)是实时API中的一项功能,允许自动检测用户何时开始或停止说话。在 语音到语音转录 实时会话中默认启用,但它是可选的,可以关闭。


概述

当启用VAD(语音活动检测)时,音频会自动分块,并且实时API会发送事件来指示用户何时开始或停止说话:

  • input_audio_buffer.speech_started:语音回合的开始
  • input_audio_buffer.speech_stopped:语音回合的结束

您可以使用这些事件来处理您的应用程序中的语音回合。例如,您可以使用它们来管理会话状态或分块处理转录本。

您可以使用session.update事件的turn_detection属性来配置每个语音到文本样本中音频的分块方式。

VAD有两种模式:

  • server_vad:根据静默期间自动分块音频。
  • semantic_vad:当模型根据用户说的词语认为他们已完成其语音时,分块音频。

默认值是server_vad

阅读以下内容了解有关不同模式的更多信息。


服务器VAD

服务器VAD是实时会话的默认模式,并使用静默时间段来自动分割音频。

您可以调整以下属性以微调VAD设置:

  • threshold:激活阈值(0到1)。较高的阈值将需要更响亮的音频来激活模型,因此可能在嘈杂环境中表现更好。
  • prefix_padding_ms:在VAD检测到语音之前包含的音频量(以毫秒为单位)。
  • silence_duration_ms:检测语音停止的静默持续时间(以毫秒为单位)。较短的值会使转弯检测更快。

以下是一个VAD配置示例:

{
  "type": "session.update",
  "session": {
    "turn_detection": {
      "type": "server_vad",
      "threshold": 0.5,
      "prefix_padding_ms": 300,
      "silence_duration_ms": 500,
      "create_response": true, // only in conversation mode
      "interrupt_response": true, // only in conversation mode
    }
  }
}

语义语音活动检测(Semantic VAD)

语义语音活动检测是一种新模式,它使用语义分类器来检测用户何时完成说话,基于他们所使用的词语。这个分类器根据用户完成说话的概率对输入音频进行评分。当概率低时,模型将等待超时,而当概率高时,则无需等待。例如,以“嗯嗯…”结尾的用户音频会导致比明确陈述更长的超时时间。

使用此模式,模型在语音到语音对话中打断用户的可能性较小,或者在使用户完成说话之前截取转录。

可以通过将 turn_detection.type 设置为 semantic_vad 在一个 session.update(https://platform.openai.com/docs/api-reference/realtime-client-events/session/update) 事件中激活语义语音活动检测。

它可以这样配置:

{
  "type": "session.update",
  "session": {
    "turn_detection": {
      "type": "semantic_vad",
      "eagerness": "low" | "medium" | "high" | "auto", // optional
      "create_response": true, // only in conversation mode
      "interrupt_response": true, // only in conversation mode
    }
  }
}

可选的 eagerness 属性是一种控制模型如何急切地打断用户的属性,调整最大等待超时时间。在转录模式下,即使模型不回复,它也会影响音频的分割方式。

  • auto 是默认值,等同于 medium
  • low 将让用户有更多时间说话。
  • high 将尽可能快地分割音频。
    如果您希望模型在对话模式下更频繁地回应,或者在转录模式下更快地返回转录事件,可以将 eagerness 设置为 high
    另一方面,如果您想在对话模式下让用户不间断地说话,或者您希望在转录模式下有更大的转录片段,您可以设置 eagernesslow

2025-03-29(六)

<think>好的,用户之前问过如何将AI接入Qt,现在他的新问题是“Qt接入API”。我需要先理解他的具体需求。可能他指的是在Qt应用程序中如何调用外部API服务,比如RESTful API或者WebSocket API,或者可能是指如何将Qt应用本身作为API服务提供接口。 首先回顾之前的对话,用户之前关注的是AI集成,现在转向API接入,可能他在开发过程中需要让Qt应用与外部服务进行数据交互。比如调用天气API、支付接口,或者企业内部的服务接口。也可能他需要将Qt应用的功能通过API暴露出去,供其他应用调用。 接下来,我需要确定用户的具体场景。如果用户是希望Qt应用作为客户端调用外部API,那么需要讲解如何使用Qt的网络模块(如QNetworkAccessManager)进行HTTP请求,处理JSON/XML数据,异步通信等。如果用户是想让Qt应用作为服务端提供API,可能需要涉及Qt的Web框架或者创建TCP/UDP服务器。 另外,用户可能对API的类型不太明确,比如REST API、GraphQL或WebSocket。需要涵盖常见的API类型,并给出相应的Qt实现方法。同时,用户可能需要了解如何处理认证(如OAuth、API密钥)、错误处理、数据解析等细节。 还要考虑用户的技术背景。之前的回答涉及C++和Python,所以用户可能熟悉这两种语言。需要提供C++的示例,因为Qt主要是C++框架,但如果有Python相关的内容(比如使用PyQt),也可以适当补充。 需要确保回答结构清晰,分步骤说明,包括环境准备、常用方法、具体实现、数据处理、安全措施、调试工具和实战案例。同时,根据用户之前的问题,可能对性能优化和多线程处理感兴趣,所以需要包含相关部分,比如使用QThread进行异步请求,避免阻塞UI线程。 还需要注意Qt版本,推荐使用Qt 5.15+或6.x,并确保示例代码符合现代Qt实践。例如,使用新的网络模块特性,如QNetworkReply的处理方式,或者JSON解析的方法(QJsonDocument等)。 另外,用户可能需要了解第三方库的支持,比如是否需要用Qt封装好的库来简化API调用,或者如何处理OAuth2.0认证流程。这部分需要简要提及可能的解决方案或推荐工具。 最后,要提供实际应用场景的例子,比如调用天气API或文件上传,帮助用户将理论应用于实践。同时,部署注意事项如跨平台问题、依赖管理等也需要提及,确保用户了解如何打包和发布集成了API调用的Qt应用。 总结来说,用户需要的是在Qt中实现API调用的全面指南,涵盖从基础到进阶的内容,包括代码示例、最佳实践和常见问题处理。需要结构清晰,分点说明,确保用户能逐步理解和实施。</think>将Qt应用程序与外部API进行集成主要涉及网络通信和数据交换,以下是具体实现方案与技术要点: 一、基础准备 1. 启用Qt网络模块 ```qmake QT += network core ``` 2. 推荐Qt版本: - 常规API调用:Qt 5.15 LTS - 高级功能需求:Qt 6.4+(支持最新的TLS协议) 二、常用API接入方式 $$ \begin{array}{|l|c|c|c|} \hline \text{协议类型} & \text{Qt对应类} & \text{数据格式} & \text{典型场景} \\ \hline \text{HTTP/HTTPS} & QNetworkAccessManager & JSON/XML & REST API调用 \\ \text{WebSocket} & QWebSocket & Binary/Text & 实时通信 \\ \text{SOAP} & QNetworkAccessManager+XML解析 & XML & 传统企业服务 \\ \hline \end{array} $$ 三、REST API调用实现流程 1. 创建网络管理器 ```cpp QNetworkAccessManager *manager = new QNetworkAccessManager(this); connect(manager, &QNetworkAccessManager::finished, this, &MainWindow::replyFinished); ``` 2. 构造请求示例(带Bearer Token认证) ```cpp void ApiClient::fetchUserData() { QUrl url("https://api.example.com/users/me"); QNetworkRequest request(url); request.setRawHeader("Authorization", "Bearer " + apiToken.toUtf8()); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); manager->get(request); } ``` 3. 异步响应处理 ```cpp void ApiClient::replyFinished(QNetworkReply *reply) { if(reply->error() == QNetworkReply::NoError) { QJsonDocument doc = QJsonDocument::fromJson(reply->readAll()); QJsonObject root = doc.object(); emit dataReceived(root["data"].toObject()); } else { qDebug() << "API Error:" << reply->errorString(); } reply->deleteLater(); } ``` 四、JSON数据处理优化 1. 使用模型视图架构: ```cpp QStandardItemModel *model = new QStandardItemModel; QJsonArray items = doc.object()["items"].toArray(); foreach(const QJsonValue &val, items) { QJsonObject obj = val.toObject(); QList<QStandardItem*> row = { new QStandardItem(obj["id"].toString()), new QStandardItem(QString::number(obj["price"].toDouble())) }; model->appendRow(row); } ``` 五、安全增强措施 1. HTTPS证书验证 ```cpp QSslConfiguration sslConfig = request.sslConfiguration(); sslConfig.setPeerVerifyMode(QSslSocket::VerifyPeer); request.setSslConfiguration(sslConfig); ``` 2. 敏感数据加密存储 ```cpp QSettings settings; QString encryptedToken = QAESEncryption::CryptQAES(apiToken, key); settings.setValue("/credentials/token", encryptedToken); ``` 六、调试工具链配置 1. 使用Qt Creator内置工具: - 网络请求分析器(Ctrl+Alt+N) - JSON树形查看器插件 2. 代理调试配置: ```cpp QNetworkProxy proxy; proxy.setType(QNetworkProxy::HttpProxy); proxy.setHostName("localhost"); proxy.setPort(8888); manager->setProxy(proxy); // 配合Charles/Fiddler抓包 ``` 七、实战案例:天气API集成 1. 界面层设计: ```qml Column { TextField { id: cityInput } Button { text: "查询" onClicked: weatherApi.getWeather(cityInput.text) } Text { id: temperatureDisplay } } ``` 2. 业务逻辑实现: ```cpp void WeatherAPI::getWeather(const QString &city) { QUrlQuery query; query.addQueryItem("city", QUrl::toPercentEncoding(city)); query.addQueryItem("appid", apiKey); QUrl url("https://api.weather.com/v3/wx/forecast"); url.setQuery(query); QNetworkRequest request(url); manager->get(request); } ``` 八、高级应用场景 1. 文件上传API: ```cpp void uploadFile(const QString &filePath) { QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); QHttpPart filePart; filePart.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream"); filePart.setBodyDevice(new QFile(filePath, this)); multiPart->append(filePart); manager->post(request, multiPart); } ``` 2. WebSocket实时通信: ```cpp QWebSocket *socket = new QWebSocket; connect(socket, &QWebSocket::connected, []{ qDebug() << "Connected to WebSocket server"; }); socket->open(QUrl("wss://realtime.example.com/feed")); ``` 最佳实践建议: 1. 使用`QNetworkConfigurationManager`检测网络状态 2. 为长时间请求设置超时控制: ```cpp QTimer *timeoutTimer = new QTimer(this); timeoutTimer->setSingleShot(true); connect(timeoutTimer, &QTimer::timeout, [reply]{ if(reply->isRunning()) reply->abort(); }); timeoutTimer->start(30000); // 30秒超时 ``` 常见问题处理: - 跨域问题(CORS):需服务端配合设置响应头 - 编码问题:使用`QUrl::toPercentEncoding()`处理特殊字符 - 大文件传输:采用分块上传策略(chunked upload) 通过合理运用Qt的网络模块,开发者可以实现从简单的数据查询到复杂的双向通信等各种API集成需求。建议结合Qt的信号槽机制实现异步处理,同时注意线程管理和内存泄漏预防。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程乐园

请我喝杯伯爵奶茶~!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值