Este repositório contém um cliente de referência, também conhecido como biblioteca de amostra para se conectar à API em tempo real do OpenAI. Esta biblioteca está na versão beta e não deve ser tratada como uma implementação final. Você pode usá -lo para prototipar facilmente os aplicativos de conversação.
A maneira mais fácil de jogar com a API imediatamente é usar o console em tempo real , ele usa o cliente de referência para fornecer um inspetor de API totalmente funcional com exemplos de visualização de voz e muito mais.
Esta biblioteca foi criada para ser usada no lado do servidor (Node.js) e no navegador (react, Vue), tanto nas bases de código JavaScript quanto no TypeScript. Enquanto estiver na versão beta, para instalar a biblioteca, você precisará npm install diretamente no repositório do 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?` } ] ) ; Você pode usar esse cliente diretamente do navegador nos aplicativos React ou Vue. Não recomendamos isso, suas chaves da API estão em risco se você se conectar ao OpenAI diretamente do navegador. Para instanciar o cliente em um ambiente de navegador, use:
import { RealtimeClient } from '@openai/realtime-api-beta' ;
const client = new RealtimeClient ( {
apiKey : process . env . OPENAI_API_KEY ,
dangerouslyAllowAPIKeyInBrowser : true ,
} ) ;Se você estiver executando seu próprio servidor de retransmissão, por exemplo, com o console em tempo real, poderá se conectar ao URL do servidor de revezamento:
const client = new RealtimeClient ( { url : RELAY_SERVER_URL } ) ; Nesta biblioteca, existem três primitivas para interface com a API em tempo real. Recomendamos começar com o RealtimeClient , mas usuários mais avançados podem se sentir mais confortáveis trabalhando mais perto do metal.
RealtimeClientconversation.updated personalizadas.Updated, conversation.item.appended , conversation.item.completed , conversation.interrupted e realtime.event EventsRealtimeAPIclient.realtimeserver.{event_name} e client.{event_name} , respectivamenteRealtimeConversationclient.conversationO cliente vem embalado com alguns utilitários básicos que facilitam a criação de aplicativos em tempo real rapidamente.
Enviar mensagens para o servidor do usuário é fácil.
client . sendUserMessageContent ( [ { type : 'input_text' , text : `How are you?` } ] ) ;
// or (empty audio)
client . sendUserMessageContent ( [
{ type : 'input_audio' , audio : new Int16Array ( 0 ) } ,
] ) ; Para enviar áudio de streaming, use o método .appendInputAudio() . Se você estiver no modo turn_detection: 'disabled' , precisará usar .createResponse() para informar o modelo para responder.
// 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 ( ) ; Trabalhar com ferramentas é fácil. Basta ligar para .addTool() e definir um retorno de chamada como o segundo parâmetro. O retorno de chamada será executado com os parâmetros da ferramenta e o resultado será enviado automaticamente de volta ao modelo.
// 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 ;
} ,
) ; O método .addTool() executa automaticamente um manipulador de ferramentas e aciona uma resposta na conclusão do manipulador. Às vezes, você pode não querer isso, por exemplo: usando ferramentas para gerar um esquema que você usa para outros fins.
Nesse caso, podemos usar o item tools com updateSession . Nesse caso, você deve especificar type: 'function' , que não é necessário para .addTool() .
NOTA: As ferramentas adicionadas ao .addTool() não serão substituídas ao atualizar sessões manualmente assim, mas todas as alterações updateSession() substituirão as alterações anteriores updateSession() . As ferramentas adicionadas via .addTool() são persistidas e anexadas a qualquer coisa definida manualmente aqui.
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' ] ,
} ,
} ,
] ,
} ) ;Então, para lidar com chamadas de função ...
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
}
} ) ; Você pode interromper manualmente o modelo, especialmente no modo turn_detection: 'disabled' . Para fazer isso, podemos usar:
// 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 ) ; Esse método fará com que o modelo cessasse imediatamente a geração, mas também truque o item que está sendo reproduzido removendo todo o áudio após sampleCount e limpando a resposta do texto. Ao usar esse método, você pode interromper o modelo e impedir que ele "lembre -se" de tudo o que gerou que está à frente de onde está o estado do usuário.
Se você precisar de mais controle manual e deseja enviar eventos de clientes personalizados de acordo com a referência da API de eventos de clientes em tempo real, você pode usar client.realtime.send() como assim:
// 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' ) ; Com RealtimeClient , reduzimos a sobrecarga do evento dos eventos do servidor para cinco eventos principais que são mais críticos para o seu fluxo de controle de aplicativos. Esses eventos não fazem parte da própria especificação da API, mas a lógica do envolvimento para facilitar o desenvolvimento de aplicativos.
// 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' */
} ) ; Se você deseja mais controle sobre o desenvolvimento do seu aplicativo, pode usar o evento realtime.event e optar por responder apenas aos eventos do servidor . A documentação completa para esses eventos está disponível na referência da API de eventos de servidor real.
// 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 ) ;
}
} ) ; Você precisará garantir que você tenha um arquivo .env com OPENAI_API_KEY= definido para executar testes. A partir daí, é fácil executar a suíte de teste.
$ npm testPara executar testes com logs de depuração (os eventos de registro serão enviados e recebidos do WebSocket), use:
$ npm test -- --debugObrigado por conferir a API em tempo real. Adoraria ouvir de você. Agradecimentos especiais à equipe da API em tempo real por tornar tudo isso possível.