Ga naar hoofdinhoud

OpenAI Realtime API: een gids met voorbeelden

Leer hoe je realtime AI-toepassingen bouwt met de Realtime API van OpenAI. Deze tutorial behandelt WebSockets, Node.js-setup, tekst-/audio-berichten, functieaanroepen en het deployen van een React-stemassistentdemo.
Bijgewerkt 2 okt 2026  · 15 min lezen

Verken met AI

ChatGPTClaudePerplexity

De nieuw geïntroduceerde OpenAI Realtime API stelt ons in staat om snelle, low-latency, multimodale ervaringen in onze apps te integreren. Met deze API kunnen we naadloze spraak-naar-spraakinteracties creëren tussen gebruikers en large language models (LLM’s).

Deze API maakt meerdere modellen voor spraakgestuurde ervaringen overbodig, omdat het een complete oplossing in één geïntegreerde API biedt. Het doel is niet alleen de latency te verlagen, maar ook de emotionele nuances en de natuurlijke flow van gesprekken te behouden.

In dit artikel leer je hoe je de OpenAI Realtime API gebruikt om spraakgestuurde AI-assistenten te bouwen. We maken persistente WebSocket-verbindingen met Node.js en zien hoe je hiermee via de terminal met de API kunt communiceren. Daarnaast laat ik zien hoe je een React-app deployt die de mogelijkheden van deze API benut.

Genereer de API-sleutel voor de OpenAI Realtime API

Om de OpenAI Realtime API te gebruiken, moeten we eerst een API-sleutel genereren. Ga hiervoor naar de API-sleutelpagina. Let op: hiervoor heb je een account nodig. Klik bovenaan de pagina op de knop “Create new secret key”.

Een nieuwe geheime sleutel aanmaken voor de OpenAI Realtime API

Er verschijnt een pop-upvenster. We kunnen de standaardopties gebruiken en op “Create secret key” klikken.

Standaardopties om een OpenAI API-sleutel te maken

Wanneer de sleutel is aangemaakt, kun je deze kopiëren. Zorg dat je dit doet voordat je het venster sluit, want dit is de enige keer dat de sleutel wordt getoond.

De OpenAI API-sleutel kopiëren

Als je de sleutel kwijtraakt, kun je deze altijd verwijderen en een nieuwe aanmaken.

Om de sleutel op te slaan, raden we aan een bestand met de naam .env te maken en de sleutel daarin op te slaan in het volgende formaat:

OPENAI_API_KEY=<paste_they_key_here>

We gebruiken dit bestand door het hele artikel om met de API te verbinden.

Kostenoverwegingen voor de Realtime API

Houd er rekening mee dat de Realtime API niet gratis is en dat we tegoed aan ons account moeten toevoegen om deze te gebruiken. We kunnen tegoed toevoegen op de factureringspagina in ons profiel.

Om een idee van de kosten te geven, hier is een overzicht van wat het mij kostte om met de API te experimenteren tijdens het schrijven van dit artikel:

Kosten van het gebruik van de OpenAI Realtime API

Ik heb in totaal ongeveer vijf dollar uitgegeven. Dat is niet veel, maar wel duurder dan de andere API’s van OpenAI. Houd daar rekening mee terwijl je dit artikel doorloopt.

Het grootste deel van de kosten (de eerste balk) komt van het spelen met de React-console-app die we aan het einde van dit artikel bekijken. De rest, zo’n halve dollar, was voor het gebruik van de API via WebSockets. Het is dus mogelijk om dit artikel te volgen voor minder dan een dollar.

Voor meer details over de prijs van de API, bekijk de sectie “Realtime API” op hun prijspagina.

De Realtime API gebruiken met WebSockets

In tegenstelling tot andere onderdelen van de OpenAI API maakt de Realtime API gebruik van WebSockets. WebSockets is een communicatieprotocol dat een bidirectioneel kanaal opzet tussen een client en een server. In tegenstelling tot het traditionele request-responsemodel van HTTP ondersteunen WebSockets voortdurende, realtime-interacties. Dit maakt WebSockets bijzonder geschikt voor realtime-apps, zoals voicechat.

Dit artikel behandelt hoe WebSockets werken en bevat verschillende voorbeelden van interactie met de Realtime API. 

We gaan Node.js gebruiken, dus zorg dat dit op je computer is geïnstalleerd. Zo niet, download en installeer Node.js via de officiële website.

Het script initialiseren

