diff --git a/.sqlx/query-7369b2f3fd9e7c1e968dc5501ef9bea7e1610fd7a044a0f9ad8b908dfada2b6a.json b/.sqlx/query-7369b2f3fd9e7c1e968dc5501ef9bea7e1610fd7a044a0f9ad8b908dfada2b6a.json new file mode 100644 index 0000000000..401d784e1b --- /dev/null +++ b/.sqlx/query-7369b2f3fd9e7c1e968dc5501ef9bea7e1610fd7a044a0f9ad8b908dfada2b6a.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO media_files\nSET\n token = ?,\n\n media_class = ?,\n media_type = ?,\n\n origin_category = ?,\n origin_product_category = ?,\n\n maybe_engine_category = ?,\n maybe_animation_type = ?,\n\n maybe_mime_type = ?,\n file_size_bytes = ?,\n\n checksum_sha2 = ?,\n\n maybe_prompt_token = ?,\n maybe_batch_token = ?,\n\n maybe_title = ?,\n maybe_duration_millis = ?,\n\n public_bucket_directory_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n\n maybe_creator_user_token = ?,\n maybe_creator_anonymous_visitor_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n\n maybe_scene_source_media_file_token = ?,\n\n is_intermediate_system_file = ?,\n is_user_upload = ?,\n\n maybe_generation_provider = ?,\n\n maybe_creator_file_synthetic_id = ?,\n maybe_creator_category_synthetic_id = ?,\n\n maybe_origin_model_type = NULL,\n maybe_origin_model_token = NULL\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 27 + }, + "nullable": [] + }, + "hash": "7369b2f3fd9e7c1e968dc5501ef9bea7e1610fd7a044a0f9ad8b908dfada2b6a" +} \ No newline at end of file diff --git a/.sqlx/query-a4901f904aa1c00d9afc23faa7008816c6e1b653bd6ad9f0b6772e32000be544.json b/.sqlx/query-a4901f904aa1c00d9afc23faa7008816c6e1b653bd6ad9f0b6772e32000be544.json new file mode 100644 index 0000000000..c5c0157d62 --- /dev/null +++ b/.sqlx/query-a4901f904aa1c00d9afc23faa7008816c6e1b653bd6ad9f0b6772e32000be544.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\n INSERT INTO media_files\n SET\n token = ?,\n\n media_class = ?,\n media_type = ?,\n\n is_user_upload = ?,\n is_intermediate_system_file = ?,\n\n origin_category = ?, \n origin_product_category = ?, \n maybe_origin_model_type = ?, \n maybe_origin_model_token = ?, \n maybe_origin_filename = ?,\n\n is_batch_generated = ?,\n maybe_batch_token = ?,\n\n maybe_mime_type = ?,\n file_size_bytes = ?,\n maybe_duration_millis = ?,\n maybe_audio_encoding = ?, \n maybe_video_encoding = ?, \n maybe_frame_width = ?, \n maybe_frame_height = ?,\n maybe_prompt_token = ?,\n checksum_sha2 = ?,\n \n maybe_engine_category = ?,\n\n maybe_title = ?,\n maybe_text_transcript = ?,\n\n maybe_scene_source_media_file_token = ?,\n\n public_bucket_directory_hash = ?, \n maybe_public_bucket_prefix = ?, \n maybe_public_bucket_extension = ?, \n\n maybe_creator_user_token = ?, \n maybe_creator_anonymous_visitor_token = ?, \n\n creator_ip_address = ?, \n creator_set_visibility = ?, \n\n maybe_creator_file_synthetic_id = ?, \n maybe_creator_category_synthetic_id = ?,\n\n extra_file_modification_info = ?,\n\n maybe_generation_provider = ?,\n\n maybe_cover_image_media_file_token = ?,\n\n maybe_mod_user_token = ?,\n is_generated_on_prem = ?,\n generated_by_worker = ?,\n generated_by_cluster = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 41 + }, + "nullable": [] + }, + "hash": "a4901f904aa1c00d9afc23faa7008816c6e1b653bd6ad9f0b6772e32000be544" +} \ No newline at end of file diff --git a/crates/schema/database/mysql_queries/src/queries/media_files/create/generic_insert/insert_media_file_generic.rs b/crates/schema/database/mysql_queries/src/queries/media_files/create/generic_insert/insert_media_file_generic.rs index 6480534ec1..a5191aacb6 100644 --- a/crates/schema/database/mysql_queries/src/queries/media_files/create/generic_insert/insert_media_file_generic.rs +++ b/crates/schema/database/mysql_queries/src/queries/media_files/create/generic_insert/insert_media_file_generic.rs @@ -9,6 +9,7 @@ use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCat use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; use enums::by_table::media_files::media_file_type::MediaFileType; +use enums::common::generation_provider::GenerationProvider; use enums::common::visibility::Visibility; use errors::AnyhowResult; use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken; @@ -88,6 +89,9 @@ pub struct InsertArgs<'a> { pub generated_by_worker: Option<&'a str>, pub generated_by_cluster: Option<&'a str>, + /// If provided, the third-party provider that generated this file. + pub maybe_generation_provider: Option, + // Cover image (e.g. thumbnail for 3D splats) pub maybe_cover_image_media_file_token: Option<&'a MediaFileToken>, @@ -110,6 +114,22 @@ pub async fn insert_media_file_generic( let is_batch_generated = args.maybe_batch_token.is_some(); + let mut maybe_generation_provider_str = None; + let mut is_intermediate_system_file = args.is_intermediate_system_file; + let mut is_user_upload = args.is_user_upload; + let mut origin_category = args.origin_category; + + if let Some(generation_provider) = args.maybe_generation_provider { + // Overrides if we're using a generation provider + maybe_generation_provider_str = Some(generation_provider.to_str()); + is_intermediate_system_file = false; + is_user_upload = false; + if generation_provider != GenerationProvider::Artcraft { + origin_category = MediaFileOriginCategory::ThirdPartyInference; + } + } + + let mut transaction = args.pool.begin().await?; if let Some(user_token) = args.maybe_creator_user_token.as_deref() { @@ -182,6 +202,8 @@ pub async fn insert_media_file_generic( extra_file_modification_info = ?, + maybe_generation_provider = ?, + maybe_cover_image_media_file_token = ?, maybe_mod_user_token = ?, @@ -194,10 +216,10 @@ pub async fn insert_media_file_generic( args.media_class.to_str(), args.media_type.to_str(), - args.is_user_upload, - args.is_intermediate_system_file, + is_user_upload, + is_intermediate_system_file, - args.origin_category.to_str(), + origin_category.to_str(), args.origin_product_category.to_str(), args.maybe_origin_model_type.map(|e| e.to_str()), args.maybe_origin_model_token.map(|t| t.to_string()), @@ -238,6 +260,8 @@ pub async fn insert_media_file_generic( extra_file_modification_info, + maybe_generation_provider_str, + args.maybe_cover_image_media_file_token.map(|t| t.as_str()), args.maybe_mod_user_token, diff --git a/crates/schema/database/mysql_queries/src/queries/media_files/create/generic_insert/insert_media_file_generic_from_job.rs b/crates/schema/database/mysql_queries/src/queries/media_files/create/generic_insert/insert_media_file_generic_from_job.rs index 60e51afbac..b921f8eda8 100644 --- a/crates/schema/database/mysql_queries/src/queries/media_files/create/generic_insert/insert_media_file_generic_from_job.rs +++ b/crates/schema/database/mysql_queries/src/queries/media_files/create/generic_insert/insert_media_file_generic_from_job.rs @@ -120,6 +120,7 @@ pub async fn insert_media_file_generic_from_job( maybe_text_transcript: args.maybe_text_transcript, maybe_title: args.maybe_title, maybe_video_encoding: args.maybe_video_encoding, + maybe_generation_provider: None, maybe_cover_image_media_file_token: None, media_class: args.media_class, media_type: args.media_type, diff --git a/crates/schema/database/mysql_queries/src/queries/media_files/create/insert_builder/media_file_insert_builder.rs b/crates/schema/database/mysql_queries/src/queries/media_files/create/insert_builder/media_file_insert_builder.rs index 59f377547f..cd017aa879 100644 --- a/crates/schema/database/mysql_queries/src/queries/media_files/create/insert_builder/media_file_insert_builder.rs +++ b/crates/schema/database/mysql_queries/src/queries/media_files/create/insert_builder/media_file_insert_builder.rs @@ -82,8 +82,6 @@ pub struct MediaFileInsertBuilder { // Generation details maybe_generation_provider: Option, - - // Remaining fields... } impl MediaFileInsertBuilder { @@ -296,8 +294,8 @@ impl MediaFileInsertBuilder { let mut is_intermediate_system_file = self.is_intermediate_system_file; let mut is_user_upload = self.is_user_upload; - // Overrides if we state we're using a generation provider if let Some(generation_provider) = self.maybe_generation_provider { + // Overrides if we're using a generation provider maybe_generation_provider_str = Some(generation_provider.to_str()); is_intermediate_system_file = false; is_user_upload = false; @@ -342,6 +340,7 @@ impl MediaFileInsertBuilder { maybe_creator_file_synthetic_id_category: IdCategory::MediaFile, // TODO: Remove this maybe_creator_category_synthetic_id_category: IdCategory::FileUpload, // TODO: Remove this maybe_extra_media_info: None, // TODO + maybe_generation_provider: self.maybe_generation_provider, maybe_cover_image_media_file_token: self.maybe_cover_image_media_file_token.as_ref(), is_generated_on_prem: false, // TODO generated_by_worker: None, // TODO diff --git a/crates/schema/database/mysql_queries/src/queries/media_files/create/insert_media_file_from_studio_scene_render.rs b/crates/schema/database/mysql_queries/src/queries/media_files/create/insert_media_file_from_studio_scene_render.rs index 411def761e..557ee36716 100644 --- a/crates/schema/database/mysql_queries/src/queries/media_files/create/insert_media_file_from_studio_scene_render.rs +++ b/crates/schema/database/mysql_queries/src/queries/media_files/create/insert_media_file_from_studio_scene_render.rs @@ -111,6 +111,7 @@ pub async fn insert_media_file_from_studio_scene_render( maybe_prompt_token: None, maybe_mod_user_token: None, maybe_engine_category: None, + maybe_generation_provider: None, maybe_cover_image_media_file_token: None, }).await?; diff --git a/crates/schema/database/mysql_queries/src/queries/media_files/create/specialized_insert/insert_media_file_from_file_upload.rs b/crates/schema/database/mysql_queries/src/queries/media_files/create/specialized_insert/insert_media_file_from_file_upload.rs index 4f26882e77..68abae73ff 100644 --- a/crates/schema/database/mysql_queries/src/queries/media_files/create/specialized_insert/insert_media_file_from_file_upload.rs +++ b/crates/schema/database/mysql_queries/src/queries/media_files/create/specialized_insert/insert_media_file_from_file_upload.rs @@ -82,8 +82,8 @@ pub async fn insert_media_file_from_file_upload( let mut is_intermediate_system_file = args.is_intermediate_system_file; let mut is_user_upload = true; - // Overrides if we state we're using a generation provider if let Some(generation_provider) = args.maybe_generation_provider { + // Overrides if we're using a generation provider origin_category = MediaFileOriginCategory::ThirdPartyInference; maybe_generation_provider_str = Some(generation_provider.to_str()); is_intermediate_system_file = false; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_engine_asset/drain_multipart_request.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_engine_asset/drain_multipart_request.rs index efc6f3cda5..2af3b0d4d8 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_engine_asset/drain_multipart_request.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_engine_asset/drain_multipart_request.rs @@ -6,8 +6,9 @@ use log::warn; use enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType; use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory; +use enums::common::generation_provider::GenerationProvider; use errors::AnyhowResult; - +use crate::http_server::endpoints::media_files::upload::common_utils::try_parse_generation_provider::try_parse_generation_provider; use crate::http_server::web_utils::read_multipart_field_bytes::{checked_read_multipart_bytes, read_multipart_field_as_text}; pub struct MediaFileUploadData { @@ -26,6 +27,9 @@ pub struct MediaFileUploadData { // Optional: visibility pub maybe_animation_type: Option, + + // Optional: The third-party generation provider (e.g. "fal", "replicate"). + pub maybe_generation_provider: Option, } /// Pull common parts out of multipart media HTTP requests, typically for handling file uploads. @@ -37,6 +41,7 @@ pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> Anyhow let mut visibility = None; let mut maybe_engine_category = None; let mut maybe_animation_type = None; + let mut generation_provider = None; while let Ok(Some(mut field)) = multipart_payload.try_next().await { let mut field_name = None; @@ -105,10 +110,21 @@ pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> Anyhow e })?; }, + Some("maybe_generation_provider") => { + generation_provider = read_multipart_field_as_text(&mut field).await + .map_err(|e| { + warn!("Error reading maybe_generation_provider: {:}", &e); + e + })?; + }, _ => continue, } } + let maybe_generation_provider = generation_provider.as_deref() + .map(|s| try_parse_generation_provider(s)) + .flatten(); + Ok(MediaFileUploadData { uuid_idempotency_token, file_name, @@ -117,5 +133,6 @@ pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> Anyhow maybe_visibility: visibility, maybe_engine_category, maybe_animation_type, + maybe_generation_provider, }) } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_engine_asset/upload_engine_asset_media_file_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_engine_asset/upload_engine_asset_media_file_handler.rs index 34967427e3..0a614c3837 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_engine_asset/upload_engine_asset_media_file_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_engine_asset/upload_engine_asset_media_file_handler.rs @@ -221,7 +221,7 @@ pub async fn upload_engine_asset_media_file_handler( maybe_title: upload_media_request.maybe_title.as_deref(), maybe_scene_source_media_file_token: None, is_intermediate_system_file: false, // NB: is_user_upload = TRUE - maybe_generation_provider: None, + maybe_generation_provider: upload_media_request.maybe_generation_provider, public_bucket_directory_hash: public_upload_path.get_object_hash(), maybe_public_bucket_prefix: PREFIX, maybe_public_bucket_extension: Some(suffix), diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_new_engine_asset_media_file_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_new_engine_asset_media_file_handler.rs index a51cf01a46..eac54e2848 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_new_engine_asset_media_file_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_new_engine_asset_media_file_handler.rs @@ -22,7 +22,7 @@ use mysql_queries::queries::idepotency_tokens::insert_idempotency_token::insert_ use mysql_queries::queries::media_files::create::specialized_insert::insert_media_file_from_file_upload::{insert_media_file_from_file_upload, InsertMediaFileFromUploadArgs, UploadType}; use mysql_queries::queries::users::user_sessions::get_user_session_by_token::SessionUserRecord; use tokens::tokens::media_files::MediaFileToken; - +use crate::http_server::endpoints::media_files::upload::common_utils::try_parse_generation_provider::try_parse_generation_provider; use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError; use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format; use crate::state::server_state::ServerState; @@ -70,6 +70,12 @@ pub struct UploadNewEngineAssetFileForm { #[multipart(limit = "2 KiB")] #[schema(value_type = Option, format = Binary)] maybe_duration_millis: Option>, + + /// Optional: The third-party generation provider (e.g. "fal", "replicate"). + /// If set, `is_user_upload` will be false and `is_intermediate_system_file` will be forced false. + #[multipart(limit = "2 KiB")] + #[schema(value_type = Option, format = Binary)] + maybe_generation_provider: Option>, } #[derive(Serialize, ToSchema)] @@ -177,6 +183,10 @@ pub async fn upload_new_engine_asset_media_file_handler( // ==================== FILE DATA ==================== // + let maybe_generation_provider = form.maybe_generation_provider + .as_ref() + .and_then(|text| try_parse_generation_provider(text.as_ref())); + let file_info = validate_and_process_form(maybe_user_session.as_ref(), form)?; // ==================== UPLOAD AND SAVE ==================== // @@ -216,7 +226,7 @@ pub async fn upload_new_engine_asset_media_file_handler( sha256_checksum: &file_info.sha256_checksum, maybe_scene_source_media_file_token: None, is_intermediate_system_file: false, // NB: is_user_upload = TRUE - maybe_generation_provider: None, + maybe_generation_provider, maybe_title: file_info.maybe_title.as_deref(), public_bucket_directory_hash: public_upload_path.get_object_hash(), maybe_public_bucket_prefix: PREFIX, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_spz_media_file_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_spz_media_file_handler.rs index c2552cb21d..11a91f4b68 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_spz_media_file_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_spz_media_file_handler.rs @@ -248,8 +248,7 @@ pub async fn upload_spz_media_file_handler( MediaFileUploadError::ServerError })?; - // TODO: Pass maybe_generation_provider to MediaFileInsertBuilder once it supports it. - let _maybe_generation_provider = form.maybe_generation_provider + let maybe_generation_provider = form.maybe_generation_provider .as_ref() .and_then(|text| try_parse_generation_provider(text.as_ref())); @@ -268,6 +267,7 @@ pub async fn upload_spz_media_file_handler( .is_intermediate_system_file(false) .public_bucket_directory_hash(&public_upload_path) .maybe_origin_filename(form.file.file_name.as_deref()) + .maybe_generation_provider(maybe_generation_provider) .insert_pool(&server_state.mysql_pool) .await .map_err(|err| {