#![ allow( clippy::doc_markdown ) ]
use api_openai::ClientApiAccessors;
use api_openai::
{
Client,
components ::realtime_shared::
{
RealtimeClientEvent,
RealtimeSessionCreateRequest,
RealtimeClientEventInputAudioBufferAppend,
},
};
use base64::{ engine::general_purpose::STANDARD as base64_engine, Engine as _ };
#[ tokio::main( flavor = "current_thread" ) ]
async fn main() -> Result< (), Box< dyn core::error::Error > >
{
tracing_subscriber::fmt::init();
tracing ::info!( "Initializing client..." );
let secret = api_openai::secret::Secret::load_with_fallbacks( "OPENAI_API_KEY" )
.expect( "Failed to load OPENAI_API_KEY. Please set environment variable or add to workspace secrets file." );
let env = api_openai::environment::OpenaiEnvironmentImpl::build(
secret,
None,
None,
api_openai::environment::OpenAIRecommended::base_url().to_string(),
api_openai::environment::OpenAIRecommended::realtime_base_url().to_string(),
).expect( "Failed to create environment" );
let client = Client::build( env ).expect( "Failed to create client" );
tracing ::info!( "Building realtime session request..." );
let request = RealtimeSessionCreateRequest::former()
.model( "gpt-4o-realtime-preview".to_string() )
.input_audio_format( "pcm16" ) .temperature( 0.7 )
.form();
tracing ::info!( "Sending request to OpenAI API to create session..." );
let session = client.realtime().create_session( request ).await?;
tracing ::info!( "Creating Realtime WebSocket Session Client..." );
let _ = session.client_secret.value;
let session_client = client.realtime().connect_ws( &session.id ).await?;
let dummy_audio_bytes = include_bytes!("data/example.wav");
let audio_base64 = base64_engine.encode( dummy_audio_bytes );
let iaba_append = RealtimeClientEventInputAudioBufferAppend::former()
.audio( audio_base64 ) .form();
tracing ::info!( "Sending input_audio_buffer.append event..." );
session_client.send_event( RealtimeClientEvent::InputAudioBufferAppend( iaba_append ) ).await?;
tracing ::info!( "Audio append event sent." );
tracing ::info!( "Waiting briefly for any subsequent events (no direct confirmation expected)..." );
let wait_duration = tokio::time::Duration::from_secs( 2 ); let start_time = tokio::time::Instant::now();
loop
{
if start_time.elapsed() > wait_duration
{
println!( "\nWait duration elapsed. No specific confirmation event for append." );
break;
}
let read_timeout = tokio::time::Duration::from_millis( 100 );
match tokio::time::timeout( read_timeout, session_client.recv_event() ).await
{
Ok( Ok( event ) ) =>
{
println!( "\n--- Received Subsequent Event ---" );
println!( "{event:?}" );
}
Ok( Err( e ) ) =>
{
eprintln!( "\nError reading from WebSocket : {e:?}" );
return Err( e.into() );
}
Err( _ ) =>
{
}
}
}
println!( "Successfully sent input_audio_buffer.append event." );
Ok( () )
}