Om mee te doen, raden we aan een map te maken met het hierboven aangemaakte .env-bestand. Voer in die map de volgende opdracht uit om het script te initialiseren:

npm init -y && touch index.js

Na afloop van deze opdracht zouden deze bestanden in de map moeten staan:

Initiële mapstructuur

De dependencies installeren

Installeer eerst twee packages:

  • ws: dit is het WebSocket-pakket, de hoofdpackage om met de API te praten.
  • dotenv: een hulppakket dat de API-sleutel uit het .env-bestand laadt.

Installeer deze met het commando:

npm install ws dotenv

Verbinden met de Realtime API

Om een verbinding met de Realtime API te starten, maken we een nieuw WebSocket-object aan met de API-URL en headers met de vereiste informatie om te verbinden:

// 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();

Een actie instellen wanneer de verbinding opent

De bovenstaande code maakt de websocketverbinding met de API, maar doet er nog niets mee.

WebSockets laten ons acties instellen die worden uitgevoerd wanneer bepaalde events plaatsvinden. We kunnen het open-event gebruiken om code op te geven die wordt uitgevoerd zodra de verbinding is opgezet.

De generieke syntaxis om een eventlistener toe te voegen is als volgt:

ws.on(<event>, <function>);

Vervang <event> door een string met de naam van het event en <function> door een functie die uitgevoerd moet worden wanneer het event plaatsvindt. 

Zo kunnen we tekst tonen zodra de verbinding klaar is:

// Add inside the main() function of index.js after creating ws
async function handleOpen() {
  console.log("Connection is opened");
}
ws.on("open", handleOpen);

We voeren deze code uit met het commando:

node index.js

Als de API-sleutel correct is ingesteld, zien we het bericht “Connection is open” in de terminal. Het script blijft draaien omdat de verbinding nog open is, dus we moeten het handmatig stoppen.

Een actie instellen wanneer een bericht wordt ontvangen

Een ander event waarop we kunnen reageren met WebSockets is het message-event. Dit wordt getriggerd telkens wanneer er een bericht van de server binnenkomt. Laten we een functie toevoegen die elk ontvangen bericht toont:

// Add inside the main() function of index.js
 async function handleMessage(messageStr) {
    const message = JSON.parse(messageStr);
    console.log(message);
}
ws.on("message", handleMessage);

Als we het script nu uitvoeren, zou ook het session.created-event getoond moeten worden dat de API verstuurt wanneer de sessie wordt geïnitialiseerd.

Andere WebSocket-events

Hierboven hebben we geleerd hoe je eventlisteners toevoegt voor de open- en message-events. WebSockets ondersteunen nog twee extra events die we in onze voorbeelden niet gebruiken.

Het close-event kan gebruikt worden om een callback toe te voegen wanneer de socket sluit:

async function handleClose() {
  console.log(“Socket closed”);
}
ws.on(“close”, handleClose);

Het error-event gebruik je om een callback toe te voegen wanneer er een fout optreedt:

async function handleError(error) {
  console.log(“Error”, error);
}
ws.on(“error”, handleError);

Communiceren met de Realtime API

Werken met WebSockets vereist programmeren op een event-driven manier. Berichten gaan over en weer via het communicatiekanaal en we kunnen niet bepalen wanneer die berichten worden verzonden of ontvangen. 

De code die de communicatie initieert, voeg je toe in handleOpen(). O Anders kan er een fout optreden omdat die code mogelijk wordt uitgevoerd voordat het websocketkanaal is opgezet.

Hetzelfde geldt voor de code die berichten afhandelt. Alle logica hoort in de functie handleMessage().

In de volgende voorbeelden gebruiken we de onderstaande code als vertrekpunt. De meeste aanpassingen zitten in handleOpen() en 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();

De Realtime API gebruiken om tekst te versturen en te ontvangen

Communicatie met de Realtime API gebeurt met events. De OpenAI realtime documentatie-API somt de ondersteunde events op. We gebruiken het conversation.item.create-event om een gesprek te starten. Events zijn JSON-objecten waarvan de velden in de documentatie staan beschreven.

Hier is een voorbeeld van een conversation.item.create-event dat de prompt ”Leg in één zin uit wat een web socket is” verstuurt:

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"
      }
    ]
  }
};

Dit event geeft de API door dat we een tekstueel gesprek willen starten. Dat staat in het content-veld, met type ”input_text” en een tekstprompt.

