From 2e76218132a0d594fed71c658046f2f4ec0ec24a Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 12 May 2025 12:25:45 -0400 Subject: [PATCH] timeouts on remix requests --- .../sora/sora_image_generation_command.rs | 3 +++ .../commands/sora/sora_image_remix_command.rs | 3 +++ .../image_remix_with_session_auto_renew.rs | 5 +++++ .../image_gen/image_gen_http_request.rs | 22 ++++++++++++++----- .../image_gen/sora_image_gen_remix.rs | 7 ++++-- .../image_gen/sora_image_gen_simple.rs | 10 +++++---- 6 files changed, 38 insertions(+), 12 deletions(-) diff --git a/crates/desktop/artcraft/src/commands/sora/sora_image_generation_command.rs b/crates/desktop/artcraft/src/commands/sora/sora_image_generation_command.rs index c2e15cfb52..1eeea144bc 100644 --- a/crates/desktop/artcraft/src/commands/sora/sora_image_generation_command.rs +++ b/crates/desktop/artcraft/src/commands/sora/sora_image_generation_command.rs @@ -19,6 +19,8 @@ use tauri::{AppHandle, Manager, State}; const SORA_IMAGE_UPLOAD_TIMEOUT: Duration = Duration::from_millis(1000 * 30); // 30 seconds +const SORA_IMAGE_REMIX_TIMEOUT: Duration = Duration::from_millis(1000 * 30); // 30 seconds + #[tauri::command] pub async fn sora_image_generation_command( prompt: &str, @@ -80,6 +82,7 @@ pub async fn generate_image( image_size: ImageSize::Square, sora_media_tokens: sora_media_tokens.clone(), credentials: CredentialMigrationRef::New(&creds), + request_timeout: Some(SORA_IMAGE_REMIX_TIMEOUT), }).await .map_err(|err| { error!("Failed to call Sora image generation: {:?}", err); diff --git a/crates/desktop/artcraft/src/commands/sora/sora_image_remix_command.rs b/crates/desktop/artcraft/src/commands/sora/sora_image_remix_command.rs index 9c99afdf7d..b7ef12c517 100644 --- a/crates/desktop/artcraft/src/commands/sora/sora_image_remix_command.rs +++ b/crates/desktop/artcraft/src/commands/sora/sora_image_remix_command.rs @@ -39,6 +39,8 @@ use tokens::tokens::media_files::MediaFileToken; const SORA_IMAGE_UPLOAD_TIMEOUT: Duration = Duration::from_millis(1000 * 30); // 30 seconds +const SORA_IMAGE_REMIX_TIMEOUT: Duration = Duration::from_millis(1000 * 30); // 30 seconds + #[derive(Deserialize)] pub struct SoraImageRemixCommand { /// Image media file; the engine or canvas snapshot (screenshot). @@ -234,6 +236,7 @@ pub async fn generate_image( image_size: ImageSize::Square, sora_media_tokens: sora_media_tokens.clone(), credentials: &creds, + request_timeout: Some(SORA_IMAGE_REMIX_TIMEOUT), }).await?; if let Some(new_creds) = maybe_new_creds { diff --git a/crates/lib/api_clients/openai_sora_client/src/recipes/image_remix_with_session_auto_renew.rs b/crates/lib/api_clients/openai_sora_client/src/recipes/image_remix_with_session_auto_renew.rs index 080906af45..eb17d90d4c 100644 --- a/crates/lib/api_clients/openai_sora_client/src/recipes/image_remix_with_session_auto_renew.rs +++ b/crates/lib/api_clients/openai_sora_client/src/recipes/image_remix_with_session_auto_renew.rs @@ -1,3 +1,4 @@ +use std::time::Duration; use anyhow::anyhow; use log::{info, warn}; use errors::AnyhowResult; @@ -18,6 +19,8 @@ pub struct ImageRemixAutoRenewRequest<'a> { pub image_size: ImageSize, pub sora_media_tokens: Vec, pub credentials: &'a SoraCredentialSet, + /// This function can try several different requests. This is the timeout for *individual* requests. + pub request_timeout: Option, } /// Image request with retry and session auto-renewal. @@ -29,6 +32,7 @@ pub async fn image_remix_with_session_auto_renew(request: ImageRemixAutoRenewReq image_size: request.image_size, sora_media_tokens: request.sora_media_tokens.clone(), // NB: Clone because used again credentials: CredentialMigrationRef::New(request.credentials), + request_timeout: request.request_timeout, }).await; let err = match result { @@ -126,6 +130,7 @@ pub async fn image_remix_with_session_auto_renew(request: ImageRemixAutoRenewReq image_size: request.image_size, sora_media_tokens: request.sora_media_tokens, credentials: CredentialMigrationRef::New(&new_creds), + request_timeout: request.request_timeout, }).await; match result { diff --git a/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/image_gen_http_request.rs b/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/image_gen_http_request.rs index c446840548..b09094f42f 100644 --- a/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/image_gen_http_request.rs +++ b/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/image_gen_http_request.rs @@ -1,8 +1,9 @@ -use log::warn; use crate::creds::credential_migration::CredentialMigrationRef; -use serde_derive::{Deserialize, Serialize}; -use thiserror::Error; use crate::requests::image_gen::image_gen_status::TaskId; +use log::warn; +use serde_derive::{Deserialize, Serialize}; +use std::time::Duration; +use thiserror::Error; const SORA_IMAGE_GEN_URL: &str = "https://sora.com/backend/video_gen"; @@ -152,7 +153,11 @@ impl std::fmt::Display for RawSoraErrorInner { } /// Don't expose the internal request implementation as there are only a few "correct" ways to call the API. -pub (crate) async fn image_gen_http_request(sora_request: RawSoraImageGenRequest, credentials: CredentialMigrationRef<'_>) -> Result { +pub (crate) async fn image_gen_http_request( + sora_request: RawSoraImageGenRequest, + credentials: CredentialMigrationRef<'_>, + request_timeout: Option, +) -> Result { let client = reqwest::Client::new(); let mut cookie; @@ -181,12 +186,17 @@ pub (crate) async fn image_gen_http_request(sora_request: RawSoraImageGenRequest } } - let http_request = client.post(SORA_IMAGE_GEN_URL) + let mut http_request = client.post(SORA_IMAGE_GEN_URL) .header("User-Agent", USER_AGENT) .header("Cookie", &cookie) .header("Authorization", &authorization_header) .header("Content-Type", "application/json") .header("OpenAI-Sentinel-Token", &sentinel); + + + if let Some(timeout) = request_timeout { + http_request = http_request.timeout(timeout); + } let http_request = http_request.json(&sora_request).build() .map_err(|e| SoraImageGenError::NetworkError(e.to_string()))?; @@ -241,8 +251,8 @@ pub (crate) async fn image_gen_http_request(sora_request: RawSoraImageGenRequest #[cfg(test)] mod tests { - use errors::AnyhowResult; use crate::requests::image_gen::image_gen_http_request::RawSoraResponse; + use errors::AnyhowResult; #[test] fn deserialize_task_id() -> AnyhowResult<()> { diff --git a/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/sora_image_gen_remix.rs b/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/sora_image_gen_remix.rs index 51422bb797..819aa49403 100644 --- a/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/sora_image_gen_remix.rs +++ b/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/sora_image_gen_remix.rs @@ -1,7 +1,8 @@ -use log::info; use crate::creds::credential_migration::CredentialMigrationRef; use crate::requests::image_gen::common::{ImageSize, NumImages, SoraImageGenResponse}; use crate::requests::image_gen::image_gen_http_request::{image_gen_http_request, InpaintItem, InpaintItemType, OperationType, RawSoraImageGenRequest, SoraImageGenError, VideoGenType}; +use log::info; +use std::time::Duration; pub struct SoraImageGenRemixRequest<'a> { pub prompt: String, @@ -9,6 +10,7 @@ pub struct SoraImageGenRemixRequest<'a> { pub image_size: ImageSize, pub sora_media_tokens: Vec, pub credentials: CredentialMigrationRef<'a>, + pub request_timeout: Option, } /// The "remix" commands let you supply additional images as context. @@ -39,7 +41,7 @@ pub async fn sora_image_gen_remix(request: SoraImageGenRemixRequest<'_>) -> Resu // TODO: Replace this with debug level logging in the future. info!("Sending remix request: {:?}", args); - let result = image_gen_http_request(args, request.credentials).await?; + let result = image_gen_http_request(args, request.credentials, request.request_timeout).await?; Ok(SoraImageGenResponse { task_id: result.id, @@ -80,6 +82,7 @@ mod tests { image_size: ImageSize::Square, sora_media_tokens: vec!["media_01jqyhrz4detyvtzwp2p4j63ad".to_string()], credentials: CredentialMigrationRef::Legacy(&creds), + request_timeout: None, }).await?; println!("task_id: {}", response.task_id); diff --git a/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/sora_image_gen_simple.rs b/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/sora_image_gen_simple.rs index 2fc3d34af6..93e247f230 100644 --- a/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/sora_image_gen_simple.rs +++ b/crates/lib/api_clients/openai_sora_client/src/requests/image_gen/sora_image_gen_simple.rs @@ -1,14 +1,15 @@ -use crate::credentials::SoraCredentials; +use crate::creds::credential_migration::CredentialMigrationRef; use crate::requests::image_gen::common::{ImageSize, NumImages, SoraImageGenResponse}; use crate::requests::image_gen::image_gen_http_request::{image_gen_http_request, OperationType, RawSoraImageGenRequest, VideoGenType}; use errors::AnyhowResult; -use crate::creds::credential_migration::CredentialMigrationRef; +use std::time::Duration; pub struct SoraImageGenSimpleRequest<'a> { pub prompt: String, pub num_images: NumImages, pub image_size: ImageSize, pub credentials: CredentialMigrationRef<'a>, + pub request_timeout: Option, } pub async fn sora_image_gen_simple(args: SoraImageGenSimpleRequest<'_>) -> AnyhowResult { @@ -24,7 +25,7 @@ pub async fn sora_image_gen_simple(args: SoraImageGenSimpleRequest<'_>) -> Anyho }; // TODO: Error handling. - let result = image_gen_http_request(sora_request, args.credentials).await?; + let result = image_gen_http_request(sora_request, args.credentials, args.request_timeout).await?; Ok(SoraImageGenResponse { task_id: result.id, @@ -34,12 +35,12 @@ pub async fn sora_image_gen_simple(args: SoraImageGenSimpleRequest<'_>) -> Anyho #[cfg(test)] mod tests { use crate::credentials::SoraCredentials; + use crate::creds::credential_migration::CredentialMigrationRef; use crate::requests::image_gen::common::{ImageSize, NumImages}; use crate::requests::image_gen::sora_image_gen_simple::{sora_image_gen_simple, SoraImageGenSimpleRequest}; use errors::AnyhowResult; use std::fs::read_to_string; use testing::test_file_path::test_file_path; - use crate::creds::credential_migration::CredentialMigrationRef; #[ignore] // You can manually run "ignore" tests in the IDE, but they won't run in CI. #[tokio::test] @@ -64,6 +65,7 @@ mod tests { num_images: NumImages::One, image_size: ImageSize::Square, credentials: CredentialMigrationRef::Legacy(&creds), + request_timeout: None, }).await?; println!("task_id: {}", response.task_id);