Pular para o conteúdo principal

API em tempo real da OpenAI: Um guia com exemplos

Saiba como criar aplicativos de IA em tempo real com a API em tempo real da OpenAI. Este tutorial aborda WebSockets, configuração do Node.js, mensagens de texto/áudio, chamadas de função e implantação de uma demonstração do assistente de voz React.
Actualizado 11 de out. de 2024  · 15 min de leitura

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).

Criando uma nova chave secreta para a API do OpenAI Realtim

Uma janela pop-up será aberta. Você pode usar as opções padrão e clicar em "Create secret key" (Criar chave secreta).

Opções padrão para criar uma chave de API da OpenAI

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.

Copiando a chave da API da OpenAI

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:

Custos de uso da API em tempo real da OpenAI

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

Aprenda a criar aplicativos de IA usando a API OpenAI.
Comece a treinar gratuitamente

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:

Estrutura de diretório inicial

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 campo delta. 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 campo text.
  • 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:

  1. Atualize o conteúdo do site createConversationEvent para usar o tipo ”input_audio” em vez de ”input_text e substitua o campo text por           audio: base64AudioData.
  2. Adicione ”audio” à modalidade de resposta em createResponseEvent.

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:

O ciclo de vida da 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 denominados a e b.

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:

  1. Obter as informações da função e chamar a função.
  2. Envio do resultado da chamada de função.
  3. 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

Comece do zero e adquira habilidades de MLOps para construir uma carreira.

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:

  1. Um front-end React que consiste na interface de usuário da Web do aplicativo.
  2. Um servidor de retransmissão é usado como intermediário entre o front-end e a API da OpenAI. 

Interação entre a API, o servidor de retransmissão e o front-end

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.

Interface de console em tempo real

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.

Conexão com a API

Quando a conexão for estabelecida, um novo botão aparecerá no centro, permitindo que você converse com o assistente de IA. 

Gravação de uma mensagem de voz

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.

Mudança para o modo de detecção de atividade de voz

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.

A função de localização e memória exibe

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: 

  1. O nome do evento.
  2. 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:


François Aubry's photo
Author
François Aubry
LinkedIn
Ensinar sempre foi minha paixão. Desde meus primeiros dias como estudante, eu buscava ansiosamente oportunidades para dar aulas particulares e ajudar outros alunos. Essa paixão me levou a fazer um doutorado, onde também atuei como assistente de ensino para apoiar meus esforços acadêmicos. Durante esses anos, encontrei imensa satisfação no ambiente tradicional da sala de aula, promovendo conexões e facilitando o aprendizado. Entretanto, com o advento das plataformas de aprendizagem on-line, reconheci o potencial transformador da educação digital. Na verdade, participei ativamente do desenvolvimento de uma dessas plataformas em nossa universidade. Estou profundamente comprometido com a integração dos princípios tradicionais de ensino com metodologias digitais inovadoras. Minha paixão é criar cursos que não sejam apenas envolventes e informativos, mas também acessíveis aos alunos nesta era digital.
Temas

Aprenda a desenvolver aplicativos de IA!

curso

Developing LLM Applications with LangChain

3 hr
12.7K
Discover how to build AI-powered applications using LLMs, prompts, chains, and agents in LangChain.
Ver DetalhesRight Arrow
Iniciar curso
Ver maisRight Arrow
Relacionado

blog

O que é IA? Um guia rápido para iniciantes

Descubra o que realmente é inteligência artificial com exemplos, opiniões de especialistas e todas as ferramentas de que você precisa para aprender mais.
Matt Crabtree's photo

Matt Crabtree

11 min

tutorial

Tutorial da API de assistentes da OpenAI

Uma visão geral abrangente da API Assistants com nosso artigo, que oferece uma análise aprofundada de seus recursos, usos no setor, orientação de configuração e práticas recomendadas para maximizar seu potencial em vários aplicativos de negócios.
Zoumana Keita 's photo

Zoumana Keita

14 min

tutorial

Como usar a API de conversão de texto em fala da OpenAI

A API TTS da OpenAI é um ponto de extremidade que permite que os usuários interajam com seu modelo de IA TTS que converte texto em linguagem falada com som natural.
Kurtis Pykes 's photo

Kurtis Pykes

12 min

tutorial

Introdução ao Text Embeddings com a API OpenAI

Explore nosso guia sobre como usar a API OpenAI para criar incorporações de texto. Descubra suas aplicações na classificação de textos, recuperação de informações e detecção de similaridade semântica.
Zoumana Keita 's photo

Zoumana Keita

7 min

tutorial

Guia para iniciantes no uso da API do ChatGPT

Este guia o orienta sobre os conceitos básicos da API ChatGPT, demonstrando seu potencial no processamento de linguagem natural e na comunicação orientada por IA.
Moez Ali's photo

Moez Ali

11 min

tutorial

Tutorial de chamada de função do OpenAI

Saiba como o novo recurso de Chamada de Função da OpenAI permite que os modelos GPT gerem saída JSON estruturada, resolvendo problemas comuns de desenvolvimento causados por saídas irregulares.
Abid Ali Awan's photo

Abid Ali Awan

12 min

See MoreSee More