openai_api_rs/realtime/
api.rs

1use futures_util::stream::{SplitSink, SplitStream};
2use futures_util::StreamExt;
3use tokio::net::TcpStream;
4use tokio_tungstenite::{
5    connect_async,
6    tungstenite::{client::IntoClientRequest, protocol::Message},
7    MaybeTlsStream, WebSocketStream,
8};
9
10const WSS_URL: &str = "wss://api.openai.com/v1/realtime";
11
12pub struct RealtimeClient {
13    pub wss_url: String,
14    pub api_key: String,
15    pub model: String,
16}
17
18impl RealtimeClient {
19    pub fn new(api_key: String, model: String) -> Self {
20        let wss_url = std::env::var("WSS_URL").unwrap_or_else(|_| WSS_URL.to_owned());
21        Self::new_with_endpoint(wss_url, api_key, model)
22    }
23
24    pub fn new_with_endpoint(wss_url: String, api_key: String, model: String) -> Self {
25        Self {
26            wss_url,
27            api_key,
28            model,
29        }
30    }
31
32    pub async fn connect(
33        &self,
34    ) -> Result<
35        (
36            SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>,
37            SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
38        ),
39        Box<dyn std::error::Error>,
40    > {
41        let url = format!("{}?model={}", self.wss_url, self.model);
42        let mut request = url.into_client_request()?;
43        let api_key = self.api_key.clone();
44        request
45            .headers_mut()
46            .insert("Authorization", format!("Bearer {api_key}").parse()?);
47        request
48            .headers_mut()
49            .insert("OpenAI-Beta", "realtime=v1".parse()?);
50        let (ws_stream, _) = connect_async(request).await?;
51        let (write, read) = ws_stream.split();
52        Ok((write, read))
53    }
54}