diff --git a/src/lib.rs b/src/lib.rs index 4a0f4e2d..475d8cc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,11 +35,8 @@ static DEEPGRAM_BASE_URL: &str = "https://api.deepgram.com"; #[derive(Debug, Clone)] pub struct Deepgram { #[cfg_attr(not(feature = "live"), allow(unused))] - api_key: String, - #[cfg_attr( - all(not(feature = "live"), not(feature = "prerecorded")), - allow(unused) - )] + api_key: Option, + #[cfg_attr(not(any(feature = "live", feature = "prerecorded")), allow(unused))] base_url: Url, client: reqwest::Client, } @@ -89,7 +86,7 @@ type Result = std::result::Result; impl Deepgram { /// Construct a new Deepgram client. /// - /// The client will be pointed at the deepgram API. + /// The client will be pointed at Deepgram's hosted API. /// /// Create your first API key on the [Deepgram Console][console]. /// @@ -99,7 +96,8 @@ impl Deepgram { /// /// Panics under the same conditions as [`reqwest::Client::new`]. pub fn new>(api_key: K) -> Self { - Self::with_base_url(api_key, DEEPGRAM_BASE_URL) + let api_key = Some(api_key.as_ref().to_owned()); + Self::inner_constructor(DEEPGRAM_BASE_URL.try_into().unwrap(), api_key) } /// Construct a new Deepgram client with the specified base URL. @@ -112,7 +110,11 @@ impl Deepgram { /// Admin features, such as billing, usage, and key management will /// still go through the hosted site at `https://api.deepgram.com`. /// - /// Create your first API key on the [Deepgram Console][console]. + /// Self-hosted instances do not in general authenticate incoming + /// requests, so unlike in [`Deepgram::new`], so no api key needs to be + /// provided. The SDK will not include an `Authorization` header in its + /// requests. If an API key is required, consider using + /// [`Deepgram::with_base_url_and_api_key`]. /// /// [console]: https://console.deepgram.com/ /// @@ -121,7 +123,6 @@ impl Deepgram { /// ``` /// # use deepgram::Deepgram; /// let deepgram = Deepgram::with_base_url( - /// "apikey12345", /// "http://localhost:8080", /// ); /// ``` @@ -130,15 +131,53 @@ impl Deepgram { /// /// Panics under the same conditions as [`reqwest::Client::new`], or if `base_url` /// is not a valid URL. + pub fn with_base_url(base_url: U) -> Self + where + U: TryInto, + U::Error: std::fmt::Debug, + { + let base_url = base_url.try_into().expect("base_url must be a valid Url"); + Self::inner_constructor(base_url, None) + } + + /// Construct a new Deepgram client with the specified base URL and + /// API Key. + /// + /// When using a self-hosted instance of deepgram, this will be the + /// host portion of your own instance. For instance, if you would + /// query your deepgram instance at `http://deepgram.internal/v1/listen`, + /// the base_url will be `http://deepgram.internal`. + /// + /// Admin features, such as billing, usage, and key management will + /// still go through the hosted site at `https://api.deepgram.com`. /// + /// [console]: https://console.deepgram.com/ /// - - pub fn with_base_url(api_key: K, base_url: U) -> Self + /// # Example: + /// + /// ``` + /// # use deepgram::Deepgram; + /// let deepgram = Deepgram::with_base_url_and_api_key( + /// "http://localhost:8080", + /// "apikey12345", + /// ); + /// ``` + /// + /// # Panics + /// + /// Panics under the same conditions as [`reqwest::Client::new`], or if `base_url` + /// is not a valid URL. + pub fn with_base_url_and_api_key(base_url: U, api_key: K) -> Self where - K: AsRef, U: TryInto, U::Error: std::fmt::Debug, + K: AsRef, { + let base_url = base_url.try_into().expect("base_url must be a valid Url"); + Self::inner_constructor(base_url, Some(api_key.as_ref().to_owned())) + } + + fn inner_constructor(base_url: Url, api_key: Option) -> Self { static USER_AGENT: &str = concat!( env!("CARGO_PKG_NAME"), "/", @@ -148,15 +187,15 @@ impl Deepgram { let authorization_header = { let mut header = HeaderMap::new(); - header.insert( - "Authorization", - HeaderValue::from_str(&format!("Token {}", api_key.as_ref())) - .expect("Invalid API key"), - ); + if let Some(api_key) = &api_key { + header.insert( + "Authorization", + HeaderValue::from_str(&format!("Token {}", api_key)).expect("Invalid API key"), + ); + } header }; - let api_key = api_key.as_ref().to_owned(); - let base_url = base_url.try_into().expect("base_url must be a valid Url"); + Deepgram { api_key, base_url, diff --git a/src/transcription/live.rs b/src/transcription/live.rs index 3755052b..e2e693e3 100644 --- a/src/transcription/live.rs +++ b/src/transcription/live.rs @@ -235,16 +235,23 @@ where .ok_or(DeepgramError::NoSource)? .map(|res| res.map(|bytes| Message::binary(Vec::from(bytes.as_ref())))); - let request = Request::builder() - .method("GET") - .uri(url.to_string()) - .header("authorization", format!("token {}", self.config.api_key)) - .header("sec-websocket-key", client::generate_key()) - .header("host", "api.deepgram.com") - .header("connection", "upgrade") - .header("upgrade", "websocket") - .header("sec-websocket-version", "13") - .body(())?; + let request = { + let builder = Request::builder() + .method("GET") + .uri(url.to_string()) + .header("sec-websocket-key", client::generate_key()) + .header("host", "api.deepgram.com") + .header("connection", "upgrade") + .header("upgrade", "websocket") + .header("sec-websocket-version", "13"); + + let builder = if let Some(api_key) = self.config.api_key.as_deref() { + builder.header("authorization", format!("token {}", api_key)) + } else { + builder + }; + builder.body(())? + }; let (ws_stream, _) = tokio_tungstenite::connect_async(request).await?; let (mut write, mut read) = ws_stream.split(); let (mut tx, rx) = mpsc::channel::>(1); @@ -310,7 +317,7 @@ mod tests { #[test] fn test_stream_url_custom_host() { - let dg = crate::Deepgram::with_base_url("token", "http://localhost:8080"); + let dg = crate::Deepgram::with_base_url_and_api_key("http://localhost:8080", "token"); assert_eq!( dg.transcription().listen_stream_url().to_string(), "ws://localhost:8080/v1/listen", diff --git a/src/transcription/prerecorded.rs b/src/transcription/prerecorded.rs index ac0eebcc..e8315f59 100644 --- a/src/transcription/prerecorded.rs +++ b/src/transcription/prerecorded.rs @@ -289,7 +289,7 @@ mod tests { #[test] fn listen_url_custom_host() { - let dg = Deepgram::with_base_url("token", "http://localhost:8888/abc/"); + let dg = Deepgram::with_base_url("http://localhost:8888/abc/"); assert_eq!( &dg.transcription().listen_url().to_string(), "http://localhost:8888/abc/v1/listen"