We gebruiken de methode ws.send() om een bericht te versturen. Het websocketpakket verwacht een string als argument, dus we moeten ons JSON-event omzetten naar een string met JSON.stringify(). Zo versturen we het bovenstaande event:

ws.send(JSON.stringify(createConversationEvent));

Dit start het gesprek, maar triggert niet automatisch een reactie van de API. Om een reactie te triggeren, sturen we een response.create-event. Bijvoorbeeld:

const createResponseEvent = {
  type: "response.create",
  response: {
      modalities: ["text"],
      instructions: "Please assist the user.",
  }
}
ws.send(JSON.stringify(createResponseEvent));

Dit event gebruikt de parameter modalities om een tekstuele reactie te vragen. De instructies zijn het belangrijkst: ze beschrijven wat we het model willen laten doen; in dit geval een generieke prompt om de gebruiker te helpen.

We sturen deze twee events in de functie handleOpen() zodat er meteen een gesprek start zodra de verbinding is opgezet. Hier is de volledige implementatie van handleOpen() voor dit voorbeeld:

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

}

Wat betreft de inkomende berichten zijn er drie typen events relevant: de events response.text.delta, response.text.done en response.done:

  • De response.text.delta-events bevatten de reactie in stukken in het veld delta. Ze zijn belangrijk als we een realtime-ervaring willen bieden, omdat we de reactie direct stuk voor stuk kunnen streamen. 
  • Het response.text.done-event markeert het einde van de tekstuele reactie en bevat het volledige antwoord in het veld text.
  • Het response.done-event markeert het einde van de reactie.

We kunnen aangeven hoe ons script op deze events moet reageren met een switch-statement in de functie 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;
  }
}

In dit voorbeeld gebruiken we het event response.text.delta om stukken van de reactie in de console te printen zodra we ze ontvangen. Wanneer de reactie compleet is, wordt het event response.text.done getriggerd en printen we een nieuwe regel om aan te geven dat de output klaar is. Tenslotte sluiten we de websocket wanneer we het event response.done ontvangen.

Om dit voorbeeld uit te voeren, plakken we deze functies in de sjablooncode hierboven en draaien we het met het commando:

node index.js

Dit genereert in de terminal een reactie op de prompt "Explain in one sentence what a web socket is", vergelijkbaar met wanneer we ChatGPT gebruiken. 

De volledige code voor het tekstvoorbeeld is hier te vinden.

De Realtime API gebruiken om audio te versturen en te ontvangen

Het vorige voorbeeld liet zien hoe we tekst afhandelen. De echte kracht van de Realtime API is echter een stemassistent die realtime reageert.

Audio afhandelen is iets ingewikkelder dan tekst. We slaan enkele details over hoe audio werkt over, omdat die ons te veel zouden afleiden van het hoofdonderwerp van dit artikel.

Installeer eerst twee packages:

npm install node-record-lpcm16 speaker
  • node-record-lpcm16 neemt geluid van de microfoon op zodat we een spraakprompt kunnen sturen.
  • speaker wordt gebruikt om de AI-stemreactie af te spelen.

We moeten ook SoX (Sound eXchange) installeren, een commandline-tool voor audiobewerking die de Node-bibliotheek gebruikt om met de microfoon te interfacen en audio op te nemen. Gebruik brew install sox op macOS of sudo apt install sox op Linux.

Met deze packages geïnstalleerd importeren we ze en voegen we een functie startRecording() toe die de audioprompts van de gebruiker opneemt. We leggen de functie niet in detail uit, om bij het hoofdonderwerp te blijven. 

Voeg de volgende code toe aan het bestand index.js na het laden van de omgeving:

// 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
    });
  });
};

De functie startRecording() neemt audio op via de microfoon en wacht tot je op “Enter” drukt. 

Vervolgens updaten we de functie main() door de Speaker() te initialiseren, die wordt gebruikt om de reactie van de AI af te spelen:

// 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)
});

Met dat uit de weg kunnen we handleOpen() en handleMessage() implementeren om audio te verwerken.

In de functie handleOpen() hoeven we alleen startRecording() aan te roepen om de audioprompt van de gebruiker op te nemen. We moeten de events ook licht aanpassen:

  1. Pas de content van createConversationEvent aan om type ”input_audio” te gebruiken in plaats van ”input_text en vervang het veld text door           audio: base64AudioData.
  2. Voeg ”audio” toe aan de response-modality in createResponseEvent.

Hier is de bijgewerkte functie handleOpen():

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));
}

