Corso
La nuova OpenAI Realtime API ci permette di integrare esperienze multimodali rapide e a bassa latenza nelle nostre applicazioni. Con questa API possiamo creare interazioni voce‑a‑voce fluide tra gli utenti e i large language model (LLM).
Questa API elimina la necessità di più modelli per ottenere esperienze vocali, perché offre una soluzione completa in un’unica API integrata. Non solo riduce la latenza, ma preserva anche le sfumature emotive e il naturale fluire della conversazione.
In questo articolo impareremo a usare l’OpenAI Realtime API per creare assistenti IA controllati dalla voce. Creeremo connessioni WebSocket persistenti con Node.js e vedremo come utilizzarle dal terminale per comunicare con l’API. Inoltre, ti guiderò nel deploy di un’app React che sfrutta le capacità di questa API.
Generare la chiave API per l’OpenAI Realtime API
Per usare la OpenAI Realtime API, dobbiamo prima generare una chiave API. Vai alla pagina delle chiavi API. Serve un account. In alto nella pagina, clicca sul pulsante “Create new secret key”.

Si aprirà una finestra pop-up. Possiamo usare le opzioni predefinite e cliccare su “Create secret key”.

Quando la chiave è stata creata, avremo l’opportunità di copiarla. Assicurati di farlo prima di chiudere la finestra: è l’unica volta in cui verrà mostrata.

Se perdi la chiave, puoi sempre eliminarla e crearne una nuova.
Per conservarla, consigliamo di creare un file chiamato .env e salvarvi la chiave con il seguente formato:
OPENAI_API_KEY=<paste_they_key_here>
Useremo questo file in tutto l’articolo per connetterci all’API.
Considerazioni sui costi della Realtime API
Prima di procedere, sappi che la Realtime API non è gratuita: dobbiamo aggiungere credito al nostro account per usarla. Possiamo farlo dalla pagina di fatturazione nel nostro profilo.
Per dare un’idea dei costi, ecco quanto mi è costato sperimentare con l’API mentre lavoravo a questo articolo:

Ho speso in totale circa cinque dollari. Non è una cifra enorme, ma è molto più costosa rispetto ad altre API di OpenAI. Tienilo a mente mentre segui l’articolo.
La maggior parte del costo (prima barra) corrisponde ai test con l’app console React che esploriamo alla fine. Il resto, circa mezzo dollaro, è il costo dell’uso dell’API via WebSocket. Quindi è possibile seguire questo articolo spendendo meno di un dollaro.
Per maggiori dettagli sui prezzi dell’API, consulta la sezione “Realtime API” sulla pagina dei prezzi.
Usare la Realtime API con i WebSocket
A differenza di altri componenti della OpenAI API, la Realtime API utilizza i WebSocket. I WebSocket sono un protocollo che stabilisce un canale di comunicazione bidirezionale tra client e server. Diversamente dal modello di richiesta‑risposta tipico di HTTP, i WebSocket supportano interazioni continue e in tempo reale. Questo li rende particolarmente adatti ad applicazioni real‑time, come la chat vocale.
Questo articolo spiega come funzionano i WebSocket e include diversi esempi di interazione con la Realtime API.
Useremo Node.js, quindi assicuriamoci che sia installato sul computer. In caso contrario, possiamo scaricarlo e installarlo dal sito ufficiale.
Inizializzare lo script
Per seguire gli esempi, ti consigliamo di creare una cartella con il file .env creato sopra. All’interno, esegui il seguente comando per inizializzare lo script:
npm init -y && touch index.js
Dopo l’esecuzione, nella cartella dovresti trovare questi file:

