Skip to content

Commit

Permalink
feat: audio isolation endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
rwxbytes committed Jul 11, 2024
1 parent db1eb5a commit f0f2080
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "elevenlabs_rs"
version = "0.3.0"
version = "0.3.1"
description = "A lib crate for ElevenLabs"
authors = ["rwxbytes <[email protected]>"]
license = "MIT"
Expand Down
174 changes: 174 additions & 0 deletions src/endpoints/audio_isolation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#![allow(dead_code)]
//! The audio isolation endpoint
//!
//! # Pricing
//!
//!The API is charged at 1000 characters per minute of audio.
use crate::error::Error;
use crate::shared::path_segments::STREAM_PATH;
use std::path::Path;
//use base64::{engine::general_purpose, Engine as _};
use futures_util::{Stream, StreamExt};
use std::pin::Pin;


use super::*;

const AUDIO_ISOLATION_PATH: &str = "v1/audio-isolation";

/// The audio isolation endpoint
///
///
/// # Example
///
/// ```no_run
/// use elevenlabs_rs::utils::{play, save,};
/// use elevenlabs_rs::*;
///
/// #[tokio::main]
/// async fn main() -> Result<()> {
/// let client = ElevenLabsClient::default()?;
/// let endpoint = AudioIsolation::new("some_audio_file.mp3");
/// let resp = client.hit(endpoint).await?;
/// save("audio_file_isolated.mp3", resp.clone())?;
/// play(resp)?;
/// Ok(())
/// }
/// ```
#[derive(Clone, Debug)]
pub struct AudioIsolation {
pub audio_file: String,
}

impl AudioIsolation {
pub fn new<T: Into<String> >(audio_file: T) -> Self {
Self { audio_file: audio_file.into() }
}
}

impl Endpoint for AudioIsolation {
//type ResponseBody = AudioIsolationResponse;
type ResponseBody = Bytes;

fn method(&self) -> Method {
Method::POST
}
fn request_body(&self) -> Result<RequestBody> {
Ok(RequestBody::Multipart(to_form(&self.audio_file)?))
}
async fn response_body(self, resp: Response) -> Result<Self::ResponseBody> {
//Ok(resp.json().await?)
Ok(resp.bytes().await?)
}
fn url(&self) -> Url {
let mut url = BASE_URL.parse::<Url>().unwrap();
url.set_path(AUDIO_ISOLATION_PATH);
url
}
}


/// The audio isolation stream endpoint
///
/// # Example
///
/// ```no_run
/// use elevenlabs_rs::utils::{save, stream_audio};
/// use elevenlabs_rs::*;
///
/// #[tokio::main]
/// async fn main() -> Result<()> {
/// let client = ElevenLabsClient::default()?;
/// let endpoint = AudioIsolationStream::new("some_audio_file.mp3");
/// let resp = client.hit(endpoint).await?;
/// stream_audio(resp).await?;
/// Ok(())
/// }
/// ```
#[derive(Clone, Debug)]
pub struct AudioIsolationStream {
pub audio_file: String,
}

impl AudioIsolationStream {
pub fn new<T: Into<String> >(audio_file: T) -> Self {
Self { audio_file: audio_file.into() }
}
}

type AudioIsolationStreamResponse = Pin<Box<dyn Stream<Item = Result<Bytes>> + Send>>;
impl Endpoint for AudioIsolationStream {
type ResponseBody = AudioIsolationStreamResponse;

fn method(&self) -> Method {
Method::POST
}
fn request_body(&self) -> Result<RequestBody> {
Ok(RequestBody::Multipart(to_form(&self.audio_file)?))
}
async fn response_body(self, resp: Response) -> Result<Self::ResponseBody> {
let stream = resp.bytes_stream();
let stream = stream.map(|r| r.map_err(Into::into));
Ok(Box::pin(stream))
}
fn url(&self) -> Url {
let mut url = BASE_URL.parse::<Url>().unwrap();
url.set_path(&format!("{}{}", AUDIO_ISOLATION_PATH, STREAM_PATH));
url
}
}


fn to_form(audio_file: &str) -> Result<Form> {
let mut form = Form::new();
let path = Path::new(audio_file);
let audio_bytes = std::fs::read(audio_file)?;
let mut part = Part::bytes(audio_bytes);
let file_path_str = path.to_str().ok_or(Box::new(Error::PathNotValidUTF8))?;
part = part.file_name(file_path_str.to_string());
let mime_subtype = path
.extension()
.ok_or(Box::new(Error::FileExtensionNotFound))?
.to_str()
.ok_or(Box::new(Error::FileExtensionNotValidUTF8))?;
let mime = format!("audio/{}", mime_subtype);
part = part.mime_str(&mime)?;
form = form.part("audio", part);
Ok(form)
}


//#[derive(Clone, Debug, Deserialize)]
//pub struct AudioIsolationResponse {
// audio: IsolatedAudio,
// waveform_base_64: String,
//}
//
//#[derive(Clone, Debug, Deserialize)]
//pub struct IsolatedAudio {
// audio_isolation_id: String,
// created_at_unix: u64,
//}
//
//impl AudioIsolationResponse {
// pub fn audio(&self) -> &IsolatedAudio {
// &self.audio
// }
// pub fn waveform_base_64(&self) -> &str {
// &self.waveform_base_64
// }
//
// pub fn audio_as_bytes(&self) -> Result<Bytes> {
// Ok(Bytes::from(general_purpose::STANDARD.decode(&self.waveform_base_64)?))
// }
//}
//
//impl IsolatedAudio {
// pub fn audio_isolation_id(&self) -> &str {
// &self.audio_isolation_id
// }
// pub fn created_at_unix(&self) -> u64 {
// self.created_at_unix
// }
//
//}
1 change: 1 addition & 0 deletions src/endpoints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod user;
pub mod voice;
pub mod voice_generation;
pub mod voice_library;
pub mod audio_isolation;

#[allow(async_fn_in_trait)]
pub trait Endpoint {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
//! ```

pub use crate::client::{ElevenLabsClient, Result};
pub use crate::endpoints::audio_isolation::*;
pub use crate::endpoints::audio_native::*;
pub use crate::endpoints::dubbing::*;
pub use crate::endpoints::history::*;
Expand Down

0 comments on commit f0f2080

Please sign in to comment.