diff --git a/openless-all/app/src-tauri/Cargo.lock b/openless-all/app/src-tauri/Cargo.lock index 9e4ca497..d55399f2 100644 --- a/openless-all/app/src-tauri/Cargo.lock +++ b/openless-all/app/src-tauri/Cargo.lock @@ -4175,12 +4175,14 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-rustls", + "tokio-util", "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams 0.4.2", "web-sys", "webpki-roots", ] @@ -4220,7 +4222,7 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", + "wasm-streams 0.5.0", "web-sys", ] @@ -6147,6 +6149,19 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasm-streams" version = "0.5.0" diff --git a/openless-all/app/src-tauri/Cargo.toml b/openless-all/app/src-tauri/Cargo.toml index 5983378e..537ba000 100644 --- a/openless-all/app/src-tauri/Cargo.toml +++ b/openless-all/app/src-tauri/Cargo.toml @@ -24,7 +24,7 @@ serde_json = "1" tokio = { version = "1", features = ["full"] } tokio-tungstenite = { version = "0.24", features = ["rustls-tls-native-roots"] } futures-util = "0.3" -reqwest = { version = "0.12", default-features = false, features = ["json", "multipart", "rustls-tls"] } +reqwest = { version = "0.12", default-features = false, features = ["json", "multipart", "rustls-tls", "stream"] } thiserror = "1" anyhow = "1" log = "0.4" diff --git a/openless-all/app/src-tauri/src/commands.rs b/openless-all/app/src-tauri/src/commands.rs index 57b19613..e5c9c00c 100644 --- a/openless-all/app/src-tauri/src/commands.rs +++ b/openless-all/app/src-tauri/src/commands.rs @@ -275,12 +275,15 @@ async fn validate_asr_transcription(config: &ProviderConfig, model: &str) -> Res return Err("providerResponseTooLarge".to_string()); } } - let body = response - .bytes() - .await - .map_err(|_| "providerReadResponseFailed".to_string())?; - if body.len() > MAX_ASR_VALIDATE_BODY_BYTES { - return Err("providerResponseTooLarge".to_string()); + use futures_util::StreamExt; + let mut body = Vec::::new(); + let mut stream = response.bytes_stream(); + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|_| "providerReadResponseFailed".to_string())?; + if body.len().saturating_add(chunk.len()) > MAX_ASR_VALIDATE_BODY_BYTES { + return Err("providerResponseTooLarge".to_string()); + } + body.extend_from_slice(&chunk); } let json: Value = serde_json::from_slice(&body).map_err(|_| "asrInvalidJson".to_string())?; if !json.is_object() || json.get("text").is_none() { @@ -303,6 +306,9 @@ fn asr_transcriptions_url(base_url: &str) -> Result { if trimmed.ends_with("/audio") { return Ok(format!("{trimmed}/transcriptions")); } + if let Some(prefix) = trimmed.strip_suffix("/chat/completions") { + return Ok(format!("{prefix}/audio/transcriptions")); + } Ok(format!("{trimmed}/audio/transcriptions")) } @@ -737,6 +743,10 @@ mod tests { asr_transcriptions_url("https://api.openai.com/v1").unwrap(), "https://api.openai.com/v1/audio/transcriptions" ); + assert_eq!( + asr_transcriptions_url("https://api.openai.com/v1/chat/completions").unwrap(), + "https://api.openai.com/v1/audio/transcriptions" + ); assert_eq!( asr_transcriptions_url("https://api.openai.com/v1/audio").unwrap(), "https://api.openai.com/v1/audio/transcriptions"