Installare le dipendenze
Inizia installando due pacchetti:
ws: il pacchetto WebSocket, necessario per interagire con l’API.dotenv: un utility che carica la chiave API dal file.env.
Installa con il comando:
npm install ws dotenv
Connessione alla Realtime API
Per iniziare una connessione con la Realtime API, creiamo un nuovo oggetto WebSocket passando l’URL dell’API e gli header con le informazioni necessarie per connetterci:
// 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();
Impostare un’azione all’apertura della connessione
Il codice sopra crea la connessione WebSocket all’API, ma per ora non fa nulla.
I WebSocket permettono di definire azioni da eseguire quando si verificano determinati eventi. Possiamo usare l’evento open per eseguire del codice quando la connessione è stabilita.
La sintassi generica per aggiungere un listener è:
ws.on(<event>, <function>);
Sostituisci <event> con il nome dell’evento e <function> con la funzione da eseguire quando l’evento si verifica.
Ecco come mostrare un messaggio quando la connessione è pronta:
// Add inside the main() function of index.js after creating ws
async function handleOpen() {
console.log("Connection is opened");
}
ws.on("open", handleOpen);
Per eseguire il codice, usa il comando:
node index.js
Se la chiave API è impostata correttamente, vedrai il messaggio “Connection is open” nel terminale. Lo script rimarrà in esecuzione perché la connessione resta aperta, quindi dovremo interromperlo manualmente.
Impostare un’azione alla ricezione di un messaggio
Un altro evento a cui possiamo rispondere è message, che si attiva ogni volta che arriva un messaggio dal server. Aggiungiamo una funzione che mostri ogni messaggio ricevuto:
// Add inside the main() function of index.js
async function handleMessage(messageStr) {
const message = JSON.parse(messageStr);
console.log(message);
}
ws.on("message", handleMessage);
Eseguendo lo script ora dovrebbe comparire anche l’evento session.created che l’API invia quando la sessione è inizializzata.
Altri eventi WebSocket
Sopra abbiamo visto come aggiungere listener agli eventi open e message. I WebSocket supportano due eventi aggiuntivi che non useremo negli esempi.
L’evento close permette di aggiungere una callback quando il socket si chiude:
async function handleClose() {
console.log(“Socket closed”);
}
ws.on(“close”, handleClose);
L’evento error serve per aggiungere una callback quando si verifica un errore:
async function handleError(error) {
console.log(“Error”, error);
}
ws.on(“error”, handleError);
Comunicare con la Realtime API
Lavorare con i WebSocket richiede una programmazione event‑driven. I messaggi vengono inviati e ricevuti sul canale di comunicazione e non possiamo controllare quando accadrà.
Il codice che avvia la comunicazione dovrebbe essere aggiunto dentro handleOpen(). O altrimenti si verificherebbe un errore, perché quel codice potrebbe essere eseguito prima che il canale WebSocket sia creato.
Lo stesso vale per il codice che gestisce i messaggi: tutta la logica dovrebbe andare nella funzione handleMessage().
Negli esempi successivi useremo il seguente codice come punto di partenza. La maggior parte delle modifiche riguarda l’aggiornamento di 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();
Usare la Realtime API per inviare e ricevere testo
La comunicazione con la Realtime API avviene tramite eventi. La documentazione real‑time di OpenAI elenca gli eventi supportati. Usiamo l’evento conversation.item.create per iniziare una conversazione. Gli eventi sono oggetti JSON i cui campi sono descritti nella documentazione.
Ecco un esempio di evento conversation.item.create che invia il prompt “Explain in one sentence what a web socket is”:
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"
}
]
}
};
Questo evento indica all’API che vogliamo avviare una conversazione testuale. È specificato nel campo content, usando il tipo “input_text” e fornendo un prompt testuale.
Usiamo il metodo ws.send() per inviare un messaggio. Il pacchetto WebSocket si aspetta una stringa come argomento, quindi convertiamo l’evento JSON in stringa con JSON.stringify(). Ecco come inviare l’evento:
ws.send(JSON.stringify(createConversationEvent));
Questo avvierà la conversazione, ma non farà sì che l’API ci risponda automaticamente. Per ottenere una risposta, inviamo un evento response.create. Esempio:
const createResponseEvent = {
type: "response.create",
response: {
modalities: ["text"],
instructions: "Please assist the user.",
}
}
ws.send(JSON.stringify(createResponseEvent));
Questo evento usa il parametro di risposta modalities per richiedere una risposta testuale. Le instructions sono la parte più importante e descrivono cosa vogliamo che faccia il modello, in questo caso un prompt generico per aiutare l’utente.
Invieremo questi due eventi nella funzione handleOpen() così la conversazione parte appena si stabilisce la connessione. Ecco l’implementazione completa di handleOpen() in questo esempio:
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));
}
Per quanto riguarda i messaggi in arrivo, in questo esempio vale la pena notare tre tipi di eventi: response.text.delta, response.text.done e response.done:
- Gli eventi
response.text.deltacontengono la risposta suddivisa in chunk nel campodelta. Sono importanti quando vogliamo un’esperienza in tempo reale perché ci permettono di fare streaming della risposta pezzo per pezzo subito. - L’evento
response.text.donesegna la fine della risposta testuale e contiene la risposta completa nel campotext. - L’evento
response.doneindica la fine della risposta.
Possiamo specificare come far reagire lo script a questi eventi usando uno switch in 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 questo esempio usiamo response.text.delta per stampare i chunk della risposta in console man mano che li riceviamo. Quando la risposta è completa, l’evento response.text.done viene attivato e stampiamo una nuova riga per indicare la fine dell’output. Infine, chiudiamo il WebSocket quando riceviamo response.done.
Per eseguire l’esempio, incolla queste funzioni nel template sopra e lancialo con:
node index.js
Questo genererà nel terminale una risposta al prompt "Explain in one sentence what a web socket is", in modo simile a quando usiamo ChatGPT.
Il codice completo per l’esempio testuale è disponibile qui.
Usare la Realtime API per inviare e ricevere audio
Nel precedente esempio abbiamo visto come gestire il testo. Tuttavia, il vero interesse della Realtime API è creare un assistente vocale che risponda in tempo reale.
Gestire l’audio è leggermente più complicato del testo. Sorvoleremo su alcuni dettagli specifici dell’audio, perché ci allontanerebbero dal tema principale.
Per prima cosa, installiamo due pacchetti:
npm install node-record-lpcm16 speaker
node-record-lpcm16registra l’audio dal microfono per poter inviare un prompt vocale.speakerserve a riprodurre la risposta vocale dell’IA.
Dobbiamo anche installare SoX (Sound eXchange), un tool a riga di comando per l’audio che la libreria Node userà per interfacciarsi con il microfono e registrare. Usa brew install sox su macOS o sudo apt install sox su Linux.
Installati i pacchetti, li importiamo e aggiungiamo una funzione startRecording() che registra i prompt vocali dell’utente. Non ne spieghiamo i dettagli per restare in tema.
Aggiungi il seguente codice al file index.js dopo il caricamento dell’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
});
});
};
La funzione startRecording() registra l’audio dal microfono e attende la pressione di “Invio”.
Poi aggiorniamo la funzione main() inizializzando Speaker(), usato per riprodurre la risposta dell’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)
});
Fatto questo, possiamo implementare handleOpen() e handleMessage() per processare l’audio.
In handleOpen() ci basta chiamare startRecording() per registrare il prompt vocale dell’utente. Dobbiamo anche aggiornare leggermente gli eventi:
- Aggiorna il contenuto di
createConversationEventusando il tipo“input_audio”al posto di“input_text”e sostituisci il campotextconaudio: base64AudioData. - Aggiungi
“audio”alla modalità di risposta increateResponseEvent.
Ecco la versione aggiornata di 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));
}
Per implementare handleMessage(), modifichiamo l’evento “response.audio.delta” per aggiornare il buffer e riprodurre il nuovo delta audio:
case "response.audio.delta":
// We got a new audio chunk
const base64AudioChunk = message.delta;
const audioBuffer = Buffer.from(base64AudioChunk, "base64");
speaker.write(audioBuffer);
break;
Rimuoviamo l’evento “response.text.done” dallo switch e aggiorniamo “response.done” per fermare lo speaker:
case "response.audio.done":
speaker.end();
ws.close();
break;
L’implementazione finale di handleMessage() è la seguente:
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;
}
}
Per eseguire questo esempio, applica le modifiche al template e lancialo con:
node index.js
Il microfono inizierà a registrare. Possiamo dire la nostra richiesta e premere “Invio” per inviarla. Poi la risposta dell’IA verrà riprodotta dagli altoparlanti (assicurati che il microfono non sia disattivato e gli altoparlanti abbiano volume).
Il codice completo per l’esempio audio è disponibile qui.
Function calling
Una caratteristica interessante dell’OpenAI API è la possibilità di effettuare function call. Possiamo aggiungere funzioni all’assistente e, se ritiene che una di esse sia utile per rispondere, invierà un evento richiedendone l’esecuzione.
La documentazione OpenAI fornisce il seguente diagramma che spiega il ciclo di vita di una function call:

