mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-03 21:10:58 -05:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07e1ddfd77 | ||
|
|
98c4fad729 | ||
|
|
f50bfa9ee7 | ||
|
|
d90d446643 | ||
|
|
c4d188a600 | ||
|
|
1d5d63fda1 | ||
|
|
6af5cc7d0b | ||
|
|
a7cd9f3b2f | ||
|
|
d538bc2a68 | ||
|
|
bec8c7ede4 | ||
|
|
0866e63dd4 | ||
|
|
78a5c4ff87 | ||
|
|
d53fad0072 | ||
|
|
2e5e9443a3 | ||
|
|
5bda2a6cb4 | ||
|
|
9cf1b8e066 | ||
|
|
aebc6ab777 | ||
|
|
d3c89face5 | ||
|
|
692e0ecf75 | ||
|
|
94e1aef78d | ||
|
|
9a4bb3b490 | ||
|
|
299d9b8d23 | ||
|
|
89eff46c6f | ||
|
|
cec3b50ae4 | ||
|
|
3040aaa0d1 | ||
|
|
f47e8b9b14 | ||
|
|
83115e7ef9 |
+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": "1c74e9c2dcc9205e2c9fe60a6de0828208e497e68560246e588092bafd03eb59"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE tts_results\nSET\n mod_deleted_at = CURRENT_TIMESTAMP,\n maybe_mod_user_token = ?\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "376e36b1357952599866262c7356ba35f15ccdfb338d8ccdbdc06ccd69331fc3"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE tts_results\nSET\n mod_deleted_at = NULL,\n maybe_mod_user_token = ?\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "40a3301e9a3201e74d49b6b339f67291e2ae22d315188401708609ac2d28a68c"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"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_media_subtype = ?,\n maybe_mime_type = ?,\n file_size_bytes = ?,\n\n checksum_sha2 = ?,\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_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\nON DUPLICATE KEY UPDATE\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_media_subtype = ?,\n maybe_mime_type = ?,\n file_size_bytes = ?,\n\n checksum_sha2 = ?,\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_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 ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 39
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "55706e6ac35be221b9d9c6e8b247812944c61941964bb53815d31dc30d506be8"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n job_type as queue_type,\n count(*) as pending_job_count,\n NOW() as present_time\n FROM (\n SELECT\n token,\n job_type\n FROM generic_inference_jobs\n WHERE status IN (\"pending\", \"attempt_failed\")\n AND job_type IS NOT NULL\n UNION\n SELECT\n token,\n job_type\n FROM generic_inference_jobs\n WHERE status IN (\"started\")\n AND created_at > (CURDATE() - INTERVAL 15 MINUTE)\n AND job_type IS NOT NULL\n) as generic_inner\nGROUP BY queue_type\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "queue_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "pending_job_count",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
"flags": "NOT_NULL | BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 21
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "present_time",
|
||||
"type_info": {
|
||||
"type": "Datetime",
|
||||
"flags": "NOT_NULL | BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "73dc054488b2fa3efc923d3a90914a1450b73e99a377562484a0498ccce1676f"
|
||||
}
|
||||
+43
-54
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n m.token as `token: tokens::tokens::media_files::MediaFileToken`,\n\n m.media_class as `media_class: enums::by_table::media_files::media_file_class::MediaFileClass`,\n m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n\n m.maybe_engine_category as `maybe_engine_category: enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory`,\n m.maybe_animation_type as `maybe_animation_type: enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType`,\n\n m.maybe_media_subtype as `maybe_media_subtype: enums::by_table::media_files::media_file_subtype::MediaFileSubtype`,\n\n m.maybe_mime_type,\n\n users.token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n users.username as maybe_creator_username,\n users.display_name as maybe_creator_display_name,\n users.email_gravatar_hash as maybe_creator_gravatar_hash,\n\n m.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n\n m.maybe_batch_token as `maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken`,\n\n m.maybe_style_transfer_source_media_file_token as `maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n m.maybe_scene_source_media_file_token as `maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n\n m.maybe_title,\n m.maybe_text_transcript,\n\n m.maybe_origin_filename,\n\n m.maybe_duration_millis,\n\n m.maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n prompts.maybe_other_args as maybe_other_prompt_args,\n\n media_file_cover_image.public_bucket_directory_hash as maybe_file_cover_image_public_bucket_hash,\n media_file_cover_image.maybe_public_bucket_prefix as maybe_file_cover_image_public_bucket_prefix,\n media_file_cover_image.maybe_public_bucket_extension as maybe_file_cover_image_public_bucket_extension,\n\n m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n m.is_user_upload,\n m.is_intermediate_system_file,\n\n model_weights.token as `maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n model_weights.title as maybe_model_weights_title,\n model_weights.weights_type as `maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n model_weights.weights_category as `maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n model_weight_cover_image.public_bucket_directory_hash as maybe_model_cover_image_public_bucket_hash,\n model_weight_cover_image.maybe_public_bucket_prefix as maybe_model_cover_image_public_bucket_prefix,\n model_weight_cover_image.maybe_public_bucket_extension as maybe_model_cover_image_public_bucket_extension,\n\n model_weight_creator.token as `maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken`,\n model_weight_creator.username as maybe_model_weight_creator_username,\n model_weight_creator.display_name as maybe_model_weight_creator_display_name,\n model_weight_creator.email_gravatar_hash as maybe_model_weight_creator_gravatar_hash,\n\n m.extra_file_modification_info,\n\n m.public_bucket_directory_hash,\n m.maybe_public_bucket_prefix,\n m.maybe_public_bucket_extension,\n\n entity_stats.ratings_positive_count as maybe_ratings_positive_count,\n entity_stats.ratings_negative_count as maybe_ratings_negative_count,\n entity_stats.bookmark_count as maybe_bookmark_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n m.created_at,\n m.updated_at\n\nFROM media_files AS m\nLEFT OUTER JOIN users\n ON m.maybe_creator_user_token = users.token\nLEFT OUTER JOIN model_weights\n ON m.maybe_origin_model_token = model_weights.token\nLEFT OUTER JOIN media_files as media_file_cover_image\n ON media_file_cover_image.token = m.maybe_cover_image_media_file_token\nLEFT OUTER JOIN media_files as model_weight_cover_image\n ON model_weight_cover_image.token = model_weights.maybe_cover_image_media_file_token\nLEFT OUTER JOIN users as model_weight_creator\n ON model_weight_creator.token = model_weights.creator_user_token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"media_file\"\n AND entity_stats.entity_token = m.token\nLEFT OUTER JOIN prompts\n ON prompts.token = m.maybe_prompt_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = 'media_file'\n AND featured_items.entity_token = m.token\n AND featured_items.deleted_at IS NULL\nWHERE\n m.token = ?\n ",
|
||||
"query": "\nSELECT\n m.token as `token: tokens::tokens::media_files::MediaFileToken`,\n\n m.media_class as `media_class: enums::by_table::media_files::media_file_class::MediaFileClass`,\n m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n\n m.maybe_engine_category as `maybe_engine_category: enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory`,\n m.maybe_animation_type as `maybe_animation_type: enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType`,\n\n m.maybe_mime_type,\n\n users.token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n users.username as maybe_creator_username,\n users.display_name as maybe_creator_display_name,\n users.email_gravatar_hash as maybe_creator_gravatar_hash,\n\n m.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n\n m.maybe_batch_token as `maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken`,\n\n m.maybe_style_transfer_source_media_file_token as `maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n m.maybe_scene_source_media_file_token as `maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n\n m.maybe_title,\n m.maybe_text_transcript,\n\n m.maybe_origin_filename,\n\n m.maybe_duration_millis,\n\n m.maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n prompts.maybe_other_args as maybe_other_prompt_args,\n\n media_file_cover_image.public_bucket_directory_hash as maybe_file_cover_image_public_bucket_hash,\n media_file_cover_image.maybe_public_bucket_prefix as maybe_file_cover_image_public_bucket_prefix,\n media_file_cover_image.maybe_public_bucket_extension as maybe_file_cover_image_public_bucket_extension,\n\n m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n m.is_user_upload,\n m.is_intermediate_system_file,\n\n model_weights.token as `maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n model_weights.title as maybe_model_weights_title,\n model_weights.weights_type as `maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n model_weights.weights_category as `maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n model_weight_cover_image.public_bucket_directory_hash as maybe_model_cover_image_public_bucket_hash,\n model_weight_cover_image.maybe_public_bucket_prefix as maybe_model_cover_image_public_bucket_prefix,\n model_weight_cover_image.maybe_public_bucket_extension as maybe_model_cover_image_public_bucket_extension,\n\n model_weight_creator.token as `maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken`,\n model_weight_creator.username as maybe_model_weight_creator_username,\n model_weight_creator.display_name as maybe_model_weight_creator_display_name,\n model_weight_creator.email_gravatar_hash as maybe_model_weight_creator_gravatar_hash,\n\n m.extra_file_modification_info,\n\n m.public_bucket_directory_hash,\n m.maybe_public_bucket_prefix,\n m.maybe_public_bucket_extension,\n\n entity_stats.ratings_positive_count as maybe_ratings_positive_count,\n entity_stats.ratings_negative_count as maybe_ratings_negative_count,\n entity_stats.bookmark_count as maybe_bookmark_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n m.created_at,\n m.updated_at\n\nFROM media_files AS m\nLEFT OUTER JOIN users\n ON m.maybe_creator_user_token = users.token\nLEFT OUTER JOIN model_weights\n ON m.maybe_origin_model_token = model_weights.token\nLEFT OUTER JOIN media_files as media_file_cover_image\n ON media_file_cover_image.token = m.maybe_cover_image_media_file_token\nLEFT OUTER JOIN media_files as model_weight_cover_image\n ON model_weight_cover_image.token = model_weights.maybe_cover_image_media_file_token\nLEFT OUTER JOIN users as model_weight_creator\n ON model_weight_creator.token = model_weights.creator_user_token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"media_file\"\n AND entity_stats.entity_token = m.token\nLEFT OUTER JOIN prompts\n ON prompts.token = m.maybe_prompt_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = 'media_file'\n AND featured_items.entity_token = m.token\n AND featured_items.deleted_at IS NULL\nWHERE\n m.token = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -55,16 +55,6 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "maybe_media_subtype: enums::by_table::media_files::media_file_subtype::MediaFileSubtype",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "maybe_mime_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -74,7 +64,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 6,
|
||||
"name": "maybe_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -84,7 +74,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 7,
|
||||
"name": "maybe_creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -94,7 +84,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 8,
|
||||
"name": "maybe_creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -104,7 +94,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 9,
|
||||
"name": "maybe_creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -114,7 +104,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 10,
|
||||
"name": "maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -124,7 +114,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 11,
|
||||
"name": "maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -134,7 +124,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 12,
|
||||
"name": "maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -144,7 +134,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 13,
|
||||
"name": "maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -154,7 +144,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 14,
|
||||
"name": "maybe_title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -164,7 +154,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 15,
|
||||
"name": "maybe_text_transcript",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -174,7 +164,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 16,
|
||||
"name": "maybe_origin_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -184,7 +174,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 17,
|
||||
"name": "maybe_duration_millis",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -194,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"ordinal": 18,
|
||||
"name": "maybe_prompt_token: tokens::tokens::prompts::PromptToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -204,7 +194,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"ordinal": 19,
|
||||
"name": "maybe_other_prompt_args",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -214,7 +204,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"ordinal": 20,
|
||||
"name": "maybe_file_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -224,7 +214,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"ordinal": 21,
|
||||
"name": "maybe_file_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -234,7 +224,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"ordinal": 22,
|
||||
"name": "maybe_file_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -244,7 +234,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"ordinal": 23,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -254,7 +244,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"ordinal": 24,
|
||||
"name": "is_user_upload",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
@@ -264,7 +254,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"ordinal": 25,
|
||||
"name": "is_intermediate_system_file",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
@@ -274,7 +264,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"ordinal": 26,
|
||||
"name": "maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -284,7 +274,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 28,
|
||||
"ordinal": 27,
|
||||
"name": "maybe_model_weights_title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -294,7 +284,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"ordinal": 28,
|
||||
"name": "maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -304,7 +294,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"ordinal": 29,
|
||||
"name": "maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -314,7 +304,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 31,
|
||||
"ordinal": 30,
|
||||
"name": "maybe_model_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -324,7 +314,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 32,
|
||||
"ordinal": 31,
|
||||
"name": "maybe_model_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -334,7 +324,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 33,
|
||||
"ordinal": 32,
|
||||
"name": "maybe_model_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -344,7 +334,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 34,
|
||||
"ordinal": 33,
|
||||
"name": "maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -354,7 +344,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 35,
|
||||
"ordinal": 34,
|
||||
"name": "maybe_model_weight_creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -364,7 +354,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 36,
|
||||
"ordinal": 35,
|
||||
"name": "maybe_model_weight_creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -374,7 +364,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 37,
|
||||
"ordinal": 36,
|
||||
"name": "maybe_model_weight_creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -384,7 +374,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 38,
|
||||
"ordinal": 37,
|
||||
"name": "extra_file_modification_info",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -394,7 +384,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 39,
|
||||
"ordinal": 38,
|
||||
"name": "public_bucket_directory_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -404,7 +394,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 40,
|
||||
"ordinal": 39,
|
||||
"name": "maybe_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -414,7 +404,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 41,
|
||||
"ordinal": 40,
|
||||
"name": "maybe_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -424,7 +414,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 42,
|
||||
"ordinal": 41,
|
||||
"name": "maybe_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -434,7 +424,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 43,
|
||||
"ordinal": 42,
|
||||
"name": "maybe_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -444,7 +434,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 44,
|
||||
"ordinal": 43,
|
||||
"name": "maybe_bookmark_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -454,7 +444,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 45,
|
||||
"ordinal": 44,
|
||||
"name": "is_featured",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -464,7 +454,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 46,
|
||||
"ordinal": 45,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -474,7 +464,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 47,
|
||||
"ordinal": 46,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -511,7 +501,6 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
@@ -538,5 +527,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "f6c37066ab3e508050e81cf3bea38cc708b05c5c59ba1c322dcfb775e4b9e7a6"
|
||||
"hash": "784ca68c6cb61d481b605bfe6ee3248a5b44499038c71b57fc9ea6c4722d170f"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO tts_model_upload_jobs\nSET\n token = ?,\n uuid_idempotency_token = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n title = ?,\n tts_model_type = ?,\n download_url = ?,\n status = \"pending\"\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 8
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "886861e91c7e8af53eb856c949389a172b8d9e079f1c2070d115423907c47c50"
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n users.token as `user_token: UserToken`,\n users.username,\n users.display_name,\n users.email_address,\n users.user_role_slug,\n users.is_banned,\n user_roles.can_ban_users,\n api_keys.token as `api_key_token: ApiKeyToken`\nFROM api_keys\nINNER JOIN users\n ON users.token = api_keys.owner_user_token\nLEFT OUTER JOIN user_roles\n ON users.user_role_slug = user_roles.slug\nWHERE api_keys.api_key = ?\n AND api_keys.maybe_deleted_at IS NULL\n AND users.user_deleted_at IS NULL\n AND users.mod_deleted_at IS NULL\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "user_token: UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "email_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "user_role_slug",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "is_banned",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "can_ban_users",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "api_key_token: ApiKeyToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "9188e235caa439d50628333c2f4722b9f1a8f575c192d4d36a2039709c412ac0"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE tts_results\nSET\n user_deleted_at = CURRENT_TIMESTAMP\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "961f792c24bee6009e3e8a215561db932871a53c48839b8cb80292de00e7b2e1"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO media_files\nSET\n token = ?,\n\n media_class = ?,\n media_type = ?,\n maybe_project_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": 28
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a25fe977f51329ed078e2441446ef7ff16683dcad8b81c8d0a0a4540b5e985bc"
|
||||
}
|
||||
-135
@@ -1,135 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n jobs.token as job_token,\n\n jobs.status,\n jobs.attempt_count,\n jobs.on_success_result_token as maybe_result_token,\n results.public_bucket_wav_audio_path as maybe_public_bucket_wav_audio_path,\n\n jobs.model_token,\n tts.tts_model_type,\n tts.title,\n\n jobs.raw_inference_text,\n\n jobs.created_at,\n jobs.updated_at\n\nFROM tts_inference_jobs as jobs\nJOIN tts_models as tts\n ON tts.token = jobs.model_token\nLEFT OUTER JOIN tts_results as results\n ON jobs.on_success_result_token = results.token\n\nWHERE jobs.token = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "job_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "status",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "attempt_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "maybe_result_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "maybe_public_bucket_wav_audio_path",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "model_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "tts_model_type",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM",
|
||||
"char_set": 224,
|
||||
"max_size": 60
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "raw_inference_text",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a2b586dd2120f29dd26281626f7381e292c821f8e826b9bc584b92ffa45035b2"
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n users.username,\n users.display_name,\n users.email_gravatar_hash as gravatar_hash,\n creator_user_token,\n count(*) as uploaded_count\nFROM tts_models\nJOIN users\nON\n users.token = creator_user_token\nWHERE\n users.is_banned IS FALSE\n AND users.token NOT IN (\"U:DRB1SKEMKHT1J\")\n AND tts_models.user_deleted_at IS NULL\n AND tts_models.mod_deleted_at IS NULL\nGROUP BY creator_user_token\nORDER BY uploaded_count desc\nLIMIT 25;\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "creator_user_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "uploaded_count",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
"flags": "NOT_NULL | BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 21
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a82fa4eb36528ebf52af2585cdda203476a4ba3645837c792830474fca2eda4f"
|
||||
}
|
||||
+43
-54
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n m.token as `token: tokens::tokens::media_files::MediaFileToken`,\n\n m.media_class as `media_class: enums::by_table::media_files::media_file_class::MediaFileClass`,\n m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n\n m.maybe_engine_category as `maybe_engine_category: enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory`,\n m.maybe_animation_type as `maybe_animation_type: enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType`,\n\n m.maybe_media_subtype as `maybe_media_subtype: enums::by_table::media_files::media_file_subtype::MediaFileSubtype`,\n\n m.maybe_mime_type,\n\n users.token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n users.username as maybe_creator_username,\n users.display_name as maybe_creator_display_name,\n users.email_gravatar_hash as maybe_creator_gravatar_hash,\n\n m.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n\n m.maybe_batch_token as `maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken`,\n\n m.maybe_style_transfer_source_media_file_token as `maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n m.maybe_scene_source_media_file_token as `maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n\n\n m.maybe_title,\n m.maybe_text_transcript,\n\n m.maybe_origin_filename,\n\n m.maybe_duration_millis,\n\n m.maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n prompts.maybe_other_args as maybe_other_prompt_args,\n\n media_file_cover_image.public_bucket_directory_hash as maybe_file_cover_image_public_bucket_hash,\n media_file_cover_image.maybe_public_bucket_prefix as maybe_file_cover_image_public_bucket_prefix,\n media_file_cover_image.maybe_public_bucket_extension as maybe_file_cover_image_public_bucket_extension,\n\n m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n m.is_user_upload,\n m.is_intermediate_system_file,\n\n model_weights.token as `maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n model_weights.title as maybe_model_weights_title,\n model_weights.weights_type as `maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n model_weights.weights_category as `maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n model_weight_cover_image.public_bucket_directory_hash as maybe_model_cover_image_public_bucket_hash,\n model_weight_cover_image.maybe_public_bucket_prefix as maybe_model_cover_image_public_bucket_prefix,\n model_weight_cover_image.maybe_public_bucket_extension as maybe_model_cover_image_public_bucket_extension,\n\n model_weight_creator.token as `maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken`,\n model_weight_creator.username as maybe_model_weight_creator_username,\n model_weight_creator.display_name as maybe_model_weight_creator_display_name,\n model_weight_creator.email_gravatar_hash as maybe_model_weight_creator_gravatar_hash,\n\n m.extra_file_modification_info,\n\n m.public_bucket_directory_hash,\n m.maybe_public_bucket_prefix,\n m.maybe_public_bucket_extension,\n\n entity_stats.ratings_positive_count as maybe_ratings_positive_count,\n entity_stats.ratings_negative_count as maybe_ratings_negative_count,\n entity_stats.bookmark_count as maybe_bookmark_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n m.created_at,\n m.updated_at\n\nFROM media_files AS m\nLEFT OUTER JOIN users\n ON m.maybe_creator_user_token = users.token\nLEFT OUTER JOIN model_weights\n ON m.maybe_origin_model_token = model_weights.token\nLEFT OUTER JOIN media_files as media_file_cover_image\n ON media_file_cover_image.token = m.maybe_cover_image_media_file_token\nLEFT OUTER JOIN media_files as model_weight_cover_image\n ON model_weight_cover_image.token = model_weights.maybe_cover_image_media_file_token\nLEFT OUTER JOIN users as model_weight_creator\n ON model_weight_creator.token = model_weights.creator_user_token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"media_file\"\n AND entity_stats.entity_token = m.token\nLEFT OUTER JOIN prompts\n ON prompts.token = m.maybe_prompt_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = 'media_file'\n AND featured_items.entity_token = m.token\n AND featured_items.deleted_at IS NULL\nWHERE\n m.token = ?\n AND m.user_deleted_at IS NULL\n AND m.mod_deleted_at IS NULL\n ",
|
||||
"query": "\nSELECT\n m.token as `token: tokens::tokens::media_files::MediaFileToken`,\n\n m.media_class as `media_class: enums::by_table::media_files::media_file_class::MediaFileClass`,\n m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n\n m.maybe_engine_category as `maybe_engine_category: enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory`,\n m.maybe_animation_type as `maybe_animation_type: enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType`,\n\n m.maybe_mime_type,\n\n users.token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n users.username as maybe_creator_username,\n users.display_name as maybe_creator_display_name,\n users.email_gravatar_hash as maybe_creator_gravatar_hash,\n\n m.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n\n m.maybe_batch_token as `maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken`,\n\n m.maybe_style_transfer_source_media_file_token as `maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n m.maybe_scene_source_media_file_token as `maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n\n\n m.maybe_title,\n m.maybe_text_transcript,\n\n m.maybe_origin_filename,\n\n m.maybe_duration_millis,\n\n m.maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n prompts.maybe_other_args as maybe_other_prompt_args,\n\n media_file_cover_image.public_bucket_directory_hash as maybe_file_cover_image_public_bucket_hash,\n media_file_cover_image.maybe_public_bucket_prefix as maybe_file_cover_image_public_bucket_prefix,\n media_file_cover_image.maybe_public_bucket_extension as maybe_file_cover_image_public_bucket_extension,\n\n m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n m.is_user_upload,\n m.is_intermediate_system_file,\n\n model_weights.token as `maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n model_weights.title as maybe_model_weights_title,\n model_weights.weights_type as `maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n model_weights.weights_category as `maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n model_weight_cover_image.public_bucket_directory_hash as maybe_model_cover_image_public_bucket_hash,\n model_weight_cover_image.maybe_public_bucket_prefix as maybe_model_cover_image_public_bucket_prefix,\n model_weight_cover_image.maybe_public_bucket_extension as maybe_model_cover_image_public_bucket_extension,\n\n model_weight_creator.token as `maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken`,\n model_weight_creator.username as maybe_model_weight_creator_username,\n model_weight_creator.display_name as maybe_model_weight_creator_display_name,\n model_weight_creator.email_gravatar_hash as maybe_model_weight_creator_gravatar_hash,\n\n m.extra_file_modification_info,\n\n m.public_bucket_directory_hash,\n m.maybe_public_bucket_prefix,\n m.maybe_public_bucket_extension,\n\n entity_stats.ratings_positive_count as maybe_ratings_positive_count,\n entity_stats.ratings_negative_count as maybe_ratings_negative_count,\n entity_stats.bookmark_count as maybe_bookmark_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n m.created_at,\n m.updated_at\n\nFROM media_files AS m\nLEFT OUTER JOIN users\n ON m.maybe_creator_user_token = users.token\nLEFT OUTER JOIN model_weights\n ON m.maybe_origin_model_token = model_weights.token\nLEFT OUTER JOIN media_files as media_file_cover_image\n ON media_file_cover_image.token = m.maybe_cover_image_media_file_token\nLEFT OUTER JOIN media_files as model_weight_cover_image\n ON model_weight_cover_image.token = model_weights.maybe_cover_image_media_file_token\nLEFT OUTER JOIN users as model_weight_creator\n ON model_weight_creator.token = model_weights.creator_user_token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"media_file\"\n AND entity_stats.entity_token = m.token\nLEFT OUTER JOIN prompts\n ON prompts.token = m.maybe_prompt_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = 'media_file'\n AND featured_items.entity_token = m.token\n AND featured_items.deleted_at IS NULL\nWHERE\n m.token = ?\n AND m.user_deleted_at IS NULL\n AND m.mod_deleted_at IS NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -55,16 +55,6 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "maybe_media_subtype: enums::by_table::media_files::media_file_subtype::MediaFileSubtype",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "maybe_mime_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -74,7 +64,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 6,
|
||||
"name": "maybe_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -84,7 +74,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 7,
|
||||
"name": "maybe_creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -94,7 +84,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 8,
|
||||
"name": "maybe_creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -104,7 +94,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 9,
|
||||
"name": "maybe_creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -114,7 +104,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 10,
|
||||
"name": "maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -124,7 +114,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 11,
|
||||
"name": "maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -134,7 +124,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 12,
|
||||
"name": "maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -144,7 +134,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 13,
|
||||
"name": "maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -154,7 +144,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 14,
|
||||
"name": "maybe_title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -164,7 +154,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 15,
|
||||
"name": "maybe_text_transcript",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -174,7 +164,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 16,
|
||||
"name": "maybe_origin_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -184,7 +174,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 17,
|
||||
"name": "maybe_duration_millis",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -194,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"ordinal": 18,
|
||||
"name": "maybe_prompt_token: tokens::tokens::prompts::PromptToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -204,7 +194,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"ordinal": 19,
|
||||
"name": "maybe_other_prompt_args",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -214,7 +204,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"ordinal": 20,
|
||||
"name": "maybe_file_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -224,7 +214,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"ordinal": 21,
|
||||
"name": "maybe_file_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -234,7 +224,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"ordinal": 22,
|
||||
"name": "maybe_file_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -244,7 +234,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"ordinal": 23,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -254,7 +244,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"ordinal": 24,
|
||||
"name": "is_user_upload",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
@@ -264,7 +254,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"ordinal": 25,
|
||||
"name": "is_intermediate_system_file",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
@@ -274,7 +264,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"ordinal": 26,
|
||||
"name": "maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -284,7 +274,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 28,
|
||||
"ordinal": 27,
|
||||
"name": "maybe_model_weights_title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -294,7 +284,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"ordinal": 28,
|
||||
"name": "maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -304,7 +294,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"ordinal": 29,
|
||||
"name": "maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -314,7 +304,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 31,
|
||||
"ordinal": 30,
|
||||
"name": "maybe_model_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -324,7 +314,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 32,
|
||||
"ordinal": 31,
|
||||
"name": "maybe_model_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -334,7 +324,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 33,
|
||||
"ordinal": 32,
|
||||
"name": "maybe_model_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -344,7 +334,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 34,
|
||||
"ordinal": 33,
|
||||
"name": "maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -354,7 +344,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 35,
|
||||
"ordinal": 34,
|
||||
"name": "maybe_model_weight_creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -364,7 +354,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 36,
|
||||
"ordinal": 35,
|
||||
"name": "maybe_model_weight_creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -374,7 +364,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 37,
|
||||
"ordinal": 36,
|
||||
"name": "maybe_model_weight_creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -384,7 +374,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 38,
|
||||
"ordinal": 37,
|
||||
"name": "extra_file_modification_info",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -394,7 +384,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 39,
|
||||
"ordinal": 38,
|
||||
"name": "public_bucket_directory_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -404,7 +394,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 40,
|
||||
"ordinal": 39,
|
||||
"name": "maybe_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -414,7 +404,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 41,
|
||||
"ordinal": 40,
|
||||
"name": "maybe_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -424,7 +414,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 42,
|
||||
"ordinal": 41,
|
||||
"name": "maybe_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -434,7 +424,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 43,
|
||||
"ordinal": 42,
|
||||
"name": "maybe_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -444,7 +434,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 44,
|
||||
"ordinal": 43,
|
||||
"name": "maybe_bookmark_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -454,7 +444,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 45,
|
||||
"ordinal": 44,
|
||||
"name": "is_featured",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -464,7 +454,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 46,
|
||||
"ordinal": 45,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -474,7 +464,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 47,
|
||||
"ordinal": 46,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -511,7 +501,6 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
@@ -538,5 +527,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "57fa22e6cd4e82b801605c96eac21babd78df3df361b3be566993b78a46efef2"
|
||||
"hash": "ad217c26087b2ebed6f2c9f79b16ead63727107dfce3366f3c1d12bc9d565c2c"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"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 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": 42
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ad2ffbd9f48e52678a5c61817bec043bf1df4033463e5c5a18468c04af391e6a"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\n UPDATE media_files\n SET\n public_bucket_directory_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n\n maybe_mime_type = ?,\n file_size_bytes = ?,\n\n creator_ip_address = ?\n WHERE token = ?\n LIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 7
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ad311b4aa95a71b1dc37aa09c27850a0e963380c6e7780f47a9fc5a95ab70583"
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n users.token as `user_token: UserToken`,\n users.username,\n users.display_name,\n users.email_address,\n users.user_role_slug,\n users.is_banned,\n user_roles.can_ban_users\nFROM user_sessions\nINNER JOIN users\n ON users.token = user_sessions.user_token\nLEFT OUTER JOIN user_roles\n ON users.user_role_slug = user_roles.slug\nWHERE user_sessions.token = ?\n AND user_sessions.deleted_at IS NULL\n AND users.user_deleted_at IS NULL\n AND users.mod_deleted_at IS NULL\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "user_token: UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "email_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "user_role_slug",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "is_banned",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "can_ban_users",
|
||||
"type_info": {
|
||||
"type": "Tiny",
|
||||
"flags": "",
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "c77126adb36f9e2f0248720eb4d8c1cd9d14719f64a02678d8021e26addd2c18"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE tts_results\nSET\n user_deleted_at = NULL\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "dbce51eb1c80dded902c9509e50713483c7131f115e8ec10646e99e88110278b"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\n UPDATE media_files\n SET\n media_class = ?,\n maybe_project_type = ?,\n\n public_bucket_directory_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n\n maybe_mime_type = ?,\n file_size_bytes = ?,\n\n creator_ip_address = ?\n WHERE token = ?\n LIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 9
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e33fa6280a39fff22b2e8c2731b7b6058b4705b5b557f34dba52a6440c22529b"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO media_files\nSET\n token = ?,\n\n media_class = ?,\n media_type = ?,\n maybe_project_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 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_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\nON DUPLICATE KEY UPDATE\n\n media_class = ?,\n media_type = ?,\n maybe_project_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 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_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 ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 39
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ed190d823c1d0cb5991666a25329578cbca124327bbf84116764f80d8ab4641d"
|
||||
}
|
||||
@@ -77,3 +77,20 @@ Organize for top-to-bottom reading. Important things first, details later.
|
||||
- Private helpers go *below* the methods that call them
|
||||
- Among helpers: meatier logic above leaf-level formatters
|
||||
- **In test modules**: constants first, then test cases (grouped into sub-modules when 2+), then helper functions last
|
||||
|
||||
## Markdown
|
||||
|
||||
- **Tables must be space-padded so columns align in plain text.** Markdown
|
||||
tables are read raw (terminals, diffs, editors) at least as often as
|
||||
rendered, and condensed tables are unreadable there. Pad every cell to its
|
||||
column width:
|
||||
|
||||
```markdown
|
||||
| Model | Configuration | Credits | Speed | Score |
|
||||
|--------------|---------------|--------------------|---------|
|
||||
| Meshy 6 | text or image | 104 | 80.0 | +24 |
|
||||
| Rodin 2.5 | text or image | 13 | 10.0 | +3 |
|
||||
```
|
||||
|
||||
Not: `| Model | Configuration | Credits | Speed | Score |` packed tight
|
||||
with varying widths per row.
|
||||
|
||||
Generated
+1
@@ -765,6 +765,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"strum",
|
||||
"test_data",
|
||||
"test_utils",
|
||||
"tokens",
|
||||
"tokio",
|
||||
"url_utils",
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
ADD COLUMN has_watermark BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER checksum_sha2;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- NB: MySQL 8.0.29+ performs DROP COLUMN with ALGORITHM=INSTANT (metadata-only).
|
||||
-- On older versions this is an INPLACE table rebuild that still permits
|
||||
-- concurrent reads and writes. No ALGORITHM clause so the server picks the
|
||||
-- best available.
|
||||
ALTER TABLE media_files
|
||||
DROP COLUMN has_watermark;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
ADD COLUMN is_in_aws BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER maybe_public_bucket_extension;
|
||||
|
||||
ALTER TABLE media_files
|
||||
ADD INDEX index_is_in_aws (is_in_aws);
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
DROP INDEX index_is_in_aws,
|
||||
DROP COLUMN is_in_aws;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- NB: anchored to maybe_public_bucket_extension (not is_in_aws) so this works
|
||||
-- whether or not the is_in_aws drop migration has been reverted yet.
|
||||
ALTER TABLE media_files
|
||||
ADD COLUMN is_not_in_gcp BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER maybe_public_bucket_extension;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
DROP COLUMN is_not_in_gcp;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
ADD COLUMN nsfw_status VARCHAR(32) NOT NULL DEFAULT 'unknown'
|
||||
AFTER maybe_scene_source_media_file_token;
|
||||
|
||||
ALTER TABLE media_files
|
||||
ADD INDEX index_nsfw_status (nsfw_status);
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
DROP INDEX index_nsfw_status,
|
||||
DROP COLUMN nsfw_status;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
ADD COLUMN is_batch_generated BOOLEAN NOT NULL DEFAULT FALSE
|
||||
AFTER maybe_origin_filename;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
DROP COLUMN is_batch_generated;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
ADD COLUMN maybe_media_subtype VARCHAR(32) DEFAULT NULL
|
||||
AFTER media_class;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
DROP COLUMN maybe_media_subtype;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE media_files
|
||||
DROP INDEX index_maybe_project_type,
|
||||
DROP COLUMN maybe_project_type;
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- Which kind of internal Artcraft project document this media file is
|
||||
-- ('scene_3d', 'mood_board', 'workflow', 'video_timeline', ...).
|
||||
-- Only set when media_class = 'project'. The file format lives in media_type;
|
||||
-- the JSON payload carries its own schema version.
|
||||
ALTER TABLE media_files
|
||||
ADD COLUMN maybe_project_type VARCHAR(32) DEFAULT NULL
|
||||
AFTER media_class;
|
||||
|
||||
-- For "list my mood boards"-style filtered queries.
|
||||
-- The column is all-NULL at creation time, so the index build is cheap.
|
||||
ALTER TABLE media_files
|
||||
ADD INDEX index_maybe_project_type (maybe_project_type);
|
||||
@@ -99,12 +99,6 @@ CREATE TABLE media_files (
|
||||
-- The original filename of the media (if uploaded by a user)
|
||||
maybe_origin_filename VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- TODO: Remove after `maybe_batch_token` gains use.
|
||||
-- Whether this media file was generated as part of a batch
|
||||
-- If so, we can look up the batch in a separate query/call to the `batch_generations` table.
|
||||
-- We won't hold the batch token in this table since it'll be very sparsely populated.
|
||||
is_batch_generated BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- If the media file is generated as part of a batch, this designates the batch.
|
||||
maybe_batch_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
@@ -138,9 +132,6 @@ CREATE TABLE media_files (
|
||||
-- The token is a media file token.
|
||||
maybe_scene_source_media_file_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- A flag for NSFW status.
|
||||
nsfw_status VARCHAR(32) NOT NULL DEFAULT "unknown",
|
||||
|
||||
-- ========== MEDIA DETAILS ==========
|
||||
|
||||
-- Type of media file:
|
||||
@@ -166,20 +157,19 @@ CREATE TABLE media_files (
|
||||
-- This is especially helpful with engine types that map to specific semantics.
|
||||
-- * 'unknown' (TODO: This is the default until all records are backfilled.)
|
||||
-- * 'audio' for wav, mp3, etc.
|
||||
-- * 'image' for a variety of video types.
|
||||
-- * 'image' for a variety of image types.
|
||||
-- * 'video' for a variety of video types.
|
||||
-- * 'dimensional' for a variety of 3d types
|
||||
-- * 'dimensional' (DEPRECATED) split into 'mesh', 'splat', and 'project'; read-only until backfilled
|
||||
-- * 'mesh' for 3d mesh assets (glb, gltf, fbx, obj, pmx, pmd, etc.)
|
||||
-- * 'splat' for Gaussian splats (spz, etc.)
|
||||
-- * 'project' for internal Artcraft project documents (see maybe_project_type)
|
||||
media_class VARCHAR(16) NOT NULL DEFAULT "unknown",
|
||||
|
||||
-- DEPRECATED / DO NOT USE. THIS FIELD IS NO LONGER RELEVANT.
|
||||
-- A media file's possible subtype. Typically used for Storyteller Studio.
|
||||
-- * 'mixamo' for mixamo animations (eg. for BVH, GLB, FBX, etc. files)
|
||||
-- * 'mocap_net' for mocapnet animations (eg. for BVH files)
|
||||
-- * 'scene'
|
||||
-- * 'character'
|
||||
-- * 'animation'
|
||||
-- DO NOT USE THE `maybe_media_subtype` FIELD!
|
||||
maybe_media_subtype VARCHAR(32) DEFAULT NULL,
|
||||
-- Which kind of internal Artcraft project document this media file is
|
||||
-- ('scene_3d', 'mood_board', 'workflow', 'video_timeline', ...).
|
||||
-- Only set when media_class = 'project'. The file format lives in media_type;
|
||||
-- the JSON payload carries its own schema version.
|
||||
maybe_project_type VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- The file's mime type.
|
||||
maybe_mime_type VARCHAR(32) DEFAULT NULL,
|
||||
@@ -227,10 +217,6 @@ CREATE TABLE media_files (
|
||||
-- and produces different lengths output depending on the choice of algorithm.
|
||||
checksum_sha2 CHAR(64) NOT NULL,
|
||||
|
||||
-- Whether the image or video has a visible watermark.
|
||||
-- If so, we may not need to add a watermark downstream in further processing steps.
|
||||
has_watermark BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
-- Tracks the thumbnail algorithm/type used for this media file.
|
||||
-- NULL = no thumbnail generated yet.
|
||||
-- 1 = video thumbnail.
|
||||
@@ -259,13 +245,6 @@ CREATE TABLE media_files (
|
||||
-- `[{maybe_public_bucket_prefix}]{public_bucket_directory_hash}[{maybe_public_bucket_extension}]`
|
||||
maybe_public_bucket_extension VARCHAR(16) DEFAULT NULL,
|
||||
|
||||
-- This is a migration flag that denotes whether this media file is stored in AWS.
|
||||
-- If not, it's stored in GCP.
|
||||
is_in_aws BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- This is a migration flag that denotes that weight is not stored in GCP.
|
||||
is_not_in_gcp BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
-- NB: Removed, since this can be derived.
|
||||
-- The directory this media is uploaded to will be exclusive for this file.
|
||||
-- Only this given record will live in this bucket, but the directory may include
|
||||
@@ -351,13 +330,12 @@ CREATE TABLE media_files (
|
||||
KEY index_is_user_upload (is_user_upload),
|
||||
KEY index_is_intermediate_system_file (is_intermediate_system_file),
|
||||
KEY index_maybe_scene_source_media_file_token (maybe_scene_source_media_file_token),
|
||||
KEY index_nsfw_status (nsfw_status),
|
||||
KEY index_media_type (media_type),
|
||||
KEY index_media_class (media_class),
|
||||
KEY index_maybe_project_type (maybe_project_type),
|
||||
KEY index_maybe_engine_category (maybe_engine_category),
|
||||
KEY fk_maybe_prompt_token (maybe_prompt_token),
|
||||
KEY index_checksum_sha2 (checksum_sha2),
|
||||
KEY index_is_in_aws (is_in_aws),
|
||||
KEY fk_maybe_creator_user_token (maybe_creator_user_token),
|
||||
KEY fk_maybe_mod_user_token (maybe_mod_user_token),
|
||||
KEY index_creator_ip_address (creator_ip_address),
|
||||
|
||||
@@ -1,267 +0,0 @@
|
||||
{
|
||||
"title": "[POST] /v1/media_files/write/scene_file",
|
||||
"description": "Auto-generated per-endpoint dashboard for `POST /v1/media_files/write/scene_file`.\n\nFilters all metrics on `service:storyteller-web,route:/v1/media_files/write/scene_file,method:post`.\n\nSource: `script/metrics/generate_endpoint_dashboards.py`. Do not hand-edit; changes will be overwritten on the next regeneration.",
|
||||
"layout_type": "ordered",
|
||||
"notify_list": [],
|
||||
"reflow_type": "fixed",
|
||||
"widgets": [
|
||||
{
|
||||
"definition": {
|
||||
"type": "group",
|
||||
"layout_type": "ordered",
|
||||
"title": "Top-line health",
|
||||
"show_title": true,
|
||||
"widgets": [
|
||||
{
|
||||
"definition": {
|
||||
"type": "query_value",
|
||||
"title": "Requests/sec",
|
||||
"title_size": "16",
|
||||
"title_align": "left",
|
||||
"precision": 2,
|
||||
"autoscale": true,
|
||||
"requests": [
|
||||
{
|
||||
"q": "sum:http.server.request.count{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post}.as_rate()",
|
||||
"aggregator": "avg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"layout": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 3,
|
||||
"height": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"definition": {
|
||||
"type": "query_value",
|
||||
"title": "5xx error rate (%)",
|
||||
"title_size": "16",
|
||||
"title_align": "left",
|
||||
"precision": 2,
|
||||
"autoscale": false,
|
||||
"custom_unit": "%",
|
||||
"requests": [
|
||||
{
|
||||
"q": "(sum:http.server.request.count{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post,status_class:5xx}.as_count() / sum:http.server.request.count{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post}.as_count()) * 100",
|
||||
"aggregator": "avg",
|
||||
"conditional_formats": [
|
||||
{
|
||||
"comparator": ">",
|
||||
"value": 5.0,
|
||||
"palette": "white_on_red"
|
||||
},
|
||||
{
|
||||
"comparator": ">",
|
||||
"value": 1.0,
|
||||
"palette": "white_on_yellow"
|
||||
},
|
||||
{
|
||||
"comparator": "<=",
|
||||
"value": 1.0,
|
||||
"palette": "white_on_green"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"layout": {
|
||||
"x": 3,
|
||||
"y": 0,
|
||||
"width": 3,
|
||||
"height": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"definition": {
|
||||
"type": "query_value",
|
||||
"title": "Latency p95 (ms)",
|
||||
"title_size": "16",
|
||||
"title_align": "left",
|
||||
"precision": 0,
|
||||
"autoscale": true,
|
||||
"custom_unit": "ms",
|
||||
"requests": [
|
||||
{
|
||||
"q": "p95:http.server.request.duration_ms{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post}",
|
||||
"aggregator": "avg",
|
||||
"conditional_formats": [
|
||||
{
|
||||
"comparator": ">",
|
||||
"value": 1000,
|
||||
"palette": "white_on_red"
|
||||
},
|
||||
{
|
||||
"comparator": ">",
|
||||
"value": 250,
|
||||
"palette": "white_on_yellow"
|
||||
},
|
||||
{
|
||||
"comparator": "<=",
|
||||
"value": 250,
|
||||
"palette": "white_on_green"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"layout": {
|
||||
"x": 6,
|
||||
"y": 0,
|
||||
"width": 3,
|
||||
"height": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"definition": {
|
||||
"type": "query_value",
|
||||
"title": "Latency p99 (ms)",
|
||||
"title_size": "16",
|
||||
"title_align": "left",
|
||||
"precision": 0,
|
||||
"autoscale": true,
|
||||
"custom_unit": "ms",
|
||||
"requests": [
|
||||
{
|
||||
"q": "p99:http.server.request.duration_ms{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post}",
|
||||
"aggregator": "avg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"layout": {
|
||||
"x": 9,
|
||||
"y": 0,
|
||||
"width": 3,
|
||||
"height": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"layout": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 12,
|
||||
"height": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"definition": {
|
||||
"type": "group",
|
||||
"layout_type": "ordered",
|
||||
"title": "Trends",
|
||||
"show_title": true,
|
||||
"widgets": [
|
||||
{
|
||||
"definition": {
|
||||
"type": "timeseries",
|
||||
"title": "Requests/sec by status class",
|
||||
"title_size": "16",
|
||||
"title_align": "left",
|
||||
"show_legend": true,
|
||||
"legend_layout": "horizontal",
|
||||
"requests": [
|
||||
{
|
||||
"q": "sum:http.server.request.count{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post} by {status_class}.as_rate()",
|
||||
"display_type": "bars",
|
||||
"style": {
|
||||
"palette": "semantic",
|
||||
"line_type": "solid",
|
||||
"line_width": "normal"
|
||||
}
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"scale": "linear",
|
||||
"include_zero": true
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"definition": {
|
||||
"type": "timeseries",
|
||||
"title": "Latency percentiles",
|
||||
"title_size": "16",
|
||||
"title_align": "left",
|
||||
"show_legend": true,
|
||||
"legend_layout": "horizontal",
|
||||
"requests": [
|
||||
{
|
||||
"q": "p50:http.server.request.duration_ms{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post}",
|
||||
"display_type": "line",
|
||||
"style": {
|
||||
"palette": "cool",
|
||||
"line_type": "solid",
|
||||
"line_width": "normal"
|
||||
}
|
||||
},
|
||||
{
|
||||
"q": "p95:http.server.request.duration_ms{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post}",
|
||||
"display_type": "line",
|
||||
"style": {
|
||||
"palette": "warm",
|
||||
"line_type": "solid",
|
||||
"line_width": "normal"
|
||||
}
|
||||
},
|
||||
{
|
||||
"q": "p99:http.server.request.duration_ms{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post}",
|
||||
"display_type": "line",
|
||||
"style": {
|
||||
"palette": "warm",
|
||||
"line_type": "dashed",
|
||||
"line_width": "normal"
|
||||
}
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"scale": "linear",
|
||||
"include_zero": true,
|
||||
"label": "ms"
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"x": 6,
|
||||
"y": 0,
|
||||
"width": 6,
|
||||
"height": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"layout": {
|
||||
"x": 0,
|
||||
"y": 3,
|
||||
"width": 12,
|
||||
"height": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"definition": {
|
||||
"type": "toplist",
|
||||
"title": "Status code distribution",
|
||||
"title_size": "16",
|
||||
"title_align": "left",
|
||||
"requests": [
|
||||
{
|
||||
"q": "top(sum:http.server.request.count{service:storyteller-web,route:/v1/media_files/write/scene_file,method:post} by {status_code}.as_count(), 25, 'sum', 'desc')"
|
||||
}
|
||||
]
|
||||
},
|
||||
"layout": {
|
||||
"x": 0,
|
||||
"y": 8,
|
||||
"width": 12,
|
||||
"height": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": "c8z-t2z-nk4"
|
||||
}
|
||||
+3
@@ -1,2 +1,5 @@
|
||||
pub mod omni_gen_audio_cost_and_generate_request;
|
||||
pub mod omni_gen_image_cost_and_generate_request;
|
||||
pub mod omni_gen_mesh_cost_and_generate_request;
|
||||
pub mod omni_gen_splat_cost_and_generate_request;
|
||||
pub mod omni_gen_video_cost_and_generate_request;
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::common::generation::common_audio_model::CommonAudioModel;
|
||||
use enums::common::generation::common_musical_key::CommonMusicalKey;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
/// Shared request body for both the audio cost estimate and audio generation endpoints.
|
||||
#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct OmniGenAudioCostAndGenerateRequest {
|
||||
/// REQUIRED (even if marked optional)
|
||||
/// Idempotency token to prevent duplicate requests.
|
||||
pub idempotency_token: Option<String>,
|
||||
|
||||
/// REQUIRED (even if marked optional)
|
||||
/// Which model to use.
|
||||
pub model: Option<CommonAudioModel>,
|
||||
|
||||
/// The text prompt for the audio generation.
|
||||
pub prompt: Option<String>,
|
||||
|
||||
/// Style/genre direction (Suno's "tags").
|
||||
pub style_prompt: Option<String>,
|
||||
|
||||
/// Reference audio (optional).
|
||||
/// The remix/sample source, or Seed Audio @Audio references (up to 3).
|
||||
pub audio_media_tokens: Option<Vec<MediaFileToken>>,
|
||||
|
||||
/// Reference image (optional).
|
||||
/// Seed Audio supports a single reference image; cannot be combined with audio references.
|
||||
pub image_media_tokens: Option<Vec<MediaFileToken>>,
|
||||
|
||||
/// Whether to keep the original lyrics (Suno Remix).
|
||||
pub keep_lyrics: Option<bool>,
|
||||
|
||||
/// Whether to generate instrumental-only audio (Suno Music / Sample).
|
||||
pub is_instrumental: Option<bool>,
|
||||
|
||||
/// Whether the sound should loop vs a single hit (Suno Sounds).
|
||||
pub is_loopable: Option<bool>,
|
||||
|
||||
/// Beats per minute (Suno Sounds).
|
||||
pub bpm: Option<u16>,
|
||||
|
||||
/// The musical key to use (Suno Sounds).
|
||||
pub musical_key: Option<CommonMusicalKey>,
|
||||
|
||||
/// Output sample rate in Hz (Seed Audio: 8000/16000/24000/32000/44100/48000).
|
||||
pub sample_rate_hz: Option<u32>,
|
||||
|
||||
/// Playback speed multiplier (Seed Audio: 0.5–2.0).
|
||||
pub speed: Option<f64>,
|
||||
|
||||
/// Volume multiplier (Seed Audio: 0.5–2.0).
|
||||
pub volume: Option<f64>,
|
||||
|
||||
/// Pitch shift in semitones (Seed Audio: -12..=12).
|
||||
pub pitch: Option<f64>,
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::common::generation::common_mesh_model::CommonMeshModel;
|
||||
use enums::common::generation::common_mesh_output_type::CommonMeshOutputType;
|
||||
use enums::common::generation::common_mesh_quality::CommonMeshQuality;
|
||||
use enums::common::generation::common_polygon_type::CommonPolygonType;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
/// Shared request body for both the mesh cost estimate and mesh generation endpoints.
|
||||
#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct OmniGenMeshCostAndGenerateRequest {
|
||||
/// REQUIRED (even if marked optional)
|
||||
/// Idempotency token to prevent duplicate requests.
|
||||
pub idempotency_token: Option<String>,
|
||||
|
||||
/// REQUIRED (even if marked optional)
|
||||
/// Which model to use.
|
||||
pub model: Option<CommonMeshModel>,
|
||||
|
||||
/// The text prompt for the mesh generation (text-to-3D).
|
||||
pub prompt: Option<String>,
|
||||
|
||||
/// Reference images (optional).
|
||||
/// The primary/front input image, or the sketch image for sketch-to-3D.
|
||||
pub reference_image_media_tokens: Option<Vec<MediaFileToken>>,
|
||||
|
||||
/// Front view image (optional; multi-view input).
|
||||
/// Can be used instead of `reference_image_media_tokens[0]` when the other
|
||||
/// side views are supplied.
|
||||
pub front_image_media_token: Option<MediaFileToken>,
|
||||
|
||||
/// Back view image (optional; multi-view input).
|
||||
pub back_image_media_token: Option<MediaFileToken>,
|
||||
|
||||
/// Left view image (optional; multi-view input).
|
||||
pub left_image_media_token: Option<MediaFileToken>,
|
||||
|
||||
/// Right view image (optional; multi-view input).
|
||||
pub right_image_media_token: Option<MediaFileToken>,
|
||||
|
||||
/// Input mesh file for mesh-to-mesh models (part splitting, retopology).
|
||||
/// Required by `hunyuan_3d_3p1_part` (FBX) and
|
||||
/// `hunyuan_3d_3p1_topology` (GLB/OBJ).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub input_mesh_media_token: Option<MediaFileToken>,
|
||||
|
||||
/// The mesh output type to generate (normal, low-poly, or geometry-only).
|
||||
pub mesh_output_type: Option<CommonMeshOutputType>,
|
||||
|
||||
/// The polygon type to use for the generated mesh (triangle or quad).
|
||||
pub polygon_type: Option<CommonPolygonType>,
|
||||
|
||||
/// Target face count for the generated mesh.
|
||||
pub face_count: Option<u64>,
|
||||
|
||||
/// Whether to generate PBR (physically based rendering) materials.
|
||||
pub enable_pbr: Option<bool>,
|
||||
|
||||
/// Whether to generate textures. Some models (Tripo3D) can skip texturing
|
||||
/// for a cheaper, faster generation.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub enable_texture: Option<bool>,
|
||||
|
||||
/// Texture quality. `Detailed` costs extra on some models (Tripo3D's HD
|
||||
/// texture tier).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub texture_quality: Option<CommonMeshQuality>,
|
||||
|
||||
/// Geometry quality. `Detailed` costs extra on some models (Tripo3D).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub geometry_quality: Option<CommonMeshQuality>,
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::common::generation::common_splat_model::CommonSplatModel;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
/// Shared request body for both the splat cost estimate and splat generation endpoints.
|
||||
#[derive(Clone, Serialize, Deserialize, ToSchema, Debug)]
|
||||
pub struct OmniGenSplatCostAndGenerateRequest {
|
||||
/// REQUIRED (even if marked optional)
|
||||
/// Idempotency token to prevent duplicate requests.
|
||||
pub idempotency_token: Option<String>,
|
||||
|
||||
/// REQUIRED (even if marked optional)
|
||||
/// Which model to use.
|
||||
pub model: Option<CommonSplatModel>,
|
||||
|
||||
/// The text prompt for the splat generation.
|
||||
pub prompt: Option<String>,
|
||||
|
||||
/// Reference images (optional).
|
||||
/// NOTE: Spherical/panorama coordinates are not yet supported per-image;
|
||||
/// multiple images are treated as multi-view input of the same world.
|
||||
pub reference_image_media_tokens: Option<Vec<MediaFileToken>>,
|
||||
|
||||
/// Reference video (optional).
|
||||
pub reference_video_media_token: Option<MediaFileToken>,
|
||||
|
||||
/// Whether the single reference image is a 360-degree panorama.
|
||||
pub is_panoramic: Option<bool>,
|
||||
|
||||
/// Whether to disable prompt recaptioning.
|
||||
pub disable_recaption: Option<bool>,
|
||||
}
|
||||
@@ -1,2 +1,5 @@
|
||||
pub mod omni_gen_audio_cost_response;
|
||||
pub mod omni_gen_image_cost_response;
|
||||
pub mod omni_gen_mesh_cost_response;
|
||||
pub mod omni_gen_splat_cost_response;
|
||||
pub mod omni_gen_video_cost_response;
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Response body for the omni-gen audio cost estimate endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct OmniGenAudioCostResponse {
|
||||
pub success: bool,
|
||||
|
||||
/// Estimated cost in credits.
|
||||
pub cost_in_credits: Option<u64>,
|
||||
|
||||
/// Estimated cost in USD cents.
|
||||
pub cost_in_usd_cents: Option<u64>,
|
||||
|
||||
/// Whether the generation is free for this user/plan.
|
||||
pub is_free: bool,
|
||||
|
||||
/// Whether the user has unlimited generations.
|
||||
pub is_unlimited: bool,
|
||||
|
||||
/// Whether the user is rate-limited.
|
||||
pub is_rate_limited: bool,
|
||||
|
||||
/// Whether the output will have a watermark.
|
||||
pub has_watermark: bool,
|
||||
|
||||
/// Whether failures are refunded.
|
||||
/// True: 100% yes
|
||||
/// False: 100% no
|
||||
/// None: Unknown or variable
|
||||
pub failures_are_refunded: Option<bool>,
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Response body for the omni-gen mesh cost estimate endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct OmniGenMeshCostResponse {
|
||||
pub success: bool,
|
||||
|
||||
/// Estimated cost in credits.
|
||||
pub cost_in_credits: Option<u64>,
|
||||
|
||||
/// Estimated cost in USD cents.
|
||||
pub cost_in_usd_cents: Option<u64>,
|
||||
|
||||
/// Whether the generation is free for this user/plan.
|
||||
pub is_free: bool,
|
||||
|
||||
/// Whether the user has unlimited generations.
|
||||
pub is_unlimited: bool,
|
||||
|
||||
/// Whether the user is rate-limited.
|
||||
pub is_rate_limited: bool,
|
||||
|
||||
/// Whether the output will have a watermark.
|
||||
pub has_watermark: bool,
|
||||
|
||||
/// Whether failures are refunded.
|
||||
/// True: 100% yes
|
||||
/// False: 100% no
|
||||
/// None: Unknown or variable
|
||||
pub failures_are_refunded: Option<bool>,
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Response body for the omni-gen splat cost estimate endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct OmniGenSplatCostResponse {
|
||||
pub success: bool,
|
||||
|
||||
/// Estimated cost in credits.
|
||||
pub cost_in_credits: Option<u64>,
|
||||
|
||||
/// Estimated cost in USD cents.
|
||||
pub cost_in_usd_cents: Option<u64>,
|
||||
|
||||
/// Whether the generation is free for this user/plan.
|
||||
pub is_free: bool,
|
||||
|
||||
/// Whether the user has unlimited generations.
|
||||
pub is_unlimited: bool,
|
||||
|
||||
/// Whether the user is rate-limited.
|
||||
pub is_rate_limited: bool,
|
||||
|
||||
/// Whether the output will have a watermark.
|
||||
pub has_watermark: bool,
|
||||
|
||||
/// Whether failures are refunded.
|
||||
/// True: 100% yes
|
||||
/// False: 100% no
|
||||
/// None: Unknown or variable
|
||||
pub failures_are_refunded: Option<bool>,
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@ use serde_derive::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Response body for the omni-gen video cost estimate endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct OmniGenVideoCostResponse {
|
||||
pub success: bool,
|
||||
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
pub mod omni_gen_audio_generate_response;
|
||||
pub mod omni_gen_image_generate_response;
|
||||
pub mod omni_gen_mesh_generate_response;
|
||||
pub mod omni_gen_splat_generate_response;
|
||||
pub mod omni_gen_video_generate_response;
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Response body for the omni-gen audio generation endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct OmniGenAudioGenerateResponse {
|
||||
pub success: bool,
|
||||
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
|
||||
/// All job tokens created by this request (including the primary).
|
||||
/// For single-job requests this will contain just one element matching
|
||||
/// `inference_job_token`. For batch requests this will contain all of them.
|
||||
pub all_job_tokens: Vec<InferenceJobToken>,
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Response body for the omni-gen mesh generation endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct OmniGenMeshGenerateResponse {
|
||||
pub success: bool,
|
||||
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
|
||||
/// All job tokens created by this request (including the primary).
|
||||
/// For single-job requests this will contain just one element matching
|
||||
/// `inference_job_token`. For batch requests this will contain all of them.
|
||||
pub all_job_tokens: Vec<InferenceJobToken>,
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Response body for the omni-gen splat generation endpoint.
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
pub struct OmniGenSplatGenerateResponse {
|
||||
pub success: bool,
|
||||
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
|
||||
/// All job tokens created by this request (including the primary).
|
||||
/// For single-job requests this will contain just one element matching
|
||||
/// `inference_job_token`. For batch requests this will contain all of them.
|
||||
pub all_job_tokens: Vec<InferenceJobToken>,
|
||||
}
|
||||
@@ -1,2 +1,5 @@
|
||||
pub mod omni_gen_audio_models;
|
||||
pub mod omni_gen_image_models;
|
||||
pub mod omni_gen_mesh_models;
|
||||
pub mod omni_gen_splat_models;
|
||||
pub mod omni_gen_video_models;
|
||||
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
use enums::common::generation::common_audio_model::CommonAudioModel;
|
||||
use enums::common::generation::model_creator::ModelCreator;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use serde_derive::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Audio model to default to if none is specified
|
||||
const DEFAULT_AUDIO_MODEL : CommonAudioModel = CommonAudioModel::SunoMusic;
|
||||
|
||||
/// Response body for the audio models endpoint.
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenAudioModelsResponse {
|
||||
pub success: bool,
|
||||
|
||||
/// A list of all models: details, features, and capabilities
|
||||
pub models: Vec<OmniGenAudioModelDetails>,
|
||||
|
||||
/// Provider-by-provider model offering and capability list,
|
||||
/// with possible capability overrides (future)
|
||||
pub providers: Vec<OmniGenAudioModelProviderDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenAudioModelProviderDetails {
|
||||
pub provider: GenerationProvider,
|
||||
pub models: Vec<OmniGenAudioProviderModelDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenAudioProviderModelDetails {
|
||||
pub model: CommonAudioModel,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub overrides: Option<OmniGenAudioModelDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenAudioModelDetails {
|
||||
|
||||
pub model: CommonAudioModel,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub model_creator: Option<ModelCreator>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub full_name: Option<String>,
|
||||
|
||||
/// Additional details about the model.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub extra_info: Option<String>,
|
||||
|
||||
/// Additional details about the model. (Brief; only a few words.)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub extra_info_short: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text_prompt_supported: Option<bool>,
|
||||
|
||||
/// Whether a style/genre prompt (Suno's "tags") is supported.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub style_prompt_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub audio_references_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub audio_references_max: Option<u16>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_references_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_references_max: Option<u16>,
|
||||
|
||||
/// Whether the "keep lyrics" toggle is supported (Suno Remix).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub keep_lyrics_supported: Option<bool>,
|
||||
|
||||
/// Whether the instrumental-only toggle is supported (Suno Music / Sample).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub instrumental_toggle_supported: Option<bool>,
|
||||
|
||||
/// Whether the loop vs single-hit toggle is supported (Suno Sounds).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub loopable_toggle_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub bpm_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub musical_key_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sample_rate_hz_options: Option<Vec<u32>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sample_rate_hz_default: Option<u32>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub speed_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub volume_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub pitch_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_disabled: Option<bool>,
|
||||
}
|
||||
|
||||
impl Default for OmniGenAudioModelDetails {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
model: DEFAULT_AUDIO_MODEL,
|
||||
model_creator: None,
|
||||
full_name: None,
|
||||
extra_info: None,
|
||||
extra_info_short: None,
|
||||
text_prompt_supported: None,
|
||||
style_prompt_supported: None,
|
||||
audio_references_supported: None,
|
||||
audio_references_max: None,
|
||||
image_references_supported: None,
|
||||
image_references_max: None,
|
||||
keep_lyrics_supported: None,
|
||||
instrumental_toggle_supported: None,
|
||||
loopable_toggle_supported: None,
|
||||
bpm_supported: None,
|
||||
musical_key_supported: None,
|
||||
sample_rate_hz_options: None,
|
||||
sample_rate_hz_default: None,
|
||||
speed_supported: None,
|
||||
volume_supported: None,
|
||||
pitch_supported: None,
|
||||
is_disabled: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
use enums::common::generation::common_mesh_model::CommonMeshModel;
|
||||
use enums::common::generation::common_mesh_output_type::CommonMeshOutputType;
|
||||
use enums::common::generation::common_polygon_type::CommonPolygonType;
|
||||
use enums::common::generation::model_creator::ModelCreator;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use serde_derive::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Mesh model to default to if none is specified
|
||||
const DEFAULT_MESH_MODEL : CommonMeshModel = CommonMeshModel::Hunyuan3d3;
|
||||
|
||||
/// Response body for the mesh models endpoint.
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenMeshModelsResponse {
|
||||
pub success: bool,
|
||||
|
||||
/// A list of all models: details, features, and capabilities
|
||||
pub models: Vec<OmniGenMeshModelDetails>,
|
||||
|
||||
/// Provider-by-provider model offering and capability list,
|
||||
/// with possible capability overrides (future)
|
||||
pub providers: Vec<OmniGenMeshModelProviderDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenMeshModelProviderDetails {
|
||||
pub provider: GenerationProvider,
|
||||
pub models: Vec<OmniGenMeshProviderModelDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenMeshProviderModelDetails {
|
||||
pub model: CommonMeshModel,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub overrides: Option<OmniGenMeshModelDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenMeshModelDetails {
|
||||
|
||||
pub model: CommonMeshModel,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub model_creator: Option<ModelCreator>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub full_name: Option<String>,
|
||||
|
||||
/// Additional details about the model.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub extra_info: Option<String>,
|
||||
|
||||
/// Additional details about the model. (Brief; only a few words.)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub extra_info_short: Option<String>,
|
||||
|
||||
/// Whether text-to-3D prompting is supported.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text_prompt_supported: Option<bool>,
|
||||
|
||||
/// Whether image-to-3D input is supported.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_input_supported: Option<bool>,
|
||||
|
||||
/// Whether sketch-to-3D input is supported.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sketch_input_supported: Option<bool>,
|
||||
|
||||
/// Whether multi-view (front/back/left/right) image input is supported.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub multi_view_supported: Option<bool>,
|
||||
|
||||
/// Whether the model takes an existing mesh file as input
|
||||
/// (mesh-to-mesh models like part splitting and retopology).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mesh_input_supported: Option<bool>,
|
||||
|
||||
/// The mesh output types the model supports.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mesh_output_types: Option<Vec<CommonMeshOutputType>>,
|
||||
|
||||
/// The polygon types the model supports.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub polygon_types: Option<Vec<CommonPolygonType>>,
|
||||
|
||||
/// Whether a target face count can be specified.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub face_count_supported: Option<bool>,
|
||||
|
||||
/// Whether PBR (physically based rendering) material generation is supported.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub pbr_supported: Option<bool>,
|
||||
|
||||
/// Whether texture generation can be toggled off (untextured output).
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub texture_toggle_supported: Option<bool>,
|
||||
|
||||
/// Whether a texture quality level (standard/detailed) can be selected.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub texture_quality_supported: Option<bool>,
|
||||
|
||||
/// Whether a geometry quality level (standard/detailed) can be selected.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub geometry_quality_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_disabled: Option<bool>,
|
||||
}
|
||||
|
||||
impl Default for OmniGenMeshModelDetails {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
model: DEFAULT_MESH_MODEL,
|
||||
model_creator: None,
|
||||
full_name: None,
|
||||
extra_info: None,
|
||||
extra_info_short: None,
|
||||
text_prompt_supported: None,
|
||||
image_input_supported: None,
|
||||
sketch_input_supported: None,
|
||||
multi_view_supported: None,
|
||||
mesh_input_supported: None,
|
||||
mesh_output_types: None,
|
||||
polygon_types: None,
|
||||
face_count_supported: None,
|
||||
pbr_supported: None,
|
||||
texture_toggle_supported: None,
|
||||
texture_quality_supported: None,
|
||||
geometry_quality_supported: None,
|
||||
is_disabled: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
use enums::common::generation::common_splat_model::CommonSplatModel;
|
||||
use enums::common::generation::model_creator::ModelCreator;
|
||||
use enums::common::generation_provider::GenerationProvider;
|
||||
use serde_derive::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Splat model to default to if none is specified
|
||||
const DEFAULT_SPLAT_MODEL : CommonSplatModel = CommonSplatModel::Marble1p1;
|
||||
|
||||
/// Response body for the splat models endpoint.
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenSplatModelsResponse {
|
||||
pub success: bool,
|
||||
|
||||
/// A list of all models: details, features, and capabilities
|
||||
pub models: Vec<OmniGenSplatModelDetails>,
|
||||
|
||||
/// Provider-by-provider model offering and capability list,
|
||||
/// with possible capability overrides (future)
|
||||
pub providers: Vec<OmniGenSplatModelProviderDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenSplatModelProviderDetails {
|
||||
pub provider: GenerationProvider,
|
||||
pub models: Vec<OmniGenSplatProviderModelDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenSplatProviderModelDetails {
|
||||
pub model: CommonSplatModel,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub overrides: Option<OmniGenSplatModelDetails>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema, Clone)]
|
||||
pub struct OmniGenSplatModelDetails {
|
||||
|
||||
pub model: CommonSplatModel,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub model_creator: Option<ModelCreator>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub full_name: Option<String>,
|
||||
|
||||
/// Additional details about the model.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub extra_info: Option<String>,
|
||||
|
||||
/// Additional details about the model. (Brief; only a few words.)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub extra_info_short: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text_prompt_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_references_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_references_max: Option<u16>,
|
||||
|
||||
/// Whether a reference video input is supported.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub video_reference_supported: Option<bool>,
|
||||
|
||||
/// Whether a 360-degree panorama reference image is supported.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub panorama_supported: Option<bool>,
|
||||
|
||||
/// Whether the "disable recaption" toggle is supported.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub disable_recaption_supported: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_disabled: Option<bool>,
|
||||
}
|
||||
|
||||
impl Default for OmniGenSplatModelDetails {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
model: DEFAULT_SPLAT_MODEL,
|
||||
model_creator: None,
|
||||
full_name: None,
|
||||
extra_info: None,
|
||||
extra_info_short: None,
|
||||
text_prompt_supported: None,
|
||||
image_references_supported: None,
|
||||
image_references_max: None,
|
||||
video_reference_supported: None,
|
||||
panorama_supported: None,
|
||||
disable_recaption_supported: None,
|
||||
is_disabled: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
-5
@@ -76,11 +76,6 @@ pub struct MediaFileInfo {
|
||||
/// this describes the animation regime used or supported.
|
||||
pub maybe_animation_type: Option<MediaFileAnimationType>,
|
||||
|
||||
// /// If the media file has a subtype, we'll report it.
|
||||
// /// This is mostly used for Bevy engine files.
|
||||
// #[deprecated(note="This was for the Bevy engine. Do not use.")]
|
||||
// pub maybe_media_subtype: Option<MediaFileSubtype>,
|
||||
|
||||
// /// Extension for the engine to load over remote:// URLs.
|
||||
// #[deprecated(note="This was for the Bevy engine. Do not use.")]
|
||||
// pub maybe_engine_extension: Option<String>,
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
pub mod omni_gen_audio;
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
use crate::credentials::storyteller_credential_set::StorytellerCredentialSet;
|
||||
use crate::error::storyteller_error::StorytellerError;
|
||||
use crate::utils::api_host::ApiHost;
|
||||
use crate::utils::basic_json_post_request::basic_json_post_request;
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_audio_cost_and_generate_request::OmniGenAudioCostAndGenerateRequest;
|
||||
use artcraft_api_defs::omni_gen::generate_response::omni_gen_audio_generate_response::OmniGenAudioGenerateResponse;
|
||||
|
||||
pub const OMNI_GEN_AUDIO_GENERATE_PATH: &str = "/v1/omni_gen/generate/audio";
|
||||
|
||||
pub async fn omni_gen_audio_generate(
|
||||
api_host: &ApiHost,
|
||||
maybe_creds: Option<&StorytellerCredentialSet>,
|
||||
request: OmniGenAudioCostAndGenerateRequest,
|
||||
) -> Result<OmniGenAudioGenerateResponse, StorytellerError> {
|
||||
Ok(basic_json_post_request(
|
||||
api_host,
|
||||
OMNI_GEN_AUDIO_GENERATE_PATH,
|
||||
maybe_creds,
|
||||
request,
|
||||
).await?)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
pub mod omni_gen_mesh;
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
use crate::credentials::storyteller_credential_set::StorytellerCredentialSet;
|
||||
use crate::error::storyteller_error::StorytellerError;
|
||||
use crate::utils::api_host::ApiHost;
|
||||
use crate::utils::basic_json_post_request::basic_json_post_request;
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_mesh_cost_and_generate_request::OmniGenMeshCostAndGenerateRequest;
|
||||
use artcraft_api_defs::omni_gen::generate_response::omni_gen_mesh_generate_response::OmniGenMeshGenerateResponse;
|
||||
|
||||
pub const OMNI_GEN_MESH_GENERATE_PATH: &str = "/v1/omni_gen/generate/mesh";
|
||||
|
||||
pub async fn omni_gen_mesh_generate(
|
||||
api_host: &ApiHost,
|
||||
maybe_creds: Option<&StorytellerCredentialSet>,
|
||||
request: OmniGenMeshCostAndGenerateRequest,
|
||||
) -> Result<OmniGenMeshGenerateResponse, StorytellerError> {
|
||||
Ok(basic_json_post_request(
|
||||
api_host,
|
||||
OMNI_GEN_MESH_GENERATE_PATH,
|
||||
maybe_creds,
|
||||
request,
|
||||
).await?)
|
||||
}
|
||||
@@ -1,2 +1,5 @@
|
||||
pub mod audio;
|
||||
pub mod image;
|
||||
pub mod mesh;
|
||||
pub mod splat;
|
||||
pub mod video;
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
pub mod omni_gen_splat;
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
use crate::credentials::storyteller_credential_set::StorytellerCredentialSet;
|
||||
use crate::error::storyteller_error::StorytellerError;
|
||||
use crate::utils::api_host::ApiHost;
|
||||
use crate::utils::basic_json_post_request::basic_json_post_request;
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_splat_cost_and_generate_request::OmniGenSplatCostAndGenerateRequest;
|
||||
use artcraft_api_defs::omni_gen::generate_response::omni_gen_splat_generate_response::OmniGenSplatGenerateResponse;
|
||||
|
||||
pub const OMNI_GEN_SPLAT_GENERATE_PATH: &str = "/v1/omni_gen/generate/splat";
|
||||
|
||||
pub async fn omni_gen_splat_generate(
|
||||
api_host: &ApiHost,
|
||||
maybe_creds: Option<&StorytellerCredentialSet>,
|
||||
request: OmniGenSplatCostAndGenerateRequest,
|
||||
) -> Result<OmniGenSplatGenerateResponse, StorytellerError> {
|
||||
Ok(basic_json_post_request(
|
||||
api_host,
|
||||
OMNI_GEN_SPLAT_GENERATE_PATH,
|
||||
maybe_creds,
|
||||
request,
|
||||
).await?)
|
||||
}
|
||||
@@ -39,6 +39,7 @@ uuid.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
test_data.workspace = true
|
||||
test_utils.workspace = true
|
||||
strum.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
/// Reference to an input 3D mesh file (e.g. GLB/OBJ/FBX) for mesh-to-mesh
|
||||
/// models like part splitting and retopology.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum MeshRef {
|
||||
MediaFileToken(MediaFileToken),
|
||||
Url(String),
|
||||
}
|
||||
@@ -2,12 +2,16 @@ pub mod audio_list_ref;
|
||||
pub mod character_list_ref;
|
||||
pub mod image_list_ref;
|
||||
pub mod image_ref;
|
||||
pub mod mesh_ref;
|
||||
pub mod router_aspect_ratio;
|
||||
pub mod router_audio_model;
|
||||
pub mod router_bitrate;
|
||||
pub mod router_image_model;
|
||||
pub mod router_mesh_model;
|
||||
pub mod router_provider;
|
||||
pub mod router_quality;
|
||||
pub mod router_resolution;
|
||||
pub mod router_splat_model;
|
||||
pub mod router_video_model;
|
||||
pub mod video_list_ref;
|
||||
pub mod video_ref;
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
/// Common audio models supported by the router.
|
||||
/// Not all models are available through all providers.
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RouterAudioModel {
|
||||
#[serde(rename = "suno_music")]
|
||||
SunoMusic,
|
||||
|
||||
#[serde(rename = "suno_remix")]
|
||||
SunoRemix,
|
||||
|
||||
#[serde(rename = "suno_sounds")]
|
||||
SunoSounds,
|
||||
|
||||
#[serde(rename = "suno_sample")]
|
||||
SunoSample,
|
||||
|
||||
#[serde(rename = "seed_audio_1p0")]
|
||||
SeedAudio1p0,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// NB: These strings must match `CommonAudioModel` — the two enums convert
|
||||
// via serde string round-trip.
|
||||
#[test]
|
||||
fn all_variants_serialize_to_common_audio_model_strings() {
|
||||
assert_serde_round_trip(RouterAudioModel::SunoMusic, "suno_music");
|
||||
assert_serde_round_trip(RouterAudioModel::SunoRemix, "suno_remix");
|
||||
assert_serde_round_trip(RouterAudioModel::SunoSounds, "suno_sounds");
|
||||
assert_serde_round_trip(RouterAudioModel::SunoSample, "suno_sample");
|
||||
assert_serde_round_trip(RouterAudioModel::SeedAudio1p0, "seed_audio_1p0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trips_through_common_audio_model() {
|
||||
use enums::common::generation::common_audio_model::CommonAudioModel;
|
||||
|
||||
let cases = [
|
||||
(RouterAudioModel::SunoMusic, CommonAudioModel::SunoMusic),
|
||||
(RouterAudioModel::SunoRemix, CommonAudioModel::SunoRemix),
|
||||
(RouterAudioModel::SunoSounds, CommonAudioModel::SunoSounds),
|
||||
(RouterAudioModel::SunoSample, CommonAudioModel::SunoSample),
|
||||
(RouterAudioModel::SeedAudio1p0, CommonAudioModel::SeedAudio1p0),
|
||||
];
|
||||
for (router_model, expected_common) in cases {
|
||||
let json = serde_json::to_string(&router_model).unwrap();
|
||||
let common: CommonAudioModel = serde_json::from_str(&json)
|
||||
.unwrap_or_else(|e| panic!("CommonAudioModel failed to parse {json}: {e}"));
|
||||
assert_eq!(common, expected_common, "for {router_model:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_serde_round_trip(model: RouterAudioModel, expected: &str) {
|
||||
let json = serde_json::to_string(&model).unwrap();
|
||||
assert_eq!(json, format!("\"{expected}\""));
|
||||
let parsed: RouterAudioModel = serde_json::from_str(&json).unwrap();
|
||||
// RouterAudioModel isn't PartialEq, so round-trip back to the wire form.
|
||||
assert_eq!(serde_json::to_string(&parsed).unwrap(), json);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
/// Common mesh (3D object) models supported by the router.
|
||||
/// Not all models are available through all providers.
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RouterMeshModel {
|
||||
#[serde(rename = "hunyuan_3d_2p0")]
|
||||
Hunyuan3d2p0,
|
||||
|
||||
#[serde(rename = "hunyuan_3d_2p1")]
|
||||
Hunyuan3d2p1,
|
||||
|
||||
#[serde(rename = "hunyuan_3d_3")]
|
||||
Hunyuan3d3,
|
||||
|
||||
/// Hunyuan 3D v3 in sketch-to-3D mode. Same underlying model as
|
||||
/// [`Self::Hunyuan3d3`], but takes a sketch image plus a prompt as input.
|
||||
#[serde(rename = "hunyuan_3d_3_sketch")]
|
||||
Hunyuan3d3Sketch,
|
||||
|
||||
/// Hunyuan 3D v3.1 Pro: text or (multi-view) image input.
|
||||
#[serde(rename = "hunyuan_3d_3p1_pro")]
|
||||
Hunyuan3d3p1Pro,
|
||||
|
||||
/// Hunyuan 3D v3.1 Rapid: the fast, low-cost tier. Text or single-image
|
||||
/// input.
|
||||
#[serde(rename = "hunyuan_3d_3p1_rapid")]
|
||||
Hunyuan3d3p1Rapid,
|
||||
|
||||
/// Hunyuan 3D v3.1 Part: splits an existing mesh into semantic parts.
|
||||
/// Takes a mesh file as input, not text/images.
|
||||
#[serde(rename = "hunyuan_3d_3p1_part")]
|
||||
Hunyuan3d3p1Part,
|
||||
|
||||
/// Hunyuan 3D v3.1 Smart Topology: retopologizes an existing mesh.
|
||||
/// Takes a mesh file as input, not text/images.
|
||||
#[serde(rename = "hunyuan_3d_3p1_topology")]
|
||||
Hunyuan3d3p1SmartTopology,
|
||||
|
||||
/// Tripo3D H3.1: text, single-image, or multi-view image input.
|
||||
#[serde(rename = "tripo3d_h3p1")]
|
||||
Tripo3dH3p1,
|
||||
|
||||
/// Meshy 6: text or single-image input.
|
||||
#[serde(rename = "meshy_v6")]
|
||||
MeshyV6,
|
||||
|
||||
/// Hyper3D Rodin v2.5 Fast: text or image(s) input.
|
||||
#[serde(rename = "rodin_2p5_fast")]
|
||||
Rodin2p5Fast,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// NB: These strings must match `CommonMeshModel` — the two enums convert
|
||||
// via serde string round-trip.
|
||||
#[test]
|
||||
fn all_variants_serialize_to_common_mesh_model_strings() {
|
||||
assert_serde_round_trip(RouterMeshModel::Hunyuan3d2p0, "hunyuan_3d_2p0");
|
||||
assert_serde_round_trip(RouterMeshModel::Hunyuan3d2p1, "hunyuan_3d_2p1");
|
||||
assert_serde_round_trip(RouterMeshModel::Hunyuan3d3, "hunyuan_3d_3");
|
||||
assert_serde_round_trip(RouterMeshModel::Hunyuan3d3Sketch, "hunyuan_3d_3_sketch");
|
||||
assert_serde_round_trip(RouterMeshModel::Hunyuan3d3p1Pro, "hunyuan_3d_3p1_pro");
|
||||
assert_serde_round_trip(RouterMeshModel::Hunyuan3d3p1Rapid, "hunyuan_3d_3p1_rapid");
|
||||
assert_serde_round_trip(RouterMeshModel::Hunyuan3d3p1Part, "hunyuan_3d_3p1_part");
|
||||
assert_serde_round_trip(RouterMeshModel::Hunyuan3d3p1SmartTopology, "hunyuan_3d_3p1_topology");
|
||||
assert_serde_round_trip(RouterMeshModel::Tripo3dH3p1, "tripo3d_h3p1");
|
||||
assert_serde_round_trip(RouterMeshModel::MeshyV6, "meshy_v6");
|
||||
assert_serde_round_trip(RouterMeshModel::Rodin2p5Fast, "rodin_2p5_fast");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trips_through_common_mesh_model() {
|
||||
use enums::common::generation::common_mesh_model::CommonMeshModel;
|
||||
|
||||
let cases = [
|
||||
(RouterMeshModel::Hunyuan3d2p0, CommonMeshModel::Hunyuan3d2p0),
|
||||
(RouterMeshModel::Hunyuan3d2p1, CommonMeshModel::Hunyuan3d2p1),
|
||||
(RouterMeshModel::Hunyuan3d3, CommonMeshModel::Hunyuan3d3),
|
||||
(RouterMeshModel::Hunyuan3d3Sketch, CommonMeshModel::Hunyuan3d3Sketch),
|
||||
(RouterMeshModel::Hunyuan3d3p1Pro, CommonMeshModel::Hunyuan3d3p1Pro),
|
||||
(RouterMeshModel::Hunyuan3d3p1Rapid, CommonMeshModel::Hunyuan3d3p1Rapid),
|
||||
(RouterMeshModel::Hunyuan3d3p1Part, CommonMeshModel::Hunyuan3d3p1Part),
|
||||
(RouterMeshModel::Hunyuan3d3p1SmartTopology, CommonMeshModel::Hunyuan3d3p1SmartTopology),
|
||||
(RouterMeshModel::Tripo3dH3p1, CommonMeshModel::Tripo3dH3p1),
|
||||
(RouterMeshModel::MeshyV6, CommonMeshModel::MeshyV6),
|
||||
(RouterMeshModel::Rodin2p5Fast, CommonMeshModel::Rodin2p5Fast),
|
||||
];
|
||||
for (router_model, expected_common) in cases {
|
||||
let json = serde_json::to_string(&router_model).unwrap();
|
||||
let common: CommonMeshModel = serde_json::from_str(&json)
|
||||
.unwrap_or_else(|e| panic!("CommonMeshModel failed to parse {json}: {e}"));
|
||||
assert_eq!(common, expected_common, "for {router_model:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_serde_round_trip(model: RouterMeshModel, expected: &str) {
|
||||
let json = serde_json::to_string(&model).unwrap();
|
||||
assert_eq!(json, format!("\"{expected}\""));
|
||||
let parsed: RouterMeshModel = serde_json::from_str(&json).unwrap();
|
||||
// RouterMeshModel isn't PartialEq, so round-trip back to the wire form.
|
||||
assert_eq!(serde_json::to_string(&parsed).unwrap(), json);
|
||||
}
|
||||
}
|
||||
@@ -9,4 +9,5 @@ pub enum RouterProvider {
|
||||
GmiCloud,
|
||||
GrokApi,
|
||||
Seedance2Pro,
|
||||
WorldLabs,
|
||||
}
|
||||
|
||||
@@ -5,9 +5,68 @@ use serde_derive::{Deserialize, Serialize};
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RouterSplatModel {
|
||||
/// Deprecated upstream; treated as [`Self::Marble1p0Draft`].
|
||||
#[serde(rename = "marble_0p1_mini")]
|
||||
Marble0p1Mini,
|
||||
|
||||
/// Deprecated upstream; treated as [`Self::Marble1p0`].
|
||||
#[serde(rename = "marble_0p1_plus")]
|
||||
Marble0p1Plus,
|
||||
|
||||
#[serde(rename = "marble_1p0")]
|
||||
Marble1p0,
|
||||
|
||||
#[serde(rename = "marble_1p0_draft")]
|
||||
Marble1p0Draft,
|
||||
|
||||
#[serde(rename = "marble_1p1")]
|
||||
Marble1p1,
|
||||
|
||||
#[serde(rename = "marble_1p1_plus")]
|
||||
Marble1p1Plus,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// NB: These strings must match `CommonSplatModel` — the two enums convert
|
||||
// via serde string round-trip.
|
||||
#[test]
|
||||
fn all_variants_serialize_to_common_splat_model_strings() {
|
||||
assert_serde_round_trip(RouterSplatModel::Marble0p1Mini, "marble_0p1_mini");
|
||||
assert_serde_round_trip(RouterSplatModel::Marble0p1Plus, "marble_0p1_plus");
|
||||
assert_serde_round_trip(RouterSplatModel::Marble1p0, "marble_1p0");
|
||||
assert_serde_round_trip(RouterSplatModel::Marble1p0Draft, "marble_1p0_draft");
|
||||
assert_serde_round_trip(RouterSplatModel::Marble1p1, "marble_1p1");
|
||||
assert_serde_round_trip(RouterSplatModel::Marble1p1Plus, "marble_1p1_plus");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trips_through_common_splat_model() {
|
||||
use enums::common::generation::common_splat_model::CommonSplatModel;
|
||||
|
||||
let cases = [
|
||||
(RouterSplatModel::Marble0p1Mini, CommonSplatModel::Marble0p1Mini),
|
||||
(RouterSplatModel::Marble0p1Plus, CommonSplatModel::Marble0p1Plus),
|
||||
(RouterSplatModel::Marble1p0, CommonSplatModel::Marble1p0),
|
||||
(RouterSplatModel::Marble1p0Draft, CommonSplatModel::Marble1p0Draft),
|
||||
(RouterSplatModel::Marble1p1, CommonSplatModel::Marble1p1),
|
||||
(RouterSplatModel::Marble1p1Plus, CommonSplatModel::Marble1p1Plus),
|
||||
];
|
||||
for (router_model, expected_common) in cases {
|
||||
let json = serde_json::to_string(&router_model).unwrap();
|
||||
let common: CommonSplatModel = serde_json::from_str(&json)
|
||||
.unwrap_or_else(|e| panic!("CommonSplatModel failed to parse {json}: {e}"));
|
||||
assert_eq!(common, expected_common, "for {router_model:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_serde_round_trip(model: RouterSplatModel, expected: &str) {
|
||||
let json = serde_json::to_string(&model).unwrap();
|
||||
assert_eq!(json, format!("\"{expected}\""));
|
||||
let parsed: RouterSplatModel = serde_json::from_str(&json).unwrap();
|
||||
// RouterSplatModel isn't PartialEq, so round-trip back to the wire form.
|
||||
assert_eq!(serde_json::to_string(&parsed).unwrap(), json);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,15 @@ pub enum RouterVideoModel {
|
||||
#[serde(rename = "veo_3p1_fast")]
|
||||
Veo3p1Fast,
|
||||
|
||||
#[serde(rename = "veo_3p1_lite")]
|
||||
Veo3p1Lite,
|
||||
|
||||
#[serde(rename = "vidu_q3")]
|
||||
ViduQ3,
|
||||
|
||||
#[serde(rename = "vidu_q3_turbo")]
|
||||
ViduQ3Turbo,
|
||||
|
||||
#[serde(rename = "preview_model")]
|
||||
PreviewModel,
|
||||
|
||||
@@ -123,4 +132,13 @@ mod tests {
|
||||
assert_serde_round_trip(RouterVideoModel::Seedance2p0BytePlusMini, "seedance_2p0_bp_mini");
|
||||
assert_serde_round_trip(RouterVideoModel::Seedance2p0BytePlusUltraMini, "seedance_2p0_bpu_mini");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn veo_3p1_lite_and_vidu_variants_serialize() {
|
||||
// NB: These strings must match `CommonVideoModel` — the two enums convert
|
||||
// via serde string round-trip in the omni handlers.
|
||||
assert_serde_round_trip(RouterVideoModel::Veo3p1Lite, "veo_3p1_lite");
|
||||
assert_serde_round_trip(RouterVideoModel::ViduQ3, "vidu_q3");
|
||||
assert_serde_round_trip(RouterVideoModel::ViduQ3Turbo, "vidu_q3_turbo");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum VideoRef {
|
||||
MediaFileToken(MediaFileToken),
|
||||
Url(String),
|
||||
}
|
||||
@@ -8,3 +8,4 @@ pub mod router_fal_client;
|
||||
pub mod router_gmicloud_client;
|
||||
pub mod router_grok_api_client;
|
||||
pub mod router_seedance2pro_client;
|
||||
pub mod router_worldlabs_client;
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::client::router_gmicloud_client::RouterGmiCloudClient;
|
||||
use crate::client::router_grok_api_client::RouterGrokApiClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
use crate::client::router_worldlabs_client::RouterWorldLabsClient;
|
||||
use crate::errors::client_error::{ClientError, ClientType};
|
||||
|
||||
pub struct MultiRouterClient {
|
||||
@@ -11,6 +12,7 @@ pub struct MultiRouterClient {
|
||||
pub(crate) gmicloud_client: Option<RouterGmiCloudClient>,
|
||||
pub(crate) grok_api_client: Option<RouterGrokApiClient>,
|
||||
pub(crate) seedance2pro_client: Option<RouterSeedance2ProClient>,
|
||||
pub(crate) worldlabs_client: Option<RouterWorldLabsClient>,
|
||||
}
|
||||
|
||||
impl MultiRouterClient {
|
||||
@@ -38,4 +40,9 @@ impl MultiRouterClient {
|
||||
self.seedance2pro_client.as_ref()
|
||||
.ok_or(ClientError::ClientNotConfigured(ClientType::Seedance2Pro))
|
||||
}
|
||||
|
||||
pub fn get_worldlabs_client_ref(&self) -> Result<&RouterWorldLabsClient, ClientError> {
|
||||
self.worldlabs_client.as_ref()
|
||||
.ok_or(ClientError::ClientNotConfigured(ClientType::WorldLabs))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::client::router_gmicloud_client::RouterGmiCloudClient;
|
||||
use crate::client::router_grok_api_client::RouterGrokApiClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
use crate::client::router_worldlabs_client::RouterWorldLabsClient;
|
||||
|
||||
pub struct MultiRouterClientBuilder {
|
||||
artcraft_client: Option<RouterArtcraftClient>,
|
||||
@@ -11,6 +12,7 @@ pub struct MultiRouterClientBuilder {
|
||||
gmicloud_client: Option<RouterGmiCloudClient>,
|
||||
grok_api_client: Option<RouterGrokApiClient>,
|
||||
seedance2pro_client: Option<RouterSeedance2ProClient>,
|
||||
worldlabs_client: Option<RouterWorldLabsClient>,
|
||||
}
|
||||
|
||||
impl MultiRouterClientBuilder {
|
||||
@@ -21,6 +23,7 @@ impl MultiRouterClientBuilder {
|
||||
gmicloud_client: None,
|
||||
grok_api_client: None,
|
||||
seedance2pro_client: None,
|
||||
worldlabs_client: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +52,11 @@ impl MultiRouterClientBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_worldlabs_client(mut self, client: RouterWorldLabsClient) -> Self {
|
||||
self.worldlabs_client = Some(client);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> MultiRouterClient {
|
||||
MultiRouterClient {
|
||||
artcraft_client: self.artcraft_client,
|
||||
@@ -56,6 +64,7 @@ impl MultiRouterClientBuilder {
|
||||
gmicloud_client: self.gmicloud_client,
|
||||
grok_api_client: self.grok_api_client,
|
||||
seedance2pro_client: self.seedance2pro_client,
|
||||
worldlabs_client: self.worldlabs_client,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::client::router_fal_client::RouterFalClient;
|
||||
use crate::client::router_gmicloud_client::RouterGmiCloudClient;
|
||||
use crate::client::router_grok_api_client::RouterGrokApiClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
use crate::client::router_worldlabs_client::RouterWorldLabsClient;
|
||||
use crate::errors::client_error::{ClientError, ClientType};
|
||||
|
||||
pub enum RouterClient {
|
||||
@@ -13,6 +14,7 @@ pub enum RouterClient {
|
||||
GmiCloud(RouterGmiCloudClient),
|
||||
GrokApi(RouterGrokApiClient),
|
||||
Seedance2Pro(RouterSeedance2ProClient),
|
||||
WorldLabs(RouterWorldLabsClient),
|
||||
}
|
||||
|
||||
impl RouterClient {
|
||||
@@ -55,4 +57,12 @@ impl RouterClient {
|
||||
_ => Err(ClientError::ClientNotConfigured(ClientType::Seedance2Pro)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_worldlabs_client_ref(&self) -> Result<&RouterWorldLabsClient, ClientError> {
|
||||
match self {
|
||||
RouterClient::WorldLabs(client) => Ok(client),
|
||||
RouterClient::Multi(multi) => multi.get_worldlabs_client_ref(),
|
||||
_ => Err(ClientError::ClientNotConfigured(ClientType::WorldLabs)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
use worldlabs_api_client::credentials::world_labs_api_creds::WorldLabsApiCreds;
|
||||
|
||||
/// A client for the official World Labs (Marble) API.
|
||||
pub struct RouterWorldLabsClient {
|
||||
pub(crate) creds: WorldLabsApiCreds,
|
||||
}
|
||||
|
||||
impl RouterWorldLabsClient {
|
||||
pub fn new(creds: WorldLabsApiCreds) -> Self {
|
||||
Self { creds }
|
||||
}
|
||||
|
||||
pub fn new_from_raw_key(api_key: &str) -> Self {
|
||||
Self::new(WorldLabsApiCreds::new(api_key.to_string()))
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ pub enum ClientType {
|
||||
GmiCloud,
|
||||
GrokApi,
|
||||
Seedance2Pro,
|
||||
WorldLabs,
|
||||
}
|
||||
|
||||
impl Display for ClientType {
|
||||
@@ -20,6 +21,7 @@ impl Display for ClientType {
|
||||
Self::GmiCloud => write!(f, "GmiCloud"),
|
||||
Self::GrokApi => write!(f, "GrokApi"),
|
||||
Self::Seedance2Pro => write!(f, "Seedance2Pro"),
|
||||
Self::WorldLabs => write!(f, "WorldLabs"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use fal_client::error::fal_error_plus::FalErrorPlus;
|
||||
use gmicloud_client::error::gmicloud_error::GmiCloudError;
|
||||
use grok_api_client::error::grok_error::GrokError;
|
||||
use seedance2pro_client::error::seedance2pro_error::Seedance2ProError;
|
||||
use worldlabs_api_client::error::world_labs_error::WorldLabsError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProviderError {
|
||||
@@ -13,6 +14,7 @@ pub enum ProviderError {
|
||||
GmiCloud(GmiCloudError),
|
||||
Grok(GrokError),
|
||||
Seedance2Pro(Seedance2ProError),
|
||||
WorldLabs(WorldLabsError),
|
||||
}
|
||||
|
||||
impl Error for ProviderError {}
|
||||
@@ -25,6 +27,7 @@ impl Display for ProviderError {
|
||||
Self::GmiCloud(e) => write!(f, "GmiCloud provider error: {}", e),
|
||||
Self::Grok(e) => write!(f, "Grok provider error: {}", e),
|
||||
Self::Seedance2Pro(e) => write!(f, "Seedance2Pro provider error: {}", e),
|
||||
Self::WorldLabs(e) => write!(f, "WorldLabs provider error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,3 +61,9 @@ impl From<Seedance2ProError> for ProviderError {
|
||||
Self::Seedance2Pro(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WorldLabsError> for ProviderError {
|
||||
fn from(error: WorldLabsError) -> Self {
|
||||
Self::WorldLabs(error)
|
||||
}
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/// The result of estimating the cost of an audio generation plan.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AudioGenerationCostEstimate {
|
||||
pub cost_in_credits: Option<u64>,
|
||||
pub cost_in_usd_cents: Option<u64>,
|
||||
pub is_free: bool,
|
||||
pub is_unlimited: bool,
|
||||
pub is_rate_limited: bool,
|
||||
pub has_watermark: bool,
|
||||
|
||||
/// Whether failures are refunded.
|
||||
/// True: 100% yes
|
||||
/// False: 100% no
|
||||
/// None: Unknown or variable
|
||||
pub failures_are_refunded: Option<bool>,
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
use crate::api::router_provider::RouterProvider;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::audio_generation_cost_estimate::AudioGenerationCostEstimate;
|
||||
use crate::generate::generate_audio::audio_generation_draft_context::AudioGenerationDraftContext;
|
||||
use crate::generate::generate_audio::audio_generation_request::AudioGenerationRequest;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_remix::cost::KinoviSunoRemixCostState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_remix::draft::KinoviSunoRemixDraftState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_sample::cost::KinoviSunoSampleCostState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_sample::draft::KinoviSunoSampleDraftState;
|
||||
|
||||
/**
|
||||
* Wrapper for all audio generation draft requests.
|
||||
*
|
||||
* Only the Kinovi remix/sample models need a draft phase: they take a user
|
||||
* audio reference that must be downloaded from our CDN and re-uploaded to the
|
||||
* Kinovi CDN before the request can be sent. All other audio providers return
|
||||
* a `Request` directly from `build2()`.
|
||||
*/
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AudioGenerationDraftRequest {
|
||||
KinoviSunoRemix(KinoviSunoRemixDraftState),
|
||||
KinoviSunoSample(KinoviSunoSampleDraftState),
|
||||
}
|
||||
|
||||
impl AudioGenerationDraftRequest {
|
||||
|
||||
pub fn get_provider(&self) -> RouterProvider {
|
||||
match self {
|
||||
Self::KinoviSunoRemix(_) => RouterProvider::Seedance2Pro,
|
||||
Self::KinoviSunoSample(_) => RouterProvider::Seedance2Pro,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a cost estimate to fulfill the request.
|
||||
pub fn estimate_cost(&self) -> Result<AudioGenerationCostEstimate, ArtcraftRouterError> {
|
||||
match self {
|
||||
AudioGenerationDraftRequest::KinoviSunoRemix(draft) => Ok(KinoviSunoRemixCostState::from_draft(draft).estimate_cost()),
|
||||
AudioGenerationDraftRequest::KinoviSunoSample(draft) => Ok(KinoviSunoSampleCostState::from_draft(draft).estimate_cost()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Finalize the draft request before generation
|
||||
/// This may involve uploading media to the provider.
|
||||
pub async fn finalize(self, draft_context: AudioGenerationDraftContext<'_>) -> Result<AudioGenerationRequest, ArtcraftRouterError> {
|
||||
match self {
|
||||
AudioGenerationDraftRequest::KinoviSunoRemix(mut draft) => {
|
||||
let result = draft.to_request(&draft_context).await?;
|
||||
Ok(AudioGenerationRequest::KinoviSunoRemix(result))
|
||||
},
|
||||
AudioGenerationDraftRequest::KinoviSunoSample(mut draft) => {
|
||||
let result = draft.to_request(&draft_context).await?;
|
||||
Ok(AudioGenerationRequest::KinoviSunoSample(result))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
use crate::client::router_client::RouterClient;
|
||||
use crate::client::router_seedance2pro_client::RouterSeedance2ProClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct AudioGenerationDraftContext<'a> {
|
||||
/// Optional: the router client, needed for providers that require authentication.
|
||||
pub client: Option<&'a RouterClient>,
|
||||
|
||||
/// Optional context: a map of Media File Tokens to their ArtCraft URLs
|
||||
/// Only needed if we have to fetch these assets and upload them to another provider.
|
||||
pub media_file_to_artcraft_url_map: Option<&'a HashMap<MediaFileToken, String>>,
|
||||
}
|
||||
|
||||
impl <'a> AudioGenerationDraftContext<'a> {
|
||||
pub fn get_seedance2pro_client_ref(&self) -> Result<&RouterSeedance2ProClient, ArtcraftRouterError> {
|
||||
let client = self.client.ok_or(ArtcraftRouterError::Client(ClientError::RouterClientNotProvided))?;
|
||||
client.get_seedance2pro_client_ref()
|
||||
.map_err(|err| ArtcraftRouterError::Client(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for AudioGenerationDraftContext<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("AudioGenerationDraftContext")
|
||||
.field("client", &self.client.is_some())
|
||||
.field("media_file_to_artcraft_url_map", &self.media_file_to_artcraft_url_map)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
use crate::api::router_provider::RouterProvider;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::audio_generation_cost_estimate::AudioGenerationCostEstimate;
|
||||
use crate::generate::generate_audio::audio_generation_draft::AudioGenerationDraftRequest;
|
||||
use crate::generate::generate_audio::audio_generation_request::AudioGenerationRequest;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AudioGenerationDraftOrRequest {
|
||||
Draft(AudioGenerationDraftRequest),
|
||||
Request(AudioGenerationRequest),
|
||||
}
|
||||
|
||||
impl AudioGenerationDraftOrRequest {
|
||||
|
||||
pub fn get_provider(&self) -> RouterProvider {
|
||||
match self {
|
||||
Self::Draft(draft) => draft.get_provider(),
|
||||
Self::Request(request) => request.get_provider(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn estimate_cost(&self) -> Result<AudioGenerationCostEstimate, ArtcraftRouterError> {
|
||||
match self {
|
||||
AudioGenerationDraftOrRequest::Draft(draft) => draft.estimate_cost(),
|
||||
AudioGenerationDraftOrRequest::Request(request) => request.estimate_cost(),
|
||||
}
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
use crate::api::router_provider::RouterProvider;
|
||||
use crate::client::router_client::RouterClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::audio_generation_cost_estimate::AudioGenerationCostEstimate;
|
||||
use crate::generate::generate_audio::generate_audio_response::GenerateAudioResponse;
|
||||
use crate::generate::generate_audio::providers::artcraft::seed_audio_1p0::cost::ArtcraftSeedAudio1p0CostState;
|
||||
use crate::generate::generate_audio::providers::artcraft::seed_audio_1p0::request::ArtcraftSeedAudio1p0RequestState;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_music::cost::ArtcraftSunoMusicCostState;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_music::request::ArtcraftSunoMusicRequestState;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_remix::cost::ArtcraftSunoRemixCostState;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_remix::request::ArtcraftSunoRemixRequestState;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_sample::cost::ArtcraftSunoSampleCostState;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_sample::request::ArtcraftSunoSampleRequestState;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_sounds::cost::ArtcraftSunoSoundsCostState;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_sounds::request::ArtcraftSunoSoundsRequestState;
|
||||
use crate::generate::generate_audio::providers::fal::seed_audio_1p0::cost::FalSeedAudio1p0CostState;
|
||||
use crate::generate::generate_audio::providers::fal::seed_audio_1p0::request::FalSeedAudio1p0RequestState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_music::cost::KinoviSunoMusicCostState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_music::request::KinoviSunoMusicRequestState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_remix::cost::KinoviSunoRemixCostState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_remix::request::KinoviSunoRemixRequestState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_sample::cost::KinoviSunoSampleCostState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_sample::request::KinoviSunoSampleRequestState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_sounds::cost::KinoviSunoSoundsCostState;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_sounds::request::KinoviSunoSoundsRequestState;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AudioGenerationRequest {
|
||||
ArtcraftSunoMusic(ArtcraftSunoMusicRequestState),
|
||||
ArtcraftSunoRemix(ArtcraftSunoRemixRequestState),
|
||||
ArtcraftSunoSounds(ArtcraftSunoSoundsRequestState),
|
||||
ArtcraftSunoSample(ArtcraftSunoSampleRequestState),
|
||||
ArtcraftSeedAudio1p0(ArtcraftSeedAudio1p0RequestState),
|
||||
FalSeedAudio1p0(FalSeedAudio1p0RequestState),
|
||||
KinoviSunoMusic(KinoviSunoMusicRequestState),
|
||||
KinoviSunoRemix(KinoviSunoRemixRequestState),
|
||||
KinoviSunoSounds(KinoviSunoSoundsRequestState),
|
||||
KinoviSunoSample(KinoviSunoSampleRequestState),
|
||||
}
|
||||
|
||||
impl AudioGenerationRequest {
|
||||
|
||||
pub fn get_provider(&self) -> RouterProvider {
|
||||
match self {
|
||||
Self::ArtcraftSunoMusic(_) => RouterProvider::Artcraft,
|
||||
Self::ArtcraftSunoRemix(_) => RouterProvider::Artcraft,
|
||||
Self::ArtcraftSunoSounds(_) => RouterProvider::Artcraft,
|
||||
Self::ArtcraftSunoSample(_) => RouterProvider::Artcraft,
|
||||
Self::ArtcraftSeedAudio1p0(_) => RouterProvider::Artcraft,
|
||||
Self::FalSeedAudio1p0(_) => RouterProvider::Fal,
|
||||
Self::KinoviSunoMusic(_) => RouterProvider::Seedance2Pro,
|
||||
Self::KinoviSunoRemix(_) => RouterProvider::Seedance2Pro,
|
||||
Self::KinoviSunoSounds(_) => RouterProvider::Seedance2Pro,
|
||||
Self::KinoviSunoSample(_) => RouterProvider::Seedance2Pro,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a cost estimate to fulfill the request.
|
||||
pub fn estimate_cost(&self) -> Result<AudioGenerationCostEstimate, ArtcraftRouterError> {
|
||||
match self {
|
||||
AudioGenerationRequest::ArtcraftSunoMusic(request) => Ok(ArtcraftSunoMusicCostState::from_request(request).estimate_cost()),
|
||||
AudioGenerationRequest::ArtcraftSunoRemix(request) => Ok(ArtcraftSunoRemixCostState::from_request(request).estimate_cost()),
|
||||
AudioGenerationRequest::ArtcraftSunoSounds(request) => Ok(ArtcraftSunoSoundsCostState::from_request(request).estimate_cost()),
|
||||
AudioGenerationRequest::ArtcraftSunoSample(request) => Ok(ArtcraftSunoSampleCostState::from_request(request).estimate_cost()),
|
||||
AudioGenerationRequest::ArtcraftSeedAudio1p0(request) => Ok(ArtcraftSeedAudio1p0CostState::from_request(request).estimate_cost()),
|
||||
AudioGenerationRequest::FalSeedAudio1p0(request) => Ok(FalSeedAudio1p0CostState::from_request(request).estimate_cost()),
|
||||
AudioGenerationRequest::KinoviSunoMusic(request) => Ok(KinoviSunoMusicCostState::from_request(request).estimate_cost()),
|
||||
AudioGenerationRequest::KinoviSunoRemix(request) => Ok(KinoviSunoRemixCostState::from_request(request).estimate_cost()),
|
||||
AudioGenerationRequest::KinoviSunoSounds(request) => Ok(KinoviSunoSoundsCostState::from_request(request).estimate_cost()),
|
||||
AudioGenerationRequest::KinoviSunoSample(request) => Ok(KinoviSunoSampleCostState::from_request(request).estimate_cost()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Send the audio generation request
|
||||
/// If successful, returns the job IDs.
|
||||
pub async fn send_request(&self, client: &RouterClient) -> Result<GenerateAudioResponse, ArtcraftRouterError> {
|
||||
match self {
|
||||
AudioGenerationRequest::ArtcraftSunoMusic(request) => {
|
||||
let client_ref = client.get_artcraft_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
AudioGenerationRequest::ArtcraftSunoRemix(request) => {
|
||||
let client_ref = client.get_artcraft_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
AudioGenerationRequest::ArtcraftSunoSounds(request) => {
|
||||
let client_ref = client.get_artcraft_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
AudioGenerationRequest::ArtcraftSunoSample(request) => {
|
||||
let client_ref = client.get_artcraft_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
AudioGenerationRequest::ArtcraftSeedAudio1p0(request) => {
|
||||
let client_ref = client.get_artcraft_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
AudioGenerationRequest::FalSeedAudio1p0(request) => {
|
||||
let client_ref = client.get_fal_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
AudioGenerationRequest::KinoviSunoMusic(request) => {
|
||||
let client_ref = client.get_seedance2pro_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
AudioGenerationRequest::KinoviSunoRemix(request) => {
|
||||
let client_ref = client.get_seedance2pro_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
AudioGenerationRequest::KinoviSunoSounds(request) => {
|
||||
let client_ref = client.get_seedance2pro_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
AudioGenerationRequest::KinoviSunoSample(request) => {
|
||||
let client_ref = client.get_seedance2pro_client_ref()?;
|
||||
request.send(client_ref).await
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
use enums::common::generation::common_musical_key::CommonMusicalKey;
|
||||
|
||||
use crate::api::audio_list_ref::AudioListRef;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::api::router_audio_model::RouterAudioModel;
|
||||
use crate::api::router_provider::RouterProvider;
|
||||
use crate::client::request_mismatch_mitigation_strategy::RequestMismatchMitigationStrategy;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::audio_generation_draft_or_request::AudioGenerationDraftOrRequest;
|
||||
use crate::generate::generate_audio::providers::artcraft::seed_audio_1p0::build::build_artcraft_seed_audio_1p0;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_music::build::build_artcraft_suno_music;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_remix::build::build_artcraft_suno_remix;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_sample::build::build_artcraft_suno_sample;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_sounds::build::build_artcraft_suno_sounds;
|
||||
use crate::generate::generate_audio::providers::fal::seed_audio_1p0::build::build_fal_seed_audio_1p0;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_music::build::build_kinovi_suno_music;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_remix::build::build_kinovi_suno_remix;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_sample::build::build_kinovi_suno_sample;
|
||||
use crate::generate::generate_audio::providers::kinovi::suno_sounds::build::build_kinovi_suno_sounds;
|
||||
|
||||
/// RouterProvider-agnostic audio generation request. Distilled by `build2()`
|
||||
/// into an `AudioGenerationDraftOrRequest` for the selected (provider, model)
|
||||
/// pair.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GenerateAudioRequestBuilder {
|
||||
/// Which model to use.
|
||||
pub model: RouterAudioModel,
|
||||
|
||||
/// Which provider to use.
|
||||
pub provider: RouterProvider,
|
||||
|
||||
/// The prompt for the audio generation.
|
||||
pub prompt: Option<String>,
|
||||
|
||||
/// Style/genre direction (Suno's "tags"), e.g. "EDM style meets dance".
|
||||
pub style_prompt: Option<String>,
|
||||
|
||||
/// Reference audio (optional).
|
||||
/// The remix/sample source, or Seed Audio @Audio references (up to 3).
|
||||
pub audio_references: Option<AudioListRef>,
|
||||
|
||||
/// Reference images (optional).
|
||||
/// Seed Audio supports a single reference image; it cannot be combined
|
||||
/// with audio references.
|
||||
pub image_references: Option<ImageListRef>,
|
||||
|
||||
/// Whether to keep the original lyrics (Suno Remix).
|
||||
pub keep_lyrics: Option<bool>,
|
||||
|
||||
/// Whether to generate instrumental-only audio (Suno Music / Sample).
|
||||
pub is_instrumental: Option<bool>,
|
||||
|
||||
/// Whether the sound should loop vs a single hit (Suno Sounds).
|
||||
pub is_loopable: Option<bool>,
|
||||
|
||||
/// Beats per minute (Suno Sounds).
|
||||
pub bpm: Option<u16>,
|
||||
|
||||
/// The musical key to use (Suno Sounds).
|
||||
pub musical_key: Option<CommonMusicalKey>,
|
||||
|
||||
/// Output sample rate in Hz (Seed Audio).
|
||||
pub sample_rate_hz: Option<u32>,
|
||||
|
||||
/// Playback speed multiplier (Seed Audio: 0.5–2.0).
|
||||
pub speed: Option<f64>,
|
||||
|
||||
/// Volume multiplier (Seed Audio: 0.5–2.0).
|
||||
pub volume: Option<f64>,
|
||||
|
||||
/// Pitch shift in semitones (Seed Audio: -12..=12).
|
||||
pub pitch: Option<f64>,
|
||||
|
||||
/// If the request is a mismatch with the (model/provider), how to mitigate it.
|
||||
pub request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy,
|
||||
|
||||
/// Some providers support idempotency.
|
||||
/// If not supplied, we'll generate one for the required providers.
|
||||
pub idempotency_token: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for GenerateAudioRequestBuilder {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
model: RouterAudioModel::SunoMusic,
|
||||
provider: RouterProvider::Artcraft,
|
||||
request_mismatch_mitigation_strategy: RequestMismatchMitigationStrategy::PayMoreUpgrade,
|
||||
prompt: None,
|
||||
style_prompt: None,
|
||||
audio_references: None,
|
||||
image_references: None,
|
||||
keep_lyrics: None,
|
||||
is_instrumental: None,
|
||||
is_loopable: None,
|
||||
bpm: None,
|
||||
musical_key: None,
|
||||
sample_rate_hz: None,
|
||||
speed: None,
|
||||
volume: None,
|
||||
pitch: None,
|
||||
idempotency_token: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GenerateAudioRequestBuilder {
|
||||
|
||||
pub fn build2(self) -> Result<AudioGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
match (self.provider, self.model) {
|
||||
// Artcraft
|
||||
(RouterProvider::Artcraft, RouterAudioModel::SunoMusic) => build_artcraft_suno_music(self),
|
||||
(RouterProvider::Artcraft, RouterAudioModel::SunoRemix) => build_artcraft_suno_remix(self),
|
||||
(RouterProvider::Artcraft, RouterAudioModel::SunoSounds) => build_artcraft_suno_sounds(self),
|
||||
(RouterProvider::Artcraft, RouterAudioModel::SunoSample) => build_artcraft_suno_sample(self),
|
||||
(RouterProvider::Artcraft, RouterAudioModel::SeedAudio1p0) => build_artcraft_seed_audio_1p0(self),
|
||||
// Fal
|
||||
(RouterProvider::Fal, RouterAudioModel::SeedAudio1p0) => build_fal_seed_audio_1p0(self),
|
||||
// Kinovi
|
||||
(RouterProvider::Seedance2Pro, RouterAudioModel::SunoMusic) => build_kinovi_suno_music(self),
|
||||
(RouterProvider::Seedance2Pro, RouterAudioModel::SunoRemix) => build_kinovi_suno_remix(self),
|
||||
(RouterProvider::Seedance2Pro, RouterAudioModel::SunoSounds) => build_kinovi_suno_sounds(self),
|
||||
(RouterProvider::Seedance2Pro, RouterAudioModel::SunoSample) => build_kinovi_suno_sample(self),
|
||||
_ => self.unsupported_provider_and_model(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_generate_idempotency_token(&self) -> String {
|
||||
self.idempotency_token.clone()
|
||||
.unwrap_or_else(|| uuid::Uuid::new_v4().to_string())
|
||||
}
|
||||
|
||||
fn unsupported_provider_and_model(&self) -> Result<AudioGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
Err(ArtcraftRouterError::UnsupportedProviderAndModelForNewApi(
|
||||
format!("Audio generation for model `{:?}` is not supported for provider {:?}", self.model, self.provider)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::generate::generate_audio::audio_generation_draft::AudioGenerationDraftRequest;
|
||||
use crate::generate::generate_audio::audio_generation_request::AudioGenerationRequest;
|
||||
|
||||
use super::*;
|
||||
|
||||
mod dispatch_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn artcraft_suno_music_dispatches() {
|
||||
let result = builder(RouterProvider::Artcraft, RouterAudioModel::SunoMusic).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::ArtcraftSunoMusic(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn artcraft_suno_remix_dispatches() {
|
||||
let result = builder_with_audio_token_ref(RouterProvider::Artcraft, RouterAudioModel::SunoRemix).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::ArtcraftSunoRemix(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn artcraft_suno_sounds_dispatches() {
|
||||
let result = builder(RouterProvider::Artcraft, RouterAudioModel::SunoSounds).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::ArtcraftSunoSounds(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn artcraft_suno_sample_dispatches() {
|
||||
let result = builder_with_audio_token_ref(RouterProvider::Artcraft, RouterAudioModel::SunoSample).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::ArtcraftSunoSample(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn artcraft_seed_audio_1p0_dispatches() {
|
||||
let result = builder(RouterProvider::Artcraft, RouterAudioModel::SeedAudio1p0).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::ArtcraftSeedAudio1p0(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fal_seed_audio_1p0_dispatches() {
|
||||
let result = builder(RouterProvider::Fal, RouterAudioModel::SeedAudio1p0).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::FalSeedAudio1p0(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kinovi_suno_music_dispatches_to_request() {
|
||||
let result = builder(RouterProvider::Seedance2Pro, RouterAudioModel::SunoMusic).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::KinoviSunoMusic(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kinovi_suno_sounds_dispatches_to_request() {
|
||||
let result = builder(RouterProvider::Seedance2Pro, RouterAudioModel::SunoSounds).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::KinoviSunoSounds(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kinovi_suno_remix_dispatches_to_draft() {
|
||||
let result = builder_with_audio_ref(RouterProvider::Seedance2Pro, RouterAudioModel::SunoRemix).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Draft(AudioGenerationDraftRequest::KinoviSunoRemix(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kinovi_suno_sample_dispatches_to_draft() {
|
||||
let result = builder_with_audio_ref(RouterProvider::Seedance2Pro, RouterAudioModel::SunoSample).build2().expect("build");
|
||||
assert!(matches!(
|
||||
result,
|
||||
AudioGenerationDraftOrRequest::Draft(AudioGenerationDraftRequest::KinoviSunoSample(_))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
mod unsupported_combo_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn kinovi_seed_audio_1p0_is_unsupported() {
|
||||
let result = builder(RouterProvider::Seedance2Pro, RouterAudioModel::SeedAudio1p0).build2();
|
||||
assert!(matches!(result, Err(ArtcraftRouterError::UnsupportedProviderAndModelForNewApi(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fal_suno_models_are_unsupported() {
|
||||
for model in [
|
||||
RouterAudioModel::SunoMusic,
|
||||
RouterAudioModel::SunoRemix,
|
||||
RouterAudioModel::SunoSounds,
|
||||
RouterAudioModel::SunoSample,
|
||||
] {
|
||||
let result = builder(RouterProvider::Fal, model).build2();
|
||||
assert!(
|
||||
matches!(result, Err(ArtcraftRouterError::UnsupportedProviderAndModelForNewApi(_))),
|
||||
"expected unsupported error for Fal + {model:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gmicloud_and_grok_are_unsupported() {
|
||||
for provider in [RouterProvider::GmiCloud, RouterProvider::GrokApi] {
|
||||
let result = builder(provider, RouterAudioModel::SunoMusic).build2();
|
||||
assert!(
|
||||
matches!(result, Err(ArtcraftRouterError::UnsupportedProviderAndModelForNewApi(_))),
|
||||
"expected unsupported error for {provider:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn builder(provider: RouterProvider, model: RouterAudioModel) -> GenerateAudioRequestBuilder {
|
||||
GenerateAudioRequestBuilder {
|
||||
provider,
|
||||
model,
|
||||
prompt: Some("a song about corgis".to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn builder_with_audio_ref(provider: RouterProvider, model: RouterAudioModel) -> GenerateAudioRequestBuilder {
|
||||
GenerateAudioRequestBuilder {
|
||||
audio_references: Some(AudioListRef::Urls(vec!["https://example.com/a.mp3".to_string()])),
|
||||
..builder(provider, model)
|
||||
}
|
||||
}
|
||||
|
||||
fn builder_with_audio_token_ref(provider: RouterProvider, model: RouterAudioModel) -> GenerateAudioRequestBuilder {
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
GenerateAudioRequestBuilder {
|
||||
audio_references: Some(AudioListRef::MediaFileTokens(vec![MediaFileToken::new("mf_test123".to_string())])),
|
||||
..builder(provider, model)
|
||||
}
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArtcraftAudioResponsePayload {
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
pub all_inference_job_tokens: Vec<InferenceJobToken>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Seedance2proAudioResponsePayload {
|
||||
pub order_id: String,
|
||||
pub task_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FalAudioResponsePayload {
|
||||
pub request_id: Option<String>,
|
||||
pub gateway_request_id: Option<String>,
|
||||
|
||||
/// Queue-mode status URL (fal's queue/polling flow). `None` for webhook
|
||||
/// dispatch — the webhook callback drives status updates instead.
|
||||
pub maybe_status_url: Option<String>,
|
||||
|
||||
/// Queue-mode response URL (fal's queue/polling flow). `None` for webhook
|
||||
/// dispatch.
|
||||
pub maybe_response_url: Option<String>,
|
||||
|
||||
/// The outbound request that was sent to Fal.
|
||||
/// Stored as a trait object so any Request type can be captured.
|
||||
/// Use `format!("{:?}", ...)` or `format!("{:#?}", ...)` to print.
|
||||
pub maybe_outbound_request: Option<Arc<dyn Debug + Send + Sync>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum GenerateAudioResponse {
|
||||
Artcraft(ArtcraftAudioResponsePayload),
|
||||
Seedance2Pro(Seedance2proAudioResponsePayload),
|
||||
Fal(FalAudioResponsePayload),
|
||||
}
|
||||
|
||||
impl GenerateAudioResponse {
|
||||
pub fn get_artcraft_payload(&self) -> Option<ArtcraftAudioResponsePayload> {
|
||||
match self {
|
||||
Self::Artcraft(p) => Some(p.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_seedance2pro_payload(&self) -> Option<Seedance2proAudioResponsePayload> {
|
||||
match self {
|
||||
Self::Seedance2Pro(p) => Some(p.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fal_payload(&self) -> Option<FalAudioResponsePayload> {
|
||||
match self {
|
||||
Self::Fal(p) => Some(p.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
pub mod audio_generation_cost_estimate;
|
||||
pub mod audio_generation_draft;
|
||||
pub mod audio_generation_draft_context;
|
||||
pub mod audio_generation_draft_or_request;
|
||||
pub mod audio_generation_request;
|
||||
pub mod generate_audio_request_builder;
|
||||
pub mod generate_audio_response;
|
||||
pub mod providers;
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_audio_cost_and_generate_request::OmniGenAudioCostAndGenerateRequest;
|
||||
use enums::common::generation::common_audio_model::CommonAudioModel as CommonAudioModelEnum;
|
||||
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::generate_audio_request_builder::GenerateAudioRequestBuilder;
|
||||
use crate::generate::generate_audio::providers::artcraft::resolve::{
|
||||
resolve_audio_list_ref, resolve_image_list_ref,
|
||||
};
|
||||
|
||||
/// Build an `OmniGenAudioCostAndGenerateRequest` from the builder. The
|
||||
/// Artcraft provider is a thin forwarding shim: the storyteller-web omni
|
||||
/// audio endpoint owns per-model validation and option mapping, so the
|
||||
/// builder's options are passed through as-is.
|
||||
pub fn build_artcraft_omni_audio_request(
|
||||
mut builder: GenerateAudioRequestBuilder,
|
||||
model: CommonAudioModelEnum,
|
||||
) -> Result<OmniGenAudioCostAndGenerateRequest, ArtcraftRouterError> {
|
||||
let audio_media_tokens = resolve_audio_list_ref(builder.audio_references.take())?;
|
||||
let image_media_tokens = resolve_image_list_ref(builder.image_references.take())?;
|
||||
let idempotency_token = builder.get_or_generate_idempotency_token();
|
||||
|
||||
Ok(OmniGenAudioCostAndGenerateRequest {
|
||||
idempotency_token: Some(idempotency_token),
|
||||
model: Some(model),
|
||||
prompt: builder.prompt.take(),
|
||||
style_prompt: builder.style_prompt.take(),
|
||||
audio_media_tokens,
|
||||
image_media_tokens,
|
||||
keep_lyrics: builder.keep_lyrics,
|
||||
is_instrumental: builder.is_instrumental,
|
||||
is_loopable: builder.is_loopable,
|
||||
bpm: builder.bpm,
|
||||
musical_key: builder.musical_key,
|
||||
sample_rate_hz: builder.sample_rate_hz,
|
||||
speed: builder.speed,
|
||||
volume: builder.volume,
|
||||
pitch: builder.pitch,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
use crate::api::audio_list_ref::AudioListRef;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::api::router_audio_model::RouterAudioModel;
|
||||
use crate::api::router_provider::RouterProvider;
|
||||
use crate::errors::client_error::ClientError;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_fields_are_forwarded() {
|
||||
use enums::common::generation::common_musical_key::CommonMusicalKey;
|
||||
|
||||
let builder = GenerateAudioRequestBuilder {
|
||||
prompt: Some("a song".to_string()),
|
||||
style_prompt: Some("EDM".to_string()),
|
||||
audio_references: Some(AudioListRef::MediaFileTokens(vec![
|
||||
MediaFileToken::new("mf_audio".to_string()),
|
||||
])),
|
||||
image_references: Some(ImageListRef::MediaFileTokens(vec![
|
||||
MediaFileToken::new("mf_image".to_string()),
|
||||
])),
|
||||
keep_lyrics: Some(true),
|
||||
is_instrumental: Some(false),
|
||||
is_loopable: Some(true),
|
||||
bpm: Some(120),
|
||||
musical_key: Some(CommonMusicalKey::AMinor),
|
||||
sample_rate_hz: Some(48_000),
|
||||
speed: Some(1.5),
|
||||
volume: Some(0.8),
|
||||
pitch: Some(-2.0),
|
||||
idempotency_token: Some("test-token".to_string()),
|
||||
..base_builder()
|
||||
};
|
||||
|
||||
let request = build_artcraft_omni_audio_request(builder, CommonAudioModelEnum::SunoMusic)
|
||||
.expect("build");
|
||||
|
||||
assert_eq!(request.idempotency_token.as_deref(), Some("test-token"));
|
||||
assert_eq!(request.model, Some(CommonAudioModelEnum::SunoMusic));
|
||||
assert_eq!(request.prompt.as_deref(), Some("a song"));
|
||||
assert_eq!(request.style_prompt.as_deref(), Some("EDM"));
|
||||
assert_eq!(request.audio_media_tokens.as_ref().map(|t| t.len()), Some(1));
|
||||
assert_eq!(request.image_media_tokens.as_ref().map(|t| t.len()), Some(1));
|
||||
assert_eq!(request.keep_lyrics, Some(true));
|
||||
assert_eq!(request.is_instrumental, Some(false));
|
||||
assert_eq!(request.is_loopable, Some(true));
|
||||
assert_eq!(request.bpm, Some(120));
|
||||
assert_eq!(request.musical_key, Some(CommonMusicalKey::AMinor));
|
||||
assert_eq!(request.sample_rate_hz, Some(48_000));
|
||||
assert_eq!(request.speed, Some(1.5));
|
||||
assert_eq!(request.volume, Some(0.8));
|
||||
assert_eq!(request.pitch, Some(-2.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn idempotency_token_is_generated_when_missing() {
|
||||
let request = build_artcraft_omni_audio_request(base_builder(), CommonAudioModelEnum::SunoMusic)
|
||||
.expect("build");
|
||||
assert!(request.idempotency_token.is_some());
|
||||
assert!(!request.idempotency_token.unwrap().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn audio_url_references_are_rejected() {
|
||||
let builder = GenerateAudioRequestBuilder {
|
||||
audio_references: Some(AudioListRef::Urls(vec!["https://example.com/a.mp3".to_string()])),
|
||||
..base_builder()
|
||||
};
|
||||
let result = build_artcraft_omni_audio_request(builder, CommonAudioModelEnum::SunoRemix);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn image_url_references_are_rejected() {
|
||||
let builder = GenerateAudioRequestBuilder {
|
||||
image_references: Some(ImageListRef::Urls(vec!["https://example.com/a.png".to_string()])),
|
||||
..base_builder()
|
||||
};
|
||||
let result = build_artcraft_omni_audio_request(builder, CommonAudioModelEnum::SeedAudio1p0);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
|
||||
));
|
||||
}
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn base_builder() -> GenerateAudioRequestBuilder {
|
||||
GenerateAudioRequestBuilder {
|
||||
model: RouterAudioModel::SunoMusic,
|
||||
provider: RouterProvider::Artcraft,
|
||||
prompt: Some("a song".to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
pub(crate) mod build_common;
|
||||
pub(crate) mod request_common;
|
||||
pub(crate) mod resolve;
|
||||
pub mod seed_audio_1p0;
|
||||
pub mod suno_music;
|
||||
pub mod suno_remix;
|
||||
pub mod suno_sample;
|
||||
pub mod suno_sounds;
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_audio_cost_and_generate_request::OmniGenAudioCostAndGenerateRequest;
|
||||
use artcraft_client::endpoints::omni_gen::generate::audio::omni_gen_audio::omni_gen_audio_generate;
|
||||
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::provider_error::ProviderError;
|
||||
use crate::generate::generate_audio::generate_audio_response::{
|
||||
ArtcraftAudioResponsePayload, GenerateAudioResponse,
|
||||
};
|
||||
|
||||
/// Send an audio generation request to the Artcraft omni-gen endpoint.
|
||||
/// All Artcraft model request states delegate to this function.
|
||||
pub async fn send_artcraft_omni_audio_request(
|
||||
request: &OmniGenAudioCostAndGenerateRequest,
|
||||
client: &RouterArtcraftClient,
|
||||
) -> Result<GenerateAudioResponse, ArtcraftRouterError> {
|
||||
let response = omni_gen_audio_generate(
|
||||
&client.api_host,
|
||||
Some(&client.credentials),
|
||||
request.clone(),
|
||||
)
|
||||
.await
|
||||
.map_err(|err| ArtcraftRouterError::Provider(ProviderError::Storyteller(err)))?;
|
||||
|
||||
Ok(GenerateAudioResponse::Artcraft(ArtcraftAudioResponsePayload {
|
||||
inference_job_token: response.inference_job_token.clone(),
|
||||
all_inference_job_tokens: vec![response.inference_job_token],
|
||||
}))
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
//! Shared resolve helpers for the Artcraft audio provider.
|
||||
//!
|
||||
//! Artcraft only accepts media file tokens — raw URLs are rejected.
|
||||
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
use crate::api::audio_list_ref::AudioListRef;
|
||||
use crate::api::image_list_ref::ImageListRef;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::errors::client_error::ClientError;
|
||||
|
||||
pub(super) fn resolve_audio_list_ref(
|
||||
audio_list_ref: Option<AudioListRef>,
|
||||
) -> Result<Option<Vec<MediaFileToken>>, ArtcraftRouterError> {
|
||||
match audio_list_ref {
|
||||
None => Ok(None),
|
||||
Some(AudioListRef::MediaFileTokens(tokens)) => Ok(Some(tokens)),
|
||||
Some(AudioListRef::Urls(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn resolve_image_list_ref(
|
||||
image_list_ref: Option<ImageListRef>,
|
||||
) -> Result<Option<Vec<MediaFileToken>>, ArtcraftRouterError> {
|
||||
match image_list_ref {
|
||||
None => Ok(None),
|
||||
Some(ImageListRef::MediaFileTokens(tokens)) => Ok(Some(tokens)),
|
||||
Some(ImageListRef::Urls(_)) => {
|
||||
Err(ArtcraftRouterError::Client(ClientError::ArtcraftOnlySupportsMediaTokens))
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
use enums::common::generation::common_audio_model::CommonAudioModel as CommonAudioModelEnum;
|
||||
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::audio_generation_draft_or_request::AudioGenerationDraftOrRequest;
|
||||
use crate::generate::generate_audio::audio_generation_request::AudioGenerationRequest;
|
||||
use crate::generate::generate_audio::generate_audio_request_builder::GenerateAudioRequestBuilder;
|
||||
use crate::generate::generate_audio::providers::artcraft::build_common::build_artcraft_omni_audio_request;
|
||||
use crate::generate::generate_audio::providers::artcraft::seed_audio_1p0::request::ArtcraftSeedAudio1p0RequestState;
|
||||
|
||||
pub fn build_artcraft_seed_audio_1p0(builder: GenerateAudioRequestBuilder) -> Result<AudioGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
let request = build_artcraft_omni_audio_request(builder, CommonAudioModelEnum::SeedAudio1p0)?;
|
||||
let state = ArtcraftSeedAudio1p0RequestState { request };
|
||||
Ok(AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::ArtcraftSeedAudio1p0(state)))
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
use crate::generate::generate_audio::audio_generation_cost_estimate::AudioGenerationCostEstimate;
|
||||
use crate::generate::generate_audio::providers::artcraft::seed_audio_1p0::request::ArtcraftSeedAudio1p0RequestState;
|
||||
|
||||
const COST_IN_USD_CENTS: u64 = 21;
|
||||
|
||||
/// Seed Audio 1.0 via Artcraft is flat priced, so the cost state carries no
|
||||
/// request fields.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArtcraftSeedAudio1p0CostState;
|
||||
|
||||
impl ArtcraftSeedAudio1p0CostState {
|
||||
pub fn from_request(_request: &ArtcraftSeedAudio1p0RequestState) -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub fn estimate_cost(&self) -> AudioGenerationCostEstimate {
|
||||
AudioGenerationCostEstimate {
|
||||
cost_in_credits: Some(COST_IN_USD_CENTS),
|
||||
cost_in_usd_cents: Some(COST_IN_USD_CENTS),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
failures_are_refunded: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::api::router_audio_model::RouterAudioModel;
|
||||
use crate::api::router_provider::RouterProvider;
|
||||
use crate::generate::generate_audio::generate_audio_request_builder::GenerateAudioRequestBuilder;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn flat_cost_is_twenty_one_cents() {
|
||||
let builder = GenerateAudioRequestBuilder {
|
||||
model: RouterAudioModel::SeedAudio1p0,
|
||||
provider: RouterProvider::Artcraft,
|
||||
prompt: Some("a suspense radio drama".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
let estimate = builder.build2().unwrap().estimate_cost().unwrap();
|
||||
assert_eq!(estimate.cost_in_usd_cents, Some(21));
|
||||
assert_eq!(estimate.cost_in_credits, Some(21));
|
||||
// Direct cost-state path matches the builder path.
|
||||
assert_eq!(ArtcraftSeedAudio1p0CostState.estimate_cost().cost_in_usd_cents, Some(21));
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
pub mod build;
|
||||
pub mod cost;
|
||||
pub mod request;
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_audio_cost_and_generate_request::OmniGenAudioCostAndGenerateRequest;
|
||||
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::generate_audio_response::GenerateAudioResponse;
|
||||
use crate::generate::generate_audio::providers::artcraft::request_common::send_artcraft_omni_audio_request;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArtcraftSeedAudio1p0RequestState {
|
||||
pub request: OmniGenAudioCostAndGenerateRequest,
|
||||
}
|
||||
|
||||
impl ArtcraftSeedAudio1p0RequestState {
|
||||
pub async fn send(&self, client: &RouterArtcraftClient) -> Result<GenerateAudioResponse, ArtcraftRouterError> {
|
||||
send_artcraft_omni_audio_request(&self.request, client).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet;
|
||||
use artcraft_client::utils::api_host::ApiHost;
|
||||
|
||||
use crate::api::router_audio_model::RouterAudioModel;
|
||||
use crate::api::router_provider::RouterProvider;
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::client::router_client::RouterClient;
|
||||
use crate::generate::generate_audio::audio_generation_draft_or_request::AudioGenerationDraftOrRequest;
|
||||
use crate::generate::generate_audio::generate_audio_request_builder::GenerateAudioRequestBuilder;
|
||||
use crate::generate::generate_audio::generate_audio_response::GenerateAudioResponse;
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore] // sends a real generation to the Artcraft backend, incurs cost
|
||||
async fn text_to_speech_drama() {
|
||||
let response = run_pipeline(GenerateAudioRequestBuilder {
|
||||
model: RouterAudioModel::SeedAudio1p0,
|
||||
provider: RouterProvider::Artcraft,
|
||||
prompt: Some("A calm narrator describes ocean waves rolling onto a moonlit beach.".to_string()),
|
||||
..Default::default()
|
||||
}).await;
|
||||
assert!(matches!(response, GenerateAudioResponse::Artcraft(_)));
|
||||
assert_eq!(1, 2, "Inspect output above");
|
||||
}
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn get_artcraft_client() -> RouterClient {
|
||||
let cookies = std::fs::read_to_string("/Users/bt/Artcraft/credentials/artcraft_cookies.txt")
|
||||
.expect("Failed to read artcraft cookies");
|
||||
let cookies = cookies.trim().to_string();
|
||||
let credentials = StorytellerCredentialSet::parse_multi_cookie_header(&cookies)
|
||||
.expect("Failed to parse cookies")
|
||||
.expect("No credentials found");
|
||||
RouterClient::Artcraft(RouterArtcraftClient::new(ApiHost::Storyteller, credentials))
|
||||
}
|
||||
|
||||
async fn run_pipeline(builder: GenerateAudioRequestBuilder) -> GenerateAudioResponse {
|
||||
let client = get_artcraft_client();
|
||||
|
||||
let draft_or_request = builder.build2().expect("build2 should succeed");
|
||||
let request = match draft_or_request {
|
||||
AudioGenerationDraftOrRequest::Request(r) => r,
|
||||
_ => panic!("expected Request variant (Artcraft skips draft)"),
|
||||
};
|
||||
|
||||
let response = request.send_request(&client).await.expect("send_request should succeed");
|
||||
|
||||
match &response {
|
||||
GenerateAudioResponse::Artcraft(p) => {
|
||||
println!("inference_job_token={:?}", p.inference_job_token);
|
||||
println!("all_inference_job_tokens={:?}", p.all_inference_job_tokens);
|
||||
}
|
||||
other => println!("response: {:?}", other),
|
||||
}
|
||||
|
||||
response
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
use enums::common::generation::common_audio_model::CommonAudioModel as CommonAudioModelEnum;
|
||||
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::audio_generation_draft_or_request::AudioGenerationDraftOrRequest;
|
||||
use crate::generate::generate_audio::audio_generation_request::AudioGenerationRequest;
|
||||
use crate::generate::generate_audio::generate_audio_request_builder::GenerateAudioRequestBuilder;
|
||||
use crate::generate::generate_audio::providers::artcraft::build_common::build_artcraft_omni_audio_request;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_music::request::ArtcraftSunoMusicRequestState;
|
||||
|
||||
pub fn build_artcraft_suno_music(builder: GenerateAudioRequestBuilder) -> Result<AudioGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
let request = build_artcraft_omni_audio_request(builder, CommonAudioModelEnum::SunoMusic)?;
|
||||
let state = ArtcraftSunoMusicRequestState { request };
|
||||
Ok(AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::ArtcraftSunoMusic(state)))
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
use crate::generate::generate_audio::audio_generation_cost_estimate::AudioGenerationCostEstimate;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_music::request::ArtcraftSunoMusicRequestState;
|
||||
|
||||
const COST_IN_USD_CENTS: u64 = 8;
|
||||
|
||||
/// Suno Music via Artcraft is flat priced, so the cost state carries no
|
||||
/// request fields.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArtcraftSunoMusicCostState;
|
||||
|
||||
impl ArtcraftSunoMusicCostState {
|
||||
pub fn from_request(_request: &ArtcraftSunoMusicRequestState) -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub fn estimate_cost(&self) -> AudioGenerationCostEstimate {
|
||||
AudioGenerationCostEstimate {
|
||||
cost_in_credits: Some(COST_IN_USD_CENTS),
|
||||
cost_in_usd_cents: Some(COST_IN_USD_CENTS),
|
||||
is_free: false,
|
||||
is_unlimited: false,
|
||||
is_rate_limited: false,
|
||||
has_watermark: false,
|
||||
failures_are_refunded: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::api::router_audio_model::RouterAudioModel;
|
||||
use crate::api::router_provider::RouterProvider;
|
||||
use crate::generate::generate_audio::generate_audio_request_builder::GenerateAudioRequestBuilder;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn flat_cost_is_eight_cents() {
|
||||
let builder = GenerateAudioRequestBuilder {
|
||||
model: RouterAudioModel::SunoMusic,
|
||||
provider: RouterProvider::Artcraft,
|
||||
prompt: Some("a song".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
let estimate = builder.build2().unwrap().estimate_cost().unwrap();
|
||||
assert_eq!(estimate.cost_in_usd_cents, Some(8));
|
||||
assert_eq!(estimate.cost_in_credits, Some(8));
|
||||
// Direct cost-state path matches the builder path.
|
||||
assert_eq!(ArtcraftSunoMusicCostState.estimate_cost().cost_in_usd_cents, Some(8));
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
pub mod build;
|
||||
pub mod cost;
|
||||
pub mod request;
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
use artcraft_api_defs::omni_gen::cost_and_generate_requests::omni_gen_audio_cost_and_generate_request::OmniGenAudioCostAndGenerateRequest;
|
||||
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::generate_audio_response::GenerateAudioResponse;
|
||||
use crate::generate::generate_audio::providers::artcraft::request_common::send_artcraft_omni_audio_request;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArtcraftSunoMusicRequestState {
|
||||
pub request: OmniGenAudioCostAndGenerateRequest,
|
||||
}
|
||||
|
||||
impl ArtcraftSunoMusicRequestState {
|
||||
pub async fn send(&self, client: &RouterArtcraftClient) -> Result<GenerateAudioResponse, ArtcraftRouterError> {
|
||||
send_artcraft_omni_audio_request(&self.request, client).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet;
|
||||
use artcraft_client::utils::api_host::ApiHost;
|
||||
|
||||
use crate::api::router_audio_model::RouterAudioModel;
|
||||
use crate::api::router_provider::RouterProvider;
|
||||
use crate::client::router_artcraft_client::RouterArtcraftClient;
|
||||
use crate::client::router_client::RouterClient;
|
||||
use crate::generate::generate_audio::audio_generation_draft_or_request::AudioGenerationDraftOrRequest;
|
||||
use crate::generate::generate_audio::generate_audio_request_builder::GenerateAudioRequestBuilder;
|
||||
use crate::generate::generate_audio::generate_audio_response::GenerateAudioResponse;
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore] // sends a real generation to the Artcraft backend, incurs cost
|
||||
async fn text_to_music() {
|
||||
let response = run_pipeline(GenerateAudioRequestBuilder {
|
||||
model: RouterAudioModel::SunoMusic,
|
||||
provider: RouterProvider::Artcraft,
|
||||
prompt: Some("A song about a corgi who learns to sail the open sea".to_string()),
|
||||
style_prompt: Some("Sea shanty, folk".to_string()),
|
||||
..Default::default()
|
||||
}).await;
|
||||
assert!(matches!(response, GenerateAudioResponse::Artcraft(_)));
|
||||
assert_eq!(1, 2, "Inspect output above");
|
||||
}
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
fn get_artcraft_client() -> RouterClient {
|
||||
let cookies = std::fs::read_to_string("/Users/bt/Artcraft/credentials/artcraft_cookies.txt")
|
||||
.expect("Failed to read artcraft cookies");
|
||||
let cookies = cookies.trim().to_string();
|
||||
let credentials = StorytellerCredentialSet::parse_multi_cookie_header(&cookies)
|
||||
.expect("Failed to parse cookies")
|
||||
.expect("No credentials found");
|
||||
RouterClient::Artcraft(RouterArtcraftClient::new(ApiHost::Storyteller, credentials))
|
||||
}
|
||||
|
||||
async fn run_pipeline(builder: GenerateAudioRequestBuilder) -> GenerateAudioResponse {
|
||||
let client = get_artcraft_client();
|
||||
|
||||
let draft_or_request = builder.build2().expect("build2 should succeed");
|
||||
let request = match draft_or_request {
|
||||
AudioGenerationDraftOrRequest::Request(r) => r,
|
||||
_ => panic!("expected Request variant (Artcraft skips draft)"),
|
||||
};
|
||||
|
||||
let response = request.send_request(&client).await.expect("send_request should succeed");
|
||||
|
||||
match &response {
|
||||
GenerateAudioResponse::Artcraft(p) => {
|
||||
println!("inference_job_token={:?}", p.inference_job_token);
|
||||
println!("all_inference_job_tokens={:?}", p.all_inference_job_tokens);
|
||||
}
|
||||
other => println!("response: {:?}", other),
|
||||
}
|
||||
|
||||
response
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
use enums::common::generation::common_audio_model::CommonAudioModel as CommonAudioModelEnum;
|
||||
|
||||
use crate::errors::artcraft_router_error::ArtcraftRouterError;
|
||||
use crate::generate::generate_audio::audio_generation_draft_or_request::AudioGenerationDraftOrRequest;
|
||||
use crate::generate::generate_audio::audio_generation_request::AudioGenerationRequest;
|
||||
use crate::generate::generate_audio::generate_audio_request_builder::GenerateAudioRequestBuilder;
|
||||
use crate::generate::generate_audio::providers::artcraft::build_common::build_artcraft_omni_audio_request;
|
||||
use crate::generate::generate_audio::providers::artcraft::suno_remix::request::ArtcraftSunoRemixRequestState;
|
||||
|
||||
pub fn build_artcraft_suno_remix(builder: GenerateAudioRequestBuilder) -> Result<AudioGenerationDraftOrRequest, ArtcraftRouterError> {
|
||||
let request = build_artcraft_omni_audio_request(builder, CommonAudioModelEnum::SunoRemix)?;
|
||||
let state = ArtcraftSunoRemixRequestState { request };
|
||||
Ok(AudioGenerationDraftOrRequest::Request(AudioGenerationRequest::ArtcraftSunoRemix(state)))
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user