curso
API em tempo real da OpenAI: Um guia com exemplos
A recém-introduzida API em tempo real da OpenAI nos permite integrar experiências rápidas, de baixa latência e multimodais em nossos aplicativos. Com essa API, podemos criar interações perfeitas de fala para fala entre usuários e grandes modelos de linguagem (LLMs).
Essa API elimina a necessidade de vários modelos para obter experiências orientadas por voz, pois oferece a solução completa em uma API integrada. O objetivo não é apenas reduzir a latência, mas também manter as nuances emocionais e o fluxo natural das conversas.
Neste artigo, aprenderemos a usar a API OpenAI Realtime para criar assistentes de IA controlados por voz. Criaremos conexões WebSocket persistentes usando o Node.js e como isso pode ser utilizado no terminal para que você se comunique com a API. Além disso, orientarei você na implantação de um aplicativo React que usa os recursos dessa API.
Gerar a chave de API para a API de tempo real da OpenAI
Para usar o OpenAI Realtime API, primeiro precisamos gerar uma chave de API. Para fazer isso, navegue até a página da chave da API. Observe que é necessário ter uma conta para isso. Na parte superior da página, clique no botão "Create new secret key" (Criar nova chave secreta).
Uma janela pop-up será aberta. Você pode usar as opções padrão e clicar em "Create secret key" (Criar chave secreta).
Quando a chave é criada, temos a oportunidade de copiá-la. Certifique-se de copiá-lo antes de fechar a janela, pois essa é a única vez que ele será exibido.
Se a chave for perdida, você sempre poderá excluí-la e criar uma nova.
Para armazenar a chave, recomendamos que você crie um arquivo chamado .env
e salve a chave nesse arquivo com o seguinte formato:
OPENAI_API_KEY=<paste_they_key_here>
Usaremos esse arquivo ao longo deste artigo para nos conectarmos à API.
Considerações sobre o custo da API em tempo real
Antes de prosseguir, observe que a Realtime API não é gratuita e que precisamos adicionar créditos à nossa conta para usá-la. Você pode adicionar créditos na página de faturamentoque está localizada em nosso perfil.
Para que você tenha uma ideia dos custos, aqui está uma visão geral de quanto me custou fazer experiências com a API enquanto trabalhava neste artigo:
Gastei cerca de cinco dólares no total. Essa não é uma quantia enorme, mas é muito mais cara do que as outras APIs fornecidas pela OpenAI. Tenha isso em mente enquanto você trabalha neste artigo.
A maior parte do custo (primeira barra) corresponde a mim brincando com o aplicativo de console React que exploramos no final deste artigo. O restante, cerca de meio dólar, é o que me custou para usar a API usando WebSockets. Portanto, é possível que você acompanhe este artigo por menos de um dólar.
Para obter mais detalhes sobre o preço da API, consulte a seção "API em tempo real" na página de preços da sua página de preços.
Desenvolver aplicativos de IA
Usando a API em tempo real com WebSockets
Diferentemente de outros componentes da API da OpenAIa API de tempo real utiliza WebSockets. O WebSockets é um protocolo de comunicação que estabelece um canal de comunicação bidirecional entre um cliente e um servidor. Em contraste com o modelo convencional de solicitação-resposta usado pelo HTTP, os WebSockets oferecem suporte a interações contínuas e em tempo real. Isso torna os WebSockets particularmente adequados para aplicativos em tempo real, como bate-papo por voz.
Este artigo abordará como funcionam os WebSockets e incluirá vários exemplos de interação com a API de tempo real.
Vamos usar o Node.js, portanto, precisamos garantir que ele esteja instalado em nosso computador. Caso contrário, você pode fazer download e instalar o Node.js em seu site oficial.
Inicialização do script
Para que você possa acompanhar o processo, recomendamos que crie uma pasta com o arquivo .env
criado acima. Dentro dessa pasta, execute o seguinte comando para inicializar o script:
npm init -y && touch index.js
Depois que esse comando for concluído, esses arquivos deverão estar dentro da pasta:
Instalando as dependências
Comece instalando dois pacotes:
ws
: Este é o pacote WebSocket, o principal pacote necessário para você interagir com a API.dotenv
: Um pacote de utilitários que carrega a chave de API do arquivo.env
.
Instale-os executando o comando:
npm install ws dotenv
Conexão com a API de tempo real
Para iniciar uma conexão com a API em tempo real, criamos um novo objeto WebSocket
, passando o URL da API e os cabeçalhos com as informações necessárias para que você se conecte a ela:
// Import the web socket library
const WebSocket = require("ws");
// Load the .env file into memory so the code has access to the key
const dotenv = require("dotenv");
dotenv.config();
function main() {
// Connect to the API
const url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01";
const ws = new WebSocket(url, {
headers: {
"Authorization": "Bearer " + process.env.OPENAI_API_KEY,
"OpenAI-Beta": "realtime=v1",
},
});
}
main();
Configuração de uma ação quando a conexão é aberta
O código acima cria a conexão de soquete da Web com a API, mas ainda não faz nada com ela.
Os WebSockets nos permitem configurar ações a serem executadas quando alguns eventos ocorrem. Podemos usar o evento open
para especificar algum código que queremos executar quando a conexão for estabelecida.
A sintaxe genérica para adicionar um ouvinte de eventos é a seguinte:
ws.on(<event>, <function>);
Substituindo por uma cadeia de caracteres que contém o nome do evento e
por uma função a ser executada quando o evento ocorrer.
Veja como podemos exibir o texto quando a conexão estiver pronta:
// Add inside the main() function of index.js after creating ws
async function handleOpen() {
console.log("Connection is opened");
}
ws.on("open", handleOpen);
Para executar esse código, usamos o comando:
node index.js
Se a chave da API estiver definida corretamente, você verá a mensagem "Connection is open" (A conexão está aberta) no terminal. O script continuará sendo executado porque a conexão ainda está aberta, portanto, precisamos interrompê-lo manualmente.
Configuração de uma ação quando uma mensagem é recebida
Outro evento ao qual podemos responder quando usamos WebSockets é o evento message
. Isso é acionado sempre que uma mensagem é recebida do servidor. Vamos adicionar uma função que exibe cada mensagem recebida:
// Add inside the main() function of index.js
async function handleMessage(messageStr) {
const message = JSON.parse(messageStr);
console.log(message);
}
ws.on("message", handleMessage);
A execução do script agora também deve exibir o session.created
evento que a API envia quando a sessão é inicializada.
Outros eventos WebSocket
Acima, aprendemos como adicionar ouvintes de eventos aos eventos open
e message
. Os WebSockets suportam dois eventos adicionais que não usaremos em nossos exemplos.
O evento close
pode ser usado para adicionar uma chamada de retorno quando o soquete for fechado:
async function handleClose() {
console.log(“Socket closed”);
}
ws.on(“close”, handleClose);
O evento error
é usado para adicionar uma chamada de retorno quando houver um erro:
async function handleError(error) {
console.log(“Error”, error);
}
ws.on(“error”, handleError);
Comunicação com a API de tempo real
Trabalhar com WebSockets exige que você programe em um ambiente orientado a eventos orientado a eventos. As mensagens são enviadas para frente e para trás no canal de comunicação, e não podemos controlar quando essas mensagens serão entregues ou recebidas.
O código que inicia a comunicação deve ser adicionado dentro de handleOpen()
. O Caso contrário, ocorreria um erro porque esse código pode ser executado antes que o canal de comunicação do soquete da Web seja criado.
O mesmo ocorre com o código que manipula as mensagens. Toda a lógica deve ir para a função handleMessage()
.
Nos próximos exemplos, usaremos o código a seguir como ponto de partida. A maioria das alterações envolve a atualização dos sites handleOpen()
e handleMessage()
.
// Import the web socket library
const WebSocket = require("ws");
// Load the .env file into memory so the code has access to the key
const dotenv = require("dotenv");
dotenv.config();
function main() {
// Connect to the API
const url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01";
const ws = new WebSocket(url, {
headers: {
"Authorization": "Bearer " + process.env.OPENAI_API_KEY,
"OpenAI-Beta": "realtime=v1",
},
});
async function handleOpen() {
console.log("Connection is opened");
}
ws.on("open", handleOpen);
async function handleMessage(messageStr) {
const message = JSON.parse(messageStr);
console.log(message);
}
ws.on("message", handleMessage);
}
main();
Usando a API de tempo real para enviar e receber texto
A comunicação com a API de tempo real ocorre por meio de eventos. A API de documentação em tempo real da OpenAI API de documentação em tempo real da OpenAI lista os eventos que ela suporta. Usamos o conversation.item.create
evento para iniciar uma conversa. Os eventos são representados como objetos JSON cujos campos são descritos na documentação.
Aqui está um exemplo de uma conversation.item.create enviando o prompt "Explique em uma frase o que é um soquete da Web":
const createConversationEvent = {
type: "conversation.item.create",
item: {
type: "message",
role: "user",
content: [
{
type: "input_text",
text: "Explain in one sentence what a web socket is"
}
]
}
};
Esse evento informa à API que você deseja iniciar uma conversa textual. Isso é especificado no campo content
, usando um tipo de ”input_text”
e fornecendo um prompt de texto.
Usamos o método ws.send()
para enviar uma mensagem. O pacote de soquete da Web espera uma string como argumento, portanto, precisamos converter nosso evento JSON em uma string usando a função JSON.stringify()
. Juntando tudo isso, você verá como podemos enviar o evento acima:
ws.send(JSON.stringify(createConversationEvent));
Isso iniciará a conversa, mas não acionará a API para nos enviar uma resposta automaticamente. Para acionar uma resposta, enviamos um response.create
evento. Aqui está um exemplo:
const createResponseEvent = {
type: "response.create",
response: {
modalities: ["text"],
instructions: "Please assist the user.",
}
}
ws.send(JSON.stringify(createResponseEvent));
Esse evento usa o parâmetro de resposta modalities
para solicitar uma resposta textual. As instruções são a parte mais importante, descrevendo o que queremos que o modelo faça, neste caso, um prompt genérico pedindo para ajudar o usuário.
Enviamos esses dois eventos na função handleOpen()
para que uma conversa seja iniciada assim que a conexão for estabelecida. Aqui está a implementação completa da função handleOpen()
deste exemplo:
async function handleOpen() {
// Define what happens when the connection is opened
// Create and send an event to initiate a conversation
const createConversationEvent = {
type: "conversation.item.create",
item: {
type: "message",
role: "user",
content: [
{
type: "input_text",
text: "Explain in one sentence what a web socket is"
}
]
}
};
// Create and send an event to initiate a response
ws.send(JSON.stringify(createConversationEvent));
const createResponseEvent = {
type: "response.create",
response: {
modalities: ["text"],
instructions: "Please assist the user.",
}
}
ws.send(JSON.stringify(createResponseEvent));
}
Com relação às mensagens recebidas, há três tipos de eventos que merecem destaque neste exemplo: os eventos response.text.delta
, response.text.done
e response.done
:
- Os
response.text.delta
eventos contêm a resposta dividida em partes no campodelta
. Eles são importantes quando queremos oferecer uma experiência em tempo real, pois permitem que você transmita a resposta por partes imediatamente. - O evento
response.text.done
evento marca o fim da resposta textual e contém a resposta completa no campotext
. - O evento
response.done
evento marca o fim da resposta.
Podemos especificar como queremos que nosso script responda a esses eventos usando uma instrução switch
na função handleMessage()
:
async function handleMessage(messageStr) {
const message = JSON.parse(messageStr);
// Define what happens when a message is received
switch(message.type) {
case "response.text.delta":
// We got a new text chunk, print it
process.stdout.write(message.delta);
break;
case "response.text.done":
// The text is complete, print a new line
process.stdout.write("\n");
break;
case "response.done":
// Response complete, close the socket
ws.close();
break;
}
}
Neste exemplo, usamos o evento response.text.delta
para imprimir partes da resposta no console à medida que a recebemos. Quando a resposta é concluída, o evento response.text.done
é acionado e imprimimos uma nova linha para mostrar que a saída foi concluída. Por fim, fechamos o soquete da Web quando recebemos o evento response.done
.
Para executar esse exemplo, colamos essas funções no código do modelo acima e o executamos com o comando:
node index.js
Isso gerará uma resposta no terminal para o prompt "Explique em uma frase o que é um soquete da Web", semelhante a quando usamos o ChatGPT.
O código completo do exemplo de texto está disponível aqui.
Usando a API de tempo real para enviar e receber áudio
O exemplo anterior mostrou como lidamos com dados de texto. No entanto, o interesse real na API Realtime é criar um assistente de voz que responda em tempo real.
Lidar com dados de áudio é um pouco mais complicado do que lidar com dados textuais. Ignoraremos alguns dos detalhes específicos de como o áudio funciona, pois eles nos distrairiam do assunto principal deste artigo.
Primeiro, instalamos dois pacotes:
npm install node-record-lpcm16 speaker
node-record-lpcm16
grava o som do microfone para que possamos enviar um prompt de voz.speaker
é usado para reproduzir a resposta de voz da IA.
Também precisamos instalar o SoX (Sound eXchange), um utilitário de linha de comando para processamento de áudio que a biblioteca de nós usará para fazer interface com o microfone e gravar áudio. Use brew install sox
para instalá-lo no macOS ou sudo apt install sox
no Linux.
Com esses pacotes instalados, nós os importamos e adicionamos uma função startRecording()
que grava os avisos de áudio do usuário. Não explicaremos a função em detalhes, pois isso nos desviaria muito do nosso assunto principal.
Adicione o seguinte código ao arquivo index.js
depois de carregar o ambiente:
// Add to index.js before the main() function
// Import the web socket library
const WebSocket = require("ws");
// Load the .env file into memory so the code has access to the key
const dotenv = require("dotenv");
dotenv.config();
const Speaker = require("speaker");
const record = require("node-record-lpcm16");
// Function to start recording audio
function startRecording() {
return new Promise((resolve, reject) => {
console.log("Speak to send a message to the assistant. Press Enter when done.");
// Create a buffer to hold the audio data
const audioData = [];
// Start recording in PCM16 format
const recordingStream = record.record({
sampleRate: 16000, // 16kHz sample rate (standard for speech recognition)
threshold: 0, // Start recording immediately
verbose: false,
recordProgram: "sox", // Specify the program
});
// Capture audio data
recordingStream.stream().on("data", (chunk) => {
audioData.push(chunk); // Store the audio chunks
});
// Handle errors in the recording stream
recordingStream.stream().on("error", (err) => {
console.error("Error in recording stream:", err);
reject(err);
});
// Set up standard input to listen for the Enter key press
process.stdin.resume(); // Start listening to stdin
process.stdin.on("data", () => {
console.log("Recording stopped.");
recordingStream.stop(); // Correctly stop the recording stream
process.stdin.pause(); // Stop listening to stdin
// Convert audio data to a single Buffer
const audioBuffer = Buffer.concat(audioData);
// Convert the Buffer to Base64
const base64Audio = audioBuffer.toString("base64");
resolve(base64Audio); // Resolve the promise with Base64 audio
});
});
};
A função startRecording()
grava o áudio do microfone e aguarda que "Enter" seja pressionado.
Em seguida, atualizamos a função main()
inicializando o Speaker()
que é usado para reproduzir a resposta da IA:
// Add to the main() function after ws is initialized
const speaker = new Speaker({
channels: 1, // Mono or Stereo
bitDepth: 16, // PCM16 (16-bit audio)
sampleRate: 24000, // Common sample rate (44.1kHz)
});
Com isso resolvido, podemos implementar o handleOpen()
e o handleMessage()
para processar o áudio.
Na função handleOpen()
, só precisamos chamar a função startRecording()
para gravar o prompt de áudio do usuário. Também precisamos atualizar um pouco os eventos:
- Atualize o conteúdo do site
createConversationEvent
para usar o tipo”input_audio”
em vez de”input_text
e substitua o campotext
poraudio: base64AudioData
. - Adicione
”audio”
à modalidade de resposta emcreateResponseEvent
.
Aqui está a função handleOpen()
atualizada:
async function handleOpen() {
// Define what happens when the connection is opened
const base64AudioData = await startRecording();
const createConversationEvent = {
type: "conversation.item.create",
item: {
type: "message",
role: "user",
content: [
{
type: "input_audio",
audio: base64AudioData,
},
],
},
};
ws.send(JSON.stringify(createConversationEvent));
const createResponseEvent = {
type: "response.create",
response: {
modalities: ["text", "audio"],
instructions: "Please assist the user.",
},
};
ws.send(JSON.stringify(createResponseEvent));
}
Para implementar a função handleMessage()
, modificamos o evento ”response.audio.delta”
para atualizar o buffer de áudio e reproduzir o novo delta de som:
case "response.audio.delta":
// We got a new audio chunk
const base64AudioChunk = message.delta;
const audioBuffer = Buffer.from(base64AudioChunk, "base64");
speaker.write(audioBuffer);
break;
Removemos o evento ”response.text.done”
da instrução switch e atualizamos o evento ”response.done”
para interromper o alto-falante:
case "response.audio.done":
speaker.end();
ws.close();
break;
A implementação final da função handleMessage()
tem a seguinte aparência:
function handleMessage(messageStr) {
const message = JSON.parse(messageStr);
// Define what happens when a message is received
switch (message.type) {
case "response.audio.delta":
// We got a new audio chunk
const base64AudioChunk = message.delta;
const audioBuffer = Buffer.from(base64AudioChunk, "base64");
speaker.write(audioBuffer);
break;
case "response.audio.done":
speaker.end();
ws.close();
break;
}
}
Para executar esse exemplo, aplique essas modificações ao código do modelo e execute-o com o comando:
node index.js
O microfone começará a gravar. Podemos dizer nossa solicitação e pressionar "Enter" para enviá-la. Em seguida, a resposta da IA será reproduzida nos alto-falantes (verifique se o microfone não está mudo e se os alto-falantes têm volume).
O código completo do exemplo de áudio está disponível aqui.
Chamada de função
Um recurso interessante da API da OpenAI é a capacidade de realizar chamadas de função. Podemos adicionar funções ao assistente e, se ele detectar que uma dessas funções pode ser útil para fornecer a resposta, ele enviará um evento solicitando que uma função específica seja chamada.
A documentação da OpenAI fornece o seguinte diagrama que explica o ciclo de vida de uma chamada de função:
Fonte: OpenAI
No diagrama, vemos que o cliente deve fornecer as definições das funções que o LLM pode chamar. Além disso, a execução da função ocorrerá no lado do cliente; a IA enviará um evento solicitando a função a ser chamada e seus argumentos. Em seguida, somos responsáveis por enviar de volta o resultado.
Vamos capacitar nosso assistente com uma função que soma dois números. Criaremos esse exemplo estendendo o exemplo de áudio acima.
Para especificar as funções disponíveis, devemos fornecer ao LLM uma lista de ferramentas. Cada ferramenta é um objeto JSON que especifica as informações sobre a função. Veja como podemos definir uma ferramenta para a função de soma:
const sumTool = {
type: "function",
name: "calculate_sum",
description: "Use this function when asked to add numbers together, for example when asked 'What's 4 + 6'?.",
parameters: {
type: "object",
properties: {
"a": { "type": "number" },
"b": { "type": "number" }
},
required: ["a", "b"]
}
}
Vamos explicar a estrutura do objeto:
- O endereço
type
especifica que estamos definindo uma função. - O endereço
name
é usado para identificar a função. Isso é o que o LLM usa para nos dizer qual função ele deseja chamar. - O endereço
description
é usado para identificar quando o LLM deve usar essa função. - O endereço
parameters
é usado para especificar os argumentos da função. Nesse caso, dois números denominadosa
eb
.
A próxima etapa é definir a função em nosso código. Usaremos um dicionário com a chave calculate_sum
para facilitar a chamada da função apropriada quando respondermos a um evento de chamada de função:
const functions = {
calculate_sum: (args) => args.a + args.b,
}
A API fornecerá os argumentos da função como um dicionário com a mesma estrutura definida no site parameters
acima. Nesse caso, para adicionar, por exemplo, 3
e 5
, o dicionário seria {“a”: 3, “b”: 5}
.
As constantes sumTool
e functions
podem ser adicionadas à parte superior de index.js
, após as importações e antes da função main()
.
Em seguida, atualizamos o evento response.create
para que o LLM saiba que o sumTools
está disponível. Isso é feito adicionando os campos tools
e tool_choice
ao response
:
const createResponseEvent = {
type: "response.create",
response: {
modalities: ["text", "audio"],
instructions: "Please assist the user.",
tools: [sumTool], // New
tool_choice: "auto", // New
},
};
Quando o LLM decidir que deseja chamar uma função, ele emitirá um evento response.function_call_arguments.done
. Precisamos reagir a isso:
- Obter as informações da função e chamar a função.
- Envio do resultado da chamada de função.
- Solicitando uma resposta.
Para lidar com isso, adicionamos o seguinte caso à instrução switch
dentro da função hanldeMessage()
:
case "response.function_call_arguments.done":
console.log(Using function ${message.name} with arguments ${message.arguments});
// 1. Get the function information and call the function
const function_name = message.name;
const function_arguments = JSON.parse(message.arguments);
const result = functions[function_name](function_arguments);
// 2. Send the result of the function call
const functionOutputEvent = {
type: "conversation.item.create",
item: {
type: "function_call_output",
role: "system",
output: ${result},
}
};
ws.send(JSON.stringify(functionOutputEvent));
// 3. Request a response
ws.send(JSON.stringify({type: "response.create"}));
break;
Se agora executarmos o script e solicitarmos o resultado da adição de dois números, o modelo deverá chamar a função e fornecer o resultado.
Essa função é relativamente simples, mas como ela é executada pelo cliente, pode ser qualquer coisa. Na próxima seção, veremos dois exemplos de funções mais complexas.
O código completo deste exemplo está disponível aqui.
Desenvolva habilidades de MLOps hoje mesmo
Aplicativo de demonstração usando a API em tempo real da OpenAI
A equipe da OpenAI fornece um aplicativo React de demonstração para mostrar a API de tempo real. Aqui você aprenderá a configurá-lo e a explorar como ele funciona. Esse é um ótimo ponto de partida para você criar um aplicativo mais complexo.
Configuração do aplicativo
Não é necessário que você tenha conhecimento de React para colocá-lo em funcionamento. No entanto, você precisa estar familiarizado com o React para modificá-lo ou estendê-lo.
Seu aplicativo está hospedado em este repositório. Para configurá-lo, comece por clonagem usando o seguinte Git a seguir:
git clone org-14957082@github.com:openai/openai-realtime-console.git
Como alternativa, você também pode baixá-lo manualmente na interface do GitHub.
Para instalar o aplicativo, usamos o seguinte comando NPM (node package manage):
npm install
Quando a instalação estiver concluída, crie um arquivo chamado .env
na pasta raiz do projeto e cole o seguinte conteúdo:
OPENAI_API_KEY=<openai_api_key>
REACT_APP_LOCAL_RELAY_SERVER_URL=http://localhost:8081
Substitua pela chave da API da OpenAI.
Agora, o aplicativo deve estar pronto para ser executado. Ele é composto de duas partes:
- Um front-end React que consiste na interface de usuário da Web do aplicativo.
- Um servidor de retransmissão é usado como intermediário entre o front-end e a API da OpenAI.
O objetivo principal da implementação de um servidor de retransmissão entre o front-end e a API da OpenAI é armazenar com segurança a chave da API. A interação com a API é impossível sem essa chave.
No entanto, se a chave fosse armazenada no frontend, ela estaria acessível a qualquer usuário. Portanto, a solução envolve a configuração de um servidor que armazena a chave com segurança e facilita a troca de dados entre a API e o front-end. Nesse cenário específico, as preocupações com a segurança são mínimas, pois o aplicativo será executado apenas localmente.
Para iniciar o aplicativo, é necessário iniciar o servidor de retransmissão e o frontend. Para iniciar o servidor de retransmissão, use o seguinte comando:
npm run relay
Para iniciar o front-end do React, use o comando:
npm start
Após o término do carregamento, uma guia será aberta no navegador com o aplicativo em execução.
Usando o aplicativo
Antes de começar a usar o aplicativo, verifique se o computador não está no modo silencioso e permita o acesso do microfone ao aplicativo.
Começamos clicando no botão "conectar". Isso enviará uma mensagem "Hello" para a API de tempo real e receberemos uma saudação.
Quando a conexão for estabelecida, um novo botão aparecerá no centro, permitindo que você converse com o assistente de IA.
Para usá-lo, pressione e fale sem soltar o botão. A mensagem é enviada quando o botão é liberado.
O aplicativo também tem um modo VAD (detecção de atividade de voz) no qual não é necessário pressionar nenhum botão. Nesse modo, o aplicativo ouvirá continuamente, permitindo que você tenha uma conversa ativa com o assistente. Para usá-lo, basta pressionar o botão "vad" e falar.
Funções
Conforme aprendemos, a API em tempo real oferece um recurso que permite que a IA execute funções específicas. Esta demonstração apresenta duas funções: uma para consultar a previsão do tempo em um determinado local e outra para adicionar itens de memória para personalizar o assistente.
Experimente essas funções fazendo perguntas como "Como estará o tempo amanhã em Nova York?" e declarando preferências como "Minha cor favorita é azul". O assistente fornecerá respostas verbais a essas consultas, e as informações também serão exibidas no lado direito do aplicativo.
Houve ocasiões em que solicitei um boletim meteorológico e a resposta indicou a impossibilidade de acessá-lo naquele momento. No entanto, as informações foram exibidas de forma consistente no lado direito. Por ser um aplicativo de demonstração, ele não se destina a ser um produto totalmente funcional, mas serve para mostrar os recursos da API.
Entendendo o cliente
Esta seção requer um conhecimento de alto nível do React para que você possa acompanhar alguns dos detalhes de implementação do aplicativo.
Vamos examinar o arquivo o arquivo ConsolePage.tsx
. É aqui que a maior parte da lógica do aplicativo é definida. O aplicativo de demonstração não usa os WebSockets brutos como fizemos em nossos exemplos de aplicativos de linha de comando do Node.js. Eles criaram um cliente em tempo real que ajuda a interagir com a API. Isso é o que é importado na parte superior do arquivo:
import { RealtimeClient } from '@openai/realtime-api-beta';
A integração com a API é definida em esta chamada useEffect()
. O código nesse site useEffect()
é executado quando a página do console é renderizada inicialmente. Semelhante ao nosso script Node.js, ele descreve como responder aos eventos da API. A principal diferença é o uso do wrapper do cliente RealtimeClient
.
Definição das ferramentas
A função RealtimeClient.addTool()
é usada para definir ferramentas. Ele usa dois parâmetros:
- O objeto JSON de definição da ferramenta.
- A função a ser executada.
Essa abordagem simplifica a integração de ferramentas, pois o cliente já está equipado para lidar com eventos e automatizar invocações de funções. A ferramenta de memória é definida aquienquanto a definição da ferramenta de clima é definida aqui.
Por exemplo, para adicionar a ferramenta de soma definida anteriormente, você pode fazer o seguinte:
client.addTool(
{
name: "calculate_sum",
description: "Use this function when asked to add numbers together, for example when asked 'What's 4 + 6'?.",
parameters: {
type: "object",
properties: {
"a": { "type": "number" },
"b": { "type": "number" }
},
required: ["a", "b"]
}
},
(a: number, b: number): number => a + b
);
Observe que o aplicativo utiliza o TypeScript, exigindo, portanto, a especificação de tipos na definição da função.
Ouvindo eventos
Para ouvir um evento, a função RealtimeClient.on()
é usada. Ele aceita dois parâmetros:
- O nome do evento.
- A função de retorno de chamada a ser executada.
Essa abordagem é semelhante à função WebSocket.on()
usada anteriormente, exceto pelo fato de que ela implementa um conjunto diferente de eventos. Sua página no GitHub fornece a lista de eventos suportados.
Neste exemplo específico, são usados os seguintes eventos:
- O evento
realtime.event
aqui é usado para manter um registro de todos os eventos. - O evento
error
aqui simplesmente registra os erros no console para fins de depuração. - O evento
conversation.interrupted
aqui é usado para cancelar as solicitações quando a conversão é interrompida. - Por fim, o evento
conversation.updated
aqui é usado para anexar novo áudio ao fluxo de áudio quando novos chucks chegam da API.
Conclusão
Neste tutorial, exploramos a API OpenAI Realtime e como ela usa WebSockets para comunicação em tempo real. Abordamos a configuração de um ambiente Node.js para interagir com a API, enviar e receber mensagens de texto e áudio e implementar a chamada de função para melhorar a funcionalidade.
Também exploramos o aplicativo React de demonstração da OpenAI, demonstrando como implantar um aplicativo básico de assistente de voz.
Para saber mais sobre as ferramentas de desenvolvimento mais recentes da OpenAI, recomendo estes tutoriais:
Aprenda a desenvolver aplicativos de IA!
programa
Developing AI Applications
curso
Fully Automated MLOps
blog
O que é IA? Um guia rápido para iniciantes
tutorial
Tutorial da API de assistentes da OpenAI
tutorial
Como usar a API de conversão de texto em fala da OpenAI
tutorial
Introdução ao Text Embeddings com a API OpenAI
tutorial
Guia para iniciantes no uso da API do ChatGPT
tutorial