Fonte: OpenAI
Dal diagramma si vede che il client deve fornire le definizioni delle funzioni che l’LLM può chiamare. Inoltre, l’esecuzione della funzione avviene lato client: l’IA invierà un evento richiedendo la chiamata della funzione e i relativi argomenti. Poi sta a noi inviare indietro il risultato.
Aggiungiamo al nostro assistente una funzione che somma due numeri. Costruiremo questo esempio estendendo quello audio visto sopra.
Per specificare le funzioni disponibili, dobbiamo fornire all’LLM un elenco di strumenti (tools). Ogni tool è un oggetto JSON con le informazioni sulla funzione. Ecco come definire un tool per la somma:
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"]
}
}
Spieghiamo la struttura dell’oggetto:
- Il
typespecifica che stiamo definendo una funzione. - Il
nameidentifica la funzione. È ciò che l’LLM userà per dirci quale funzione vuole chiamare. - La
descriptionindica quando l’LLM dovrebbe usare questa funzione. - I
parametersspecificano gli argomenti della funzione: in questo caso due numeri chiamatiaeb.
Il passo successivo è definire la funzione nel nostro codice. Useremo un dizionario con la chiave calculate_sum per richiamare facilmente la funzione appropriata quando rispondiamo all’evento di function call:
const functions = {
calculate_sum: (args) => args.a + args.b,
}
L’API fornirà gli argomenti come dizionario con la stessa struttura definita nei parameters sopra. In questo caso, per sommare 3 e 5, il dizionario sarebbe {“a”: 3, “b”: 5}.
Le costanti sumTool e functions possono essere aggiunte in cima a index.js, dopo gli import e prima della funzione main().
Poi aggiorniamo l’evento response.create per far sapere all’LLM che sumTools è disponibile. Si fa aggiungendo i campi tools e tool_choice nella response:
const createResponseEvent = {
type: "response.create",
response: {
modalities: ["text", "audio"],
instructions: "Please assist the user.",
tools: [sumTool], // New
tool_choice: "auto", // New
},
};
Quando l’LLM decide di chiamare una funzione, emetterà un evento response.function_call_arguments.done. Dobbiamo rispondergli:
- Ottenendo le informazioni sulla funzione e chiamandola.
- Inviando il risultato della chiamata.
- Richiedendo una risposta.
Gestiamo il tutto aggiungendo il seguente case allo switch dentro 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 ora eseguiamo lo script e chiediamo il risultato della somma di due numeri, il modello chiamerà la funzione e fornirà il risultato.
Questa funzione è piuttosto semplice, ma poiché l’esecuzione avviene lato client, potrebbe fare qualunque cosa. Nella prossima sezione vedremo due esempi di funzioni più complesse.
Il codice completo di questo esempio è disponibile qui.
App demo che usa l’OpenAI Realtime API
Il team di OpenAI fornisce un’app React demo per mostrare la Realtime API. Qui vedremo come impostarla ed esplorarne il funzionamento. È un ottimo punto di partenza per creare un’app più complessa.
Setup dell’app
Non serve conoscere React per eseguirla. Tuttavia, per modificarla o estenderla dovrai avere familiarità con React.
L’app è ospitata in questo repository. Per configurarla, inizia clonandola con il seguente comando Git:
git clone org-14957082@github.com:openai/openai-realtime-console.git
In alternativa, possiamo anche scaricarla manualmente dall’interfaccia di GitHub.
Per installare l’app, usa il seguente comando NPM (node package manager):
npm install
Completata l’installazione, crea un file chiamato .env nella cartella radice del progetto e incolla il seguente contenuto:
OPENAI_API_KEY=<openai_api_key>
REACT_APP_LOCAL_RELAY_SERVER_URL=http://localhost:8081
Sostituisci <openai_api_key> con la tua chiave API OpenAI.
L’applicazione ora è pronta per essere eseguita. È composta da due parti:
- Un frontend React che costituisce l’interfaccia web dell’applicazione.
- Un relay server usato come intermediario tra frontend e OpenAI API.