Om de functie handleMessage() te implementeren, voegen we het event ”response.audio.delta” toe om de audiobuffer bij te werken en de nieuwe audiodelta af te spelen:

case "response.audio.delta":
  // We got a new audio chunk
  const base64AudioChunk = message.delta;
  const audioBuffer = Buffer.from(base64AudioChunk, "base64");
  speaker.write(audioBuffer);
  break;

We verwijderen het event ”response.text.done” uit de switch en updaten het event ”response.done” om de speaker te stoppen:

case "response.audio.done":
  speaker.end();
  ws.close();
  break;

De definitieve implementatie van de functie handleMessage() ziet er zo uit:

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;
  }
}

Om dit voorbeeld te draaien, pas je deze wijzigingen toe op de sjablooncode en voer je het uit met het commando:

node index.js

De microfoon start met opnemen. Zeg je verzoek en druk op “Enter” om het te verzenden. Vervolgens wordt de reactie van de AI via de speakers afgespeeld (zorg dat de microfoon niet gedempt is en de speakers volume hebben).

De volledige code voor het audiovoorbeeld is hier te vinden.

Function calling

Een fijne feature van de OpenAI API is de mogelijkheid om functieaanroepen uit te voeren. We kunnen functies aan de assistent toevoegen en als die detecteert dat een van die functies nuttig is om het antwoord te geven, stuurt hij een event met het verzoek om een specifieke functie aan te roepen.

De OpenAI-documentatie toont onderstaand schema dat de levenscyclus van een functieaanroep uitlegt:

De levenscyclus van een functieaanroep

Bron: OpenAI

Uit het schema blijkt dat de client de definities moet aanleveren van de functies die de LLM kan aanroepen. Ook wordt de functie-uitvoering aan de clientzijde gedaan; de AI stuurt een event met het verzoek om de functie en de argumenten, waarna wij verantwoordelijk zijn voor het terugsturen van het resultaat.

Laten we onze assistent uitbreiden met een functie die twee getallen optelt. We bouwen dit voorbeeld voort op het audiovoorbeeld hierboven.

Om de beschikbare functies te specificeren, moeten we de LLM een lijst met tools geven. Elke tool is een JSON-object met informatie over de functie. Zo definiëren we een tool voor de somfunctie:

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"]
  }
}

Toelichting op de objectstructuur:

  • Met type geven we aan dat we een functie definiëren.
  • De name identificeert de functie. Dit gebruikt de LLM om aan te geven welke functie hij wil aanroepen.
  • De description beschrijft wanneer de LLM deze functie moet gebruiken.
  • De parameters specificeren de argumenten van de functie. In dit geval twee getallen met de namen a en b.

De volgende stap is de functie in onze code definiëren. We gebruiken een dictionary met de sleutel calculate_sum zodat we eenvoudig de juiste functie kunnen aanroepen wanneer we op een functieaanroep-event reageren:

const functions = {
  calculate_sum: (args) => args.a + args.b,
}

De API levert de functieargumenten als een dictionary met dezelfde structuur als hierboven bij parameters. In dit geval, om bijvoorbeeld 3 en 5 op te tellen, zou de dictionary {“a”: 3, “b”: 5} zijn.

De constanten sumTool en functions kun je bovenaan index.js plaatsen, na de imports en vóór de functie main().

Vervolgens updaten we het event response.create om de LLM te laten weten dat de sumTools beschikbaar is. Dat doen we door de velden tools en tool_choice toe te voegen aan de response:

const createResponseEvent = {
  type: "response.create",
  response: {
    modalities: ["text", "audio"],
    instructions: "Please assist the user.",
    tools: [sumTool], // New
    tool_choice: "auto", // New
  },
};

Wanneer de LLM besluit een functie te willen aanroepen, emit hij een event response.function_call_arguments.done. We moeten daarop reageren door:

  1. De functie-informatie op te halen en de functie aan te roepen.
  2. Het resultaat van de functieaanroep te versturen.
  3. Een reactie aan te vragen.

Dit handelen we af door de volgende case toe te voegen aan de switch in de functie 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;

Als we nu het script draaien en vragen om de uitkomst van het optellen van twee getallen, zou het model de functie moeten aanroepen en het resultaat geven.

Deze functie is relatief simpel, maar omdat de uitvoering aan de clientzijde gebeurt, kan het van alles zijn. In de volgende sectie zien we twee voorbeelden van complexere functies.

