mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-29 21:12:52 -04:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
436f368c35 | ||
|
|
b9e54702fd | ||
|
|
460f475f7c | ||
|
|
98a617569b | ||
|
|
a75080b650 | ||
|
|
5224f90b57 |
+3
-3
@@ -1,12 +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 is_intermediate_system_file = ?,\n\n maybe_creator_file_synthetic_id = ?,\n maybe_creator_category_synthetic_id = ?,\n\n is_user_upload = TRUE,\n\n maybe_origin_model_type = NULL,\n maybe_origin_model_token = NULL\n ",
|
||||
"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": 25
|
||||
"Right": 27
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "8d6c1f608ec25a74dddf375d525c3e30467c5eba5389094401b74b7dc74552d7"
|
||||
"hash": "7369b2f3fd9e7c1e968dc5501ef9bea7e1610fd7a044a0f9ad8b908dfada2b6a"
|
||||
}
|
||||
+3
-3
@@ -1,12 +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_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 ",
|
||||
"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": 40
|
||||
"Right": 41
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "87d5511700985daaabfc9f2972f018d56b6672c07be082daa7c1a782400cb18d"
|
||||
"hash": "a4901f904aa1c00d9afc23faa7008816c6e1b653bd6ad9f0b6772e32000be544"
|
||||
}
|
||||
@@ -28,6 +28,7 @@ CREATE TABLE media_files (
|
||||
-- There is an index on this column.
|
||||
-- Broad "category" for where the file came from:
|
||||
-- * 'inference' for inference output
|
||||
-- * 'inference_third' for inference output
|
||||
-- * 'processed' for processed file (eg. mp3 encoding, stem splitting, etc.)
|
||||
-- * 'upload' for direct user upload (from the filesystem)
|
||||
-- * 'device_api' for direct user uploads recorded using Browser/Device APIs.
|
||||
|
||||
+27
-3
@@ -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<GenerationProvider>,
|
||||
|
||||
// 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,
|
||||
|
||||
+1
@@ -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,
|
||||
|
||||
+31
-7
@@ -9,6 +9,7 @@ use enums::by_table::media_files::media_file_origin_product_category::MediaFileO
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use sqlx::MySqlPool;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken;
|
||||
use tokens::tokens::batch_generations::BatchGenerationToken;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
@@ -79,7 +80,8 @@ pub struct MediaFileInsertBuilder {
|
||||
// Storage details
|
||||
public_bucket_directory_hash: Option<MediaFileBucketPath>, // NB: Non-nullable field(s)
|
||||
|
||||
// Remaining fields...
|
||||
// Generation details
|
||||
maybe_generation_provider: Option<GenerationProvider>,
|
||||
}
|
||||
|
||||
impl MediaFileInsertBuilder {
|
||||
@@ -113,6 +115,7 @@ impl MediaFileInsertBuilder {
|
||||
maybe_cover_image_media_file_token: None,
|
||||
public_bucket_directory_hash: None,
|
||||
maybe_prompt_token: None,
|
||||
maybe_generation_provider: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,16 +267,17 @@ impl MediaFileInsertBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn maybe_generation_provider(mut self, maybe_generation_provider: Option<GenerationProvider>) -> Self {
|
||||
self.maybe_generation_provider = maybe_generation_provider;
|
||||
self
|
||||
}
|
||||
|
||||
// TODO(bt,2025-04-26): Other connector options.
|
||||
pub async fn insert_pool(self, mysql_pool: &MySqlPool) -> Result<MediaFileToken, MediaFileInsertBuilderError> {
|
||||
let media_file_type = self.media_file_type
|
||||
.ok_or_else(|| MediaFileInsertBuilderError::MissingRequiredField(
|
||||
"Media file type is required".to_string()))?;
|
||||
|
||||
let origin_category = self.origin_category
|
||||
.ok_or_else(|| MediaFileInsertBuilderError::MissingRequiredField(
|
||||
"Origin category is required".to_string()))?;
|
||||
|
||||
let checksum_sha2 = self.checksum_sha2
|
||||
.ok_or_else(|| MediaFileInsertBuilderError::MissingRequiredField(
|
||||
"Checksum SHA2 is required".to_string()))?;
|
||||
@@ -281,6 +285,25 @@ impl MediaFileInsertBuilder {
|
||||
let bucket_path = self.public_bucket_directory_hash
|
||||
.ok_or_else(|| MediaFileInsertBuilderError::MissingRequiredField(
|
||||
"Public bucket directory hash is required".to_string()))?;
|
||||
|
||||
let mut origin_category = self.origin_category
|
||||
.ok_or_else(|| MediaFileInsertBuilderError::MissingRequiredField(
|
||||
"Origin category is required".to_string()))?;
|
||||
|
||||
let mut maybe_generation_provider_str = None;
|
||||
let mut is_intermediate_system_file = self.is_intermediate_system_file;
|
||||
let mut is_user_upload = self.is_user_upload;
|
||||
|
||||
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;
|
||||
if generation_provider != GenerationProvider::Artcraft {
|
||||
origin_category = MediaFileOriginCategory::ThirdPartyInference;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let result = insert_media_file_generic(InsertArgs {
|
||||
pool: mysql_pool,
|
||||
@@ -290,8 +313,8 @@ impl MediaFileInsertBuilder {
|
||||
creator_set_visibility: self.creator_set_visibility,
|
||||
media_class: self.media_file_class,
|
||||
media_type: media_file_type,
|
||||
is_user_upload: self.is_user_upload,
|
||||
is_intermediate_system_file: self.is_intermediate_system_file,
|
||||
is_user_upload,
|
||||
is_intermediate_system_file,
|
||||
origin_category,
|
||||
origin_product_category: self.origin_product_category,
|
||||
maybe_origin_model_type: None, // TODO
|
||||
@@ -317,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
|
||||
|
||||
+1
@@ -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?;
|
||||
|
||||
|
||||
+31
-4
@@ -9,6 +9,7 @@ use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCat
|
||||
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
|
||||
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;
|
||||
@@ -20,6 +21,7 @@ use tokens::tokens::users::UserToken;
|
||||
use crate::queries::generic_synthetic_ids::transactional_increment_generic_synthetic_id::transactional_increment_generic_synthetic_id;
|
||||
|
||||
pub enum UploadType {
|
||||
ThirdPartyInference,
|
||||
Filesystem,
|
||||
DeviceCaptureApi,
|
||||
StorytellerEngine,
|
||||
@@ -54,6 +56,10 @@ pub struct InsertMediaFileFromUploadArgs<'a> {
|
||||
pub maybe_scene_source_media_file_token: Option<&'a MediaFileToken>,
|
||||
pub is_intermediate_system_file: bool,
|
||||
|
||||
/// If provided, the third-party provider that generated this file.
|
||||
/// When set, `is_user_upload` and `is_intermediate_system_file` will be set to false.
|
||||
pub maybe_generation_provider: Option<GenerationProvider>,
|
||||
|
||||
pub public_bucket_directory_hash: &'a str,
|
||||
pub maybe_public_bucket_prefix: Option<&'a str>,
|
||||
pub maybe_public_bucket_extension: Option<&'a str>,
|
||||
@@ -65,12 +71,27 @@ pub async fn insert_media_file_from_file_upload(
|
||||
{
|
||||
let token = MediaFileToken::generate();
|
||||
|
||||
let origin_category = match args.upload_type {
|
||||
let mut origin_category = match args.upload_type {
|
||||
UploadType::ThirdPartyInference => MediaFileOriginCategory::ThirdPartyInference,
|
||||
UploadType::Filesystem => MediaFileOriginCategory::Upload,
|
||||
UploadType::DeviceCaptureApi => MediaFileOriginCategory::DeviceApi,
|
||||
UploadType::StorytellerEngine => MediaFileOriginCategory::StorytellerStudio,
|
||||
};
|
||||
|
||||
let mut maybe_generation_provider_str = None;
|
||||
let mut is_intermediate_system_file = args.is_intermediate_system_file;
|
||||
let mut is_user_upload = true;
|
||||
|
||||
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 maybe_creator_file_synthetic_id : Option<u64> = None;
|
||||
let mut maybe_creator_category_synthetic_id : Option<u64> = None;
|
||||
|
||||
@@ -134,13 +155,15 @@ SET
|
||||
creator_set_visibility = ?,
|
||||
|
||||
maybe_scene_source_media_file_token = ?,
|
||||
|
||||
is_intermediate_system_file = ?,
|
||||
is_user_upload = ?,
|
||||
|
||||
maybe_generation_provider = ?,
|
||||
|
||||
maybe_creator_file_synthetic_id = ?,
|
||||
maybe_creator_category_synthetic_id = ?,
|
||||
|
||||
is_user_upload = TRUE,
|
||||
|
||||
maybe_origin_model_type = NULL,
|
||||
maybe_origin_model_token = NULL
|
||||
"#,
|
||||
@@ -180,7 +203,11 @@ SET
|
||||
args.creator_set_visibility.to_str(),
|
||||
|
||||
args.maybe_scene_source_media_file_token.map(|t| t.as_str()),
|
||||
args.is_intermediate_system_file,
|
||||
|
||||
is_intermediate_system_file,
|
||||
is_user_upload,
|
||||
|
||||
maybe_generation_provider_str,
|
||||
|
||||
maybe_creator_file_synthetic_id,
|
||||
maybe_creator_category_synthetic_id,
|
||||
|
||||
@@ -18,6 +18,11 @@ pub enum MediaFileOriginCategory {
|
||||
/// ML model inference output - uploaded models or zero shot.
|
||||
Inference,
|
||||
|
||||
/// Third-party inference output (e.g. FAL, Replicate).
|
||||
/// The file was generated by a third-party AI service and uploaded by the client.
|
||||
#[serde(rename = "inference3rd")]
|
||||
ThirdPartyInference,
|
||||
|
||||
/// Processed results - (we don't have these systems yet, but eg. trim, transcode, etc).
|
||||
Processed,
|
||||
|
||||
@@ -47,6 +52,7 @@ impl MediaFileOriginCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Inference => "inference",
|
||||
Self::ThirdPartyInference => "inference3rd",
|
||||
Self::Processed => "processed",
|
||||
Self::Upload => "upload",
|
||||
Self::DeviceApi => "device_api",
|
||||
@@ -58,6 +64,7 @@ impl MediaFileOriginCategory {
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"inference" => Ok(Self::Inference),
|
||||
"inference3rd" => Ok(Self::ThirdPartyInference),
|
||||
"processed" => Ok(Self::Processed),
|
||||
"upload" => Ok(Self::Upload),
|
||||
"device_api" => Ok(Self::DeviceApi),
|
||||
@@ -68,10 +75,9 @@ impl MediaFileOriginCategory {
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Inference,
|
||||
Self::ThirdPartyInference,
|
||||
Self::Processed,
|
||||
Self::Upload,
|
||||
Self::DeviceApi,
|
||||
@@ -92,6 +98,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileOriginCategory::Inference, "inference");
|
||||
assert_serialization(MediaFileOriginCategory::ThirdPartyInference, "inference3rd");
|
||||
assert_serialization(MediaFileOriginCategory::Processed, "processed");
|
||||
assert_serialization(MediaFileOriginCategory::Upload, "upload");
|
||||
assert_serialization(MediaFileOriginCategory::DeviceApi, "device_api");
|
||||
@@ -102,6 +109,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(MediaFileOriginCategory::Inference.to_str(), "inference");
|
||||
assert_eq!(MediaFileOriginCategory::ThirdPartyInference.to_str(), "inference3rd");
|
||||
assert_eq!(MediaFileOriginCategory::Processed.to_str(), "processed");
|
||||
assert_eq!(MediaFileOriginCategory::Upload.to_str(), "upload");
|
||||
assert_eq!(MediaFileOriginCategory::DeviceApi.to_str(), "device_api");
|
||||
@@ -112,6 +120,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(MediaFileOriginCategory::from_str("inference").unwrap(), MediaFileOriginCategory::Inference);
|
||||
assert_eq!(MediaFileOriginCategory::from_str("inference3rd").unwrap(), MediaFileOriginCategory::ThirdPartyInference);
|
||||
assert_eq!(MediaFileOriginCategory::from_str("processed").unwrap(), MediaFileOriginCategory::Processed);
|
||||
assert_eq!(MediaFileOriginCategory::from_str("upload").unwrap(), MediaFileOriginCategory::Upload);
|
||||
assert_eq!(MediaFileOriginCategory::from_str("device_api").unwrap(), MediaFileOriginCategory::DeviceApi);
|
||||
@@ -123,8 +132,9 @@ mod tests {
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileOriginCategory::all_variants();
|
||||
assert_eq!(variants.len(), 6);
|
||||
assert_eq!(variants.len(), 7);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::Inference));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::ThirdPartyInference));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::Processed));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::Upload));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::DeviceApi));
|
||||
|
||||
+1
@@ -213,6 +213,7 @@ pub async fn create_scene_handler(
|
||||
maybe_title: upload_media_request.title.as_deref(),
|
||||
maybe_scene_source_media_file_token: None,
|
||||
is_intermediate_system_file: false,
|
||||
maybe_generation_provider: None,
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
maybe_public_bucket_extension: SUFFIX,
|
||||
|
||||
+1
@@ -341,6 +341,7 @@ pub async fn process_upload_media_file(
|
||||
maybe_title: upload_media_request.title.as_deref(),
|
||||
maybe_scene_source_media_file_token: None,
|
||||
is_intermediate_system_file: false,
|
||||
maybe_generation_provider: None,
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
maybe_public_bucket_extension: extension.as_deref(),
|
||||
|
||||
+1
@@ -255,6 +255,7 @@ pub async fn upload_snapshot_media_file_handler(
|
||||
maybe_title: Some("Snapshot"),
|
||||
maybe_scene_source_media_file_token: None,
|
||||
is_intermediate_system_file: true,
|
||||
maybe_generation_provider: None,
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
maybe_public_bucket_extension: Some(&extension),
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
pub mod try_parse_generation_provider;
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use log::warn;
|
||||
|
||||
/// Try to parse a generation provider from a string value.
|
||||
/// Fails open: returns None if parsing fails, but logs a warning.
|
||||
pub fn try_parse_generation_provider(value: &str) -> Option<GenerationProvider> {
|
||||
let trimmed = value.trim();
|
||||
if trimmed.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match GenerationProvider::from_str(trimmed) {
|
||||
Ok(provider) => Some(provider),
|
||||
Err(_) => {
|
||||
warn!("Could not parse generation provider: {:?}", trimmed);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parses_known_providers() {
|
||||
assert_eq!(try_parse_generation_provider("fal"), Some(GenerationProvider::Fal));
|
||||
assert_eq!(try_parse_generation_provider("artcraft"), Some(GenerationProvider::Artcraft));
|
||||
assert_eq!(try_parse_generation_provider("grok"), Some(GenerationProvider::Grok));
|
||||
assert_eq!(try_parse_generation_provider("midjourney"), Some(GenerationProvider::Midjourney));
|
||||
assert_eq!(try_parse_generation_provider("sora"), Some(GenerationProvider::Sora));
|
||||
assert_eq!(try_parse_generation_provider("world_labs"), Some(GenerationProvider::WorldLabs));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trims_whitespace() {
|
||||
assert_eq!(try_parse_generation_provider(" fal "), Some(GenerationProvider::Fal));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_none_for_empty() {
|
||||
assert_eq!(try_parse_generation_provider(""), None);
|
||||
assert_eq!(try_parse_generation_provider(" "), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_none_for_unknown() {
|
||||
assert_eq!(try_parse_generation_provider("unknown_provider"), None);
|
||||
assert_eq!(try_parse_generation_provider("DALL-E"), None);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod common_utils;
|
||||
pub mod upload_audio_media_file_handler;
|
||||
pub mod upload_engine_asset;
|
||||
pub mod upload_error;
|
||||
|
||||
+19
-1
@@ -26,6 +26,7 @@ use mysql_queries::queries::media_files::create::specialized_insert::insert_medi
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError;
|
||||
use crate::http_server::endpoints::media_files::upload::common_utils::try_parse_generation_provider::try_parse_generation_provider;
|
||||
use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format;
|
||||
use crate::state::server_state::ServerState;
|
||||
|
||||
@@ -55,6 +56,12 @@ pub struct UploadAudioMediaFileForm {
|
||||
#[multipart(limit = "2 KiB")]
|
||||
#[schema(value_type = Option<Visibility>, format = Binary)]
|
||||
maybe_visibility: Option<Text<Visibility>>,
|
||||
|
||||
/// 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<String>, format = Binary)]
|
||||
maybe_generation_provider: Option<Text<String>>,
|
||||
}
|
||||
|
||||
// Unlike the "upload" endpoints, which are pure inserts, these endpoints are *upserts*.
|
||||
@@ -314,6 +321,16 @@ pub async fn upload_audio_media_file_handler(
|
||||
MediaFileUploadError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_generation_provider = form.maybe_generation_provider
|
||||
.as_ref()
|
||||
.and_then(|text| try_parse_generation_provider(text.as_ref()));
|
||||
|
||||
let upload_type = if maybe_generation_provider.is_some() {
|
||||
UploadType::ThirdPartyInference
|
||||
} else {
|
||||
UploadType::Filesystem
|
||||
};
|
||||
|
||||
let (token, record_id) = insert_media_file_from_file_upload(InsertMediaFileFromUploadArgs {
|
||||
maybe_media_class: Some(MediaFileClass::Audio),
|
||||
media_file_type: MediaFileType::Audio,
|
||||
@@ -321,7 +338,7 @@ pub async fn upload_audio_media_file_handler(
|
||||
maybe_creator_anonymous_visitor_token: maybe_avt_token.as_ref(),
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility,
|
||||
upload_type: UploadType::Filesystem, // TODO(bt,2024-05-02): This should be a parameter and a well-known enum.
|
||||
upload_type,
|
||||
maybe_engine_category: None,
|
||||
maybe_animation_type: None,
|
||||
maybe_prompt_token: None,
|
||||
@@ -333,6 +350,7 @@ pub async fn upload_audio_media_file_handler(
|
||||
maybe_title: maybe_title.as_deref(),
|
||||
maybe_scene_source_media_file_token: None,
|
||||
is_intermediate_system_file: false, // NB: is_user_upload = true
|
||||
maybe_generation_provider,
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
maybe_public_bucket_extension: Some(&extension),
|
||||
|
||||
+18
-1
@@ -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<MediaFileAnimationType>,
|
||||
|
||||
// Optional: The third-party generation provider (e.g. "fal", "replicate").
|
||||
pub maybe_generation_provider: Option<GenerationProvider>,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
})
|
||||
}
|
||||
|
||||
+1
@@ -221,6 +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: 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),
|
||||
|
||||
+23
-7
@@ -1,12 +1,12 @@
|
||||
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};
|
||||
use actix_multipart::Multipart;
|
||||
use actix_web::web::BytesMut;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use errors::AnyhowResult;
|
||||
use futures::TryStreamExt;
|
||||
use log::warn;
|
||||
|
||||
use errors::AnyhowResult;
|
||||
|
||||
use crate::http_server::web_utils::read_multipart_field_bytes::{checked_read_multipart_bytes, read_multipart_field_as_text};
|
||||
|
||||
pub struct MediaFileUploadData {
|
||||
pub uuid_idempotency_token: Option<String>,
|
||||
pub file_name: Option<String>,
|
||||
@@ -18,6 +18,9 @@ pub struct MediaFileUploadData {
|
||||
|
||||
// Optional: visibility
|
||||
pub visibility: Option<String>,
|
||||
|
||||
// Optional: The third-party generation provider (e.g. "fal", "replicate").
|
||||
pub maybe_generation_provider: Option<GenerationProvider>,
|
||||
}
|
||||
|
||||
/// Where the frontend tells us the file came from.
|
||||
@@ -38,6 +41,7 @@ pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> Anyhow
|
||||
let mut media_source = None;
|
||||
let mut title = None;
|
||||
let mut visibility = None;
|
||||
let mut generation_provider = None;
|
||||
|
||||
while let Ok(Some(mut field)) = multipart_payload.try_next().await {
|
||||
let mut field_name = None;
|
||||
@@ -54,7 +58,7 @@ pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> Anyhow
|
||||
Some("uuid_idempotency_token") => {
|
||||
uuid_idempotency_token = read_multipart_field_as_text(&mut field).await
|
||||
.map_err(|e| {
|
||||
warn!("Error reading idempotency token: {:}", &e);
|
||||
warn!("Error reading uuid_idempotency_token: {:}", &e);
|
||||
e
|
||||
})?;
|
||||
},
|
||||
@@ -62,7 +66,7 @@ pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> Anyhow
|
||||
file_name = field_filename.clone();
|
||||
file_bytes = checked_read_multipart_bytes(&mut field).await
|
||||
.map_err(|e| {
|
||||
warn!("Error reading audio upload: {:}", &e);
|
||||
warn!("Error reading file: {:}", &e);
|
||||
e
|
||||
})?;
|
||||
},
|
||||
@@ -83,7 +87,14 @@ pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> Anyhow
|
||||
Some("visibility") => {
|
||||
visibility = read_multipart_field_as_text(&mut field).await
|
||||
.map_err(|e| {
|
||||
warn!("Error reading title: {:}", &e);
|
||||
warn!("Error reading visibility: {:}", &e);
|
||||
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
|
||||
})?;
|
||||
},
|
||||
@@ -103,6 +114,10 @@ pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> Anyhow
|
||||
},
|
||||
};
|
||||
|
||||
let maybe_generation_provider = generation_provider.as_deref()
|
||||
.map(|s| try_parse_generation_provider(s))
|
||||
.flatten();
|
||||
|
||||
Ok(MediaFileUploadData {
|
||||
uuid_idempotency_token,
|
||||
file_name,
|
||||
@@ -110,5 +125,6 @@ pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> Anyhow
|
||||
media_source,
|
||||
title,
|
||||
visibility,
|
||||
maybe_generation_provider,
|
||||
})
|
||||
}
|
||||
|
||||
+1
@@ -405,6 +405,7 @@ pub async fn process_upload_media_file(
|
||||
.checksum_sha2(&hash)
|
||||
.maybe_title(upload_media_request.title.as_deref())
|
||||
.maybe_origin_filename(upload_media_request.file_name.as_deref())
|
||||
.maybe_generation_provider(upload_media_request.maybe_generation_provider)
|
||||
.is_intermediate_system_file(false)
|
||||
.insert_pool(&server_state.mysql_pool)
|
||||
.await
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ static ALLOWED_MIME_TYPES : Lazy<HashSet<&'static str>> = Lazy::new(|| {
|
||||
});
|
||||
|
||||
/// DEPRECATED: Use one of the various specialized upload endpoints instead.
|
||||
/// TODO: Does not support `maybe_generation_provider`. Use the specialized upload endpoints instead.
|
||||
#[deprecated]
|
||||
#[utoipa::path(
|
||||
post,
|
||||
|
||||
+20
-2
@@ -13,6 +13,7 @@ use once_cell::sync::Lazy;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError;
|
||||
use crate::http_server::endpoints::media_files::upload::common_utils::try_parse_generation_provider::try_parse_generation_provider;
|
||||
use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format;
|
||||
use crate::state::server_state::ServerState;
|
||||
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
|
||||
@@ -72,6 +73,12 @@ pub struct UploadImageMediaFileForm {
|
||||
#[multipart(limit = "2 KiB")]
|
||||
#[schema(value_type = Option<bool>, format = Binary)]
|
||||
is_intermediate_system_file: Option<Text<bool>>,
|
||||
|
||||
/// 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<String>, format = Binary)]
|
||||
maybe_generation_provider: Option<Text<String>>,
|
||||
}
|
||||
|
||||
// Unlike the "upload" endpoints, which are pure inserts, these endpoints are *upserts*.
|
||||
@@ -282,6 +289,16 @@ pub async fn upload_image_media_file_handler(
|
||||
.as_ref()
|
||||
.map(|token| token.0.clone());
|
||||
|
||||
let maybe_generation_provider = form.maybe_generation_provider
|
||||
.as_ref()
|
||||
.and_then(|text| try_parse_generation_provider(text.as_ref()));
|
||||
|
||||
let upload_type = if maybe_generation_provider.is_some() {
|
||||
UploadType::ThirdPartyInference
|
||||
} else {
|
||||
UploadType::Filesystem
|
||||
};
|
||||
|
||||
let (token, record_id) = insert_media_file_from_file_upload(InsertMediaFileFromUploadArgs {
|
||||
maybe_media_class: Some(MediaFileClass::Image),
|
||||
media_file_type: MediaFileType::Image,
|
||||
@@ -289,7 +306,7 @@ pub async fn upload_image_media_file_handler(
|
||||
maybe_creator_anonymous_visitor_token: maybe_avt_token.as_ref(),
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility,
|
||||
upload_type: UploadType::Filesystem, // TODO(bt,2024-05-02): This should be a parameter and a well-known enum.
|
||||
upload_type,
|
||||
maybe_engine_category: None,
|
||||
maybe_animation_type: None,
|
||||
maybe_mime_type: Some(&mimetype),
|
||||
@@ -300,7 +317,8 @@ pub async fn upload_image_media_file_handler(
|
||||
sha256_checksum: &hash,
|
||||
maybe_title: maybe_title.as_deref(),
|
||||
maybe_scene_source_media_file_token: None,
|
||||
is_intermediate_system_file, // NB: is_user_upload = TRUE
|
||||
is_intermediate_system_file,
|
||||
maybe_generation_provider,
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
maybe_public_bucket_extension: Some(&extension),
|
||||
|
||||
+12
-1
@@ -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<u64>, format = Binary)]
|
||||
maybe_duration_millis: Option<Text<u64>>,
|
||||
|
||||
/// 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<String>, format = Binary)]
|
||||
maybe_generation_provider: Option<Text<String>>,
|
||||
}
|
||||
|
||||
#[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,6 +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,
|
||||
maybe_title: file_info.maybe_title.as_deref(),
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
|
||||
+1
@@ -242,6 +242,7 @@ pub async fn upload_new_scene_media_file_handler(
|
||||
maybe_title: 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,
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
maybe_public_bucket_extension: Some(SUFFIX),
|
||||
|
||||
+1
@@ -272,6 +272,7 @@ pub async fn upload_pmx_media_file_handler(
|
||||
sha256_checksum: &pmx_details.sha256_checksum,
|
||||
maybe_scene_source_media_file_token: None,
|
||||
is_intermediate_system_file: false, // NB: is_user_upload = TRUE
|
||||
maybe_generation_provider: None,
|
||||
maybe_title: maybe_title.as_deref(),
|
||||
public_bucket_directory_hash: pmx_details.pmx_public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
|
||||
+1
@@ -236,6 +236,7 @@ pub async fn upload_scene_snapshot_media_file_handler(
|
||||
maybe_scene_source_media_file_token: maybe_scene_source_media_file_token.as_ref(),
|
||||
// NB: is_user_upload = TRUE
|
||||
is_intermediate_system_file: true, // NB: This is a snapshot, so we shouldn't show it off in lists.
|
||||
maybe_generation_provider: None,
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
maybe_public_bucket_extension: Some(SUFFIX),
|
||||
|
||||
+11
@@ -24,6 +24,7 @@ use mysql_queries::queries::media_files::create::specialized_insert::insert_medi
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError;
|
||||
use crate::http_server::endpoints::media_files::upload::common_utils::try_parse_generation_provider::try_parse_generation_provider;
|
||||
use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format;
|
||||
use crate::state::server_state::ServerState;
|
||||
|
||||
@@ -56,6 +57,11 @@ pub struct UploadSpzMediaFileForm {
|
||||
#[multipart(limit = "2 KiB")]
|
||||
#[schema(value_type = Option<String>, format = Binary)]
|
||||
maybe_visibility: Option<Text<Visibility>>,
|
||||
|
||||
/// Optional: The third-party generation provider (e.g. "fal", "replicate").
|
||||
#[multipart(limit = "2 KiB")]
|
||||
#[schema(value_type = Option<String>, format = Binary)]
|
||||
maybe_generation_provider: Option<Text<String>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
@@ -242,6 +248,10 @@ pub async fn upload_spz_media_file_handler(
|
||||
MediaFileUploadError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_generation_provider = form.maybe_generation_provider
|
||||
.as_ref()
|
||||
.and_then(|text| try_parse_generation_provider(text.as_ref()));
|
||||
|
||||
let media_token = MediaFileInsertBuilder::new()
|
||||
.media_file_class(MediaFileClass::Dimensional)
|
||||
.media_file_type(MediaFileType::Spz)
|
||||
@@ -257,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| {
|
||||
|
||||
+19
-1
@@ -33,6 +33,7 @@ use tokens::tokens::media_files::MediaFileToken;
|
||||
use tokens::tokens::prompts::PromptToken;
|
||||
|
||||
use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError;
|
||||
use crate::http_server::endpoints::media_files::upload::common_utils::try_parse_generation_provider::try_parse_generation_provider;
|
||||
use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format;
|
||||
use crate::state::server_state::ServerState;
|
||||
|
||||
@@ -99,6 +100,12 @@ pub struct UploadNewVideoMediaFileForm {
|
||||
#[multipart(limit = "2 KiB")]
|
||||
#[schema(value_type = Option<u64>, format = Binary)]
|
||||
maybe_resample_fps: Option<Text<u8>>,
|
||||
|
||||
/// 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<String>, format = Binary)]
|
||||
maybe_generation_provider: Option<Text<String>>,
|
||||
}
|
||||
|
||||
// Unlike the "upload" endpoints, which are pure inserts, these endpoints are *upserts*.
|
||||
@@ -487,6 +494,16 @@ pub async fn upload_new_video_media_file_handler(
|
||||
maybe_scene_source_media_file_token.is_some() ||
|
||||
form.is_intermediate_system_file.map(|b| b.0).unwrap_or(false);
|
||||
|
||||
let maybe_generation_provider = form.maybe_generation_provider
|
||||
.as_ref()
|
||||
.and_then(|text| try_parse_generation_provider(text.as_ref()));
|
||||
|
||||
let upload_type = if maybe_generation_provider.is_some() {
|
||||
UploadType::ThirdPartyInference
|
||||
} else {
|
||||
UploadType::Filesystem
|
||||
};
|
||||
|
||||
let (token, record_id) = insert_media_file_from_file_upload(InsertMediaFileFromUploadArgs {
|
||||
maybe_media_class: Some(MediaFileClass::Video),
|
||||
media_file_type: MediaFileType::Video,
|
||||
@@ -494,7 +511,7 @@ pub async fn upload_new_video_media_file_handler(
|
||||
maybe_creator_anonymous_visitor_token: maybe_avt_token.as_ref(),
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility,
|
||||
upload_type: UploadType::Filesystem, // TODO(bt,2024-05-02): This should be a parameter and a well-known enum.
|
||||
upload_type,
|
||||
maybe_engine_category: None,
|
||||
maybe_animation_type: None,
|
||||
maybe_prompt_token: maybe_prompt_token.as_ref(),
|
||||
@@ -506,6 +523,7 @@ pub async fn upload_new_video_media_file_handler(
|
||||
maybe_title: maybe_title.as_deref(),
|
||||
maybe_scene_source_media_file_token,
|
||||
is_intermediate_system_file, // NB: is_user_upload = TRUE
|
||||
maybe_generation_provider,
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
maybe_public_bucket_extension: Some(&extension),
|
||||
|
||||
+1
@@ -237,6 +237,7 @@ pub async fn upload_video_media_file_handler(
|
||||
maybe_title: upload_media_request.title.as_deref(),
|
||||
maybe_scene_source_media_file_token: None,
|
||||
is_intermediate_system_file: false, // NB: is_user_upload = TRUE
|
||||
maybe_generation_provider: None,
|
||||
public_bucket_directory_hash: public_upload_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: PREFIX,
|
||||
maybe_public_bucket_extension: Some(&extension),
|
||||
|
||||
Reference in New Issue
Block a user