Lo scopo principale di un relay server tra frontend e OpenAI API è conservare in modo sicuro la chiave API. Senza questa chiave non è possibile interagire con l’API.
Se però la chiave fosse salvata nel frontend, sarebbe accessibile a chiunque. La soluzione quindi è impostare un server che conservi la chiave in modo sicuro e faciliti lo scambio dati tra API e frontend. In questo scenario specifico, le preoccupazioni di sicurezza sono minime poiché l’app sarà eseguita solo in locale.
Per avviare l’app, è necessario far partire sia il relay server sia il frontend. Per il relay server, usa:
npm run relay
Per avviare il frontend React usa:
npm start
Al termine del caricamento, si aprirà una scheda del browser con l’app in esecuzione.

Uso dell’app
Prima di iniziare, assicurati che il computer non sia in muto e concedi all’app l’accesso al microfono.
Iniziamo cliccando il pulsante “connect”. Questo invierà un messaggio “Hello” alla Realtime API e riceveremo un saluto.

Una volta stabilita la connessione, apparirà un nuovo pulsante al centro per parlare con l’assistente IA.

Per usarlo, tieni premuto e parla senza rilasciare il pulsante. Il messaggio viene inviato quando rilasci.
L’app dispone anche di una modalità VAD (voice activity detection) in cui non serve premere alcun pulsante. In questa modalità, l’app ascolta continuamente permettendoci di conversare in modo attivo con l’assistente. Per usarla, premi il pulsante “vad” e parla.