De volledige code van dit voorbeeld is hier te vinden.

Demo-app met de OpenAI Realtime API

Het OpenAI-team biedt een demo-React-app om de Realtime API te demonstreren. Hier leer je hoe je die opzet en verkennen we hoe het werkt. Dit is een goed startpunt om een complexere app te bouwen.

App-setup

Kennis van React is niet vereist om de app te starten. Wil je deze echter aanpassen of uitbreiden, dan is React-kennis wel nodig.

Hun app staat in deze repository. Om hem op te zetten, begin je met clonen met het volgende Git-commando:

git clone org-14957082@github.com:openai/openai-realtime-console.git

Je kunt het ook handmatig downloaden via de GitHub-interface.

Om de app te installeren gebruiken we de volgende NPM-opdracht (node package manager):

npm install

Wanneer de installatie voltooid is, maak je een bestand .env in de hoofdmap van het project en plak je de volgende inhoud:

OPENAI_API_KEY=<openai_api_key>
REACT_APP_LOCAL_RELAY_SERVER_URL=http://localhost:8081

Vervang <openai_api_key> door je OpenAI API-sleutel.

De applicatie is nu klaar om te draaien. Hij bestaat uit twee onderdelen:

  1. Een React-frontend met de webinterface van de applicatie.
  2. Een relayserver die fungeert als tussenlaag tussen de frontend en de OpenAI API. 

Interactie tussen de API, de relayserver en de frontend

Het primaire doel van een relayserver tussen de frontend en de OpenAI API is het veilig opslaan van de API-sleutel. Zonder die sleutel kun je niet met de API communiceren.

Als de sleutel echter in de frontend wordt opgeslagen, is deze toegankelijk voor iedere gebruiker. De oplossing is daarom een server die de sleutel veilig bewaart en het dataverkeer tussen de API en de frontend faciliteert. In dit specifieke scenario zijn de beveiligingszorgen minimaal, aangezien de applicatie alleen lokaal draait. 

Om de applicatie te starten, moet je zowel de relayserver als de frontend opstarten. Start de relayserver met het volgende commando:

npm run relay

Start de React-frontend met het commando:

npm start

Na het laden opent er een browsertabblad met de draaiende applicatie.

Realtime-console-interface

De app gebruiken

Controleer voordat je de app gebruikt of de computer niet op stil staat en geef de applicatie microfoontoegang.

We beginnen door op de knop “connect” te klikken. Dit stuurt een “Hello”-bericht naar de Realtime API, en we krijgen een begroeting terug.

Verbinden met de API

Zodra de verbinding tot stand is gebracht, verschijnt er in het midden een nieuwe knop waarmee we met de AI-assistent kunnen praten. 

Een spraakbericht opnemen

Houd de knop ingedrukt terwijl je praat. Het bericht wordt verzonden zodra je de knop loslaat.

De applicatie heeft ook een VAD-modus (voice activity detection) waarin je geen knop hoeft in te drukken. In deze modus luistert de applicatie continu, zodat je een actief gesprek met de assistent kunt voeren. Druk hiervoor gewoon op de knop “vad” en praat.

Overschakelen naar voice activity detection-modus

Functies

Zoals we hebben gezien, biedt de Realtime API een functie waarmee de AI specifieke functies kan uitvoeren. Deze demo laat twee functies zien: één om het weerbericht voor een bepaalde locatie op te vragen en één om geheugenitems toe te voegen om de assistent te personaliseren. 

Probeer deze functies door vragen te stellen als “What’s the weather like tomorrow in New York?” en voorkeuren te noemen zoals “My favorite color is blue.” De assistent geeft mondeling antwoord en de informatie wordt ook aan de rechterkant van de applicatie getoond.

De weergave van locatie- en geheugenfuncties

Soms vroeg ik om een weerbericht en gaf de reactie aan dat het op dat moment niet toegankelijk was. Toch werd de informatie consequent rechts weergegeven. Het is een demo-app; hij is niet bedoeld als volledig product, maar om de mogelijkheden van de API te tonen.

De client begrijpen

Voor dit onderdeel is een globaal begrip van React nodig, omdat we enkele implementatiedetails van de applicatie behandelen.

We kijken naar het bestand ConsolePage.tsx. Daar staat het grootste deel van de applicatielogica. De demo-app gebruikt niet de ruwe WebSockets zoals in onze Node.js-voorbeelden. Ze hebben een realtimeclient gebouwd die helpt bij de interactie met de API. Die wordt bovenaan het bestand geïmporteerd:

