La console OpenAI Realtime est conçue comme un inspecteur et une référence d'API interactive pour l'API OpenAI Realtime. Il est livré avec deux bibliothèques d'utilitaires, openai/openai-realtime-api-beta qui agit comme un client de référence (pour le navigateur et Node.js) et /src/lib/wavtools
qui permet une gestion audio simple dans le navigateur.
Il s'agit d'un projet React créé à l'aide create-react-app
fourni via Webpack. Installez-le en extrayant le contenu de ce package et en utilisant ;
$ npm i
Démarrez votre serveur avec :
$ npm start
Il devrait être disponible via localhost:3000
.
La console nécessite une clé API OpenAI ( clé utilisateur ou clé de projet ) qui a accès à l'API Realtime. Vous serez invité au démarrage à le saisir. Il sera enregistré via localStorage
et pourra être modifié à tout moment depuis l'interface utilisateur.
Pour démarrer une session, vous devrez vous connecter . Cela nécessitera un accès au microphone. Vous pourrez alors choisir entre les modes de conversation manuel (Push-to-talk) et vad (Voice Activity Detection), et basculer entre eux à tout moment.
Deux fonctions sont activées :
get_weather
: demandez la météo n'importe où et le modèle fera de son mieux pour localiser l'emplacement, l'afficher sur une carte et obtenir la météo de cet emplacement. Notez qu'il n'a pas d'accès à la localisation et que les coordonnées sont « devinées » à partir des données d'entraînement du modèle, la précision peut donc ne pas être parfaite.set_memory
: Vous pouvez demander au modèle de mémoriser les informations pour vous, et il les stockera dans un blob JSON sur la gauche.Vous pouvez librement interrompre le modèle à tout moment en mode push-to-talk ou VAD.
Si vous souhaitez créer une implémentation plus robuste et jouer avec le client de référence en utilisant votre propre serveur, nous avons inclus un serveur relais Node.js.
$ npm run relay
Il démarrera automatiquement sur localhost:8081
.
Vous devrez créer un fichier .env
avec la configuration suivante :
OPENAI_API_KEY=YOUR_API_KEY
REACT_APP_LOCAL_RELAY_SERVER_URL=http://localhost:8081
Vous devrez redémarrer votre application React et votre serveur relais pour le .env.
les changements entrent en vigueur. L'URL du serveur local est chargée via ConsolePage.tsx
. Pour arrêter d'utiliser le serveur relais à tout moment, supprimez simplement la variable d'environnement ou définissez-la sur une chaîne vide.
/**
* Running a local relay server will allow you to hide your API key
* and run custom logic on the server
*
* Set the local relay server address to:
* REACT_APP_LOCAL_RELAY_SERVER_URL=http://localhost:8081
*
* This will also require you to set OPENAI_API_KEY= in a `.env` file
* You can run it with `npm run relay`, in parallel with `npm start`
*/
const LOCAL_RELAY_SERVER_URL : string =
process . env . REACT_APP_LOCAL_RELAY_SERVER_URL || '' ;
Ce serveur n'est qu'un simple relais de messages , mais il peut être étendu à :
instructions
) directement sur le serveurVous devrez implémenter ces fonctionnalités vous-même.
Le dernier client de référence et la documentation sont disponibles sur GitHub à l'adresse openai/openai-realtime-api-beta.
Vous pouvez utiliser ce client vous-même dans n'importe quel projet React (front-end) ou Node.js. Pour une documentation complète, reportez-vous au référentiel GitHub, mais vous pouvez utiliser le guide ici comme introduction pour commencer.
import { RealtimeClient } from '/src/lib/realtime-api-beta/index.js' ;
const client = new RealtimeClient ( { apiKey : process . env . OPENAI_API_KEY } ) ;
// Can set parameters ahead of connecting
client . updateSession ( { instructions : 'You are a great, upbeat friend.' } ) ;
client . updateSession ( { voice : 'alloy' } ) ;
client . updateSession ( { turn_detection : 'server_vad' } ) ;
client . updateSession ( { input_audio_transcription : { model : 'whisper-1' } } ) ;
// Set up event handling
client . on ( 'conversation.updated' , ( { item , delta } ) => {
const items = client . conversation . getItems ( ) ; // can use this to render all items
/* includes all changes to conversations, delta may be populated */
} ) ;
// Connect to Realtime API
await client . connect ( ) ;
// Send an item and triggers a generation
client . sendUserMessageContent ( [ { type : 'text' , text : `How are you?` } ] ) ;
Pour envoyer de l'audio en streaming, utilisez la méthode .appendInputAudio()
. Si vous êtes en mode turn_detection: 'disabled'
, vous devez alors utiliser .generate()
pour indiquer au modèle de répondre.
// Send user audio, must be Int16Array or ArrayBuffer
// Default audio format is pcm16 with sample rate of 24,000 Hz
// This populates 1s of noise in 0.1s chunks
for ( let i = 0 ; i < 10 ; i ++ ) {
const data = new Int16Array ( 2400 ) ;
for ( let n = 0 ; n < 2400 ; n ++ ) {
const value = Math . floor ( ( Math . random ( ) * 2 - 1 ) * 0x8000 ) ;
data [ n ] = value ;
}
client . appendInputAudio ( data ) ;
}
// Pending audio is committed and model is asked to generate
client . createResponse ( ) ;
Travailler avec des outils est facile. Appelez simplement .addTool()
et définissez un rappel comme deuxième paramètre. Le rappel sera exécuté avec les paramètres de l'outil et le résultat sera automatiquement renvoyé au modèle.
// We can add tools as well, with callbacks specified
client . addTool (
{
name : 'get_weather' ,
description :
'Retrieves the weather for a given lat, lng coordinate pair. Specify a label for the location.' ,
parameters : {
type : 'object' ,
properties : {
lat : {
type : 'number' ,
description : 'Latitude' ,
} ,
lng : {
type : 'number' ,
description : 'Longitude' ,
} ,
location : {
type : 'string' ,
description : 'Name of the location' ,
} ,
} ,
required : [ 'lat' , 'lng' , 'location' ] ,
} ,
} ,
async ( { lat , lng , location } ) => {
const result = await fetch (
`https://api.open-meteo.com/v1/forecast?latitude= ${ lat } &longitude= ${ lng } ¤t=temperature_2m,wind_speed_10m`
) ;
const json = await result . json ( ) ;
return json ;
}
) ;
Vous souhaiterez peut-être interrompre manuellement le modèle, en particulier en mode turn_detection: 'disabled'
. Pour ce faire, nous pouvons utiliser :
// id is the id of the item currently being generated
// sampleCount is the number of audio samples that have been heard by the listener
client . cancelResponse ( id , sampleCount ) ;
Cette méthode entraînera l'arrêt immédiat de la génération du modèle, mais tronquera également l'élément en cours de lecture en supprimant tout l'audio après sampleCount
et en effaçant la réponse textuelle. En utilisant cette méthode, vous pouvez interrompre le modèle et l'empêcher de "se souvenir" de tout ce qu'il a généré et qui est en avance sur l'état de l'utilisateur.
Il existe cinq événements client principaux pour le flux de contrôle des applications dans RealtimeClient
. Notez qu'il ne s'agit que d'un aperçu de l'utilisation du client, la spécification complète des événements de l'API en temps réel est considérablement plus grande, si vous avez besoin de plus de contrôle, consultez le référentiel GitHub : openai/openai-realtime-api-beta.
// errors like connection failures
client . on ( 'error' , ( event ) => {
// do thing
} ) ;
// in VAD mode, the user starts speaking
// we can use this to stop audio playback of a previous response if necessary
client . on ( 'conversation.interrupted' , ( ) => {
/* do something */
} ) ;
// includes all changes to conversations
// delta may be populated
client . on ( 'conversation.updated' , ( { item , delta } ) => {
// get all items, e.g. if you need to update a chat window
const items = client . conversation . getItems ( ) ;
switch ( item . type ) {
case 'message' :
// system, user, or assistant message (item.role)
break ;
case 'function_call' :
// always a function call from the model
break ;
case 'function_call_output' :
// always a response from the user / application
break ;
}
if ( delta ) {
// Only one of the following will be populated for any given event
// delta.audio = Int16Array, audio added
// delta.transcript = string, transcript added
// delta.arguments = string, function arguments added
}
} ) ;
// only triggered after item added to conversation
client . on ( 'conversation.item.appended' , ( { item } ) => {
/* item status can be 'in_progress' or 'completed' */
} ) ;
// only triggered after item completed in conversation
// will always be triggered after conversation.item.appended
client . on ( 'conversation.item.completed' , ( { item } ) => {
/* item status will always be 'completed' */
} ) ;
Wavtools permet une gestion simple des flux audio PCM16 dans le navigateur, à la fois pour l'enregistrement et la lecture.
import { WavRecorder } from '/src/lib/wavtools/index.js' ;
const wavRecorder = new WavRecorder ( { sampleRate : 24000 } ) ;
wavRecorder . getStatus ( ) ; // "ended"
// request permissions, connect microphone
await wavRecorder . begin ( ) ;
wavRecorder . getStatus ( ) ; // "paused"
// Start recording
// This callback will be triggered in chunks of 8192 samples by default
// { mono, raw } are Int16Array (PCM16) mono & full channel data
await wavRecorder . record ( ( data ) => {
const { mono , raw } = data ;
} ) ;
wavRecorder . getStatus ( ) ; // "recording"
// Stop recording
await wavRecorder . pause ( ) ;
wavRecorder . getStatus ( ) ; // "paused"
// outputs "audio/wav" audio file
const audio = await wavRecorder . save ( ) ;
// clears current audio buffer and starts recording
await wavRecorder . clear ( ) ;
await wavRecorder . record ( ) ;
// get data for visualization
const frequencyData = wavRecorder . getFrequencies ( ) ;
// Stop recording, disconnects microphone, output file
await wavRecorder . pause ( ) ;
const finalAudio = await wavRecorder . end ( ) ;
// Listen for device change; e.g. if somebody disconnects a microphone
// deviceList is array of MediaDeviceInfo[] + `default` property
wavRecorder . listenForDeviceChange ( ( deviceList ) => { } ) ;
import { WavStreamPlayer } from '/src/lib/wavtools/index.js' ;
const wavStreamPlayer = new WavStreamPlayer ( { sampleRate : 24000 } ) ;
// Connect to audio output
await wavStreamPlayer . connect ( ) ;
// Create 1s of empty PCM16 audio
const audio = new Int16Array ( 24000 ) ;
// Queue 3s of audio, will start playing immediately
wavStreamPlayer . add16BitPCM ( audio , 'my-track' ) ;
wavStreamPlayer . add16BitPCM ( audio , 'my-track' ) ;
wavStreamPlayer . add16BitPCM ( audio , 'my-track' ) ;
// get data for visualization
const frequencyData = wavStreamPlayer . getFrequencies ( ) ;
// Interrupt the audio (halt playback) at any time
// To restart, need to call .add16BitPCM() again
const trackOffset = await wavStreamPlayer . interrupt ( ) ;
trackOffset . trackId ; // "my-track"
trackOffset . offset ; // sample number
trackOffset . currentTime ; // time in track
Merci d'avoir consulté la console en temps réel. Nous espérons que vous vous amuserez avec l'API Realtime. Un merci spécial à toute l'équipe de l'API Realtime pour avoir rendu cela possible. N'hésitez pas à nous contacter, à poser des questions ou à donner votre avis en créant un problème sur le référentiel. Vous pouvez également nous contacter et nous faire savoir directement ce que vous en pensez !