Ce référentiel contient un client de référence AKA Sample Library pour se connecter à l'API en temps réel d'OpenAI. Cette bibliothèque est en version bêta et ne doit pas être traitée comme une implémentation finale. Vous pouvez l'utiliser pour prototyper facilement les applications conversationnelles.
Le moyen le plus simple de jouer tout de suite avec l'API est d'utiliser la console en temps réel , il utilise le client de référence pour livrer un inspecteur API entièrement fonctionnel avec des exemples de visualisation vocale et plus encore.
Cette bibliothèque est conçue pour être utilisée à la fois côté serveur (Node.js) et dans Browser (React, Vue), dans les bases de code JavaScript et TypeScript. En bêta, pour installer la bibliothèque, vous devrez npm install directement à partir du référentiel GitHub.
$ npm i openai/openai-realtime-api-beta --save import { RealtimeClient } from '@openai/realtime-api-beta' ;
const client = new RealtimeClient ( { apiKey : process . env . OPENAI_API_KEY } ) ;
// Can set parameters ahead of connecting, either separately or all at once
client . updateSession ( { instructions : 'You are a great, upbeat friend.' } ) ;
client . updateSession ( { voice : 'alloy' } ) ;
client . updateSession ( {
turn_detection : { type : 'none' } , // or 'server_vad'
input_audio_transcription : { model : 'whisper-1' } ,
} ) ;
// Set up event handling
client . on ( 'conversation.updated' , ( event ) => {
const { item , delta } = event ;
const items = client . conversation . getItems ( ) ;
/**
* item is the current item being updated
* delta can be null or populated
* you can fetch a full list of items at any time
*/
} ) ;
// Connect to Realtime API
await client . connect ( ) ;
// Send a item and triggers a generation
client . sendUserMessageContent ( [ { type : 'input_text' , text : `How are you?` } ] ) ; Vous pouvez utiliser ce client directement à partir du navigateur dans des applications React ou Vue. Nous ne recommandons pas cela, vos clés API sont à risque si vous vous connectez à Openai directement à partir du navigateur. Afin d'instancier le client dans un environnement de navigateur, utilisez:
import { RealtimeClient } from '@openai/realtime-api-beta' ;
const client = new RealtimeClient ( {
apiKey : process . env . OPENAI_API_KEY ,
dangerouslyAllowAPIKeyInBrowser : true ,
} ) ;Si vous exécutez votre propre serveur de relais, par exemple avec la console en temps réel, vous pouvez plutôt vous connecter à l'URL du serveur de relais comme ça:
const client = new RealtimeClient ( { url : RELAY_SERVER_URL } ) ; Dans cette bibliothèque, il y a trois primitives pour interfacer avec l'API en temps réel. Nous vous recommandons de commencer par les RealtimeClient , mais les utilisateurs plus avancés peuvent être plus à l'aise de travailler plus près du métal.
RealtimeClientconversation.updated , conversation.item.appended , conversation.item.completed , conversation.interrupted and realtime.event EventsRealtimeAPIclient.realtimeserver.{event_name} et client.{event_name} , respectivementRealtimeConversationclient.conversationLe client est emballé avec certains utilitaires de base qui facilitent la création d'applications en temps réel rapidement.
L'envoi de messages au serveur de l'utilisateur est facile.
client . sendUserMessageContent ( [ { type : 'input_text' , text : `How are you?` } ] ) ;
// or (empty audio)
client . sendUserMessageContent ( [
{ type : 'input_audio' , audio : new Int16Array ( 0 ) } ,
] ) ; Pour envoyer un audio de streaming, utilisez la méthode .appendInputAudio() . Si vous êtes dans le mode turn_detection: 'disabled' , vous devez utiliser .createResponse() pour dire 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 ;
} ,
) ; La méthode .addTool() exécute automatiquement un gestionnaire d'outils et déclenche une réponse à l'achèvement du gestionnaire. Parfois, vous ne voudrez peut-être pas cela, par exemple: utiliser des outils pour générer un schéma que vous utilisez à d'autres fins.
Dans ce cas, nous pouvons utiliser l'élément tools avec updateSession . Dans ce cas, vous devez spécifier type: 'function' , qui n'est pas requis pour .addTool() .
Remarque: les outils ajoutés avec .addTool() ne seront pas remplacés lors de la mise à jour des sessions manuellement, mais chaque modification updateSession() remplacera les modifications précédentes updateSession() . Les outils ajoutés via .addTool() sont persistés et annexés à tout ce qui est défini manuellement ici.
client . updateSession ( {
tools : [
{
type : 'function' ,
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' ] ,
} ,
} ,
] ,
} ) ;Ensuite, pour gérer les appels de fonction ...
client . on ( 'conversation.updated' , ( { item , delta } ) => {
if ( item . type === 'function_call' ) {
// do something
if ( delta . arguments ) {
// populating the arguments
}
}
} ) ;
client . on ( 'conversation.item.completed' , ( { item } ) => {
if ( item . type === 'function_call' ) {
// your function call is complete, execute some custom code
}
} ) ; Vous voudrez peut-être interrompre manuellement le modèle, en particulier dans 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 fera ce que le modèle cesse immédiatement de la génération, mais tronquera également l'élément joué en supprimant tout son après sampleCount et en effaçant la réponse du texte. 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é qui est en avance sur l'endroit où se trouve l'état de l'utilisateur.
Si vous avez besoin de plus de contrôle manuel et que vous souhaitez envoyer des événements clients personnalisés en fonction de la référence API des événements du client en temps réel, vous pouvez utiliser client.realtime.send() comme ça:
// manually send a function call output
client . realtime . send ( 'conversation.item.create' , {
item : {
type : 'function_call_output' ,
call_id : 'my-call-id' ,
output : '{function_succeeded:true}' ,
} ,
} ) ;
client . realtime . send ( 'response.create' ) ; Avec RealtimeClient nous avons réduit les frais généraux de l'événement des événements de serveur à cinq événements principaux qui sont les plus critiques pour votre flux de contrôle d'application. Ces événements ne font pas partie de la spécification API lui-même, mais enveloppent la logique pour faciliter le développement des applications.
// 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' */
} ) ; Si vous souhaitez plus de contrôle sur votre développement d'applications, vous pouvez utiliser l'événement realtime.event et choisir uniquement pour répondre aux événements du serveur . La documentation complète de ces événements est disponible sur la référence API des événements de serveur en temps réel.
// all events, can use for logging, debugging, or manual event handling
client . on ( 'realtime.event' , ( { time , source , event } ) => {
// time is an ISO timestamp
// source is 'client' or 'server'
// event is the raw event payload (json)
if ( source === 'server' ) {
doSomething ( event ) ;
}
} ) ; Vous devrez vous assurer d'avoir un fichier .env avec OPENAI_API_KEY= set afin d'exécuter des tests. De là, l'exécution de la suite de test est facile.
$ npm testPour exécuter des tests avec les journaux de débogage (enregistrera les événements envoyés et reçus de WebSocket), utilisez:
$ npm test -- --debugMerci d'avoir vérifié l'API en temps réel. J'adorerais avoir de vos nouvelles. Un merci spécial à l'équipe API en temps réel pour avoir rendu tout cela possible.