import { RealtimeClient } from '@openai/realtime-api-beta';

De integratie met de API staat in deze useEffect()-aanroep. De code in deze useEffect() wordt uitgevoerd wanneer de consolepagina voor het eerst rendert. Net als in ons Node.js-script beschrijft het hoe op API-events wordt gereageerd. Het belangrijkste verschil is het gebruik van de clientwrapper RealtimeClient.

De tools definiëren

De functie RealtimeClient.addTool() wordt gebruikt om tools te definiëren. Deze neemt twee parameters:

  • Het JSON-object met de tooldefinitie.
  • De uit te voeren functie.

Deze aanpak vereenvoudigt de integratie van tools omdat de client al is uitgerust om events af te handelen en functieaanroepen te automatiseren. De memorytool is gedefinieerd hier, en de definitie van de weertool staat hier.

Om bijvoorbeeld de eerder gedefinieerde somtool toe te voegen, kunnen we het volgende doen:

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

Let op: de applicatie gebruikt TypeScript, dus je moet typen opgeven in de functiedefinitie.

Luisteren naar events

Om naar een event te luisteren, gebruik je de functie RealtimeClient.on(). Die accepteert twee parameters: 

  1. De naam van het event.
  2. De callbackfunctie die moet worden uitgevoerd.

Dit lijkt op de eerder gebruikte functie WebSocket.on(), maar implementeert een andere set events. Hun GitHub-pagina geeft de lijst met ondersteunde events.

In dit specifieke voorbeeld worden de volgende events gebruikt:

  • Het event realtime.event hier wordt gebruikt om alle events te loggen.
  • Het error-event hier logt simpelweg fouten naar de console voor debugging.
  • Het event conversation.interrupted hier wordt gebruikt om verzoeken te annuleren wanneer het gesprek wordt onderbroken.
  • En tot slot het event conversation.updated hier om nieuwe audio aan de audiostream toe te voegen wanneer er nieuwe chunks van de API binnenkomen.

Conclusie

In deze tutorial hebben we de OpenAI Realtime API verkend en hoe die WebSockets gebruikt voor realtimecommunicatie. We hebben de setup van een Node.js-omgeving behandeld om met de API te interacteren, het verzenden en ontvangen van tekst- en audioberichten, en het implementeren van functieaanroepen voor extra functionaliteit.

We hebben ook de OpenAI demo-React-app bekeken en laten zien hoe je een basis-stemassistentapplicatie deployt.

Wil je meer leren over de nieuwste ontwikkeltools van OpenAI, bekijk dan deze tutorials:


François Aubry's photo
Author
François Aubry
LinkedIn
Full-stack engineer & oprichter bij CheapGPT. Lesgeven is altijd mijn passie geweest. Al vanaf mijn studententijd zocht ik actief naar kansen om bijles te geven en andere studenten te helpen. Die passie bracht me ertoe om te promoveren, waarbij ik ook als onderwijsassistent werkte ter ondersteuning van mijn academische werk. In die jaren vond ik veel voldoening in de traditionele klasomgeving, waar ik verbindingen kon leggen en leren kon begeleiden. Met de opkomst van online leerplatforms zag ik echter het transformerende potentieel van digitaal onderwijs. Sterker nog, ik was actief betrokken bij de ontwikkeling van zo’n platform op onze universiteit. Ik zet me sterk in om traditionele didactische principes te combineren met innovatieve digitale methoden. Mijn passie is om cursussen te maken die niet alleen boeiend en informatief zijn, maar ook toegankelijk voor lerenden in dit digitale tijdperk.
Onderwerpen
Kunstmatige intelligentie
OpenAI
Large Language Models

Leer AI-apps ontwikkelen!

Cursus

LLM-toepassingen ontwikkelen met LangChain

3 uur
51.2K
Ontdek hoe je AI-gedreven applicaties bouwt met behulp van LLM's, prompts, ketens en agents in LangChain.
Bekijk detailsRight Arrow
Start Cursus
Meer bekijkenRight Arrow
Gerelateerd

blog

AI vanaf nul leren in 2026: een complete gids van de experts

Ontdek alles wat je moet weten om in 2026 AI te leren, van tips om te beginnen tot handige resources en inzichten van industrie-experts.
Adel Nehme's photo

Adel Nehme

15 min

Meer BekijkenMeer Bekijken