Funzioni
Come abbiamo visto, la Realtime API offre una funzionalità che permette all’IA di eseguire funzioni specifiche. Questa demo mostra due funzioni: una per chiedere le previsioni meteo in una località e un’altra per aggiungere elementi di memoria per personalizzare l’assistente.
Provale facendo domande come “What’s the weather like tomorrow in New York?” e indicando preferenze come “My favorite color is blue.” L’assistente fornirà risposte vocali e le informazioni saranno mostrate anche nel riquadro a destra dell’app.

A volte, quando ho richiesto il meteo, la risposta indicava l’impossibilità di accedervi in quel momento. Tuttavia, le informazioni venivano sempre mostrate a destra. Essendo un’app demo, non è pensata per essere un prodotto completo, ma per mostrare le capacità dell’API.
Comprendere il client
Questa sezione richiede una comprensione ad alto livello di React, poiché copre alcuni dettagli implementativi dell’app.
Esamineremo il file ConsolePage.tsx. Qui è definita gran parte della logica. La demo non usa i WebSocket raw come nel nostro esempio da riga di comando con Node.js: è stato costruito un client real‑time che facilita l’interazione con l’API. Questo è ciò che viene importato in cima al file:
import { RealtimeClient } from '@openai/realtime-api-beta';
L’integrazione con l’API è definita in questa chiamata a useEffect(). Il codice all’interno viene eseguito quando la pagina console viene renderizzata inizialmente. Come nel nostro script Node.js, definisce come rispondere agli eventi dell’API. La differenza principale è l’uso del wrapper client RealtimeClient.
Definire i tool
La funzione RealtimeClient.addTool() è usata per definire i tool. Accetta due parametri:
- L’oggetto JSON di definizione del tool.
- La funzione da eseguire.
Questo approccio semplifica l’integrazione, perché il client è già pronto a gestire gli eventi e ad automatizzare le chiamate funzione. Il tool di memoria è definito qui, mentre la definizione del tool meteo è qui.
Per esempio, per aggiungere il tool somma definito in precedenza, possiamo fare così:
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
);
Nota che l’app usa TypeScript, quindi occorre specificare i tipi nella definizione della funzione.
Ascoltare gli eventi
Per ascoltare un evento si usa RealtimeClient.on(). Accetta due parametri:
- Il nome dell’evento.
- La callback da eseguire.
Questo approccio è simile a WebSocket.on() che abbiamo usato prima, ma implementa un set di eventi diverso. La loro pagina GitHub elenca gli eventi supportati.
In questo esempio vengono usati i seguenti eventi:
- L’evento
realtime.eventqui tiene un log di tutti gli eventi. - L’evento
errorqui registra semplicemente gli errori in console per il debug. - L’evento
conversation.interruptedqui annulla le richieste quando la conversazione viene interrotta. - Infine, l’evento
conversation.updatedqui serve ad aggiungere nuovo audio allo stream quando arrivano chunk dall’API.
Conclusione
In questo tutorial abbiamo esplorato l’OpenAI Realtime API e come utilizza i WebSocket per la comunicazione in tempo reale. Abbiamo coperto il setup di un ambiente Node.js per interagire con l’API, l’invio e la ricezione di messaggi testuali e audio, e l’implementazione del function calling per funzionalità avanzate.
Abbiamo anche esplorato l’app demo React di OpenAI, mostrando come distribuire una semplice applicazione di assistente vocale.
Per approfondire i più recenti strumenti di sviluppo OpenAI, ti consiglio questi tutorial:


