mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-20 17:02:53 -04:00
Fix cover images (#1773)
This commit is contained in:
+12
@@ -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 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 platform_type = ?,\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": "f5bc4a956a20f6c0998585092a0922301d53c95ae8ea9cb808ae2dbcf8d0bb32"
|
||||
}
|
||||
+50
-143
@@ -1,5 +1,4 @@
|
||||
use anyhow::anyhow;
|
||||
use sqlx;
|
||||
use sqlx::MySqlPool;
|
||||
|
||||
use enums::by_table::generic_synthetic_ids::id_category::IdCategory;
|
||||
@@ -22,6 +21,7 @@ use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::payloads::media_file_extra_info::media_file_extra_info::MediaFileExtraInfo;
|
||||
use crate::queries::generic_synthetic_ids::transactional_increment_generic_synthetic_id::transactional_increment_generic_synthetic_id;
|
||||
use crate::queries::media_files::create::generic_insert::insert_media_file_generic_executor::{insert_media_file_generic_executor, InsertMediaFileGenericExecutorArgs};
|
||||
|
||||
pub struct InsertArgs<'a> {
|
||||
pub pool: &'a MySqlPool,
|
||||
@@ -54,7 +54,7 @@ pub struct InsertArgs<'a> {
|
||||
pub maybe_frame_width: Option<u32>,
|
||||
pub maybe_frame_height: Option<u32>,
|
||||
pub checksum_sha2: &'a str,
|
||||
|
||||
|
||||
// Media info for certain product areas
|
||||
pub maybe_engine_category: Option<MediaFileEngineCategory>, // TODO: Deprecate
|
||||
|
||||
@@ -104,12 +104,13 @@ pub struct InsertArgs<'a> {
|
||||
pub maybe_mod_user_token: Option<&'a UserToken>,
|
||||
}
|
||||
|
||||
/// Insert a media file record, allocating the creator's synthetic IDs in the
|
||||
/// same transaction. Wraps [`insert_media_file_generic_executor`], which runs
|
||||
/// the actual INSERT.
|
||||
pub async fn insert_media_file_generic(
|
||||
args: InsertArgs<'_>
|
||||
) -> AnyhowResult<(MediaFileToken, u64)>
|
||||
{
|
||||
let result_token = MediaFileToken::generate();
|
||||
|
||||
let extra_file_modification_info = args
|
||||
.maybe_extra_media_info.map(|extra| extra.to_json_string())
|
||||
.transpose()?;
|
||||
@@ -117,24 +118,8 @@ pub async fn insert_media_file_generic(
|
||||
let mut maybe_creator_file_synthetic_id : Option<u64> = None;
|
||||
let mut maybe_creator_category_synthetic_id : Option<u64> = None;
|
||||
|
||||
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() {
|
||||
let next_media_file_id = transactional_increment_generic_synthetic_id(
|
||||
user_token,
|
||||
@@ -152,131 +137,53 @@ pub async fn insert_media_file_generic(
|
||||
maybe_creator_category_synthetic_id = Some(category_id);
|
||||
}
|
||||
|
||||
let query_result = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO media_files
|
||||
SET
|
||||
token = ?,
|
||||
|
||||
media_class = ?,
|
||||
media_type = ?,
|
||||
|
||||
is_user_upload = ?,
|
||||
is_intermediate_system_file = ?,
|
||||
|
||||
origin_category = ?,
|
||||
origin_product_category = ?,
|
||||
maybe_origin_model_type = ?,
|
||||
maybe_origin_model_token = ?,
|
||||
maybe_origin_filename = ?,
|
||||
|
||||
maybe_batch_token = ?,
|
||||
|
||||
maybe_mime_type = ?,
|
||||
file_size_bytes = ?,
|
||||
maybe_duration_millis = ?,
|
||||
maybe_audio_encoding = ?,
|
||||
maybe_video_encoding = ?,
|
||||
maybe_frame_width = ?,
|
||||
maybe_frame_height = ?,
|
||||
maybe_prompt_token = ?,
|
||||
checksum_sha2 = ?,
|
||||
|
||||
maybe_engine_category = ?,
|
||||
|
||||
maybe_title = ?,
|
||||
maybe_text_transcript = ?,
|
||||
|
||||
maybe_scene_source_media_file_token = ?,
|
||||
|
||||
public_bucket_directory_hash = ?,
|
||||
maybe_public_bucket_prefix = ?,
|
||||
maybe_public_bucket_extension = ?,
|
||||
|
||||
maybe_creator_user_token = ?,
|
||||
maybe_creator_anonymous_visitor_token = ?,
|
||||
|
||||
creator_ip_address = ?,
|
||||
creator_set_visibility = ?,
|
||||
|
||||
maybe_creator_file_synthetic_id = ?,
|
||||
maybe_creator_category_synthetic_id = ?,
|
||||
|
||||
extra_file_modification_info = ?,
|
||||
|
||||
maybe_generation_provider = ?,
|
||||
|
||||
platform_type = ?,
|
||||
|
||||
maybe_cover_image_media_file_token = ?,
|
||||
|
||||
maybe_mod_user_token = ?,
|
||||
is_generated_on_prem = ?,
|
||||
generated_by_worker = ?,
|
||||
generated_by_cluster = ?
|
||||
"#,
|
||||
result_token,
|
||||
|
||||
args.media_class.to_str(),
|
||||
args.media_type.to_str(),
|
||||
|
||||
is_user_upload,
|
||||
is_intermediate_system_file,
|
||||
|
||||
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()),
|
||||
args.maybe_origin_filename,
|
||||
|
||||
args.maybe_batch_token.map(|t| t.as_str()),
|
||||
|
||||
args.maybe_mime_type,
|
||||
args.file_size_bytes,
|
||||
args.maybe_duration_millis,
|
||||
args.maybe_audio_encoding,
|
||||
args.maybe_video_encoding,
|
||||
args.maybe_frame_width,
|
||||
args.maybe_frame_height,
|
||||
args.maybe_prompt_token.map(|t| t.as_str()),
|
||||
args.checksum_sha2,
|
||||
|
||||
args.maybe_engine_category.map(|e| e.to_str()),
|
||||
|
||||
args.maybe_title,
|
||||
args.maybe_text_transcript,
|
||||
|
||||
args.maybe_scene_source_media_file_token.map(|t| t.as_str()),
|
||||
|
||||
args.public_bucket_directory_hash,
|
||||
args.maybe_public_bucket_prefix,
|
||||
args.maybe_public_bucket_extension,
|
||||
|
||||
args.maybe_creator_user_token.map(|t| t.as_str()),
|
||||
args.maybe_creator_anonymous_visitor_token.map(|t| t.as_str()),
|
||||
|
||||
args.creator_ip_address,
|
||||
args.creator_set_visibility.to_str(),
|
||||
|
||||
let query_result = insert_media_file_generic_executor(InsertMediaFileGenericExecutorArgs {
|
||||
maybe_creator_user_token: args.maybe_creator_user_token,
|
||||
maybe_creator_anonymous_visitor_token: args.maybe_creator_anonymous_visitor_token,
|
||||
creator_ip_address: args.creator_ip_address,
|
||||
creator_set_visibility: args.creator_set_visibility,
|
||||
media_class: args.media_class,
|
||||
media_type: args.media_type,
|
||||
is_user_upload: args.is_user_upload,
|
||||
is_intermediate_system_file: args.is_intermediate_system_file,
|
||||
origin_category: args.origin_category,
|
||||
origin_product_category: args.origin_product_category,
|
||||
maybe_origin_model_type: args.maybe_origin_model_type,
|
||||
maybe_origin_model_token: args.maybe_origin_model_token,
|
||||
maybe_origin_filename: args.maybe_origin_filename,
|
||||
maybe_mime_type: args.maybe_mime_type,
|
||||
file_size_bytes: args.file_size_bytes,
|
||||
maybe_duration_millis: args.maybe_duration_millis,
|
||||
maybe_audio_encoding: args.maybe_audio_encoding,
|
||||
maybe_video_encoding: args.maybe_video_encoding,
|
||||
maybe_frame_width: args.maybe_frame_width,
|
||||
maybe_frame_height: args.maybe_frame_height,
|
||||
checksum_sha2: args.checksum_sha2,
|
||||
maybe_engine_category: args.maybe_engine_category,
|
||||
maybe_title: args.maybe_title,
|
||||
maybe_text_transcript: args.maybe_text_transcript,
|
||||
maybe_scene_source_media_file_token: args.maybe_scene_source_media_file_token,
|
||||
maybe_prompt_token: args.maybe_prompt_token,
|
||||
maybe_batch_token: args.maybe_batch_token,
|
||||
public_bucket_directory_hash: args.public_bucket_directory_hash,
|
||||
maybe_public_bucket_prefix: args.maybe_public_bucket_prefix,
|
||||
maybe_public_bucket_extension: args.maybe_public_bucket_extension,
|
||||
maybe_creator_file_synthetic_id,
|
||||
maybe_creator_category_synthetic_id,
|
||||
maybe_extra_file_modification_info: extra_file_modification_info,
|
||||
is_generated_on_prem: args.is_generated_on_prem,
|
||||
generated_by_worker: args.generated_by_worker,
|
||||
generated_by_cluster: args.generated_by_cluster,
|
||||
maybe_generation_provider: args.maybe_generation_provider,
|
||||
maybe_platform_type: args.maybe_platform_type,
|
||||
maybe_cover_image_media_file_token: args.maybe_cover_image_media_file_token,
|
||||
maybe_mod_user_token: args.maybe_mod_user_token,
|
||||
mysql_executor: &mut *transaction,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
extra_file_modification_info,
|
||||
|
||||
maybe_generation_provider_str,
|
||||
|
||||
args.maybe_platform_type.map(|p| p.to_str()),
|
||||
|
||||
args.maybe_cover_image_media_file_token.map(|t| t.as_str()),
|
||||
|
||||
args.maybe_mod_user_token,
|
||||
args.is_generated_on_prem,
|
||||
args.generated_by_worker,
|
||||
args.generated_by_cluster
|
||||
).execute(&mut *transaction).await;
|
||||
|
||||
let record_id = match query_result {
|
||||
Ok(res) => res.last_insert_id(),
|
||||
let (result_token, record_id) = match query_result {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
// TODO: handle better
|
||||
//transaction.rollback().await?;
|
||||
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use sqlx;
|
||||
use sqlx::{Executor, MySql};
|
||||
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory;
|
||||
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
|
||||
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::platform_type::PlatformType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken;
|
||||
use tokens::tokens::batch_generations::BatchGenerationToken;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use tokens::tokens::model_weights::ModelWeightToken;
|
||||
use tokens::tokens::prompts::PromptToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
/// Arguments for [`insert_media_file_generic_executor`].
|
||||
///
|
||||
/// This is the executor-generic core of `insert_media_file_generic`: it runs
|
||||
/// the single INSERT statement and nothing else. Synthetic-ID increments and
|
||||
/// extra-info serialization stay with the caller (see
|
||||
/// `insert_media_file_generic`, which wraps this in a transaction).
|
||||
pub struct InsertMediaFileGenericExecutorArgs<'a, 'c, E>
|
||||
where
|
||||
E: 'a + Executor<'c, Database = MySql>,
|
||||
{
|
||||
// Creator info
|
||||
pub maybe_creator_user_token: Option<&'a UserToken>,
|
||||
pub maybe_creator_anonymous_visitor_token: Option<&'a AnonymousVisitorTrackingToken>,
|
||||
pub creator_ip_address: &'a str,
|
||||
pub creator_set_visibility: Visibility,
|
||||
|
||||
// Important database indices
|
||||
pub media_class: MediaFileClass,
|
||||
pub media_type: MediaFileType,
|
||||
pub is_user_upload: bool,
|
||||
pub is_intermediate_system_file: bool,
|
||||
|
||||
// Product and other origination information
|
||||
pub origin_category: MediaFileOriginCategory,
|
||||
pub origin_product_category: MediaFileOriginProductCategory,
|
||||
pub maybe_origin_model_type: Option<MediaFileOriginModelType>,
|
||||
pub maybe_origin_model_token: Option<&'a ModelWeightToken>,
|
||||
pub maybe_origin_filename: Option<String>,
|
||||
|
||||
// Media info
|
||||
pub maybe_mime_type: Option<&'a str>,
|
||||
pub file_size_bytes: u64,
|
||||
pub maybe_duration_millis: Option<u64>,
|
||||
pub maybe_audio_encoding: Option<&'a str>,
|
||||
pub maybe_video_encoding: Option<&'a str>,
|
||||
pub maybe_frame_width: Option<u32>,
|
||||
pub maybe_frame_height: Option<u32>,
|
||||
pub checksum_sha2: &'a str,
|
||||
|
||||
// Media info for certain product areas
|
||||
pub maybe_engine_category: Option<MediaFileEngineCategory>, // TODO: Deprecate
|
||||
|
||||
// User text information
|
||||
pub maybe_title: Option<&'a str>,
|
||||
pub maybe_text_transcript: Option<&'a str>,
|
||||
|
||||
// If generated from a scene, this is the scene media file token.
|
||||
pub maybe_scene_source_media_file_token: Option<&'a MediaFileToken>,
|
||||
|
||||
// If additional prompt details are stored, this is the prompt token.
|
||||
pub maybe_prompt_token: Option<&'a PromptToken>,
|
||||
|
||||
// If batch generated, this is the batch token.
|
||||
pub maybe_batch_token: Option<&'a BatchGenerationToken>,
|
||||
|
||||
// Storage details
|
||||
pub public_bucket_directory_hash: &'a str,
|
||||
pub maybe_public_bucket_prefix: Option<&'a str>,
|
||||
pub maybe_public_bucket_extension: Option<&'a str>,
|
||||
|
||||
// Counters, pre-computed by the caller (see
|
||||
// `transactional_increment_generic_synthetic_id`).
|
||||
pub maybe_creator_file_synthetic_id: Option<u64>,
|
||||
pub maybe_creator_category_synthetic_id: Option<u64>,
|
||||
|
||||
/// Extra polymorphic data stored in `extra_file_modification_info`,
|
||||
/// pre-serialized to JSON by the caller.
|
||||
pub maybe_extra_file_modification_info: Option<String>,
|
||||
|
||||
// Worker generation info
|
||||
pub is_generated_on_prem: bool,
|
||||
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>,
|
||||
|
||||
/// The platform the creating request came from, inferred from its User-Agent.
|
||||
/// For inference results, this is copied from the originating job.
|
||||
pub maybe_platform_type: Option<PlatformType>,
|
||||
|
||||
// Cover image (e.g. thumbnail for 3D splats)
|
||||
pub maybe_cover_image_media_file_token: Option<&'a MediaFileToken>,
|
||||
|
||||
// Moderation details (deprecated)
|
||||
pub maybe_mod_user_token: Option<&'a UserToken>,
|
||||
|
||||
pub mysql_executor: E,
|
||||
pub phantom: PhantomData<&'c E>,
|
||||
}
|
||||
|
||||
/// Insert a media file record using any executor (pool, connection, or open
|
||||
/// transaction). This is the single-statement core shared by
|
||||
/// `insert_media_file_generic` and the specialized inserts.
|
||||
pub async fn insert_media_file_generic_executor<'a, 'c: 'a, E>(
|
||||
args: InsertMediaFileGenericExecutorArgs<'a, 'c, E>,
|
||||
) -> Result<(MediaFileToken, u64), sqlx::Error>
|
||||
where
|
||||
E: 'a + Executor<'c, Database = MySql>,
|
||||
{
|
||||
let result_token = MediaFileToken::generate();
|
||||
|
||||
let mut maybe_generation_provider_str = None;
|
||||
let 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.
|
||||
// NB: `is_intermediate_system_file` is deliberately NOT reset here:
|
||||
// generated cover images / thumbnails set both a generation provider
|
||||
// and the intermediate flag, and clobbering the flag made them appear
|
||||
// in users' asset collections. The flag defaults to false at call
|
||||
// sites, so honoring the explicit setting is always correct.
|
||||
maybe_generation_provider_str = Some(generation_provider.to_str());
|
||||
is_user_upload = false;
|
||||
if generation_provider != GenerationProvider::Artcraft {
|
||||
origin_category = MediaFileOriginCategory::ThirdPartyInference;
|
||||
}
|
||||
}
|
||||
|
||||
let query_result = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO media_files
|
||||
SET
|
||||
token = ?,
|
||||
|
||||
media_class = ?,
|
||||
media_type = ?,
|
||||
|
||||
is_user_upload = ?,
|
||||
is_intermediate_system_file = ?,
|
||||
|
||||
origin_category = ?,
|
||||
origin_product_category = ?,
|
||||
maybe_origin_model_type = ?,
|
||||
maybe_origin_model_token = ?,
|
||||
maybe_origin_filename = ?,
|
||||
|
||||
maybe_batch_token = ?,
|
||||
|
||||
maybe_mime_type = ?,
|
||||
file_size_bytes = ?,
|
||||
maybe_duration_millis = ?,
|
||||
maybe_audio_encoding = ?,
|
||||
maybe_video_encoding = ?,
|
||||
maybe_frame_width = ?,
|
||||
maybe_frame_height = ?,
|
||||
maybe_prompt_token = ?,
|
||||
checksum_sha2 = ?,
|
||||
|
||||
maybe_engine_category = ?,
|
||||
|
||||
maybe_title = ?,
|
||||
maybe_text_transcript = ?,
|
||||
|
||||
maybe_scene_source_media_file_token = ?,
|
||||
|
||||
public_bucket_directory_hash = ?,
|
||||
maybe_public_bucket_prefix = ?,
|
||||
maybe_public_bucket_extension = ?,
|
||||
|
||||
maybe_creator_user_token = ?,
|
||||
maybe_creator_anonymous_visitor_token = ?,
|
||||
|
||||
creator_ip_address = ?,
|
||||
creator_set_visibility = ?,
|
||||
|
||||
maybe_creator_file_synthetic_id = ?,
|
||||
maybe_creator_category_synthetic_id = ?,
|
||||
|
||||
extra_file_modification_info = ?,
|
||||
|
||||
maybe_generation_provider = ?,
|
||||
|
||||
platform_type = ?,
|
||||
|
||||
maybe_cover_image_media_file_token = ?,
|
||||
|
||||
maybe_mod_user_token = ?,
|
||||
is_generated_on_prem = ?,
|
||||
generated_by_worker = ?,
|
||||
generated_by_cluster = ?
|
||||
"#,
|
||||
result_token,
|
||||
|
||||
args.media_class.to_str(),
|
||||
args.media_type.to_str(),
|
||||
|
||||
is_user_upload,
|
||||
is_intermediate_system_file,
|
||||
|
||||
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()),
|
||||
args.maybe_origin_filename,
|
||||
|
||||
args.maybe_batch_token.map(|t| t.as_str()),
|
||||
|
||||
args.maybe_mime_type,
|
||||
args.file_size_bytes,
|
||||
args.maybe_duration_millis,
|
||||
args.maybe_audio_encoding,
|
||||
args.maybe_video_encoding,
|
||||
args.maybe_frame_width,
|
||||
args.maybe_frame_height,
|
||||
args.maybe_prompt_token.map(|t| t.as_str()),
|
||||
args.checksum_sha2,
|
||||
|
||||
args.maybe_engine_category.map(|e| e.to_str()),
|
||||
|
||||
args.maybe_title,
|
||||
args.maybe_text_transcript,
|
||||
|
||||
args.maybe_scene_source_media_file_token.map(|t| t.as_str()),
|
||||
|
||||
args.public_bucket_directory_hash,
|
||||
args.maybe_public_bucket_prefix,
|
||||
args.maybe_public_bucket_extension,
|
||||
|
||||
args.maybe_creator_user_token.map(|t| t.as_str()),
|
||||
args.maybe_creator_anonymous_visitor_token.map(|t| t.as_str()),
|
||||
|
||||
args.creator_ip_address,
|
||||
args.creator_set_visibility.to_str(),
|
||||
|
||||
args.maybe_creator_file_synthetic_id,
|
||||
args.maybe_creator_category_synthetic_id,
|
||||
|
||||
args.maybe_extra_file_modification_info,
|
||||
|
||||
maybe_generation_provider_str,
|
||||
|
||||
args.maybe_platform_type.map(|p| p.to_str()),
|
||||
|
||||
args.maybe_cover_image_media_file_token.map(|t| t.as_str()),
|
||||
|
||||
args.maybe_mod_user_token,
|
||||
args.is_generated_on_prem,
|
||||
args.generated_by_worker,
|
||||
args.generated_by_cluster
|
||||
).execute(args.mysql_executor).await?;
|
||||
|
||||
Ok((result_token, query_result.last_insert_id()))
|
||||
}
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
pub mod insert_media_file_generic;
|
||||
pub mod insert_media_file_generic_executor;
|
||||
pub mod insert_media_file_generic_from_job;
|
||||
|
||||
+7
-4
@@ -302,19 +302,22 @@ impl MediaFileInsertBuilder {
|
||||
"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 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
|
||||
// Overrides if we're using a generation provider.
|
||||
// NB: `is_intermediate_system_file` is deliberately NOT reset here:
|
||||
// generated cover images / thumbnails set both a generation provider
|
||||
// and the intermediate flag, and clobbering the flag made them appear
|
||||
// in users' asset collections. The flag defaults to false, so honoring
|
||||
// the explicit setter is always correct.
|
||||
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,
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use sqlx::{Executor, MySql};
|
||||
|
||||
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
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::platform_type::PlatformType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use tokens::tokens::prompts::PromptToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::queries::media_files::create::generic_insert::insert_media_file_generic_executor::{insert_media_file_generic_executor, InsertMediaFileGenericExecutorArgs};
|
||||
|
||||
pub struct InsertCoverMediaFileArgs<'a, 'c, E>
|
||||
where
|
||||
E: 'a + Executor<'c, Database = MySql>,
|
||||
{
|
||||
// Creator info (copied from the generation job).
|
||||
pub maybe_creator_user_token: Option<&'a UserToken>,
|
||||
pub maybe_creator_anonymous_visitor_token: Option<&'a AnonymousVisitorTrackingToken>,
|
||||
pub creator_ip_address: &'a str,
|
||||
|
||||
/// The image format of the cover (png, jpg, webp, ...).
|
||||
pub media_file_type: MediaFileType,
|
||||
pub mime_type: &'a str,
|
||||
pub file_size_bytes: u64,
|
||||
pub checksum_sha2: &'a str,
|
||||
pub public_bucket_path: &'a MediaFileBucketPath,
|
||||
|
||||
/// Product category of the generation the cover belongs to (e.g.
|
||||
/// `WorldGeneration` for gaussian splat covers).
|
||||
pub maybe_origin_product_category: Option<MediaFileOriginProductCategory>,
|
||||
pub maybe_prompt_token: Option<&'a PromptToken>,
|
||||
pub maybe_platform_type: Option<PlatformType>,
|
||||
|
||||
pub mysql_executor: E,
|
||||
pub phantom: PhantomData<&'c E>,
|
||||
}
|
||||
|
||||
/// Insert a cover image media file record (e.g. a mesh/splat thumbnail
|
||||
/// downloaded from a generation provider).
|
||||
///
|
||||
/// Cover images are always `media_class = image` and — critically — always
|
||||
/// `is_intermediate_system_file = TRUE`, so they never appear in the user's
|
||||
/// asset collection. They are low-quality preview renders, not assets the
|
||||
/// user paid to generate.
|
||||
///
|
||||
/// Cover images deliberately do not consume the creator's synthetic file IDs:
|
||||
/// those number the user's visible assets, and covers are hidden.
|
||||
pub async fn insert_cover_media_file<'a, 'c: 'a, E>(
|
||||
args: InsertCoverMediaFileArgs<'a, 'c, E>,
|
||||
) -> Result<MediaFileToken, sqlx::Error>
|
||||
where
|
||||
E: 'a + Executor<'c, Database = MySql>,
|
||||
{
|
||||
let (media_token, _record_id) = insert_media_file_generic_executor(InsertMediaFileGenericExecutorArgs {
|
||||
// User details
|
||||
maybe_creator_user_token: args.maybe_creator_user_token,
|
||||
maybe_creator_anonymous_visitor_token: args.maybe_creator_anonymous_visitor_token,
|
||||
creator_ip_address: args.creator_ip_address,
|
||||
maybe_platform_type: args.maybe_platform_type,
|
||||
|
||||
// Storage
|
||||
public_bucket_directory_hash: args.public_bucket_path.get_object_hash(),
|
||||
maybe_public_bucket_prefix: args.public_bucket_path.get_optional_prefix(),
|
||||
maybe_public_bucket_extension: args.public_bucket_path.get_optional_extension(),
|
||||
|
||||
// File details
|
||||
checksum_sha2: args.checksum_sha2,
|
||||
file_size_bytes: args.file_size_bytes,
|
||||
maybe_mime_type: Some(args.mime_type),
|
||||
media_class: MediaFileClass::Image,
|
||||
|
||||
// Additional foreign keys and misc
|
||||
maybe_generation_provider: Some(GenerationProvider::Artcraft),
|
||||
maybe_prompt_token: args.maybe_prompt_token,
|
||||
media_type: args.media_file_type,
|
||||
origin_product_category: args.maybe_origin_product_category // TODO: Not useful here.
|
||||
.unwrap_or(MediaFileOriginProductCategory::Unknown),
|
||||
|
||||
// Essential - this is a hidden file
|
||||
is_intermediate_system_file: true,
|
||||
creator_set_visibility: Visibility::Hidden,
|
||||
|
||||
// Other Constants
|
||||
generated_by_cluster: None,
|
||||
generated_by_worker: None,
|
||||
is_generated_on_prem: false,
|
||||
is_user_upload: false,
|
||||
maybe_audio_encoding: None,
|
||||
maybe_batch_token: None,
|
||||
maybe_cover_image_media_file_token: None,
|
||||
maybe_creator_category_synthetic_id: None,
|
||||
maybe_creator_file_synthetic_id: None,
|
||||
maybe_duration_millis: None,
|
||||
maybe_engine_category: None,
|
||||
maybe_extra_file_modification_info: None,
|
||||
maybe_frame_height: None,
|
||||
maybe_frame_width: None,
|
||||
maybe_mod_user_token: None,
|
||||
maybe_origin_filename: None,
|
||||
maybe_origin_model_token: None,
|
||||
maybe_origin_model_type: None,
|
||||
maybe_scene_source_media_file_token: None,
|
||||
maybe_text_transcript: None,
|
||||
maybe_title: None,
|
||||
maybe_video_encoding: None,
|
||||
origin_category: MediaFileOriginCategory::Inference, // TODO: Not useful here.
|
||||
|
||||
// Connection
|
||||
mysql_executor: args.mysql_executor,
|
||||
phantom: Default::default(),
|
||||
}).await?;
|
||||
|
||||
Ok(media_token)
|
||||
}
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
pub mod insert_cover_media_file;
|
||||
pub mod insert_media_file_from_cli_tool;
|
||||
pub mod insert_media_file_from_comfy_ui;
|
||||
pub mod insert_media_file_from_f5_tts;
|
||||
@@ -9,4 +10,4 @@ pub mod insert_media_file_from_seed_vc;
|
||||
pub mod insert_media_file_from_studio_gen2;
|
||||
pub mod insert_media_file_from_tacotron2;
|
||||
pub mod insert_media_file_from_voice_conversion;
|
||||
pub mod insert_media_file_from_zero_shot_tts;
|
||||
pub mod insert_media_file_from_zero_shot_tts;
|
||||
|
||||
+16
-27
@@ -7,15 +7,12 @@ use crate::http_server::endpoints::webhooks::fal::process_success::resolve_file_
|
||||
use crate::state::server_state::ServerState;
|
||||
use crate::util::http_download_url_to_bytes::http_download_url_to_bytes;
|
||||
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
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 hashing::sha256::sha256_hash_bytes::sha256_hash_bytes;
|
||||
use log::{info, warn};
|
||||
use mysql_queries::queries::generic_inference::api_providers::fal::get_inference_job_by_fal_id::FalJobDetails;
|
||||
use mysql_queries::queries::media_files::create::insert_builder::media_file_insert_builder::MediaFileInsertBuilder;
|
||||
use mysql_queries::queries::media_files::create::specialized_insert::insert_cover_media_file::{insert_cover_media_file, InsertCoverMediaFileArgs};
|
||||
use mysql_queries::queries::media_files::edit::set_media_file_cover_image::{set_media_file_cover_image, UpdateArgs};
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
@@ -120,29 +117,21 @@ pub(crate) async fn attach_cover_image(
|
||||
CommonWebError::from_anyhow_error(err)
|
||||
})?;
|
||||
|
||||
let mut insert_builder = MediaFileInsertBuilder::new()
|
||||
.checksum_sha2(&file_hash)
|
||||
.creator_ip_address(&job.creator_ip_address)
|
||||
.file_size_bytes(file_size_bytes as u64)
|
||||
.is_intermediate_system_file(true)
|
||||
.maybe_creator_anonymous_visitor(job.maybe_creator_anonymous_visitor_token.as_ref())
|
||||
.maybe_creator_user(job.maybe_creator_user_token.as_ref())
|
||||
.maybe_generation_provider(Some(GenerationProvider::Artcraft))
|
||||
.maybe_prompt_token(job.maybe_prompt_token.as_ref())
|
||||
.maybe_platform_type(job.maybe_platform_type)
|
||||
.media_file_class(MediaFileClass::Image)
|
||||
.media_file_origin_category(MediaFileOriginCategory::Inference)
|
||||
.media_file_type(media_file_type)
|
||||
.mime_type(mime_type)
|
||||
.public_bucket_directory_hash(&public_upload_path);
|
||||
|
||||
if let Some(origin_product_category) = maybe_origin_product_category {
|
||||
insert_builder = insert_builder
|
||||
.media_file_origin_product_category(origin_product_category);
|
||||
}
|
||||
|
||||
let cover_media_token = insert_builder
|
||||
.insert_pool(&server_state.mysql_pool)
|
||||
let cover_media_token = insert_cover_media_file(InsertCoverMediaFileArgs {
|
||||
maybe_creator_user_token: job.maybe_creator_user_token.as_ref(),
|
||||
maybe_creator_anonymous_visitor_token: job.maybe_creator_anonymous_visitor_token.as_ref(),
|
||||
creator_ip_address: &job.creator_ip_address,
|
||||
media_file_type,
|
||||
mime_type,
|
||||
file_size_bytes: file_size_bytes as u64,
|
||||
checksum_sha2: &file_hash,
|
||||
public_bucket_path: &public_upload_path,
|
||||
maybe_origin_product_category,
|
||||
maybe_prompt_token: job.maybe_prompt_token.as_ref(),
|
||||
maybe_platform_type: job.maybe_platform_type,
|
||||
mysql_executor: &server_state.mysql_pool,
|
||||
phantom: Default::default(),
|
||||
})
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("Failed to insert cover image media file record: {:?}", err);
|
||||
|
||||
Reference in New Issue
Block a user