Compare commits

..
Author SHA1 Message Date
Brandon Thomas 197174bbc9 handle failures in thread 2024-09-28 00:34:23 -04:00
252 changed files with 1331 additions and 10097 deletions
-1
View File
@@ -50,7 +50,6 @@
<w>unpermitted</w>
<w>upserting</w>
<w>upserts</w>
<w>upvoted</w>
<w>vits</w>
<w>vocoded</w>
<w>vocoder</w>
@@ -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 maybe_origin_model_type = ?,\n\n maybe_mime_type = ?,\n file_size_bytes = ?,\n\n checksum_sha2 = ?,\n\n maybe_style_transfer_source_media_file_token = ?,\n maybe_scene_source_media_file_token = ?,\n\n maybe_title = ?,\n maybe_prompt_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 creator_ip_address = ?,\n\n creator_set_visibility = ?,\n\n maybe_creator_file_synthetic_id = ?,\n maybe_creator_category_synthetic_id = ?,\n\n is_generated_on_prem = ?,\n generated_by_worker = ?,\n generated_by_cluster = ?\n\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 25
},
"nullable": []
},
"hash": "039c24023c93deacc0b09fbbfe747821ba9f7e06bc17f651628edf1a82f5feb6"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_description_markdown,\n wt.maybe_description_rendered_html,\n\n wt.maybe_ietf_language_tag,\n wt.maybe_ietf_primary_language_subtag,\n\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,\n cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,\n cover_image.maybe_public_bucket_extension as maybe_cover_image_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 wt.cached_usage_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as cover_image\n ON cover_image.token = wt.maybe_cover_image_media_file_token\n LEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"model_weight\"\n AND entity_stats.entity_token = wt.token\n LEFT OUTER JOIN featured_items\n ON featured_items.entity_type = \"model_weight\"\n AND featured_items.entity_token = wt.token\n AND featured_items.deleted_at IS NULL\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ",
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_description_markdown,\n wt.maybe_description_rendered_html,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,\n cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,\n cover_image.maybe_public_bucket_extension as maybe_cover_image_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 wt.cached_usage_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as cover_image\n ON cover_image.token = wt.maybe_cover_image_media_file_token\n LEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"model_weight\"\n AND entity_stats.entity_token = wt.token\n LEFT OUTER JOIN featured_items\n ON featured_items.entity_type = \"model_weight\"\n AND featured_items.entity_token = wt.token\n AND featured_items.deleted_at IS NULL\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ",
"describe": {
"columns": [
{
@@ -65,26 +65,6 @@
},
{
"ordinal": 6,
"name": "maybe_ietf_language_tag",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 256
}
},
{
"ordinal": 7,
"name": "maybe_ietf_primary_language_subtag",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 48
}
},
{
"ordinal": 8,
"name": "creator_ip_address",
"type_info": {
"type": "VarString",
@@ -94,7 +74,7 @@
}
},
{
"ordinal": 9,
"ordinal": 7,
"name": "creator_set_visibility: enums::common::visibility::Visibility",
"type_info": {
"type": "String",
@@ -104,7 +84,7 @@
}
},
{
"ordinal": 10,
"ordinal": 8,
"name": "creator_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
@@ -114,7 +94,7 @@
}
},
{
"ordinal": 11,
"ordinal": 9,
"name": "creator_username",
"type_info": {
"type": "VarString",
@@ -124,7 +104,7 @@
}
},
{
"ordinal": 12,
"ordinal": 10,
"name": "creator_display_name",
"type_info": {
"type": "VarString",
@@ -134,7 +114,7 @@
}
},
{
"ordinal": 13,
"ordinal": 11,
"name": "creator_gravatar_hash",
"type_info": {
"type": "String",
@@ -144,7 +124,7 @@
}
},
{
"ordinal": 14,
"ordinal": 12,
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
@@ -154,7 +134,7 @@
}
},
{
"ordinal": 15,
"ordinal": 13,
"name": "original_download_url",
"type_info": {
"type": "VarString",
@@ -164,7 +144,7 @@
}
},
{
"ordinal": 16,
"ordinal": 14,
"name": "original_filename",
"type_info": {
"type": "VarString",
@@ -174,7 +154,7 @@
}
},
{
"ordinal": 17,
"ordinal": 15,
"name": "file_size_bytes",
"type_info": {
"type": "LongLong",
@@ -184,7 +164,7 @@
}
},
{
"ordinal": 18,
"ordinal": 16,
"name": "file_checksum_sha2",
"type_info": {
"type": "String",
@@ -194,7 +174,7 @@
}
},
{
"ordinal": 19,
"ordinal": 17,
"name": "public_bucket_hash",
"type_info": {
"type": "VarString",
@@ -204,7 +184,7 @@
}
},
{
"ordinal": 20,
"ordinal": 18,
"name": "maybe_public_bucket_prefix",
"type_info": {
"type": "VarString",
@@ -214,7 +194,7 @@
}
},
{
"ordinal": 21,
"ordinal": 19,
"name": "maybe_public_bucket_extension",
"type_info": {
"type": "VarString",
@@ -224,7 +204,7 @@
}
},
{
"ordinal": 22,
"ordinal": 20,
"name": "maybe_cover_image_public_bucket_hash",
"type_info": {
"type": "VarString",
@@ -234,7 +214,7 @@
}
},
{
"ordinal": 23,
"ordinal": 21,
"name": "maybe_cover_image_public_bucket_prefix",
"type_info": {
"type": "VarString",
@@ -244,7 +224,7 @@
}
},
{
"ordinal": 24,
"ordinal": 22,
"name": "maybe_cover_image_public_bucket_extension",
"type_info": {
"type": "VarString",
@@ -254,7 +234,7 @@
}
},
{
"ordinal": 25,
"ordinal": 23,
"name": "maybe_ratings_positive_count",
"type_info": {
"type": "Long",
@@ -264,7 +244,7 @@
}
},
{
"ordinal": 26,
"ordinal": 24,
"name": "maybe_ratings_negative_count",
"type_info": {
"type": "Long",
@@ -274,7 +254,7 @@
}
},
{
"ordinal": 27,
"ordinal": 25,
"name": "maybe_bookmark_count",
"type_info": {
"type": "Long",
@@ -284,7 +264,7 @@
}
},
{
"ordinal": 28,
"ordinal": 26,
"name": "cached_usage_count",
"type_info": {
"type": "LongLong",
@@ -294,7 +274,7 @@
}
},
{
"ordinal": 29,
"ordinal": 27,
"name": "is_featured",
"type_info": {
"type": "LongLong",
@@ -304,7 +284,7 @@
}
},
{
"ordinal": 30,
"ordinal": 28,
"name": "version",
"type_info": {
"type": "Long",
@@ -314,7 +294,7 @@
}
},
{
"ordinal": 31,
"ordinal": 29,
"name": "created_at",
"type_info": {
"type": "Timestamp",
@@ -324,7 +304,7 @@
}
},
{
"ordinal": 32,
"ordinal": 30,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
@@ -334,7 +314,7 @@
}
},
{
"ordinal": 33,
"ordinal": 31,
"name": "user_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -344,7 +324,7 @@
}
},
{
"ordinal": 34,
"ordinal": 32,
"name": "mod_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -364,8 +344,6 @@
false,
true,
true,
true,
true,
false,
false,
false,
@@ -395,5 +373,5 @@
true
]
},
"hash": "29fe7f8464257537840d7f095ec01f850d79f970109549d14978fc3bed7cef32"
"hash": "1053294a21439ddb41fdd1053547b3f5c50457f6ba9450e5167a1db5caf896d1"
}
@@ -1,36 +0,0 @@
{
"db_name": "MySQL",
"query": "\nSELECT\n t.token as `token: tokens::tokens::tags::TagToken`,\n t.tag_value\n\nFROM\n tags AS t\nJOIN tag_uses AS u\n ON t.token = u.tag_token\nWHERE\n u.entity_type = ?\n AND u.entity_token = ?\n AND u.maybe_deleted_at IS NULL\nORDER BY t.id DESC\nLIMIT 500\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token: tokens::tokens::tags::TagToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 1,
"name": "tag_value",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false
]
},
"hash": "3929e9fe74e75fad7252681880c6c3bd7e76e96b0bf603f77f6a9b2d4fcda18d"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nDELETE FROM tag_uses\nWHERE entity_type = ?\nAND entity_token = ?\nLIMIT 1\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "41b16ccf04ef1ffb8b48bc59edf9389f61f54b871f6361f35529706b98d419ec"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\nSELECT\n w.id,\n w.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n\n w.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n w.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n w.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n w.title,\n\n w.maybe_ietf_language_tag,\n w.maybe_ietf_primary_language_subtag,\n\n cover_image.token as `maybe_cover_image_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,\n cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,\n cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,\n\n w.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_gravatar_hash,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\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 w.cached_usage_count,\n\n extension_tts.ietf_language_tag as maybe_tts_ietf_language_tag,\n extension_tts.ietf_primary_language_subtag as maybe_tts_ietf_primary_language_subtag,\n\n extension_vc.ietf_language_tag as maybe_vc_ietf_language_tag,\n extension_vc.ietf_primary_language_subtag as maybe_vc_ietf_primary_language_subtag,\n\n w.created_at,\n w.updated_at,\n w.user_deleted_at,\n w.mod_deleted_at,\n\n NOW() as database_read_time\n\nFROM model_weights as w\n\nJOIN users\n ON users.token = w.creator_user_token\n\nLEFT OUTER JOIN model_weights_extension_tts_details as extension_tts\n ON extension_tts.model_weights_token = w.token\nLEFT OUTER JOIN model_weights_extension_voice_conversion_details as extension_vc\n ON extension_vc.model_weights_token = w.token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"model_weight\"\n AND entity_stats.entity_token = w.token\nLEFT OUTER JOIN media_files as cover_image\n ON cover_image.token = w.maybe_cover_image_media_file_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = \"model_weight\"\n AND featured_items.entity_token = w.token\n AND featured_items.deleted_at IS NULL\n\nWHERE\n w.id > ?\nORDER BY id ASC\nLIMIT ?\n ",
"query": "\nSELECT\n w.id,\n w.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n\n w.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n w.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n w.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n w.title,\n\n cover_image.token as `maybe_cover_image_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,\n cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,\n cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,\n\n w.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_gravatar_hash,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\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 w.cached_usage_count,\n\n extension_tts.ietf_language_tag as maybe_tts_ietf_language_tag,\n extension_tts.ietf_primary_language_subtag as maybe_tts_ietf_primary_language_subtag,\n\n extension_vc.ietf_language_tag as maybe_vc_ietf_language_tag,\n extension_vc.ietf_primary_language_subtag as maybe_vc_ietf_primary_language_subtag,\n\n w.created_at,\n w.updated_at,\n w.user_deleted_at,\n w.mod_deleted_at,\n\n NOW() as database_read_time\n\nFROM model_weights as w\n\nJOIN users\n ON users.token = w.creator_user_token\n\nLEFT OUTER JOIN model_weights_extension_tts_details as extension_tts\n ON extension_tts.model_weights_token = w.token\nLEFT OUTER JOIN model_weights_extension_voice_conversion_details as extension_vc\n ON extension_vc.model_weights_token = w.token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"model_weight\"\n AND entity_stats.entity_token = w.token\nLEFT OUTER JOIN media_files as cover_image\n ON cover_image.token = w.maybe_cover_image_media_file_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = \"model_weight\"\n AND featured_items.entity_token = w.token\n AND featured_items.deleted_at IS NULL\n\nWHERE\n w.id > ?\nORDER BY id ASC\nLIMIT ?\n ",
"describe": {
"columns": [
{
@@ -65,26 +65,6 @@
},
{
"ordinal": 6,
"name": "maybe_ietf_language_tag",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 256
}
},
{
"ordinal": 7,
"name": "maybe_ietf_primary_language_subtag",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 48
}
},
{
"ordinal": 8,
"name": "maybe_cover_image_media_file_token: tokens::tokens::media_files::MediaFileToken",
"type_info": {
"type": "VarString",
@@ -94,7 +74,7 @@
}
},
{
"ordinal": 9,
"ordinal": 7,
"name": "maybe_cover_image_public_bucket_hash",
"type_info": {
"type": "VarString",
@@ -104,7 +84,7 @@
}
},
{
"ordinal": 10,
"ordinal": 8,
"name": "maybe_cover_image_public_bucket_prefix",
"type_info": {
"type": "VarString",
@@ -114,7 +94,7 @@
}
},
{
"ordinal": 11,
"ordinal": 9,
"name": "maybe_cover_image_public_bucket_extension",
"type_info": {
"type": "VarString",
@@ -124,7 +104,7 @@
}
},
{
"ordinal": 12,
"ordinal": 10,
"name": "creator_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
@@ -134,7 +114,7 @@
}
},
{
"ordinal": 13,
"ordinal": 11,
"name": "creator_username",
"type_info": {
"type": "VarString",
@@ -144,7 +124,7 @@
}
},
{
"ordinal": 14,
"ordinal": 12,
"name": "creator_display_name",
"type_info": {
"type": "VarString",
@@ -154,7 +134,7 @@
}
},
{
"ordinal": 15,
"ordinal": 13,
"name": "creator_gravatar_hash",
"type_info": {
"type": "String",
@@ -164,7 +144,7 @@
}
},
{
"ordinal": 16,
"ordinal": 14,
"name": "is_featured",
"type_info": {
"type": "LongLong",
@@ -174,7 +154,7 @@
}
},
{
"ordinal": 17,
"ordinal": 15,
"name": "maybe_ratings_positive_count",
"type_info": {
"type": "Long",
@@ -184,7 +164,7 @@
}
},
{
"ordinal": 18,
"ordinal": 16,
"name": "maybe_ratings_negative_count",
"type_info": {
"type": "Long",
@@ -194,7 +174,7 @@
}
},
{
"ordinal": 19,
"ordinal": 17,
"name": "maybe_bookmark_count",
"type_info": {
"type": "Long",
@@ -204,7 +184,7 @@
}
},
{
"ordinal": 20,
"ordinal": 18,
"name": "cached_usage_count",
"type_info": {
"type": "LongLong",
@@ -214,7 +194,7 @@
}
},
{
"ordinal": 21,
"ordinal": 19,
"name": "maybe_tts_ietf_language_tag",
"type_info": {
"type": "VarString",
@@ -224,7 +204,7 @@
}
},
{
"ordinal": 22,
"ordinal": 20,
"name": "maybe_tts_ietf_primary_language_subtag",
"type_info": {
"type": "VarString",
@@ -234,7 +214,7 @@
}
},
{
"ordinal": 23,
"ordinal": 21,
"name": "maybe_vc_ietf_language_tag",
"type_info": {
"type": "VarString",
@@ -244,7 +224,7 @@
}
},
{
"ordinal": 24,
"ordinal": 22,
"name": "maybe_vc_ietf_primary_language_subtag",
"type_info": {
"type": "VarString",
@@ -254,7 +234,7 @@
}
},
{
"ordinal": 25,
"ordinal": 23,
"name": "created_at",
"type_info": {
"type": "Timestamp",
@@ -264,7 +244,7 @@
}
},
{
"ordinal": 26,
"ordinal": 24,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
@@ -274,7 +254,7 @@
}
},
{
"ordinal": 27,
"ordinal": 25,
"name": "user_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -284,7 +264,7 @@
}
},
{
"ordinal": 28,
"ordinal": 26,
"name": "mod_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -294,7 +274,7 @@
}
},
{
"ordinal": 29,
"ordinal": 27,
"name": "database_read_time",
"type_info": {
"type": "Datetime",
@@ -318,8 +298,6 @@
true,
true,
true,
true,
true,
false,
false,
false,
@@ -340,5 +318,5 @@
false
]
},
"hash": "d0f9d2cf4176c3f7f8fbff66eb6ff9415d989afc2b5944629a7bcea4b5a822f3"
"hash": "4bce2b10f0510feca7f5705049a5c0eaae6e1a840146628495827468a38c05dd"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_description_markdown,\n wt.maybe_description_rendered_html,\n\n wt.maybe_ietf_language_tag,\n wt.maybe_ietf_primary_language_subtag,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,\n cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,\n cover_image.maybe_public_bucket_extension as maybe_cover_image_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 wt.cached_usage_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as cover_image\n ON cover_image.token = wt.maybe_cover_image_media_file_token\n LEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"model_weight\"\n AND entity_stats.entity_token = wt.token\n LEFT OUTER JOIN featured_items\n ON featured_items.entity_type = \"model_weight\"\n AND featured_items.entity_token = wt.token\n AND featured_items.deleted_at IS NULL\n WHERE\n wt.token = ?\n ",
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_description_markdown,\n wt.maybe_description_rendered_html,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,\n cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,\n cover_image.maybe_public_bucket_extension as maybe_cover_image_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 wt.cached_usage_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as cover_image\n ON cover_image.token = wt.maybe_cover_image_media_file_token\n LEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"model_weight\"\n AND entity_stats.entity_token = wt.token\n LEFT OUTER JOIN featured_items\n ON featured_items.entity_type = \"model_weight\"\n AND featured_items.entity_token = wt.token\n AND featured_items.deleted_at IS NULL\n WHERE\n wt.token = ?\n ",
"describe": {
"columns": [
{
@@ -65,26 +65,6 @@
},
{
"ordinal": 6,
"name": "maybe_ietf_language_tag",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 256
}
},
{
"ordinal": 7,
"name": "maybe_ietf_primary_language_subtag",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 48
}
},
{
"ordinal": 8,
"name": "creator_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
@@ -94,7 +74,7 @@
}
},
{
"ordinal": 9,
"ordinal": 7,
"name": "creator_username",
"type_info": {
"type": "VarString",
@@ -104,7 +84,7 @@
}
},
{
"ordinal": 10,
"ordinal": 8,
"name": "creator_display_name",
"type_info": {
"type": "VarString",
@@ -114,7 +94,7 @@
}
},
{
"ordinal": 11,
"ordinal": 9,
"name": "creator_gravatar_hash",
"type_info": {
"type": "String",
@@ -124,7 +104,7 @@
}
},
{
"ordinal": 12,
"ordinal": 10,
"name": "creator_ip_address",
"type_info": {
"type": "VarString",
@@ -134,7 +114,7 @@
}
},
{
"ordinal": 13,
"ordinal": 11,
"name": "creator_set_visibility: enums::common::visibility::Visibility",
"type_info": {
"type": "String",
@@ -144,7 +124,7 @@
}
},
{
"ordinal": 14,
"ordinal": 12,
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
@@ -154,7 +134,7 @@
}
},
{
"ordinal": 15,
"ordinal": 13,
"name": "original_download_url",
"type_info": {
"type": "VarString",
@@ -164,7 +144,7 @@
}
},
{
"ordinal": 16,
"ordinal": 14,
"name": "original_filename",
"type_info": {
"type": "VarString",
@@ -174,7 +154,7 @@
}
},
{
"ordinal": 17,
"ordinal": 15,
"name": "file_size_bytes",
"type_info": {
"type": "LongLong",
@@ -184,7 +164,7 @@
}
},
{
"ordinal": 18,
"ordinal": 16,
"name": "file_checksum_sha2",
"type_info": {
"type": "String",
@@ -194,7 +174,7 @@
}
},
{
"ordinal": 19,
"ordinal": 17,
"name": "public_bucket_hash",
"type_info": {
"type": "VarString",
@@ -204,7 +184,7 @@
}
},
{
"ordinal": 20,
"ordinal": 18,
"name": "maybe_public_bucket_prefix",
"type_info": {
"type": "VarString",
@@ -214,7 +194,7 @@
}
},
{
"ordinal": 21,
"ordinal": 19,
"name": "maybe_public_bucket_extension",
"type_info": {
"type": "VarString",
@@ -224,7 +204,7 @@
}
},
{
"ordinal": 22,
"ordinal": 20,
"name": "maybe_cover_image_public_bucket_hash",
"type_info": {
"type": "VarString",
@@ -234,7 +214,7 @@
}
},
{
"ordinal": 23,
"ordinal": 21,
"name": "maybe_cover_image_public_bucket_prefix",
"type_info": {
"type": "VarString",
@@ -244,7 +224,7 @@
}
},
{
"ordinal": 24,
"ordinal": 22,
"name": "maybe_cover_image_public_bucket_extension",
"type_info": {
"type": "VarString",
@@ -254,7 +234,7 @@
}
},
{
"ordinal": 25,
"ordinal": 23,
"name": "maybe_ratings_positive_count",
"type_info": {
"type": "Long",
@@ -264,7 +244,7 @@
}
},
{
"ordinal": 26,
"ordinal": 24,
"name": "maybe_ratings_negative_count",
"type_info": {
"type": "Long",
@@ -274,7 +254,7 @@
}
},
{
"ordinal": 27,
"ordinal": 25,
"name": "maybe_bookmark_count",
"type_info": {
"type": "Long",
@@ -284,7 +264,7 @@
}
},
{
"ordinal": 28,
"ordinal": 26,
"name": "cached_usage_count",
"type_info": {
"type": "LongLong",
@@ -294,7 +274,7 @@
}
},
{
"ordinal": 29,
"ordinal": 27,
"name": "is_featured",
"type_info": {
"type": "LongLong",
@@ -304,7 +284,7 @@
}
},
{
"ordinal": 30,
"ordinal": 28,
"name": "version",
"type_info": {
"type": "Long",
@@ -314,7 +294,7 @@
}
},
{
"ordinal": 31,
"ordinal": 29,
"name": "created_at",
"type_info": {
"type": "Timestamp",
@@ -324,7 +304,7 @@
}
},
{
"ordinal": 32,
"ordinal": 30,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
@@ -334,7 +314,7 @@
}
},
{
"ordinal": 33,
"ordinal": 31,
"name": "user_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -344,7 +324,7 @@
}
},
{
"ordinal": 34,
"ordinal": 32,
"name": "mod_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -364,8 +344,6 @@
false,
true,
true,
true,
true,
false,
false,
false,
@@ -395,5 +373,5 @@
true
]
},
"hash": "53c90f5230aa202aead37a224ec70e350172bc0ec4eeaebde22878ca4aa0f695"
"hash": "5e953a6ad7bcaaed0918109593652b03c7ab497cc65b59bbb6add011de6401f0"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nUPDATE generic_inference_jobs\nSET\n status = 'cancelled_by_user',\n retry_at = NULL\nWHERE status IN (\n 'pending',\n 'started',\n 'attempt_failed'\n )\nLIMIT 100\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 0
},
"nullable": []
},
"hash": "84320887e8157a450ad46ec0843071c60c054eab61958a9148789ed76cd476e3"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nINSERT INTO tags\nSET\n token = ?,\n tag_value = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "c7e848e4c906a34ac5a4ad8cc73354baa8d5cd81170dd06d66d7f414505d538b"
}
Generated
+13 -24
View File
@@ -3703,7 +3703,6 @@ dependencies = [
"time",
"tokens",
"tokio",
"tokio-stream",
"tokio-util",
"tts_common",
"url",
@@ -4455,18 +4454,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "mio"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [
"hermit-abi",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0",
]
[[package]]
name = "mio-uds"
version = "0.6.8"
@@ -4541,7 +4528,6 @@ dependencies = [
"anstream",
"arrayvec",
"base64 0.21.7",
"base64 0.22.1",
"base64ct",
"bitflags 2.5.0",
"block-buffer 0.9.0",
@@ -4582,6 +4568,7 @@ dependencies = [
"md-5 0.10.6",
"memchr",
"miniz_oxide",
"mio 0.8.11",
"native-tls",
"num-bigint",
"num-integer",
@@ -7822,20 +7809,21 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.40.0"
version = "1.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
dependencies = [
"backtrace",
"bytes 1.6.0",
"libc",
"mio 1.0.2",
"mio 0.8.11",
"num_cpus",
"parking_lot 0.12.2",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.52.0",
"windows-sys 0.48.0",
]
[[package]]
@@ -7882,9 +7870,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "2.4.0"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [
"proc-macro2",
"quote",
@@ -7933,9 +7921,9 @@ dependencies = [
[[package]]
name = "tokio-stream"
version = "0.1.16"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1"
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
dependencies = [
"futures-core",
"pin-project-lite",
@@ -7986,15 +7974,16 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.7.12"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
dependencies = [
"bytes 1.6.0",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
"tracing",
]
[[package]]
@@ -1,15 +0,0 @@
-- User sign up histogram by method
-- Since we don't have an index on created_at, we threshold by id
-- Current ID count = 7578799 (September 28, 2024)
select
date(created_at) as date,
case
when maybe_signup_method is null then 'email_password'
else maybe_signup_method
end as method,
count(*) as signup_count
from users
where id > 7200000
and created_at >= NOW() - INTERVAL 60 DAY
group by date(created_at), method
@@ -1,14 +0,0 @@
-- User sign up histogram by method
-- Since we don't have an index on created_at, we threshold by id
-- Current ID count = 7578799 (September 28, 2024)
select
date(created_at) as date,
case
when maybe_source is null then 'unknown'
else maybe_source
end as source,
count(*) as signup_count
from users
where id > 7200000
and created_at >= NOW() - INTERVAL 60 DAY
group by date(created_at), maybe_source
@@ -1,69 +0,0 @@
-- Select popular models without cover images or language
select
mw.token,
mw.title,
mw.maybe_ietf_language_tag,
mw.maybe_cover_image_media_file_token,
count(*) as use_count
from generic_inference_jobs as gij
left outer join model_weights as mw
on gij.maybe_model_token = mw.token
where gij.created_at >= (CURDATE() - INTERVAL 5 DAY)
and (
mw.maybe_ietf_language_tag IS NULL
or mw.maybe_cover_image_media_file_token IS NULL
)
and mw.mod_deleted_at IS NULL
and mw.user_deleted_at IS NULL
group by
mw.token,
mw.title,
mw.maybe_ietf_language_tag,
mw.maybe_cover_image_media_file_token
order by use_count desc
limit 100;
-- Select popular models without streamer usage distorting the totals
select
mw.token,
mw.title,
mw.maybe_ietf_language_tag,
mw.maybe_cover_image_media_file_token,
count(*) as use_count
from generic_inference_jobs as gij
left outer join model_weights as mw
on gij.maybe_model_token = mw.token
where gij.created_at >= (CURDATE() - INTERVAL 5 DAY)
and (
mw.maybe_ietf_language_tag IS NULL
or mw.maybe_cover_image_media_file_token IS NULL
)
and mw.mod_deleted_at IS NULL
and mw.user_deleted_at IS NULL
and gij.maybe_creator_user_token NOT IN (
-- This subquery returns streamers that generated over a certain threshold number of results
select
user_token
from (
select
u.token as user_token,
count(*) as generations
from generic_inference_jobs as gij
join users as u
on gij.maybe_creator_user_token = u.token
where gij.created_at >= (CURDATE() - INTERVAL 5 DAY)
and gij.maybe_creator_user_token is not null
group by user_token
order by generations desc
) as top_users
where top_users.generations > 300
)
group by
mw.token,
mw.title,
mw.maybe_ietf_language_tag,
mw.maybe_cover_image_media_file_token
order by use_count desc
limit 50;
@@ -1,5 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE model_weights DROP COLUMN maybe_ietf_language_tag;
@@ -1,9 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE model_weights
ADD COLUMN
maybe_ietf_language_tag VARCHAR(64) DEFAULT NULL
AFTER maybe_description_rendered_html;
@@ -1,5 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE model_weights DROP COLUMN maybe_ietf_primary_language_subtag;
@@ -1,9 +0,0 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE model_weights
ADD COLUMN
maybe_ietf_primary_language_subtag VARCHAR(12) DEFAULT NULL
AFTER maybe_ietf_language_tag;
@@ -53,22 +53,6 @@ CREATE TABLE model_weights (
-- models don't deserve a description).
maybe_description_rendered_html TEXT DEFAULT NULL,
-- OPTIONAL. Only for TTS and Voice Conversion models.
-- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.)
-- (Not that it matters apart from categorization, since voice conversion is universal.)
-- NB: There's another set of tables (model_weights_extension_voice_conversion_details, etc.) that
-- may have older post-migration data for some models. We'll want to backfill this field from there
-- and then make this one authoritative.
maybe_ietf_language_tag VARCHAR(64) DEFAULT NULL,
-- OPTIONAL. Only for TTS and Voice Conversion models.
-- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es")
-- (Not that it matters apart from categorization, since voice conversion is universal.)
-- NB: There's another set of tables (model_weights_extension_voice_conversion_details, etc.) that
-- may have older post-migration data for some models. We'll want to backfill this field from there
-- and then make this one authoritative.
maybe_ietf_primary_language_subtag VARCHAR(12) DEFAULT NULL,
-- ========== CREATOR DETAILS ==========
@@ -1,4 +1,3 @@
pub mod audit_logs;
pub mod batch_generations;
pub mod featured_items;
pub mod tag_uses;
@@ -1 +0,0 @@
pub mod tag_use_entity;
@@ -1,40 +0,0 @@
use enums::by_table::tag_uses::tag_use_entity_type::TagUseEntityType;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::model_weights::ModelWeightToken;
// TODO(bt, 2024-01-16): A ref type with <'a> lifetime of inner data instead of ownership?
pub enum TagUseEntity {
MediaFile(MediaFileToken),
ModelWeight(ModelWeightToken),
}
// TODO(bt, 2024-01-16): Codegen? Make traits for these? Maybe overkill.
impl TagUseEntity {
pub fn from_entity_type_and_token(entity_type: TagUseEntityType, token: &str) -> Self {
match entity_type {
TagUseEntityType::ModelWeight => Self::ModelWeight(ModelWeightToken::new_from_str(token)),
TagUseEntityType::MediaFile => Self::MediaFile(MediaFileToken::new_from_str(token)),
}
}
pub fn get_entity_type(&self) -> TagUseEntityType {
match self {
Self::MediaFile(_) => TagUseEntityType::MediaFile,
Self::ModelWeight(_) => TagUseEntityType::ModelWeight,
}
}
pub fn get_entity_token_str(&self) -> &str {
match self {
Self::MediaFile(token) => token.as_str(),
Self::ModelWeight(token) => token.as_str(),
}
}
pub fn get_composite_keys(&self) -> (TagUseEntityType, &str) {
match self {
Self::MediaFile(token) => (TagUseEntityType::MediaFile, token.as_str()),
Self::ModelWeight(token) => (TagUseEntityType::ModelWeight, token.as_str()),
}
}
}
@@ -57,9 +57,6 @@ pub enum InferenceCategory {
#[serde(rename = "live_portrait")]
LivePortrait,
#[serde(rename="seed_vc")]
SeedVc,
/// DEPRECATED. Do not use.
/// This was for ReRenderAVideo, which we never productionized.
#[deprecated(note = "This was for ReRenderAVideo, which we never productionized.")]
@@ -70,9 +67,6 @@ pub enum InferenceCategory {
#[deprecated(note = "This was for Bevy engine's server side rendering.")]
#[serde(rename = "convert_bvh_to_workflow")]
ConvertBvhToWorkflow,
#[serde(rename = "f5_tts")]
F5TTS,
}
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
@@ -91,10 +85,8 @@ impl InferenceCategory {
Self::ImageGeneration => "image_generation",
Self::Mocap => "mocap",
Self::Workflow => "workflow",
Self::F5TTS => "f5_tts",
Self::FormatConversion => "format_conversion",
Self::LivePortrait => "live_portrait",
Self::SeedVc => "seed_vc",
Self::VideoFilter => "video_filter",
Self::ConvertBvhToWorkflow => "convert_bvh_to_workflow",
}
@@ -107,12 +99,10 @@ impl InferenceCategory {
"text_to_speech" => Ok(Self::TextToSpeech),
"voice_conversion" => Ok(Self::VoiceConversion),
"image_generation" => Ok(Self::ImageGeneration),
"f5_tts" => Ok(Self::F5TTS),
"mocap" => Ok(Self::Mocap),
"workflow" => Ok(Self::Workflow),
"format_conversion" => Ok(Self::FormatConversion),
"live_portrait" => Ok(Self::LivePortrait),
"seed_vc" => Ok(Self::SeedVc),
"video_filter" => Ok(Self::VideoFilter),
"convert_bvh_to_workflow" => Ok(Self::ConvertBvhToWorkflow),
_ => Err(format!("invalid value: {:?}", value)),
@@ -129,8 +119,6 @@ impl InferenceCategory {
Self::VoiceConversion,
Self::ImageGeneration,
Self::Mocap,
Self::F5TTS,
Self::SeedVc,
Self::Workflow,
Self::FormatConversion,
Self::LivePortrait,
@@ -156,8 +144,6 @@ mod tests {
assert_serialization(InferenceCategory::VoiceConversion, "voice_conversion");
assert_serialization(InferenceCategory::ImageGeneration, "image_generation");
assert_serialization(InferenceCategory::Mocap, "mocap");
assert_serialization(InferenceCategory::F5TTS, "f5_tts");
assert_serialization(InferenceCategory::SeedVc, "seed_vc");
assert_serialization(InferenceCategory::Workflow, "workflow");
assert_serialization(InferenceCategory::FormatConversion, "format_conversion");
assert_serialization(InferenceCategory::LivePortrait, "live_portrait");
@@ -172,8 +158,6 @@ mod tests {
assert_eq!(InferenceCategory::TextToSpeech.to_str(), "text_to_speech");
assert_eq!(InferenceCategory::VoiceConversion.to_str(), "voice_conversion");
assert_eq!(InferenceCategory::ImageGeneration.to_str(), "image_generation");
assert_eq!(InferenceCategory::F5TTS.to_str(), "f5_tts");
assert_eq!(InferenceCategory::SeedVc.to_str(), "seed_vc");
assert_eq!(InferenceCategory::Mocap.to_str(), "mocap");
assert_eq!(InferenceCategory::Workflow.to_str(), "workflow");
assert_eq!(InferenceCategory::FormatConversion.to_str(), "format_conversion");
@@ -189,8 +173,6 @@ mod tests {
assert_eq!(InferenceCategory::from_str("text_to_speech").unwrap(), InferenceCategory::TextToSpeech);
assert_eq!(InferenceCategory::from_str("voice_conversion").unwrap(), InferenceCategory::VoiceConversion);
assert_eq!(InferenceCategory::from_str("image_generation").unwrap(), InferenceCategory::ImageGeneration);
assert_eq!(InferenceCategory::from_str("f5_tts").unwrap(), InferenceCategory::F5TTS);
assert_eq!(InferenceCategory::from_str("seed_vc").unwrap(), InferenceCategory::SeedVc);
assert_eq!(InferenceCategory::from_str("mocap").unwrap(), InferenceCategory::Mocap);
assert_eq!(InferenceCategory::from_str("workflow").unwrap(), InferenceCategory::Workflow);
assert_eq!(InferenceCategory::from_str("format_conversion").unwrap(), InferenceCategory::FormatConversion);
@@ -203,15 +185,13 @@ mod tests {
fn all_variants() {
// Static check
let mut variants = InferenceCategory::all_variants();
assert_eq!(variants.len(), 12);
assert_eq!(variants.len(), 11);
assert_eq!(variants.pop_first(), Some(InferenceCategory::DeprecatedField));
assert_eq!(variants.pop_first(), Some(InferenceCategory::LipsyncAnimation));
assert_eq!(variants.pop_first(), Some(InferenceCategory::TextToSpeech));
assert_eq!(variants.pop_first(), Some(InferenceCategory::VoiceConversion));
assert_eq!(variants.pop_first(), Some(InferenceCategory::ImageGeneration));
assert_eq!(variants.pop_first(), Some(InferenceCategory::F5TTS));
assert_eq!(variants.pop_first(), Some(InferenceCategory::Mocap));
assert_eq!(variants.pop_first(), Some(InferenceCategory::SeedVc));
assert_eq!(variants.pop_first(), Some(InferenceCategory::Workflow));
assert_eq!(variants.pop_first(), Some(InferenceCategory::FormatConversion));
assert_eq!(variants.pop_first(), Some(InferenceCategory::LivePortrait));
@@ -27,9 +27,6 @@ pub enum InferenceJobProductCategory {
/// TTS: GptSoVits
TtsGptSoVits,
/// TTS: F5Tts (Zero Shot)
TtsF5,
/// TTS: StyleTts2 (Zero Shot)
TtsStyleTts2,
@@ -44,8 +41,6 @@ pub enum InferenceJobProductCategory {
/// Voice Conversion: SoVitsSvc
VcSvc,
VcSeedVc, // Ugh
// =============== VIDEO ===============
/// Video: Face Fusion (Lipsync)
@@ -63,9 +58,6 @@ pub enum InferenceJobProductCategory {
/// Video: Studio
VidStudio,
/// Video: Studio Gen 2
VidStudioGen2,
/// Video: Style Transfer
VidStyleTransfer,
@@ -116,16 +108,13 @@ impl InferenceJobProductCategory {
Self::TtsGptSoVits => "tts_gpt_so_vits",
Self::TtsStyleTts2 => "tts_style_tts2",
Self::TtsTacotron2 => "tts_tacotron2",
Self::TtsF5 => "tts_f5",
Self::VcSvc => "vc_svc",
Self::VcRvc2 => "vc_rvc2",
Self::VcSeedVc => "vc_seed_vc",
Self::VidLipsyncFaceFusion => "vid_lipsync_face_fusion",
Self::VidLipsyncSadTalker => "vid_lipsync_sad_talker",
Self::VidLivePortrait => "vid_live_portrait",
Self::VidLivePortraitWebcam => "vid_live_portrait_webcam",
Self::VidStudio => "vid_studio",
Self::VidStudioGen2 => "vid_studio_gen2",
Self::VidStyleTransfer => "vid_style_transfer",
Self::LipsyncFaceFusion => "lipsync_face_fusion",
Self::LipsyncSadTalker => "lipsync_sad_talker",
@@ -144,16 +133,13 @@ impl InferenceJobProductCategory {
"tts_gpt_so_vits" => Ok(Self::TtsGptSoVits),
"tts_style_tts2" => Ok(Self::TtsStyleTts2),
"tts_tacotron2" => Ok(Self::TtsTacotron2),
"tts_f5" => Ok(Self::TtsF5),
"vc_svc" => Ok(Self::VcSvc),
"vc_rvc2" => Ok(Self::VcRvc2),
"vc_seed_vc" => Ok(Self::VcSeedVc),
"vid_lipsync_face_fusion" => Ok(Self::VidLipsyncFaceFusion),
"vid_lipsync_sad_talker" => Ok(Self::VidLipsyncSadTalker),
"vid_live_portrait" => Ok(Self::VidLivePortrait),
"vid_live_portrait_webcam" => Ok(Self::VidLivePortraitWebcam),
"vid_studio" => Ok(Self::VidStudio),
"vid_studio_gen2" => Ok(Self::VidStudioGen2),
"vid_style_transfer" => Ok(Self::VidStyleTransfer),
"lipsync_face_fusion" => Ok(Self::LipsyncFaceFusion),
"lipsync_sad_talker" => Ok(Self::LipsyncSadTalker),
@@ -175,8 +161,6 @@ impl InferenceJobProductCategory {
Self::TtsGptSoVits,
Self::TtsStyleTts2,
Self::TtsTacotron2,
Self::TtsF5,
Self::VcSeedVc,
Self::VcSvc,
Self::VcRvc2,
Self::VidLipsyncFaceFusion,
@@ -184,7 +168,6 @@ impl InferenceJobProductCategory {
Self::VidLivePortrait,
Self::VidLivePortraitWebcam,
Self::VidStudio,
Self::VidStudioGen2,
Self::VidStyleTransfer,
Self::LipsyncFaceFusion,
Self::LipsyncSadTalker,
@@ -212,16 +195,13 @@ mod tests {
assert_serialization(InferenceJobProductCategory::TtsGptSoVits, "tts_gpt_so_vits");
assert_serialization(InferenceJobProductCategory::TtsStyleTts2, "tts_style_tts2");
assert_serialization(InferenceJobProductCategory::TtsTacotron2, "tts_tacotron2");
assert_serialization(InferenceJobProductCategory::TtsF5, "tts_f5");
assert_serialization(InferenceJobProductCategory::VcRvc2, "vc_rvc2");
assert_serialization(InferenceJobProductCategory::VcSvc, "vc_svc");
assert_serialization(InferenceJobProductCategory::VcSvc, "vc_svc");
assert_serialization(InferenceJobProductCategory::VidLipsyncFaceFusion, "vid_lipsync_face_fusion");
assert_serialization(InferenceJobProductCategory::VidLipsyncSadTalker, "vid_lipsync_sad_talker");
assert_serialization(InferenceJobProductCategory::VidLivePortrait, "vid_live_portrait");
assert_serialization(InferenceJobProductCategory::VidLivePortraitWebcam, "vid_live_portrait_webcam");
assert_serialization(InferenceJobProductCategory::VidStudio, "vid_studio");
assert_serialization(InferenceJobProductCategory::VidStudioGen2, "vid_studio_gen2");
assert_serialization(InferenceJobProductCategory::VidStyleTransfer, "vid_style_transfer");
assert_serialization(InferenceJobProductCategory::LipsyncFaceFusion, "lipsync_face_fusion");
assert_serialization(InferenceJobProductCategory::LipsyncSadTalker, "lipsync_sad_talker");
@@ -241,13 +221,11 @@ mod tests {
assert_eq!(InferenceJobProductCategory::TtsTacotron2.to_str(), "tts_tacotron2");
assert_eq!(InferenceJobProductCategory::VcRvc2.to_str(), "vc_rvc2");
assert_eq!(InferenceJobProductCategory::VcSvc.to_str(), "vc_svc");
assert_eq!(InferenceJobProductCategory::VcSvc.to_str(), "vc_svc");
assert_eq!(InferenceJobProductCategory::VidLipsyncFaceFusion.to_str(), "vid_lipsync_face_fusion");
assert_eq!(InferenceJobProductCategory::VidLipsyncSadTalker.to_str(), "vid_lipsync_sad_talker");
assert_eq!(InferenceJobProductCategory::VidLivePortrait.to_str(), "vid_live_portrait");
assert_eq!(InferenceJobProductCategory::VidLivePortraitWebcam.to_str(), "vid_live_portrait_webcam");
assert_eq!(InferenceJobProductCategory::VidStudio.to_str(), "vid_studio");
assert_eq!(InferenceJobProductCategory::VidStudioGen2.to_str(), "vid_studio_gen2");
assert_eq!(InferenceJobProductCategory::VidStyleTransfer.to_str(), "vid_style_transfer");
assert_eq!(InferenceJobProductCategory::LipsyncFaceFusion.to_str(), "lipsync_face_fusion");
assert_eq!(InferenceJobProductCategory::LipsyncSadTalker.to_str(), "lipsync_sad_talker");
@@ -267,13 +245,11 @@ mod tests {
assert_eq!(InferenceJobProductCategory::from_str("tts_tacotron2").unwrap(), InferenceJobProductCategory::TtsTacotron2);
assert_eq!(InferenceJobProductCategory::from_str("vc_rvc2").unwrap(), InferenceJobProductCategory::VcRvc2);
assert_eq!(InferenceJobProductCategory::from_str("vc_svc").unwrap(), InferenceJobProductCategory::VcSvc);
assert_eq!(InferenceJobProductCategory::from_str("vc_svc").unwrap(), InferenceJobProductCategory::VcSvc);
assert_eq!(InferenceJobProductCategory::from_str("vid_lipsync_face_fusion").unwrap(), InferenceJobProductCategory::VidLipsyncFaceFusion);
assert_eq!(InferenceJobProductCategory::from_str("vid_lipsync_sad_talker").unwrap(), InferenceJobProductCategory::VidLipsyncSadTalker);
assert_eq!(InferenceJobProductCategory::from_str("vid_live_portrait").unwrap(), InferenceJobProductCategory::VidLivePortrait);
assert_eq!(InferenceJobProductCategory::from_str("vid_live_portrait_webcam").unwrap(), InferenceJobProductCategory::VidLivePortraitWebcam);
assert_eq!(InferenceJobProductCategory::from_str("vid_studio").unwrap(), InferenceJobProductCategory::VidStudio);
assert_eq!(InferenceJobProductCategory::from_str("vid_studio_gen2").unwrap(), InferenceJobProductCategory::VidStudioGen2);
assert_eq!(InferenceJobProductCategory::from_str("vid_style_transfer").unwrap(), InferenceJobProductCategory::VidStyleTransfer);
assert_eq!(InferenceJobProductCategory::from_str("lipsync_face_fusion").unwrap(), InferenceJobProductCategory::LipsyncFaceFusion);
assert_eq!(InferenceJobProductCategory::from_str("lipsync_sad_talker").unwrap(), InferenceJobProductCategory::LipsyncSadTalker);
@@ -289,20 +265,18 @@ mod tests {
fn all_variants() {
// Static check
let mut variants = InferenceJobProductCategory::all_variants();
assert_eq!(variants.len(), 21);
assert_eq!(variants.len(), 20);
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::DownloadGptSoVits));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::TtsGptSoVits));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::TtsStyleTts2));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::TtsTacotron2));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VcRvc2));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VcSeedVc));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VcSvc));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VidLipsyncFaceFusion));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VidLipsyncSadTalker));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VidLivePortrait));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VidLivePortraitWebcam));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VidStudio));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VidStudioGen2));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::VidStyleTransfer));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::LipsyncFaceFusion));
assert_eq!(variants.pop_first(), Some(InferenceJobProductCategory::LipsyncSadTalker));
@@ -36,10 +36,6 @@ pub enum InferenceJobType {
#[deprecated(note = "Use VideoRender instead.")]
ComfyUi,
/// Second gen studio
#[serde(rename = "studio_gen2")]
StudioGen2,
/// A job that turns "FBX" game engine files into "GLTF" files (Bevy-compatible).
#[serde(rename = "convert_fbx_gltf")]
ConvertFbxToGltf,
@@ -47,10 +43,6 @@ pub enum InferenceJobType {
/// Process a video into BVH mocap animation data for game engines
MocapNet,
/// Jobs that run F5TTS
#[serde(rename = "f5_tts")]
F5TTS,
/// RVC is a voice conversion model. RVCv2 is the most popular such model currently.
#[serde(rename = "rvc_v2")]
RvcV2,
@@ -61,9 +53,6 @@ pub enum InferenceJobType {
/// so-vits-svc voice conversion. This predates RVCv2.
SoVitsSvc,
#[serde(rename = "seed_vc")]
SeedVc,
/// Stable diffusion image generation
StableDiffusion,
@@ -104,15 +93,12 @@ impl InferenceJobType {
Self::VideoRender => "video_render",
Self::LivePortrait => "live_portrait",
Self::FaceFusion => "face_fusion",
Self::F5TTS => "f5_tts",
Self::GptSovits => "gpt_sovits",
Self::ComfyUi => "comfy_ui",
Self::StudioGen2 => "studio_gen2",
Self::ConvertFbxToGltf => "convert_fbx_gltf",
Self::MocapNet => "mocap_net",
Self::RvcV2 => "rvc_v2",
Self::SadTalker => "sad_talker",
Self::SeedVc => "seed_vc",
Self::SoVitsSvc => "so_vits_svc",
Self::StableDiffusion => "stable_diffusion",
Self::StyleTTS2 => "styletts2",
@@ -128,15 +114,12 @@ impl InferenceJobType {
"video_render" => Ok(Self::VideoRender),
"live_portrait" => Ok(Self::LivePortrait),
"face_fusion" => Ok(Self::FaceFusion),
"f5_tts" => Ok(Self::F5TTS),
"gpt_sovits" => Ok(Self::GptSovits),
"comfy_ui" => Ok(Self::ComfyUi),
"studio_gen2" => Ok(Self::StudioGen2),
"convert_fbx_gltf" => Ok(Self::ConvertFbxToGltf),
"mocap_net" => Ok(Self::MocapNet),
"rvc_v2" => Ok(Self::RvcV2),
"sad_talker" => Ok(Self::SadTalker),
"seed_vc" => Ok(Self::SeedVc),
"so_vits_svc" => Ok(Self::SoVitsSvc),
"stable_diffusion" => Ok(Self::StableDiffusion),
"styletts2" => Ok(Self::StyleTTS2),
@@ -155,15 +138,12 @@ impl InferenceJobType {
Self::VideoRender,
Self::LivePortrait,
Self::FaceFusion,
Self::F5TTS,
Self::GptSovits,
Self::ComfyUi,
Self::StudioGen2,
Self::ConvertFbxToGltf,
Self::MocapNet,
Self::RvcV2,
Self::SadTalker,
Self::SeedVc,
Self::SoVitsSvc,
Self::StableDiffusion,
Self::StyleTTS2,
@@ -193,15 +173,12 @@ mod tests {
assert_serialization(InferenceJobType::VideoRender, "video_render");
assert_serialization(InferenceJobType::LivePortrait, "live_portrait");
assert_serialization(InferenceJobType::FaceFusion, "face_fusion");
assert_serialization(InferenceJobType::F5TTS, "f5_tts");
assert_serialization(InferenceJobType::GptSovits, "gpt_sovits");
assert_serialization(InferenceJobType::ComfyUi, "comfy_ui");
assert_serialization(InferenceJobType::StudioGen2, "studio_gen2");
assert_serialization(InferenceJobType::ConvertFbxToGltf, "convert_fbx_gltf");
assert_serialization(InferenceJobType::MocapNet, "mocap_net");
assert_serialization(InferenceJobType::RvcV2, "rvc_v2");
assert_serialization(InferenceJobType::SadTalker, "sad_talker");
assert_serialization(InferenceJobType::SeedVc, "seed_vc");
assert_serialization(InferenceJobType::SoVitsSvc, "so_vits_svc");
assert_serialization(InferenceJobType::StableDiffusion, "stable_diffusion");
assert_serialization(InferenceJobType::StyleTTS2, "styletts2");
@@ -216,15 +193,12 @@ mod tests {
assert_eq!(InferenceJobType::VideoRender.to_str(), "video_render");
assert_eq!(InferenceJobType::LivePortrait.to_str(), "live_portrait");
assert_eq!(InferenceJobType::FaceFusion.to_str(), "face_fusion");
assert_eq!(InferenceJobType::F5TTS.to_str(), "f5_tts");
assert_eq!(InferenceJobType::GptSovits.to_str(), "gpt_sovits");
assert_eq!(InferenceJobType::ComfyUi.to_str(), "comfy_ui");
assert_eq!(InferenceJobType::StudioGen2.to_str(), "studio_gen2");
assert_eq!(InferenceJobType::ConvertFbxToGltf.to_str(), "convert_fbx_gltf");
assert_eq!(InferenceJobType::MocapNet.to_str(), "mocap_net");
assert_eq!(InferenceJobType::RvcV2.to_str(), "rvc_v2");
assert_eq!(InferenceJobType::SadTalker.to_str(), "sad_talker");
assert_eq!(InferenceJobType::SeedVc.to_str(), "seed_vc");
assert_eq!(InferenceJobType::SoVitsSvc.to_str(), "so_vits_svc");
assert_eq!(InferenceJobType::StableDiffusion.to_str(), "stable_diffusion");
assert_eq!(InferenceJobType::StyleTTS2.to_str(), "styletts2");
@@ -239,15 +213,12 @@ mod tests {
assert_eq!(InferenceJobType::from_str("video_render").unwrap(), InferenceJobType::VideoRender);
assert_eq!(InferenceJobType::from_str("live_portrait").unwrap(), InferenceJobType::LivePortrait);
assert_eq!(InferenceJobType::from_str("face_fusion").unwrap(), InferenceJobType::FaceFusion);
assert_eq!(InferenceJobType::from_str("f5_tts").unwrap(), InferenceJobType::F5TTS);
assert_eq!(InferenceJobType::from_str("gpt_sovits").unwrap(), InferenceJobType::GptSovits);
assert_eq!(InferenceJobType::from_str("comfy_ui").unwrap(), InferenceJobType::ComfyUi);
assert_eq!(InferenceJobType::from_str("studio_gen2").unwrap(), InferenceJobType::StudioGen2);
assert_eq!(InferenceJobType::from_str("convert_fbx_gltf").unwrap(), InferenceJobType::ConvertFbxToGltf);
assert_eq!(InferenceJobType::from_str("mocap_net").unwrap(), InferenceJobType::MocapNet);
assert_eq!(InferenceJobType::from_str("rvc_v2").unwrap(), InferenceJobType::RvcV2);
assert_eq!(InferenceJobType::from_str("sad_talker").unwrap(), InferenceJobType::SadTalker);
assert_eq!(InferenceJobType::from_str("seed_vc").unwrap(), InferenceJobType::SeedVc);
assert_eq!(InferenceJobType::from_str("so_vits_svc").unwrap(), InferenceJobType::SoVitsSvc);
assert_eq!(InferenceJobType::from_str("stable_diffusion").unwrap(), InferenceJobType::StableDiffusion);
assert_eq!(InferenceJobType::from_str("styletts2").unwrap(), InferenceJobType::StyleTTS2);
@@ -265,15 +236,12 @@ mod tests {
assert_eq!(variants.pop_first(), Some(InferenceJobType::VideoRender));
assert_eq!(variants.pop_first(), Some(InferenceJobType::LivePortrait));
assert_eq!(variants.pop_first(), Some(InferenceJobType::FaceFusion));
assert_eq!(variants.pop_first(), Some(InferenceJobType::F5TTS));
assert_eq!(variants.pop_first(), Some(InferenceJobType::GptSovits));
assert_eq!(variants.pop_first(), Some(InferenceJobType::ComfyUi));
assert_eq!(variants.pop_first(), Some(InferenceJobType::StudioGen2));
assert_eq!(variants.pop_first(), Some(InferenceJobType::ConvertFbxToGltf));
assert_eq!(variants.pop_first(), Some(InferenceJobType::MocapNet));
assert_eq!(variants.pop_first(), Some(InferenceJobType::RvcV2));
assert_eq!(variants.pop_first(), Some(InferenceJobType::SadTalker));
assert_eq!(variants.pop_first(), Some(InferenceJobType::SeedVc));
assert_eq!(variants.pop_first(), Some(InferenceJobType::SoVitsSvc));
assert_eq!(variants.pop_first(), Some(InferenceJobType::StableDiffusion));
assert_eq!(variants.pop_first(), Some(InferenceJobType::StyleTTS2));
@@ -29,10 +29,6 @@ pub enum InferenceModelType {
#[serde(rename = "so_vits_svc")]
SoVitsSvc,
// TODO: Does this need to be "legacy_tacotron2" ?
#[serde(rename = "seed_vc")]
SeedVc,
#[serde(rename = "tacotron2")]
Tacotron2,
#[serde(rename = "vits")]
@@ -70,7 +66,6 @@ impl InferenceModelType {
Self::VallEX => "vall_e_x",
Self::RerenderAVideo => "rerender_a_video",
Self::StableDiffusion => "stable_diffusion",
Self::SeedVc => "seed_vc",
Self::MocapNet => "mocap_net",
Self::StyleTTS2 => "styletts2",
Self::ComfyUi => "comfy_ui",
@@ -84,7 +79,6 @@ impl InferenceModelType {
"rvc_v2" => Ok(Self::RvcV2),
"sad_talker" => Ok(Self::SadTalker),
"so_vits_svc" => Ok(Self::SoVitsSvc),
"seed_vc" => Ok(Self::SeedVc),
"tacotron2" => Ok(Self::Tacotron2),
"vits" => Ok(Self::Vits),
"vall_e_x" => Ok(Self::VallEX),
@@ -107,7 +101,6 @@ impl InferenceModelType {
Self::RvcV2,
Self::SadTalker,
Self::SoVitsSvc,
Self::SeedVc,
Self::Tacotron2,
Self::Vits,
Self::VallEX,
@@ -133,7 +126,6 @@ mod tests {
fn test_serialization() {
assert_serialization(InferenceModelType::RvcV2, "rvc_v2");
assert_serialization(InferenceModelType::SadTalker, "sad_talker");
assert_serialization(InferenceModelType::SeedVc, "seed_vc");
assert_serialization(InferenceModelType::SoVitsSvc, "so_vits_svc");
assert_serialization(InferenceModelType::Tacotron2, "tacotron2");
assert_serialization(InferenceModelType::Vits, "vits");
@@ -153,7 +145,6 @@ mod tests {
assert_eq!(InferenceModelType::RvcV2.to_str(), "rvc_v2");
assert_eq!(InferenceModelType::SadTalker.to_str(), "sad_talker");
assert_eq!(InferenceModelType::SoVitsSvc.to_str(), "so_vits_svc");
assert_eq!(InferenceModelType::SoVitsSvc.to_str(), "so_vits_svc");
assert_eq!(InferenceModelType::Tacotron2.to_str(), "tacotron2");
assert_eq!(InferenceModelType::Vits.to_str(), "vits");
assert_eq!(InferenceModelType::VallEX.to_str(), "vall_e_x");
@@ -169,7 +160,6 @@ mod tests {
fn from_str() {
assert_eq!(InferenceModelType::from_str("rvc_v2").unwrap(), InferenceModelType::RvcV2);
assert_eq!(InferenceModelType::from_str("sad_talker").unwrap(), InferenceModelType::SadTalker);
assert_eq!(InferenceModelType::from_str("seed_vc").unwrap(), InferenceModelType::SeedVc);
assert_eq!(InferenceModelType::from_str("so_vits_svc").unwrap(), InferenceModelType::SoVitsSvc);
assert_eq!(InferenceModelType::from_str("tacotron2").unwrap(), InferenceModelType::Tacotron2);
assert_eq!(InferenceModelType::from_str("vits").unwrap(), InferenceModelType::Vits);
@@ -191,7 +181,6 @@ mod tests {
assert_eq!(variants.pop_first(), Some(InferenceModelType::ComfyUi));
assert_eq!(variants.pop_first(), Some(InferenceModelType::RvcV2));
assert_eq!(variants.pop_first(), Some(InferenceModelType::SadTalker));
assert_eq!(variants.pop_first(), Some(InferenceModelType::SeedVc));
assert_eq!(variants.pop_first(), Some(InferenceModelType::SoVitsSvc));
assert_eq!(variants.pop_first(), Some(InferenceModelType::Tacotron2));
assert_eq!(variants.pop_first(), Some(InferenceModelType::Vits));
@@ -18,9 +18,6 @@ pub enum MediaFileOriginModelType {
#[serde(rename = "face_fusion")]
FaceFusion,
#[serde(rename = "f5_tts")]
F5TTS,
#[serde(rename = "live_portrait")]
LivePortrait,
@@ -42,9 +39,6 @@ pub enum MediaFileOriginModelType {
#[serde(rename = "mocap_net")]
MocapNet,
#[serde(rename = "seed_vc")]
SeedVc,
#[serde(rename = "styletts2")]
StyleTTS2,
@@ -83,11 +77,9 @@ impl MediaFileOriginModelType {
pub fn to_str(&self) -> &'static str {
match self {
Self::FaceFusion => "face_fusion",
Self::F5TTS => "f5_tts",
Self::LivePortrait => "live_portrait",
Self::RvcV2 => "rvc_v2",
Self::SadTalker => "sad_talker",
Self::SeedVc => "seed_vc",
Self::SoVitsSvc => "so_vits_svc",
Self::Tacotron2 => "tacotron2",
Self::MocapNet => "mocap_net",
@@ -105,11 +97,9 @@ impl MediaFileOriginModelType {
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"face_fusion" => Ok(Self::FaceFusion),
"f5_tts" => Ok(Self::F5TTS),
"live_portrait" => Ok(Self::LivePortrait),
"rvc_v2" => Ok(Self::RvcV2),
"sad_talker" => Ok(Self::SadTalker),
"seed_vc" => Ok(Self::SeedVc),
"so_vits_svc" => Ok(Self::SoVitsSvc),
"tacotron2" => Ok(Self::Tacotron2),
"mocap_net" => Ok(Self::MocapNet),
@@ -130,11 +120,9 @@ impl MediaFileOriginModelType {
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::FaceFusion,
Self::F5TTS,
Self::LivePortrait,
Self::RvcV2,
Self::SadTalker,
Self::SeedVc,
Self::SoVitsSvc,
Self::Tacotron2,
Self::MocapNet,
@@ -167,11 +155,9 @@ mod tests {
#[test]
fn test_to_str() {
assert_eq!(MediaFileOriginModelType::FaceFusion.to_str(), "face_fusion");
assert_eq!(MediaFileOriginModelType::F5TTS.to_str(), "f5_tts");
assert_eq!(MediaFileOriginModelType::LivePortrait.to_str(), "live_portrait");
assert_eq!(MediaFileOriginModelType::RvcV2.to_str(), "rvc_v2");
assert_eq!(MediaFileOriginModelType::SadTalker.to_str(), "sad_talker");
assert_eq!(MediaFileOriginModelType::SeedVc.to_str(), "seed_vc");
assert_eq!(MediaFileOriginModelType::SoVitsSvc.to_str(), "so_vits_svc");
assert_eq!(MediaFileOriginModelType::Tacotron2.to_str(), "tacotron2");
assert_eq!(MediaFileOriginModelType::MocapNet.to_str(), "mocap_net");
@@ -188,11 +174,9 @@ mod tests {
#[test]
fn test_from_str() {
assert_eq!(MediaFileOriginModelType::from_str("face_fusion").unwrap(), MediaFileOriginModelType::FaceFusion);
assert_eq!(MediaFileOriginModelType::from_str("f5_tts").unwrap(), MediaFileOriginModelType::F5TTS);
assert_eq!(MediaFileOriginModelType::from_str("live_portrait").unwrap(), MediaFileOriginModelType::LivePortrait);
assert_eq!(MediaFileOriginModelType::from_str("rvc_v2").unwrap(), MediaFileOriginModelType::RvcV2);
assert_eq!(MediaFileOriginModelType::from_str("sad_talker").unwrap(), MediaFileOriginModelType::SadTalker);
assert_eq!(MediaFileOriginModelType::from_str("seed_vc").unwrap(), MediaFileOriginModelType::SeedVc);
assert_eq!(MediaFileOriginModelType::from_str("so_vits_svc").unwrap(), MediaFileOriginModelType::SoVitsSvc);
assert_eq!(MediaFileOriginModelType::from_str("tacotron2").unwrap(), MediaFileOriginModelType::Tacotron2);
assert_eq!(MediaFileOriginModelType::from_str("mocap_net").unwrap(), MediaFileOriginModelType::MocapNet);
@@ -212,11 +196,9 @@ mod tests {
let mut variants = MediaFileOriginModelType::all_variants();
assert_eq!(variants.len(), 15);
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::FaceFusion));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::F5TTS));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::LivePortrait));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::RvcV2));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SadTalker));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SeedVc));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SoVitsSvc));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::Tacotron2));
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::MocapNet));
-1
View File
@@ -14,7 +14,6 @@ pub mod media_uploads;
pub mod model_categories;
pub mod model_weights;
pub mod prompts;
pub mod tag_uses;
pub mod trending_model_analytics;
pub mod tts_models;
pub mod usages;
@@ -1 +0,0 @@
pub mod tag_use_entity_type;
@@ -1,127 +0,0 @@
use std::collections::BTreeSet;
use serde::Deserialize;
use serde::Serialize;
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
use utoipa::ToSchema;
/// Used in the `tag_uses` table in a `VARCHAR(32)` field named `entity_type`.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, ToSchema)]
pub enum TagUseEntityType {
/// Media files
#[serde(rename = "media_file")]
MediaFile,
/// Model weights
#[serde(rename = "model_weight")]
ModelWeight,
}
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
impl_enum_display_and_debug_using_to_str!(TagUseEntityType);
impl_mysql_enum_coders!(TagUseEntityType);
/// NB: Legacy API for older code.
impl TagUseEntityType {
pub fn to_str(&self) -> &'static str {
match self {
Self::MediaFile => "media_file",
Self::ModelWeight => "model_weight",
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"media_file" => Ok(Self::MediaFile),
"model_weight" => Ok(Self::ModelWeight),
_ => Err(format!("invalid value: {:?}", value)),
}
}
pub fn all_variants() -> BTreeSet<Self> {
// NB: BTreeSet is sorted
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::MediaFile,
Self::ModelWeight,
])
}
}
#[cfg(test)]
mod tests {
use crate::test_helpers::assert_serialization;
use crate::by_table::tag_uses::tag_use_entity_type::TagUseEntityType;
mod serde {
use super::*;
#[test]
fn test_serialization() {
assert_serialization(TagUseEntityType::MediaFile, "media_file");
assert_serialization(TagUseEntityType::ModelWeight, "model_weight");
}
}
mod impl_methods {
use super::*;
#[test]
fn test_to_str() {
assert_eq!(TagUseEntityType::MediaFile.to_str(), "media_file");
assert_eq!(TagUseEntityType::ModelWeight.to_str(), "model_weight");
}
#[test]
fn test_from_str() {
assert_eq!(TagUseEntityType::from_str("media_file").unwrap(), TagUseEntityType::MediaFile);
assert_eq!(TagUseEntityType::from_str("model_weight").unwrap(), TagUseEntityType::ModelWeight);
assert!(TagUseEntityType::from_str("foo").is_err());
}
}
mod manual_variant_checks {
use super::*;
#[test]
fn all_variants() {
let mut variants = TagUseEntityType::all_variants();
assert_eq!(variants.len(), 2);
assert_eq!(variants.pop_first(), Some(TagUseEntityType::MediaFile));
assert_eq!(variants.pop_first(), Some(TagUseEntityType::ModelWeight));
assert_eq!(variants.pop_first(), None);
}
}
mod mechanical_checks {
use super::*;
#[test]
fn variant_length() {
use strum::IntoEnumIterator;
assert_eq!(TagUseEntityType::all_variants().len(), TagUseEntityType::iter().len());
}
#[test]
fn round_trip() {
for variant in TagUseEntityType::all_variants() {
assert_eq!(variant, TagUseEntityType::from_str(variant.to_str()).unwrap());
assert_eq!(variant, TagUseEntityType::from_str(&format!("{}", variant)).unwrap());
assert_eq!(variant, TagUseEntityType::from_str(&format!("{:?}", variant)).unwrap());
}
}
#[test]
fn serialized_length_ok_for_database() {
const MAX_LENGTH : usize = 32;
for variant in TagUseEntityType::all_variants() {
let serialized = variant.to_str();
assert!(serialized.len() > 0, "variant {:?} is too short", variant);
assert!(serialized.len() <= MAX_LENGTH, "variant {:?} is too long", variant);
}
}
}
}
@@ -30,8 +30,6 @@ pub enum PublicInferenceJobType {
GptSovits,
#[serde(rename = "f5_tts")]
F5TTS,
// ======= Everything else is the same =======
/// Jobs that run ComfyUI workflows
@@ -39,10 +37,6 @@ pub enum PublicInferenceJobType {
#[deprecated(note = "Use VideoRender instead.")]
ComfyUi,
/// Second gen studio
#[serde(rename = "studio_gen2")]
StudioGen2,
/// A job that turns "FBX" game engine files into "GLTF" files (Bevy-compatible).
#[serde(rename = "convert_fbx_gltf")]
ConvertFbxToGltf,
@@ -57,10 +51,6 @@ pub enum PublicInferenceJobType {
/// SadTalker does image-to-video lip-syncing when given an audio file and image.
SadTalker,
/// Seed-VC
#[serde(rename = "seed_vc")]
SeedVc,
/// so-vits-svc voice conversion. This predates RVCv2.
SoVitsSvc,
@@ -104,14 +94,11 @@ impl PublicInferenceJobType {
// Conserved variants
InferenceJobType::VideoRender => Self::VideoRender,
InferenceJobType::GptSovits => Self::GptSovits,
InferenceJobType::F5TTS => Self::F5TTS,
InferenceJobType::ComfyUi => Self::ComfyUi,
InferenceJobType::StudioGen2 => Self::StudioGen2,
InferenceJobType::ConvertFbxToGltf => Self::ConvertFbxToGltf,
InferenceJobType::MocapNet => Self::MocapNet,
InferenceJobType::RvcV2 => Self::RvcV2,
InferenceJobType::SadTalker => Self::SadTalker,
InferenceJobType::SeedVc => Self::SeedVc,
InferenceJobType::SoVitsSvc => Self::SoVitsSvc,
InferenceJobType::StableDiffusion => Self::StableDiffusion,
InferenceJobType::StyleTTS2 => Self::StyleTTS2,
@@ -130,14 +117,11 @@ impl PublicInferenceJobType {
// Conserved variants
Self::VideoRender => InferenceJobType::VideoRender,
Self::GptSovits => InferenceJobType::GptSovits,
Self::F5TTS => InferenceJobType::F5TTS,
Self::ComfyUi => InferenceJobType::ComfyUi,
Self::StudioGen2 => InferenceJobType::StudioGen2,
Self::ConvertFbxToGltf => InferenceJobType::ConvertFbxToGltf,
Self::MocapNet => InferenceJobType::MocapNet,
Self::RvcV2 => InferenceJobType::RvcV2,
Self::SadTalker => InferenceJobType::SadTalker,
Self::SeedVc => InferenceJobType::SeedVc,
Self::SoVitsSvc => InferenceJobType::SoVitsSvc,
Self::StableDiffusion => InferenceJobType::StableDiffusion,
Self::StyleTTS2 => InferenceJobType::StyleTTS2,
@@ -55,12 +55,6 @@ pub enum PublicMediaFileModelType {
#[serde(rename = "gpt_sovits")]
GptSovits,
#[serde(rename = "f5_tts")]
F5TTS,
#[serde(rename = "seed_vc")]
SeedVc,
#[serde(rename = "studio")]
StorytellerStudio,
@@ -92,12 +86,10 @@ impl PublicMediaFileModelType {
// Conserved variants
MediaFileOriginModelType::RvcV2 => Self::RvcV2,
MediaFileOriginModelType::SoVitsSvc => Self::SoVitsSvc,
MediaFileOriginModelType::SeedVc => Self::SeedVc,
MediaFileOriginModelType::Tacotron2 => Self::Tacotron2,
MediaFileOriginModelType::MocapNet => Self::MocapNet,
MediaFileOriginModelType::StableDiffusion15 => Self::StableDiffusion15,
MediaFileOriginModelType::GptSovits => Self::GptSovits,
MediaFileOriginModelType::F5TTS => Self::F5TTS,
MediaFileOriginModelType::StorytellerStudio => Self::StorytellerStudio,
MediaFileOriginModelType::VideoStyleTransfer => Self::VideoStyleTransfer,
MediaFileOriginModelType::ComfyUi => Self::ComfyUi,
@@ -116,12 +108,10 @@ impl PublicMediaFileModelType {
// Conserved variants
Self::RvcV2 => MediaFileOriginModelType::RvcV2,
Self::SoVitsSvc => MediaFileOriginModelType::SoVitsSvc,
Self::SeedVc => MediaFileOriginModelType::SeedVc,
Self::Tacotron2 => MediaFileOriginModelType::Tacotron2,
Self::MocapNet => MediaFileOriginModelType::MocapNet,
Self::StableDiffusion15 => MediaFileOriginModelType::StableDiffusion15,
Self::GptSovits => MediaFileOriginModelType::GptSovits,
Self::F5TTS => MediaFileOriginModelType::F5TTS,
Self::StorytellerStudio => MediaFileOriginModelType::StorytellerStudio,
Self::VideoStyleTransfer => MediaFileOriginModelType::VideoStyleTransfer,
Self::ComfyUi => MediaFileOriginModelType::ComfyUi,
@@ -30,9 +30,6 @@ pub enum Action {
/// Search the model weights
SearchModelWeights,
/// Evaluate the search algorithm
EvaluateModelWeights,
/// Reindex media_files into ElasticSearch
/// For now, this is just media files that are relevant to the engine.
ReindexMediaFiles,
@@ -6,26 +6,25 @@
//! The intent is to be able to quickly populate documents and indices.
//!
use elasticsearch::http::transport::Transport;
use elasticsearch::Elasticsearch;
use log::info;
use sqlx::mysql::MySqlPoolOptions;
use sqlx::{MySql, Pool};
use std::collections::HashSet;
use std::iter::FromIterator;
use elasticsearch::Elasticsearch;
use elasticsearch::http::transport::Transport;
use log::info;
use sqlx::{MySql, Pool};
use sqlx::mysql::MySqlPoolOptions;
use config::shared_constants::DEFAULT_RUST_LOG;
use elasticsearch_schema::searches::search_model_weights::{search_model_weights, SearchArgs};
use elasticsearch_schema::searches::search_tts_models::search_tts_models;
use enums::by_table::model_weights::weights_types::WeightsType;
use errors::AnyhowResult;
use crate::cli_args::{parse_cli_args, Action, Environment};
use crate::cli_args::{Action, Environment, parse_cli_args};
use crate::plans::create_all_model_weight_documents::create_all_model_weight_documents;
use crate::plans::create_all_tts_documents::create_all_tts_documents;
use crate::plans::media_files::create_dimensional_media_file_documents::create_dimensional_media_file_documents;
use crate::plans::media_files::test_search_media_files_documents::test_search_media_files;
use crate::plans::model_weights::create_all_model_weight_documents::create_all_model_weight_documents;
use crate::plans::model_weights::evaluate::evaluate_model_weights_search::evaluate_model_weights_search;
use crate::plans::model_weights::test_search_model_weights_documents::test_search_model_weights_documents;
pub mod cli_args;
pub mod plans;
@@ -34,7 +33,7 @@ pub mod plans;
pub async fn main() -> AnyhowResult<()> {
println!("elasticsearch-cli: operational tooling for Elasticsearch");
easyenv::init_all_with_default_logging(Some("info"));
easyenv::init_all_with_default_logging(Some(DEFAULT_RUST_LOG));
// NB: This secrets file differs from the rest because we might actually want to cross
// development/production boundaries for seeding, or scope to production for rebuilding indices.
@@ -62,16 +61,20 @@ pub async fn main() -> AnyhowResult<()> {
}
Action::SearchModelWeights => {
info!("Searching model weights...");
let results = test_search_model_weights_documents(&elasticsearch).await?;
let results = search_model_weights(SearchArgs {
search_term: "zel",
maybe_creator_user_token: None,
maybe_ietf_primary_language_subtag: None,
maybe_weights_categories: None,
maybe_weights_types: Some(HashSet::from_iter(vec![WeightsType::RvcV2])),
client: &elasticsearch,
}).await?;
for result in results {
println!("Result: {:#?}", result);
}
}
Action::EvaluateModelWeights => {
info!("Evaluate model weights search...");
let _ = evaluate_model_weights_search(&elasticsearch).await?;
}
Action::ReindexMediaFiles => {
info!("Reindexing media files...");
create_dimensional_media_file_documents(&mysql, &elasticsearch).await?;
@@ -60,24 +60,6 @@ async fn create_document_from_record(elasticsearch: &Elasticsearch, record: Mode
let is_deleted = record.user_deleted_at.is_some() || record.mod_deleted_at.is_some();
let maybe_ietf_language_tag = record.maybe_ietf_language_tag
.as_deref()
.or_else(|| match record.weights_category {
WeightsCategory::TextToSpeech => record.maybe_tts_ietf_language_tag.as_deref(),
WeightsCategory::VoiceConversion => record.maybe_voice_conversion_ietf_language_tag.as_deref(),
_ => None,
})
.map(|t| t.to_string());
let maybe_ietf_primary_language_subtag = record.maybe_ietf_primary_language_subtag
.as_deref()
.or_else(|| match &record.weights_category {
WeightsCategory::TextToSpeech => record.maybe_tts_ietf_primary_language_subtag.as_deref(),
WeightsCategory::VoiceConversion => record.maybe_voice_conversion_ietf_primary_language_subtag.as_deref(),
_ => None,
})
.map(|t| t.to_string());
let document = ModelWeightDocument {
token: record.token,
@@ -107,8 +89,17 @@ async fn create_document_from_record(elasticsearch: &Elasticsearch, record: Mode
cached_usage_count: Some(u64_to_i32_saturating(record.cached_usage_count)),
maybe_ietf_language_tag,
maybe_ietf_primary_language_subtag,
maybe_ietf_language_tag: match record.weights_category {
WeightsCategory::TextToSpeech => record.maybe_tts_ietf_language_tag,
WeightsCategory::VoiceConversion => record.maybe_voice_conversion_ietf_language_tag,
_ => None,
},
maybe_ietf_primary_language_subtag: match record.weights_category {
WeightsCategory::TextToSpeech => record.maybe_tts_ietf_primary_language_subtag,
WeightsCategory::VoiceConversion => record.maybe_voice_conversion_ietf_primary_language_subtag,
_ => None,
},
created_at: record.created_at,
updated_at: record.updated_at,
@@ -1,3 +1,3 @@
pub mod create_all_model_weight_documents;
pub mod create_all_tts_documents;
pub mod media_files;
pub mod model_weights;
pub mod media_files;
@@ -1,83 +0,0 @@
use crate::plans::model_weights::evaluate::print_debugging::{print_titles, to_title_set};
use crate::plans::model_weights::evaluate::search::search_term_only;
use elasticsearch::Elasticsearch;
use elasticsearch_schema::documents::model_weight_document::ModelWeightDocument;
use errors::{anyhow, AnyhowResult};
use log::error;
use std::collections::HashSet;
use tokens::tokens::model_weights::ModelWeightToken;
pub async fn assert_search_term_contains_titles(
client: &Elasticsearch,
search_term: &str,
expected_titles: &Vec<&str>,
) -> AnyhowResult<()> {
let results = search_term_only(search_term, client).await?;
let titles = to_title_set(&results);
println!("Titles:");
print_titles(&results);
if let Err(err) = assert_contains_all(&titles, expected_titles, search_term) {
error!("Title not found for search: {}", search_term);
print_titles(&results);
return Err(err);
}
Ok(())
}
pub fn assert_contains(titles: &HashSet<String>, expected: &str, search_term: &str) -> AnyhowResult<()> {
if !titles.contains(expected) {
error!("Expected title not found: {} for search {} ({} results)",
expected, search_term, titles.len());
return Err(anyhow!("Expected title not found: {} for search {} ({} results)",
expected, search_term, titles.len()));
}
Ok(())
}
pub fn assert_contains_all(titles: &HashSet<String>, expected: &Vec<&str>, search_term: &str) -> AnyhowResult<()> {
for title in expected.iter() {
assert_contains(titles, title, search_term)?;
}
Ok(())
}
pub fn assert_results_contain_tokens(
results: &Vec<ModelWeightDocument>,
expected_tokens: &[&str],
) -> AnyhowResult<()> {
let tokens = results.iter()
.map(|result| result.token.clone())
.collect::<HashSet<_>>();
for token in expected_tokens.iter() {
let token = ModelWeightToken::new_from_str(token);
if !tokens.contains(&token) {
error!("Expected token not found: {}", token);
return Err(anyhow!("Expected token not found: {}", token));
}
}
Ok(())
}
pub fn assert_results_do_not_contain_tokens(
results: &Vec<ModelWeightDocument>,
expected_tokens: &[&str],
) -> AnyhowResult<()> {
let tokens = results.iter()
.map(|result| result.token.clone())
.collect::<HashSet<_>>();
for token in expected_tokens.iter() {
let token = ModelWeightToken::new_from_str(token);
if tokens.contains(&token) {
error!("Unexpected token found: {}", token);
return Err(anyhow!("Unexpected token found: {}", token));
}
}
Ok(())
}
@@ -1,19 +0,0 @@
use crate::plans::model_weights::evaluate::test_cases::test_search_term_zelda::test_search_term_zelda;
use crate::plans::model_weights::evaluate::test_cases::test_upvoted_models::test_upvoted_models;
use crate::plans::model_weights::evaluate::test_cases::test_use_count::test_use_count;
use elasticsearch::Elasticsearch;
use errors::AnyhowResult;
pub async fn evaluate_model_weights_search(client: &Elasticsearch) -> AnyhowResult<()> {
// Test sorting filters
test_upvoted_models(client).await?;
test_use_count(client).await?;
// Test search terms and boosting algorithm
test_search_term_zelda(client).await?;
// New tests
Ok(())
}
@@ -1,5 +0,0 @@
pub mod asserts;
pub mod evaluate_model_weights_search;
pub mod search;
pub mod test_cases;
pub mod print_debugging;
@@ -1,31 +0,0 @@
use std::collections::HashSet;
use elasticsearch_schema::documents::model_weight_document::ModelWeightDocument;
pub fn print_titles(results: &Vec<ModelWeightDocument>) {
for result in results {
println!(" - result: {:#?} ({:?})", result.title, result.token);
}
}
pub fn print_titles_and_usage_counts(results: &Vec<ModelWeightDocument>) {
for result in results {
println!(" - result: {:#?} {} ({:?})",
result.title,
result.cached_usage_count.unwrap_or(0),
result.token);
}
}
pub fn print_titles_and_rating_count(results: &Vec<ModelWeightDocument>) {
for result in results {
println!(" - result: {:#?} {} ({:?})",
result.title,
result.ratings_positive_count,
result.token);
}
}
pub fn to_title_set(results: &Vec<ModelWeightDocument>) -> HashSet<String> {
results.iter().map(|result| result.title.clone()).collect()
}
@@ -1,19 +0,0 @@
use elasticsearch::Elasticsearch;
use elasticsearch_schema::documents::model_weight_document::ModelWeightDocument;
use elasticsearch_schema::searches::search_model_weights::search_model_weights::{search_model_weights, SearchArgs};
use errors::AnyhowResult;
pub async fn search_term_only(search_term: &str, client: &Elasticsearch) -> AnyhowResult<Vec<ModelWeightDocument>> {
search_model_weights(SearchArgs {
search_term,
maybe_creator_user_token: None,
maybe_ietf_primary_language_subtag: None,
maybe_weights_categories: None,
maybe_weights_types: None,
sort_field: None,
sort_direction: None,
minimum_score: None,
client: &client,
}).await
}
@@ -1,3 +0,0 @@
pub mod test_search_term_zelda;
pub mod test_upvoted_models;
pub mod test_use_count;
@@ -1,31 +0,0 @@
use crate::plans::model_weights::evaluate::asserts::assert_search_term_contains_titles;
use elasticsearch::Elasticsearch;
use errors::AnyhowResult;
pub async fn test_search_term_zelda(
client: &Elasticsearch
) -> AnyhowResult<()> {
assert_search_term_contains_titles(client, "zeld", &vec![
"Link (Zelda CDI) (Français)",
"Zelda (BOTW Español Latino)",
"Zelda (BOTW) (Ita)",
"Zelda (BOTW)",
"Zelda (Breath of the Wild)",
"Zelda Rubinstein",
"Zelda. (The Legend of Zelda: Breath of the Wild, Castillian Spanish.) Versión MEJORADA.",
]).await?;
assert_search_term_contains_titles(client, "zelad", &vec![
"Link (Zelda CDI) (Français)",
"Zelda (BOTW Español Latino)",
"Zelda (BOTW) (Ita)",
"Zelda (BOTW)",
"Zelda (Breath of the Wild)",
"Zelda Rubinstein",
"Zelda. (The Legend of Zelda: Breath of the Wild, Castillian Spanish.) Versión MEJORADA.",
]).await?;
Ok(())
}
@@ -1,50 +0,0 @@
use crate::plans::model_weights::evaluate::asserts::{assert_results_contain_tokens, assert_results_do_not_contain_tokens};
use crate::plans::model_weights::evaluate::print_debugging::print_titles_and_rating_count;
use elasticsearch::Elasticsearch;
use elasticsearch_schema::searches::search_model_weights::search_model_weights::{search_model_weights, ModelWeightsSortDirection, ModelWeightsSortField, SearchArgs};
use errors::AnyhowResult;
const UPVOTED_MODELS: [&str; 3] = [
"weight_ppqs5038bvkm6wc29w0xfebzy", // Donald Trump : 132
"weight_ahxbf2104ngsgyegncaefyy6j", // Plankton v2 (Doug Lawrence) : 128
"weight_7jk8mgwkzsycqrxmfw5q4245y", // Homer Simpson: 115
];
pub async fn test_upvoted_models(
client: &Elasticsearch
) -> AnyhowResult<()> {
let results = search_model_weights(SearchArgs {
search_term: "", // No search term
maybe_creator_user_token: None,
maybe_ietf_primary_language_subtag: None,
maybe_weights_categories: None,
maybe_weights_types: None,
sort_field: Some(ModelWeightsSortField::PositiveRatingCount),
sort_direction: None,
minimum_score: None,
client: &client,
}).await?;
print_titles_and_rating_count(&results);
assert_results_contain_tokens(&results, &UPVOTED_MODELS)?;
// Now invert, and we shouldn't expect popular tokens to be found
let results = search_model_weights(SearchArgs {
search_term: "", // No search term
maybe_creator_user_token: None,
maybe_ietf_primary_language_subtag: None,
maybe_weights_categories: None,
maybe_weights_types: None,
sort_field: Some(ModelWeightsSortField::PositiveRatingCount),
sort_direction: Some(ModelWeightsSortDirection::Ascending), // Least popular first
minimum_score: None,
client: &client,
}).await?;
assert_results_do_not_contain_tokens(&results, &UPVOTED_MODELS)?;
Ok(())
}
@@ -1,47 +0,0 @@
use crate::plans::model_weights::evaluate::asserts::{assert_results_contain_tokens, assert_results_do_not_contain_tokens};
use elasticsearch::Elasticsearch;
use elasticsearch_schema::searches::search_model_weights::search_model_weights::{search_model_weights, ModelWeightsSortDirection, ModelWeightsSortField, SearchArgs};
use errors::AnyhowResult;
const POPULAR_VOICES : [&str; 3] = [
"weight_hz7g8f1j4psrsw2sv67e4y61q", // Mariano Closs (Relator de fútbol Argentino)
"weight_rhfg4chgrp42bnha8kqfrtmcq", // Mariano Closs (full version)
"weight_mbcr352wfb1eq76tpy3ef3kx1", // Lionel Messi
];
pub async fn test_use_count(
client: &Elasticsearch
) -> AnyhowResult<()> {
let results = search_model_weights(SearchArgs {
search_term: "", // No search term
maybe_creator_user_token: None,
maybe_ietf_primary_language_subtag: None,
maybe_weights_categories: None,
maybe_weights_types: None,
sort_field: Some(ModelWeightsSortField::UsageCount),
sort_direction: None,
minimum_score: None,
client: &client,
}).await?;
assert_results_contain_tokens(&results, &POPULAR_VOICES)?;
// Now invert, and we shouldn't expect popular tokens to be found
let results = search_model_weights(SearchArgs {
search_term: "", // No search term
maybe_creator_user_token: None,
maybe_ietf_primary_language_subtag: None,
maybe_weights_categories: None,
maybe_weights_types: None,
sort_field: Some(ModelWeightsSortField::UsageCount),
sort_direction: Some(ModelWeightsSortDirection::Ascending), // Least popular first
minimum_score: None,
client: &client,
}).await?;
assert_results_do_not_contain_tokens(&results, &POPULAR_VOICES)?;
Ok(())
}
@@ -1,3 +0,0 @@
pub mod create_all_model_weight_documents;
pub mod evaluate;
pub mod test_search_model_weights_documents;
@@ -1,25 +0,0 @@
use elasticsearch::Elasticsearch;
use elasticsearch_schema::documents::model_weight_document::ModelWeightDocument;
use elasticsearch_schema::searches::search_model_weights::search_model_weights::{search_model_weights, ModelWeightsSortDirection, ModelWeightsSortField, SearchArgs};
use enums::by_table::model_weights::weights_types::WeightsType;
use errors::AnyhowResult;
use std::collections::HashSet;
use std::iter::FromIterator;
pub async fn test_search_model_weights_documents(client: &Elasticsearch) -> AnyhowResult<Vec<ModelWeightDocument>> {
let results = search_model_weights(SearchArgs {
//search_term: "zel",
search_term: "mariano",
maybe_creator_user_token: None,
maybe_ietf_primary_language_subtag: None,
maybe_weights_categories: None,
maybe_weights_types: Some(HashSet::from_iter(vec![WeightsType::Tacotron2])),
sort_field: Some(ModelWeightsSortField::UsageCount),
sort_direction: Some(ModelWeightsSortDirection::Ascending),
minimum_score: None,
client: &client,
}).await?;
Ok(results)
}
@@ -2,6 +2,5 @@ pub (crate) mod development_only;
pub (crate) mod fakeyou;
pub (crate) mod legacy;
pub (crate) mod storyteller;
pub (crate) mod storyteller_board;
pub (crate) mod storyteller_render;
pub (crate) mod storyteller_studio;
pub (crate) mod storyteller_studio;
pub (crate) mod video_compositor;
@@ -1,61 +0,0 @@
use actix_cors::Cors;
use crate::util::netlify_branch_domain_matches::netlify_branch_domain_matches;
pub fn add_storyteller_render(cors: Cors, _is_production: bool) -> Cors {
cors
// Hypothetical domains
.allowed_origin("https://render.storyteller.ai")
// Netlify project
.allowed_origin_fn(|origin, _req_head| {
netlify_branch_domain_matches(origin, "storyteller-render.netlify.app")
})
}
#[cfg(test)]
mod tests {
use reusable_types::server_environment::ServerEnvironment;
use crate::cors::build_cors_config;
use crate::testing::assert_origin_invalid;
use crate::testing::assert_origin_ok;
mod domains {
use super::*;
#[actix_rt::test]
async fn board_dot_storyteller() {
let production_cors = build_cors_config(ServerEnvironment::Production);
assert_origin_ok(&production_cors, "https://render.storyteller.ai").await;
}
}
mod netlify {
use super::*;
#[actix_rt::test]
async fn netlify_main() {
let production_cors = build_cors_config(ServerEnvironment::Production);
assert_origin_ok(&production_cors, "https://storyteller-render.netlify.app").await;
}
#[actix_rt::test]
async fn netlify_branch_deploy() {
let production_cors = build_cors_config(ServerEnvironment::Production);
assert_origin_ok(&production_cors, "https://test--storyteller-render.netlify.app").await;
}
#[actix_rt::test]
async fn netlify_deploy_preview() {
let production_cors = build_cors_config(ServerEnvironment::Production);
assert_origin_ok(&production_cors, "https://deploy-preview-123--storyteller-render.netlify.app").await;
}
#[actix_rt::test]
async fn invalid_netlify_preview_deploy() {
let production_cors = build_cors_config(ServerEnvironment::Production);
assert_origin_invalid(&production_cors, "https://storyteller-render--unrelated.netlify.app").await;
assert_origin_invalid(&production_cors, "https://deploy-preview-123--unrelated.netlify.app").await;
}
}
}
@@ -13,7 +13,6 @@ pub fn add_storyteller_studio(cors: Cors, _is_production: bool) -> Cors {
netlify_branch_domain_matches(origin, "pipeline-gottagofast.netlify.app")
})
.allowed_origin("http://localhost:5173")
.allowed_origin("https://animate.storyteller.ai") // NB: Gen2 Studio
}
#[cfg(test)]
@@ -2,12 +2,11 @@ use actix_cors::Cors;
use crate::util::netlify_branch_domain_matches::netlify_branch_domain_matches;
pub fn add_storyteller_board(cors: Cors, _is_production: bool) -> Cors {
pub fn add_video_compositor(cors: Cors, _is_production: bool) -> Cors {
cors
// Hypothetical domains
.allowed_origin("https://memeboard.ai")
.allowed_origin("https://dingboard.ai")
.allowed_origin("https://board.storyteller.ai")
// Netlify project
.allowed_origin_fn(|origin, _req_head| {
netlify_branch_domain_matches(origin, "storyteller-board.netlify.app")
@@ -38,12 +37,6 @@ mod tests {
let production_cors = build_cors_config(ServerEnvironment::Production);
assert_origin_ok(&production_cors, "https://dingboard.ai").await;
}
#[actix_rt::test]
async fn board_dot_storyteller() {
let production_cors = build_cors_config(ServerEnvironment::Production);
assert_origin_ok(&production_cors, "https://board.storyteller.ai").await;
}
}
mod netlify {
+3 -5
View File
@@ -5,11 +5,10 @@ use reusable_types::server_environment::ServerEnvironment;
use crate::configs::development_only::add_development_only;
use crate::configs::fakeyou::{add_fakeyou, add_fakeyou_dev_proxy};
use crate::configs::storyteller_studio::add_storyteller_studio;
use crate::configs::legacy::{add_legacy_storyteller_stream, add_legacy_trumped, add_legacy_vocodes, add_power_stream};
use crate::configs::storyteller::{add_storyteller, add_storyteller_dev_proxy};
use crate::configs::storyteller_board::add_storyteller_board;
use crate::configs::storyteller_render::add_storyteller_render;
use crate::configs::storyteller_studio::add_storyteller_studio;
use crate::configs::video_compositor::add_video_compositor;
/// Return cors config for FakeYou / Vocodes / OBS / local development
pub fn build_cors_config(server_environment: ServerEnvironment) -> Cors {
@@ -37,8 +36,7 @@ fn do_build_cors_config(is_production: bool) -> Cors {
cors = add_storyteller(cors, is_production);
cors = add_storyteller_dev_proxy(cors, is_production);
cors = add_storyteller_studio(cors, is_production);
cors = add_storyteller_board(cors, is_production);
cors = add_storyteller_render(cors, is_production);
cors = add_video_compositor(cors, is_production);
// Legacy
cors = add_legacy_trumped(cors, is_production);
@@ -4,13 +4,11 @@ use std::time::Duration;
use anyhow::anyhow;
use anyhow::bail;
use log::{error, warn};
use log::{debug, info};
use log::info;
use log::warn;
use s3::bucket::Bucket;
use s3::creds::Credentials;
use s3::error::S3Error;
use s3::region::Region;
use s3::request::ResponseData;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
@@ -72,15 +70,8 @@ impl BucketClient {
let mut bucket = Bucket::new(&bucket_name, region, credentials)?;
bucket.set_request_timeout(bucket_request_timeout);
match s3_endpoint {
"https://storage.googleapis.com" => {
bucket.set_subdomain_style();
},
_ => {
bucket.set_path_style();
}
}
bucket.set_path_style();
bucket.set_subdomain_style();
let optional_bucket_root = optional_bucket_root.map(|s| s.to_string());
@@ -98,25 +89,23 @@ impl BucketClient {
}
pub async fn upload_file(&self, object_name: &str, bytes: &[u8]) -> anyhow::Result<()> {
debug!("Filename for bucket: {}", object_name);
info!("Filename for bucket: {}", object_name);
let object_name = self.get_rooted_object_name(object_name);
debug!("Rooted filename for bucket: {}", object_name);
info!("Rooted filename for bucket: {}", object_name);
let response = self.bucket.put_object(&object_name, bytes).await?;
let body_bytes = response.bytes();
let code = response.status_code();
debug!("upload code for {}: {}", object_name, code);
info!("upload code: {}", code);
if code != 200 {
let body = String::from_utf8_lossy(body_bytes);
warn!("failed upload body: {}", body);
warn!("upload body: {}", body);
}
info!("Successfully uploaded file to bucket: {}", object_name);
Ok(())
}
@@ -145,13 +134,7 @@ impl BucketClient {
let object_name = self.get_rooted_object_name(object_name);
info!("Rooted filename for bucket: {}", object_name);
let response = self.bucket.put_object_with_content_type(&object_name, bytes, content_type).await;
if let Err(err) = &response {
error!("S3 Upload Error for bucket name {}: {:?}", &self.bucket.name, err);
}
let response = response?;
let response = self.bucket.put_object_with_content_type(&object_name, bytes, content_type).await?;
let body_bytes = response.bytes();
let code = response.status_code();
+1 -10
View File
@@ -15,11 +15,6 @@ pub struct BootstrapArgs<'a, P: AsRef<Path>> {
/// Where to look for env conf files.
pub config_search_directories: &'a [P],
/// If true, ignore the root '.env' file.
/// TODO(bt,2025-01-23): Make this the default behavior, then remove reading from '.env' entirely,
/// There are too many apps that share this file.
pub ignore_legacy_dot_env_file: bool,
}
/// Information about how the application is deployed.
@@ -50,11 +45,7 @@ pub struct ContainerEnvironment {
const SERVER_ENVIRONMENT : &str = "SERVER_ENVIRONMENT";
pub fn bootstrap<P: AsRef<Path>>(args: BootstrapArgs<'_, P>) -> AnyhowResult<ContainerEnvironment> {
if args.ignore_legacy_dot_env_file {
easyenv::init_env_logger(args.default_logging_override);
} else {
easyenv::init_all_with_default_logging(args.default_logging_override);
}
easyenv::init_all_with_default_logging(args.default_logging_override);
info!("Bootstrapping application {}", &args.app_name);
@@ -10,7 +10,7 @@ const MEDIA_FILE_DIRECTORY: &str = "/media";
/// Directory for user media uploads.
/// Each uploaded file gets its own directory so that we can store the original
/// file alongside re-processed derivatives.
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct MediaFileBucketDirectory {
object_hash: String,
directory: String,
@@ -2,20 +2,17 @@ use std::collections::HashSet;
use elasticsearch::{Elasticsearch, SearchParts};
use once_cell::sync::Lazy;
use serde_json::{json, Number, Value};
use serde_json::{json, Value};
use enums::by_table::model_weights::weights_category::WeightsCategory;
use enums::by_table::model_weights::weights_types::WeightsType;
use errors::AnyhowResult;
use errors::{anyhow, AnyhowResult};
use tokens::tokens::users::UserToken;
use crate::documents::model_weight_document::{ModelWeightDocument, MODEL_WEIGHT_INDEX};
use crate::searches::search_model_weights::min_score::add_min_score;
use crate::searches::search_model_weights::predicates::{creator_user_token_predicate, language_subtag_predicate, must_be_not_deleted, weights_categories_predicates, weights_types_predicates};
use crate::searches::search_model_weights::sort::add_sort;
use crate::documents::model_weight_document::{MODEL_WEIGHT_INDEX, ModelWeightDocument};
static JSON_QUERY : Lazy<Value> = Lazy::new(|| {
const QUERY_TEMPLATE : &str = include_str!("../../../../../../_elasticsearch/searches/model_weights/search.json");
const QUERY_TEMPLATE : &str = include_str!("../../../../../_elasticsearch/searches/model_weights/search.json");
let json : Value = serde_json::from_str(QUERY_TEMPLATE)
.expect("json should parse");
@@ -23,34 +20,99 @@ static JSON_QUERY : Lazy<Value> = Lazy::new(|| {
json
});
#[derive(Default, Copy, Clone, Eq, PartialEq)]
pub enum ModelWeightsSortField {
/// Sort based on the match score of the search term alone.
#[default]
MatchScore,
/// Sort based on the creation date
CreatedAt,
/// Sort based on the model usage count
UsageCount,
/// Sort based on the model bookmark count
BookmarkCount,
/// Sort based on the model positive ratings count
PositiveRatingCount,
pub struct SearchModelWeightsQuery<'a> {
pub search_term: &'a str,
pub maybe_language_subtag: Option<&'a str>,
pub maybe_weights_type: Option<WeightsType>,
pub maybe_weights_category: Option<WeightsCategory>,
}
#[derive(Default, Copy, Clone, Eq, PartialEq)]
pub enum ModelWeightsSortDirection {
Ascending,
#[default]
Descending,
}
impl <'a>SearchModelWeightsQuery<'a> {
impl ModelWeightsSortDirection {
pub fn to_str(&self) -> &str {
match self {
Self::Ascending => "asc",
Self::Descending => "desc",
fn base_query(&self) -> Value {
json!({
"query": {
"bool": {
"must": [
{
"bool": {
"should": [
{
"fuzzy": {
"title": {
"value": self.search_term,
"fuzziness": 2
}
}
},
{
"match": {
"title": {
"query": self.search_term,
"boost": 1
}
}
},
{
"multi_match": {
"query": self.search_term,
"type": "bool_prefix",
"fields": [
"title",
"title._2gram",
"title._3gram"
],
"boost": 50
}
}
]
}
}
]
}
}
})
}
pub fn query(&self) -> AnyhowResult<Value> {
let mut search_json = self.base_query();
let must_clause = search_json.pointer_mut("/query/bool/must")
.map(|pointer| pointer.as_array_mut())
.flatten()
.ok_or_else(|| anyhow!("could not get pointer to must clause"))?;
if let Some(maybe_language_subtag) = &self.maybe_language_subtag {
must_clause.push(json!(
{
"match": {
"maybe_ietf_primary_language_subtag": maybe_language_subtag
}
}
));
}
if let Some(weights_type) = &self.maybe_weights_type {
must_clause.push(json!(
{
"match": {
"weights_type": weights_type.to_string(),
}
}
));
}
if let Some(weights_category) = &self.maybe_weights_category {
must_clause.push(json!(
{
"match": {
"weights_category": weights_category.to_string(),
}
}
));
}
Ok(search_json)
}
}
@@ -62,21 +124,12 @@ pub struct SearchArgs<'a> {
pub maybe_weights_categories: Option<HashSet<WeightsCategory>>,
pub maybe_weights_types: Option<HashSet<WeightsType>>,
pub sort_field: Option<ModelWeightsSortField>,
pub sort_direction: Option<ModelWeightsSortDirection>,
pub minimum_score: Option<u64>,
pub client: &'a Elasticsearch,
}
pub async fn search_model_weights(args: SearchArgs<'_>) -> AnyhowResult<Vec<ModelWeightDocument>> {
let query = build_query(&args)?;
let json_query = serde_json::to_string(&query)?;
println!("Query: {:#?}", json_query);
let search_response = args.client
.search(SearchParts::Index(&[MODEL_WEIGHT_INDEX]))
.body(query)
@@ -160,12 +213,75 @@ fn build_query(args: &SearchArgs) -> AnyhowResult<Value> {
Some(json!(args.search_term))
})?;
let query = add_sort(query, args.sort_field, args.sort_direction);
let query = add_min_score(query, args.search_term, args.minimum_score);
Ok(query)
}
fn must_be_not_deleted() -> Value {
json!({
"term": {
"is_deleted": false,
}
})
}
// fn featured_predicate(is_featured: bool) -> Value {
// json!({
// "term": {
// "is_featured": is_featured,
// }
// })
// }
fn creator_user_token_predicate(creator_user_token: &UserToken) -> Value {
json!({
"term": {
"maybe_creator_user_token": creator_user_token.as_str(),
}
})
}
fn language_subtag_predicate(language_subtag: &str) -> Value {
json!({
"term": {
"maybe_ietf_primary_language_subtag": language_subtag,
}
})
}
fn weights_categories_predicates(weights_categories: &HashSet<WeightsCategory>) -> Value {
should_predicates(weights_categories.iter()
.map(|weight_category| {
json!({
"term": {
"weights_category": weight_category.to_str(),
}
})
})
.collect())
}
fn weights_types_predicates(weights_types: &HashSet<WeightsType>) -> Value {
should_predicates(weights_types.iter()
.map(|weights_type| {
json!({
"term": {
"weights_type": weights_type.to_str(),
}
})
})
.collect())
}
// NB: "Should" is a logical OR.
fn should_predicates(predicates: Vec<Value>) -> Value {
json!({
"bool": {
"should": predicates,
}
})
}
#[cfg(test)]
mod tests {
@@ -178,8 +294,8 @@ mod tests {
use enums::by_table::model_weights::weights_types::WeightsType;
use tokens::tokens::users::UserToken;
use crate::searches::search_model_weights::search_model_weights::build_query;
use crate::searches::search_model_weights::search_model_weights::SearchArgs;
use crate::searches::search_model_weights::build_query;
use crate::searches::search_model_weights::SearchArgs;
#[test]
fn test_default_search() {
@@ -189,9 +305,6 @@ mod tests {
maybe_ietf_primary_language_subtag: None,
maybe_weights_categories: None,
maybe_weights_types: None,
sort_field: Default::default(),
sort_direction: Default::default(),
minimum_score: None,
client: &elasticsearch::Elasticsearch::default(),
}).unwrap();
@@ -224,9 +337,6 @@ mod tests {
maybe_ietf_primary_language_subtag: None,
maybe_weights_categories: None,
maybe_weights_types: None,
sort_field: Default::default(),
sort_direction: Default::default(),
minimum_score: None,
client: &elasticsearch::Elasticsearch::default(),
}).unwrap();
@@ -265,9 +375,6 @@ mod tests {
maybe_weights_categories: None,
maybe_weights_types: None,
client: &elasticsearch::Elasticsearch::default(),
minimum_score: None,
sort_field: Default::default(),
sort_direction: Default::default(),
}).unwrap();
let value = jsonpath_lib::select(
@@ -307,9 +414,6 @@ mod tests {
WeightsType::Tacotron2,
WeightsType::GptSoVits,
])),
sort_field: Default::default(),
sort_direction: Default::default(),
minimum_score: None,
client: &elasticsearch::Elasticsearch::default(),
}).unwrap();
@@ -337,9 +441,6 @@ mod tests {
WeightsCategory::VoiceConversion,
])),
client: &elasticsearch::Elasticsearch::default(),
minimum_score: None,
sort_field: Default::default(),
sort_direction: Default::default(),
}).unwrap();
let value = select(&search, "$.query.bool.must[0].bool.must[0].term.is_deleted");
@@ -368,4 +469,165 @@ mod tests {
})
.collect()
}
mod old_tests {
use regex::Regex;
use enums::by_table::model_weights::weights_category::WeightsCategory;
use enums::by_table::model_weights::weights_types::WeightsType;
use errors::AnyhowResult;
use crate::searches::search_model_weights::SearchModelWeightsQuery;
fn query_to_json_string(query: SearchModelWeightsQuery<'_>) -> AnyhowResult<String> {
let json = query.query()?;
let json = serde_json::to_string(&json)?;
Ok(json)
}
fn compact_json(json: &str) -> String {
let regex = Regex::new("\\s+").expect("regex should parse");
let json = regex.replace_all(&json, "");
json.to_string()
}
#[test]
fn default_search_only_keyword() {
let query = SearchModelWeightsQuery {
search_term: "FOO_BAR_BAZ",
maybe_language_subtag: None,
maybe_weights_type: None,
maybe_weights_category: None,
};
let json = query_to_json_string(query).unwrap();
// NB: Keys in emitted JSON are sorted.
let expected_json = r#"
{
"query": {
"bool": {
"must": [
{
"bool": {
"should": [
{
"fuzzy": {
"title": {
"value": "FOO_BAR_BAZ",
"fuzziness": 2
}
}
},
{
"match": {
"title": {
"query": "FOO_BAR_BAZ",
"boost": 1
}
}
},
{
"multi_match": {
"query": "FOO_BAR_BAZ",
"type": "bool_prefix",
"fields": [
"title",
"title._2gram",
"title._3gram"
],
"boost": 50
}
}
]
}
}
]
}
}
}
"#;
let expected_json = compact_json(&expected_json);
assert_eq!(&json, &expected_json);
}
#[test]
fn search_with_language_and_weights() {
let query = SearchModelWeightsQuery {
search_term: "FOO_BAR_BAZ",
maybe_language_subtag: Some("en"),
maybe_weights_type: Some(WeightsType::SoVitsSvc),
maybe_weights_category: Some(WeightsCategory::Vocoder),
};
let json = query_to_json_string(query).unwrap();
// NB: Keys in emitted JSON are sorted.
let expected_json = r#"
{
"query": {
"bool": {
"must": [
{
"bool": {
"should": [
{
"fuzzy": {
"title": {
"value": "FOO_BAR_BAZ",
"fuzziness": 2
}
}
},
{
"match": {
"title": {
"query": "FOO_BAR_BAZ",
"boost": 1
}
}
},
{
"multi_match": {
"query": "FOO_BAR_BAZ",
"type": "bool_prefix",
"fields": [
"title",
"title._2gram",
"title._3gram"
],
"boost": 50
}
}
]
}
},
{
"match": {
"maybe_ietf_primary_language_subtag": "en"
}
},
{
"match": {
"weights_type": "so_vits_svc"
}
},
{
"match": {
"weights_category": "vocoder"
}
}
]
}
}
}
"#;
let expected_json = compact_json(&expected_json);
assert_eq!(&json, &expected_json);
}
}
}
@@ -1,40 +0,0 @@
use serde_json::{Number, Value};
pub fn add_min_score(
mut query: Value,
search_term: &str,
maybe_user_defined_minimum_score: Option<u64>,
) -> Value {
if let Some(mimimum_score) = maybe_user_defined_minimum_score {
if let Some(mut object) = query.as_object_mut() {
object.insert(
"min_score".to_string(),
Value::Number(Number::from(mimimum_score))
);
}
return query;
}
if search_term.is_empty() {
return query;
}
let minimum_score = match search_term.len() {
1..=3 => 0,
4 => 1,
5 => 3,
6 => 5,
7 => 7,
_ => 10,
};
if let Some(mut object) = query.as_object_mut() {
object.insert(
"min_score".to_string(),
Value::Number(Number::from(minimum_score))
);
}
query
}
@@ -1,4 +0,0 @@
pub mod search_model_weights;
pub (crate) mod predicates;
pub (crate) mod sort;
pub (crate) mod min_score;
@@ -1,72 +0,0 @@
use std::collections::HashSet;
use serde_json::{json, Value};
use enums::by_table::model_weights::weights_category::WeightsCategory;
use enums::by_table::model_weights::weights_types::WeightsType;
use tokens::tokens::users::UserToken;
pub fn must_be_not_deleted() -> Value {
json!({
"term": {
"is_deleted": false,
}
})
}
// pub fn featured_predicate(is_featured: bool) -> Value {
// json!({
// "term": {
// "is_featured": is_featured,
// }
// })
// }
pub fn creator_user_token_predicate(creator_user_token: &UserToken) -> Value {
json!({
"term": {
"maybe_creator_user_token": creator_user_token.as_str(),
}
})
}
pub fn language_subtag_predicate(language_subtag: &str) -> Value {
json!({
"term": {
"maybe_ietf_primary_language_subtag": language_subtag,
}
})
}
pub fn weights_categories_predicates(weights_categories: &HashSet<WeightsCategory>) -> Value {
should_predicates(weights_categories.iter()
.map(|weight_category| {
json!({
"term": {
"weights_category": weight_category.to_str(),
}
})
})
.collect())
}
pub fn weights_types_predicates(weights_types: &HashSet<WeightsType>) -> Value {
should_predicates(weights_types.iter()
.map(|weights_type| {
json!({
"term": {
"weights_type": weights_type.to_str(),
}
})
})
.collect())
}
// NB: "Should" is a logical OR.
pub fn should_predicates(predicates: Vec<Value>) -> Value {
json!({
"bool": {
"should": predicates,
}
})
}
@@ -1,56 +0,0 @@
use crate::searches::search_model_weights::search_model_weights::{ModelWeightsSortDirection, ModelWeightsSortField};
use serde_json::{json, Value};
pub fn add_sort(
mut query: Value,
sort_field: Option<ModelWeightsSortField>,
sort_direction: Option<ModelWeightsSortDirection>,
) -> Value {
let sort_field = sort_field.unwrap_or_default();
let sort_direction = sort_direction.unwrap_or_default();
if sort_field == ModelWeightsSortField::MatchScore
&& sort_direction == ModelWeightsSortDirection::Descending {
return query;
}
let sort = match sort_field {
ModelWeightsSortField::CreatedAt => json!([
{
"created_at": {
"order": sort_direction.to_str(),
}
},
"_score"
]),
ModelWeightsSortField::UsageCount => json!([
{
"cached_usage_count": {
"order": sort_direction.to_str(),
}
},
"_score"
]),
ModelWeightsSortField::BookmarkCount => json!([
{
"bookmark_count": {
"order": sort_direction.to_str(),
}
},
"_score"
]),
ModelWeightsSortField::PositiveRatingCount => json!({
"ratings_positive_count": {
"order": sort_direction.to_str(),
}
}),
_ => return query,
};
if let Some(mut object) = query.as_object_mut() {
object.insert("sort".to_string(), sort);
}
query
}
@@ -1,10 +1,9 @@
use errors::AnyhowResult;
use std::path::Path;
use errors::AnyhowResult;
pub struct VideoDimensions {
pub width: u64,
pub height: u64,
pub length: u64,
}
pub fn ffprobe_get_dimensions(
@@ -23,20 +22,11 @@ pub fn ffprobe_get_dimensions(
}
});
let maybe_duration = result.streams.iter()
.filter(|stream| stream.codec_type.as_deref() == Some("video"))
.find_map(|stream| {
stream.duration_ts
});
match (maybe_dimensions, maybe_duration) {
(None, None) => Ok(None),
(None, Some(_)) => Ok(None),
(Some(_), None) => Ok(None),
(Some((width, height)), Some(length)) => Ok(Some(VideoDimensions {
match maybe_dimensions {
None => Ok(None),
Some((width, height)) => Ok(Some(VideoDimensions {
width: width.unsigned_abs(),
height: height.unsigned_abs(),
length: length.unsigned_abs(),
})),
}
}
@@ -1,63 +0,0 @@
use std::error::Error;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub enum DatabaseInsertError {
/// A duplicate key error occurred.
/// This should be surfaced as a 400 to the user.
DuplicateKeyError,
/// An uncategorized error occurred.
/// This will likely result in a 500 for the user.
SqlxError(sqlx::Error),
/// An uncategorized non-database error occurred.
/// This will likely result in a 500 for the user.
AnyhowError(anyhow::Error),
}
impl Error for DatabaseInsertError {}
impl Display for DatabaseInsertError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
DatabaseInsertError::DuplicateKeyError => write!(f, "Duplicate key error"),
DatabaseInsertError::SqlxError(e) => write!(f, "SQLx error: {:?}", e),
DatabaseInsertError::AnyhowError(e) => write!(f, "Query error: {:?}", e),
}
}
}
impl From<anyhow::Error> for DatabaseInsertError {
fn from(err: anyhow::Error) -> Self {
DatabaseInsertError::AnyhowError(err)
}
}
impl From<sqlx::Error> for DatabaseInsertError {
fn from(err: sqlx::Error) -> Self {
if let Some(db_err) = err.as_database_error() {
// NB: SQLSTATE[23000]: Integrity constraint violation
// NB: MySQL Error Code 1062: Duplicate key insertion (this is harder to access)
let is_integrity_violation = db_err.code().as_deref() == Some("23000");
let is_duplicate_key = db_err.message().contains("Duplicate entry");
if is_integrity_violation && is_duplicate_key {
return Self::DuplicateKeyError;
}
}
Self::SqlxError(err)
}
}
impl DatabaseInsertError {
/// Whether we should surface this failure as a 400 to the user.
/// This could be any field (for now we only have the idempotency token).
pub fn is_400_error(&self) -> bool {
match self {
DatabaseInsertError::DuplicateKeyError => true,
_ => false,
}
}
}
@@ -1,5 +1,4 @@
// TODO(bt,2024-10-01): This is only used for inserts into the idempotency table. We should move or rename it.
#[derive(Debug)]
pub enum DatabaseQueryError {
/// A duplicate idempotency token error occurred.
@@ -1,2 +1 @@
pub mod database_insert_error;
pub mod database_query_error;
@@ -1,4 +1,5 @@
use crate::payloads::generic_inference_args::inner_payloads::f5_tts_payload::F5TTSPayload;
use errors::AnyhowResult;
use crate::payloads::generic_inference_args::inner_payloads::face_fusion_payload::FaceFusionPayload;
use crate::payloads::generic_inference_args::inner_payloads::gptsovits_payload::GptSovitsPayload;
use crate::payloads::generic_inference_args::inner_payloads::image_generation_payload::StableDiffusionArgs;
@@ -6,12 +7,9 @@ use crate::payloads::generic_inference_args::inner_payloads::lipsync_payload::Li
use crate::payloads::generic_inference_args::inner_payloads::live_portrait_payload::LivePortraitPayload;
use crate::payloads::generic_inference_args::inner_payloads::mocap_payload::MocapArgs;
use crate::payloads::generic_inference_args::inner_payloads::render_engine_scene_to_video_payload::RenderEngineSceneToVideoArgs;
use crate::payloads::generic_inference_args::inner_payloads::seed_vc_payload::SeedVcPayload;
use crate::payloads::generic_inference_args::inner_payloads::studio_gen2_payload::StudioGen2Payload;
use crate::payloads::generic_inference_args::inner_payloads::tts_payload::TTSArgs;
use crate::payloads::generic_inference_args::inner_payloads::videofilter_payload::RerenderArgs;
use crate::payloads::generic_inference_args::inner_payloads::workflow_payload::WorkflowArgs;
use errors::AnyhowResult;
/// Used to encode extra state for the `generic_inference_jobs` table.
/// This should act somewhat like a serialized protobuf stored inside a record.
@@ -78,15 +76,7 @@ pub enum InferenceCategoryAbbreviated {
#[serde(rename = "gs")] // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes.
#[serde(alias = "gpt_sovits")]
GptSovits,
#[serde(rename = "ft")] // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes.
#[serde(alias = "f5_tts")]
F5TTS,
#[serde(rename = "sv")] // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes.
#[serde(alias = "seed_vc")]
SeedVc
GptSovits
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
@@ -149,9 +139,6 @@ pub enum PolymorphicInferenceArgs {
/// ComfyUI (Short name to save space when serializing.)
Cu(WorkflowArgs),
/// Studio Gen2 (Short name to save space when serializing.)
S2(StudioGen2Payload),
/// ComfyUI (Short name to save space when serializing.)
Lp(LivePortraitPayload),
@@ -163,10 +150,6 @@ pub enum PolymorphicInferenceArgs {
/// GPT Sovits
Gs(GptSovitsPayload),
Ft(F5TTSPayload),
Sv(SeedVcPayload),
}
impl GenericInferenceArgs {
@@ -1,2 +0,0 @@
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct F5TTSPayload {}
@@ -5,9 +5,6 @@ pub mod lipsync_payload;
pub mod live_portrait_payload;
pub mod mocap_payload;
pub mod render_engine_scene_to_video_payload;
pub mod studio_gen2_payload;
pub mod tts_payload;
pub mod videofilter_payload;
pub mod workflow_payload;
pub mod f5_tts_payload;
pub mod seed_vc_payload;
@@ -1,8 +0,0 @@
use tokens::tokens::media_files::MediaFileToken;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SeedVcPayload {
#[serde(rename = "r")]
#[serde(skip_serializing_if = "Option::is_none")]
pub reference_media_file_token: Option<MediaFileToken>,
}
@@ -1,65 +0,0 @@
use crate::payloads::generic_inference_args::common::watermark_type::WatermarkType;
use enums::common::visibility::Visibility;
use std::time::Duration;
use tokens::tokens::media_files::MediaFileToken;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct StudioGen2Payload {
/// The input image media file (required)
#[serde(rename = "i")]
#[serde(skip_serializing_if = "Option::is_none")]
pub image_file: Option<MediaFileToken>,
/// The input video media file (required)
#[serde(rename = "v")]
#[serde(skip_serializing_if = "Option::is_none")]
pub video_file: Option<MediaFileToken>,
#[serde(rename = "wt")]
#[serde(skip_serializing_if = "Option::is_none")]
pub watermark_type: Option<WatermarkType>,
#[serde(rename = "cv")]
#[serde(skip_serializing_if = "Option::is_none")]
pub creator_visibility: Option<Visibility>,
#[serde(rename = "sm")]
#[serde(skip_serializing_if = "Option::is_none")]
pub after_job_debug_sleep_millis: Option<u64>,
#[serde(rename = "ow")]
#[serde(skip_serializing_if = "Option::is_none")]
pub output_width: Option<u64>,
#[serde(rename = "oh")]
#[serde(skip_serializing_if = "Option::is_none")]
pub output_height: Option<u64>,
#[serde(rename = "fp")]
#[serde(skip_serializing_if = "Option::is_none")]
pub fps: Option<u64>,
#[serde(rename = "mf")]
#[serde(skip_serializing_if = "Option::is_none")]
pub max_frames: Option<u64>,
#[serde(rename = "rnd")]
#[serde(skip_serializing_if = "Option::is_none")]
pub rounds: Option<u64>,
#[serde(rename = "td")]
#[serde(skip_serializing_if = "Option::is_none")]
pub trim_duration_millis: Option<u64>,
#[serde(rename = "ski")]
#[serde(skip_serializing_if = "Option::is_none")]
pub skip_image_resize: Option<bool>,
#[serde(rename = "tw")]
#[serde(skip_serializing_if = "Option::is_none")]
pub tensor_image_width: Option<u64>,
#[serde(rename = "th")]
#[serde(skip_serializing_if = "Option::is_none")]
pub tensor_image_height: Option<u64>,
}
@@ -211,10 +211,6 @@ pub struct WorkflowArgs {
#[serde(skip_serializing_if = "Option::is_none")]
pub use_cinematic: Option<bool>,
#[serde(rename = "uv")]
#[serde(skip_serializing_if = "Option::is_none")]
pub use_cogvideo: Option<bool>,
#[serde(rename = "s")]
#[serde(skip_serializing_if = "Option::is_none")]
pub strength: Option<f32>,
@@ -1,228 +0,0 @@
use std::collections::BTreeSet;
use anyhow::anyhow;
use chrono::Utc;
use sqlx::MySqlPool;
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
use enums::by_table::generic_inference_jobs::inference_input_source_token_type::InferenceInputSourceTokenType;
use enums::by_table::generic_inference_jobs::inference_job_type::InferenceJobType;
use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType;
use enums::common::job_status_plus::JobStatusPlus;
use enums::common::visibility::Visibility;
use errors::AnyhowResult;
use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken;
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::users::UserToken;
use crate::helpers::boolean_converters::i8_to_bool;
use crate::payloads::generic_inference_args::generic_inference_args::GenericInferenceArgs;
use crate::queries::generic_inference::job::_keys::GenericInferenceJobId;
pub struct UntriedJobCount {
pub job_count: usize,
}
pub struct CountUntriedJobsOfTypeArgs<'a> {
pub maybe_scope_by_job_type: Option<&'a BTreeSet<InferenceJobType>>,
pub maybe_scope_by_model_type: Option<&'a BTreeSet<InferenceModelType>>,
pub maybe_scope_by_job_category: Option<&'a BTreeSet<InferenceCategory>>,
pub mysql_pool: &'a MySqlPool,
}
pub async fn count_untried_jobs_of_type(
args: CountUntriedJobsOfTypeArgs<'_>,
)
-> AnyhowResult<UntriedJobCount>
{
let query = perform_query(args).await;
let result = query?;
Ok(UntriedJobCount {
job_count: result.job_count as usize,
})
}
async fn perform_query(args: CountUntriedJobsOfTypeArgs<'_>) -> Result<UntriedJobCountRawInternal, sqlx::Error> {
// NB: Can't be type checked because of WHERE IN clause with dynamic contents
let mut query = core_query(&args);
let query = sqlx::query_as::<_, UntriedJobCountRawInternal>(&query);
query.fetch_one(args.mysql_pool)
.await
}
// TODO(bt,2024-01-25): Make QueryBuilder
fn core_query(args: &CountUntriedJobsOfTypeArgs<'_>) -> String {
// NB: Can't be type checked because of WHERE IN clause with dynamic contents
let mut query = r#"
SELECT
count(*) as job_count
FROM generic_inference_jobs
WHERE
(
status IN ("pending")
)
AND
(
retry_at IS NULL
)
AND
(
attempt_count = 0
)
"#.to_string();
if let Some(job_types) = args.maybe_scope_by_job_type {
if !job_types.is_empty() {
query.push_str(&format!(r#"
AND
(
job_type IN ({})
)
"#, job_type_predicate(job_types)));
}
}
if let Some(model_types) = args.maybe_scope_by_model_type {
if !model_types.is_empty() {
query.push_str(&format!(r#"
AND
(
maybe_model_type IN ({})
)
"#, model_type_predicate(model_types)));
}
}
if let Some(inference_categories) = args.maybe_scope_by_job_category {
if !inference_categories.is_empty() {
query.push_str(&format!(r#"
AND
(
inference_category IN ({})
)
"#, inference_category_predicate(&inference_categories)));
}
}
query
}
#[derive(Debug)]
#[derive(sqlx::FromRow)]
struct UntriedJobCountRawInternal {
pub job_count: u64,
}
/// Return a comma-separated predicate, since SQLx does not yet support WHERE IN(?) for Vec<T>, etc.
/// Issue: https://github.com/launchbadge/sqlx/issues/875
fn job_type_predicate(types: &BTreeSet<InferenceJobType>) -> String {
let mut vec = types.iter()
.map(|ty| ty.to_str())
.map(|ty| format!("\"{}\"", ty))
.collect::<Vec<String>>();
vec.sort(); // NB: For the benefit of tests.
vec.join(", ")
}
/// Return a comma-separated predicate, since SQLx does not yet support WHERE IN(?) for Vec<T>, etc.
/// Issue: https://github.com/launchbadge/sqlx/issues/875
fn model_type_predicate(types: &BTreeSet<InferenceModelType>) -> String {
let mut vec = types.iter()
.map(|ty| ty.to_str())
.map(|ty| format!("\"{}\"", ty))
.collect::<Vec<String>>();
vec.sort(); // NB: For the benefit of tests.
vec.join(", ")
}
/// Return a comma-separated predicate, since SQLx does not yet support WHERE IN(?) for Vec<T>, etc.
/// Issue: https://github.com/launchbadge/sqlx/issues/875
fn inference_category_predicate(categories: &BTreeSet<InferenceCategory>) -> String {
let mut vec = categories.iter()
.map(|ty| ty.to_str())
.map(|ty| format!("\"{}\"", ty))
.collect::<Vec<String>>();
vec.sort(); // NB: For the benefit of tests.
vec.join(", ")
}
#[cfg(test)]
mod tests {
use std::collections::BTreeSet;
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
use enums::by_table::generic_inference_jobs::inference_job_type::InferenceJobType;
use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType;
use crate::queries::generic_inference::job::count_untried_jobs_of_type::{inference_category_predicate, job_type_predicate, model_type_predicate};
#[test]
fn test_job_type_predicate() {
// None
let types = BTreeSet::from([]);
assert_eq!(job_type_predicate(&types), "".to_string());
// One
let types = BTreeSet::from([
InferenceJobType::RvcV2,
]);
assert_eq!(job_type_predicate(&types), "\"rvc_v2\"".to_string());
// Multiple
let types = BTreeSet::from([
InferenceJobType::MocapNet,
InferenceJobType::RvcV2,
]);
assert_eq!(job_type_predicate(&types), "\"mocap_net\", \"rvc_v2\"".to_string());
}
#[test]
fn test_model_type_predicate() {
// None
let types = BTreeSet::from([]);
assert_eq!(model_type_predicate(&types), "".to_string());
// One
let types = BTreeSet::from([
InferenceModelType::RvcV2,
]);
assert_eq!(model_type_predicate(&types), "\"rvc_v2\"".to_string());
// Multiple
let types = BTreeSet::from([
InferenceModelType::RvcV2,
InferenceModelType::SoVitsSvc,
]);
assert_eq!(model_type_predicate(&types), "\"rvc_v2\", \"so_vits_svc\"".to_string());
}
#[test]
fn test_inference_category_predicate() {
// None
let types = BTreeSet::from([]);
assert_eq!(inference_category_predicate(&types), "".to_string());
// Some
let types = BTreeSet::from([
InferenceCategory::VoiceConversion,
]);
assert_eq!(inference_category_predicate(&types), "\"voice_conversion\"".to_string());
// All
let types = BTreeSet::from([
InferenceCategory::TextToSpeech,
InferenceCategory::VoiceConversion,
]);
assert_eq!(inference_category_predicate(&types), "\"text_to_speech\", \"voice_conversion\"".to_string());
}
}
@@ -1,5 +1,4 @@
pub mod _keys;
pub mod count_untried_jobs_of_type;
pub mod list_available_generic_inference_jobs;
pub mod mark_generic_inference_job_completely_failed;
pub mod mark_generic_inference_job_failure;
@@ -1,8 +1,8 @@
use anyhow::anyhow;
use chrono::{DateTime, Utc};
use sqlx::{FromRow, MySql, MySqlPool, QueryBuilder, Row};
use sqlx::mysql::MySqlRow;
use sqlx::pool::PoolConnection;
use sqlx::{FromRow, MySql, MySqlPool, QueryBuilder, Row};
use enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
@@ -178,8 +178,6 @@ fn raw_records_to_public_result(records: Vec<RawGenericInferenceJobStatus>) -> V
InferenceCategory::Workflow => Some("Workflow"),
InferenceCategory::FormatConversion => Some("format conversion"),
InferenceCategory::LivePortrait => Some("Live Portrait"),
InferenceCategory::F5TTS => Some("F5 TTS"),
InferenceCategory::SeedVc => Some("Seed VC"),
InferenceCategory::ConvertBvhToWorkflow => Some("BVH to Workflow"),
InferenceCategory::DeprecatedField => Some("Job"), // TODO(bt,2024-07-16): Fix
};
@@ -190,14 +188,12 @@ fn raw_records_to_public_result(records: Vec<RawGenericInferenceJobStatus>) -> V
let (mut bucket_path_is_hash, mut maybe_public_bucket_hash) = match record.inference_category {
InferenceCategory::LipsyncAnimation => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::TextToSpeech => (false, record.maybe_tts_public_bucket_path.as_deref()),
InferenceCategory::F5TTS => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::VoiceConversion => (true, record.maybe_voice_conversion_public_bucket_hash.as_deref()),
InferenceCategory::VideoFilter => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::ImageGeneration => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::Mocap => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::Workflow => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::FormatConversion => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::SeedVc => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::LivePortrait => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::ConvertBvhToWorkflow => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::DeprecatedField => (true, None), // TODO(bt,2024-07-16): We'll need to read another field!
@@ -1,8 +1,8 @@
use anyhow::anyhow;
use chrono::{DateTime, NaiveDateTime, TimeZone, Utc};
use log::warn;
use sqlx::pool::PoolConnection;
use sqlx::{MySql, MySqlPool};
use sqlx::pool::PoolConnection;
use enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
@@ -154,8 +154,6 @@ fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericI
InferenceCategory::Workflow => Some("Workflow"),
InferenceCategory::FormatConversion => Some("format conversion"),
InferenceCategory::LivePortrait => Some("Live Portrait"),
InferenceCategory::F5TTS => Some("F5 TTS"),
InferenceCategory::SeedVc => Some("Seed VC"),
InferenceCategory::ConvertBvhToWorkflow => Some("BVH to Workflow"),
InferenceCategory::DeprecatedField => Some("Job"), // TODO(bt,2024-07-16): Fix
};
@@ -166,7 +164,6 @@ fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericI
let (mut bucket_path_is_hash, mut maybe_public_bucket_hash) = match record.inference_category {
InferenceCategory::LipsyncAnimation => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::TextToSpeech => (false, record.maybe_tts_public_bucket_path.as_deref()),
InferenceCategory::F5TTS => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::VoiceConversion => (true, record.maybe_voice_conversion_public_bucket_hash.as_deref()),
InferenceCategory::VideoFilter => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::ImageGeneration => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
@@ -174,7 +171,6 @@ fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericI
InferenceCategory::Workflow => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::FormatConversion => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::LivePortrait => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::SeedVc => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::ConvertBvhToWorkflow => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::DeprecatedField => (true, None), // TODO(bt,2024-07-16): We'll need to read another field!
};
@@ -1,48 +0,0 @@
use anyhow::anyhow;
use sqlx;
use sqlx::pool::PoolConnection;
use sqlx::{MySql, MySqlPool};
use errors::AnyhowResult;
/// Kill a handful of jobs when called.
/// This should only be used in development to keep the job queue empty.
pub async fn kill_jobs_in_development(mysql_pool: &MySqlPool) -> AnyhowResult<()>
{
let mut connection = mysql_pool.acquire().await?;
kill_jobs_in_development_using_connection(&mut connection).await
}
/// Kill a handful of jobs when called.
/// This should only be used in development to keep the job queue empty.
pub async fn kill_jobs_in_development_using_connection(
mysql_connection: &mut PoolConnection<MySql>,
) -> AnyhowResult<()> {
// We cancel any non-complete / non-terminal jobs
// We also mark "started" jobs in the event that they're left in a bad state.
// Any started jobs that are actually running should still run to completion, and
// the user should still see the final result even if the job system UI doesn't
// indicate it.
let query_result = sqlx::query!(
r#"
UPDATE generic_inference_jobs
SET
status = 'cancelled_by_user',
retry_at = NULL
WHERE status IN (
'pending',
'started',
'attempt_failed'
)
LIMIT 100
"#
)
.execute(&mut **mysql_connection)
.await;
if let Err(err) = query_result {
return Err(anyhow!("error with terminate job query (1): {:?}", err));
}
Ok(())
}
@@ -2,9 +2,9 @@ use std::collections::HashSet;
use anyhow::anyhow;
use chrono::{DateTime, Utc};
use sqlx::{FromRow, MySql, MySqlPool, QueryBuilder, Row};
use sqlx::mysql::MySqlRow;
use sqlx::pool::PoolConnection;
use sqlx::{FromRow, MySql, MySqlPool, QueryBuilder, Row};
use enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
@@ -217,7 +217,6 @@ fn raw_records_to_public_result(records: Vec<RawGenericInferenceJobStatus>) -> V
maybe_model_title = match record.inference_category {
InferenceCategory::LipsyncAnimation => Some("lipsync animation"),
InferenceCategory::TextToSpeech => record.maybe_tts_model_title.as_deref(),
InferenceCategory::F5TTS => Some("F5 TTS"),
InferenceCategory::VoiceConversion => record.maybe_voice_conversion_model_title.as_deref(),
InferenceCategory::VideoFilter => Some("Video Filter"),
InferenceCategory::ImageGeneration => Some("Image Generation"),
@@ -226,7 +225,6 @@ fn raw_records_to_public_result(records: Vec<RawGenericInferenceJobStatus>) -> V
InferenceCategory::FormatConversion => Some("format conversion"),
InferenceCategory::ConvertBvhToWorkflow => Some("BVH to Workflow"),
InferenceCategory::LivePortrait => Some("Live Portrait"),
InferenceCategory::SeedVc => Some("Seed VC"),
InferenceCategory::DeprecatedField => Some("Job"), // TODO(bt,2024-07-16): Fix
};
}
@@ -236,7 +234,6 @@ fn raw_records_to_public_result(records: Vec<RawGenericInferenceJobStatus>) -> V
let (mut bucket_path_is_hash, mut maybe_public_bucket_hash) = match record.inference_category {
InferenceCategory::LipsyncAnimation => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::TextToSpeech => (false, record.maybe_tts_public_bucket_path.as_deref()),
InferenceCategory::F5TTS => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::VoiceConversion => (true, record.maybe_voice_conversion_public_bucket_hash.as_deref()),
InferenceCategory::VideoFilter => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::ImageGeneration => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
@@ -244,7 +241,6 @@ fn raw_records_to_public_result(records: Vec<RawGenericInferenceJobStatus>) -> V
InferenceCategory::Workflow => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::FormatConversion => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::LivePortrait => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::SeedVc => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::ConvertBvhToWorkflow => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
InferenceCategory::DeprecatedField => (true, None), // TODO(bt,2024-07-16): We'll need to read another field!
};
@@ -5,6 +5,5 @@ pub mod get_pending_inference_job_count;
pub mod insert_generic_inference_job;
pub mod job_status;
pub mod kill_generic_inference_jobs;
pub mod kill_jobs_in_development;
pub mod list_session_jobs;
pub mod mark_generic_inference_job_cancelled_by_user;
@@ -1,174 +0,0 @@
use anyhow::anyhow;
use sqlx;
use sqlx::MySqlPool;
use enums::by_table::generic_synthetic_ids::id_category::IdCategory;
use enums::by_table::media_files::media_file_class::MediaFileClass;
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use errors::AnyhowResult;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::users::UserToken;
use crate::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
use crate::queries::generic_synthetic_ids::transactional_increment_generic_synthetic_id::transactional_increment_generic_synthetic_id;
pub struct InsertF5TTSMediaFileArgs<'a> {
pub pool: &'a MySqlPool,
pub job: &'a AvailableInferenceJob,
pub maybe_mime_type: Option<&'a str>,
pub file_size_bytes: u64,
pub sha256_checksum: &'a str,
pub maybe_duration_millis: Option<u64>,
pub maybe_audio_codec_name: Option<&'a str>,
pub public_bucket_directory_hash: &'a str,
pub maybe_public_bucket_prefix: Option<&'a str>,
pub maybe_public_bucket_extension: Option<&'a str>,
pub is_on_prem: bool,
pub worker_hostname: &'a str,
pub worker_cluster: &'a str,
}
pub async fn insert_media_file_from_f5_tts(
args: InsertF5TTSMediaFileArgs<'_>
) -> AnyhowResult<(MediaFileToken, u64)>
{
let result_token = MediaFileToken::generate();
let origin_model_type = MediaFileOriginModelType::F5TTS;
let mut maybe_creator_file_synthetic_id : Option<u64> = None;
let mut maybe_creator_category_synthetic_id : Option<u64> = None;
let mut transaction = args.pool.begin().await?;
if let Some(creator_user_token) = args.job.maybe_creator_user_token.as_deref() {
let user_token = UserToken::new_from_str(creator_user_token);
let next_media_file_id = transactional_increment_generic_synthetic_id(
&user_token,
IdCategory::MediaFile,
&mut transaction
).await?;
let next_voice_conversion_id = transactional_increment_generic_synthetic_id(
&user_token,
IdCategory::TtsResult,
&mut transaction
).await?;
maybe_creator_file_synthetic_id = Some(next_media_file_id);
maybe_creator_category_synthetic_id = Some(next_voice_conversion_id);
}
const ORIGIN_CATEGORY : MediaFileOriginCategory = MediaFileOriginCategory::Inference;
const ORIGIN_PRODUCT_CATEGORY : MediaFileOriginProductCategory = MediaFileOriginProductCategory::TextToSpeech;
let record_id = {
let query_result = sqlx::query!(
r#"
INSERT INTO media_files
SET
token = ?,
media_class = ?,
media_type = ?,
origin_category = ?,
origin_product_category = ?,
maybe_origin_model_type = ?,
maybe_origin_model_token = ?,
maybe_text_transcript = ?,
maybe_mime_type = ?,
file_size_bytes = ?,
maybe_duration_millis = ?,
maybe_audio_encoding = ?,
checksum_sha2 = ?,
public_bucket_directory_hash = ?,
maybe_public_bucket_prefix = ?,
maybe_public_bucket_extension = ?,
maybe_creator_user_token = ?,
maybe_creator_anonymous_visitor_token = ?,
creator_ip_address = ?,
creator_set_visibility = ?,
maybe_creator_file_synthetic_id = ?,
maybe_creator_category_synthetic_id = ?,
is_generated_on_prem = ?,
generated_by_worker = ?,
generated_by_cluster = ?
"#,
result_token.as_str(),
MediaFileClass::Audio.to_str(),
MediaFileType::Audio.to_str(), // TODO(bt,2024-04-30): This needs to become "wav" after a frontend migration
ORIGIN_CATEGORY.to_str(),
ORIGIN_PRODUCT_CATEGORY.to_str(),
origin_model_type.to_str(),
args.job.maybe_model_token,
args.job.maybe_raw_inference_text,
args.maybe_mime_type,
args.file_size_bytes,
args.maybe_duration_millis,
args.maybe_audio_codec_name,
args.sha256_checksum,
args.public_bucket_directory_hash,
args.maybe_public_bucket_prefix,
args.maybe_public_bucket_extension,
args.job.maybe_creator_user_token,
args.job.maybe_creator_anonymous_visitor_token,
args.job.creator_ip_address,
args.job.creator_set_visibility.to_str(),
maybe_creator_file_synthetic_id,
maybe_creator_category_synthetic_id,
args.is_on_prem,
args.worker_hostname,
args.worker_cluster
)
.execute(&mut *transaction)
.await;
let record_id = match query_result {
Ok(res) => {
res.last_insert_id()
},
Err(err) => {
// TODO: handle better
//transaction.rollback().await?;
return Err(anyhow!("Mysql error: {:?}", err));
}
};
record_id
};
transaction.commit().await?;
Ok((result_token, record_id))
}
@@ -1,174 +0,0 @@
use anyhow::anyhow;
use sqlx;
use sqlx::MySqlPool;
use enums::by_table::generic_synthetic_ids::id_category::IdCategory;
use enums::by_table::media_files::media_file_class::MediaFileClass;
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use errors::AnyhowResult;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::users::UserToken;
use crate::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
use crate::queries::generic_synthetic_ids::transactional_increment_generic_synthetic_id::transactional_increment_generic_synthetic_id;
pub struct InsertSeedVcMediaFileArgs<'a> {
pub pool: &'a MySqlPool,
pub job: &'a AvailableInferenceJob,
pub maybe_mime_type: Option<&'a str>,
pub file_size_bytes: u64,
pub sha256_checksum: &'a str,
pub maybe_duration_millis: Option<u64>,
pub maybe_audio_codec_name: Option<&'a str>,
pub public_bucket_directory_hash: &'a str,
pub maybe_public_bucket_prefix: Option<&'a str>,
pub maybe_public_bucket_extension: Option<&'a str>,
pub is_on_prem: bool,
pub worker_hostname: &'a str,
pub worker_cluster: &'a str,
}
pub async fn insert_media_file_from_seed_vc(
args: InsertSeedVcMediaFileArgs<'_>
) -> AnyhowResult<(MediaFileToken, u64)>
{
let result_token = MediaFileToken::generate();
let origin_model_type = MediaFileOriginModelType::SeedVc;
let mut maybe_creator_file_synthetic_id : Option<u64> = None;
let mut maybe_creator_category_synthetic_id : Option<u64> = None;
let mut transaction = args.pool.begin().await?;
if let Some(creator_user_token) = args.job.maybe_creator_user_token.as_deref() {
let user_token = UserToken::new_from_str(creator_user_token);
let next_media_file_id = transactional_increment_generic_synthetic_id(
&user_token,
IdCategory::MediaFile,
&mut transaction
).await?;
let next_voice_conversion_id = transactional_increment_generic_synthetic_id(
&user_token,
IdCategory::VoiceConversionResult,
&mut transaction
).await?;
maybe_creator_file_synthetic_id = Some(next_media_file_id);
maybe_creator_category_synthetic_id = Some(next_voice_conversion_id);
}
const ORIGIN_CATEGORY : MediaFileOriginCategory = MediaFileOriginCategory::Inference;
const ORIGIN_PRODUCT_CATEGORY : MediaFileOriginProductCategory = MediaFileOriginProductCategory::TextToSpeech;
let record_id = {
let query_result = sqlx::query!(
r#"
INSERT INTO media_files
SET
token = ?,
media_class = ?,
media_type = ?,
origin_category = ?,
origin_product_category = ?,
maybe_origin_model_type = ?,
maybe_origin_model_token = ?,
maybe_text_transcript = ?,
maybe_mime_type = ?,
file_size_bytes = ?,
maybe_duration_millis = ?,
maybe_audio_encoding = ?,
checksum_sha2 = ?,
public_bucket_directory_hash = ?,
maybe_public_bucket_prefix = ?,
maybe_public_bucket_extension = ?,
maybe_creator_user_token = ?,
maybe_creator_anonymous_visitor_token = ?,
creator_ip_address = ?,
creator_set_visibility = ?,
maybe_creator_file_synthetic_id = ?,
maybe_creator_category_synthetic_id = ?,
is_generated_on_prem = ?,
generated_by_worker = ?,
generated_by_cluster = ?
"#,
result_token.as_str(),
MediaFileClass::Audio.to_str(),
MediaFileType::Audio.to_str(), // TODO(bt,2024-04-30): This needs to become "wav" after a frontend migration
ORIGIN_CATEGORY.to_str(),
ORIGIN_PRODUCT_CATEGORY.to_str(),
origin_model_type.to_str(),
args.job.maybe_model_token,
args.job.maybe_raw_inference_text,
args.maybe_mime_type,
args.file_size_bytes,
args.maybe_duration_millis,
args.maybe_audio_codec_name,
args.sha256_checksum,
args.public_bucket_directory_hash,
args.maybe_public_bucket_prefix,
args.maybe_public_bucket_extension,
args.job.maybe_creator_user_token,
args.job.maybe_creator_anonymous_visitor_token,
args.job.creator_ip_address,
args.job.creator_set_visibility.to_str(),
maybe_creator_file_synthetic_id,
maybe_creator_category_synthetic_id,
args.is_on_prem,
args.worker_hostname,
args.worker_cluster
)
.execute(&mut *transaction)
.await;
let record_id = match query_result {
Ok(res) => {
res.last_insert_id()
},
Err(err) => {
// TODO: handle better
//transaction.rollback().await?;
return Err(anyhow!("Mysql error: {:?}", err));
}
};
record_id
};
transaction.commit().await?;
Ok((result_token, record_id))
}
@@ -1,178 +0,0 @@
use anyhow::anyhow;
use sqlx;
use sqlx::MySqlPool;
use enums::by_table::generic_synthetic_ids::id_category::IdCategory;
use enums::by_table::media_files::media_file_class::MediaFileClass;
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use errors::AnyhowResult;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::prompts::PromptToken;
use tokens::tokens::users::UserToken;
use crate::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
use crate::queries::generic_synthetic_ids::transactional_increment_generic_synthetic_id::transactional_increment_generic_synthetic_id;
pub struct InsertArgs<'a> {
pub pool: &'a MySqlPool,
pub job: &'a AvailableInferenceJob,
pub maybe_mime_type: Option<&'a str>,
pub file_size_bytes: u64,
pub sha256_checksum: &'a str,
// TODO: Media duration.
//pub duration_millis: u64,
pub maybe_title: Option<&'a str>,
pub maybe_style_transfer_source_media_file_token: Option<&'a MediaFileToken>,
pub maybe_scene_source_media_file_token: Option<&'a MediaFileToken>,
pub maybe_prompt_token: Option<&'a PromptToken>,
pub public_bucket_directory_hash: &'a str,
pub maybe_public_bucket_prefix: Option<&'a str>,
pub maybe_public_bucket_extension: Option<&'a str>,
pub is_on_prem: bool,
pub worker_hostname: &'a str,
pub worker_cluster: &'a str,
}
pub async fn insert_media_file_from_studio_gen2(args: InsertArgs<'_>) -> AnyhowResult<(MediaFileToken, u64)>
{
let result_token = MediaFileToken::generate();
let mut maybe_creator_file_synthetic_id : Option<u64> = None;
let mut maybe_creator_category_synthetic_id : Option<u64> = None;
let mut transaction = args.pool.begin().await?;
if let Some(creator_user_token) = args.job.maybe_creator_user_token.as_deref() {
let user_token = UserToken::new_from_str(creator_user_token);
let next_media_file_id = transactional_increment_generic_synthetic_id(
&user_token,
IdCategory::MediaFile,
&mut transaction
).await?;
let next_comfy_ui_id = transactional_increment_generic_synthetic_id(
&user_token,
IdCategory::WorkflowResult,
&mut transaction
).await?;
maybe_creator_file_synthetic_id = Some(next_media_file_id);
maybe_creator_category_synthetic_id = Some(next_comfy_ui_id);
}
const ORIGIN_CATEGORY : MediaFileOriginCategory = MediaFileOriginCategory::Inference;
const PRODUCT : MediaFileOriginProductCategory = MediaFileOriginProductCategory::StorytellerStudio;
const MODEL_TYPE : MediaFileOriginModelType = MediaFileOriginModelType::StorytellerStudio;
let record_id = {
let query_result = sqlx::query!(
r#"
INSERT INTO media_files
SET
token = ?,
media_class = ?,
media_type = ?,
origin_category = ?,
origin_product_category = ?,
maybe_origin_model_type = ?,
maybe_mime_type = ?,
file_size_bytes = ?,
checksum_sha2 = ?,
maybe_style_transfer_source_media_file_token = ?,
maybe_scene_source_media_file_token = ?,
maybe_title = ?,
maybe_prompt_token = ?,
public_bucket_directory_hash = ?,
maybe_public_bucket_prefix = ?,
maybe_public_bucket_extension = ?,
maybe_creator_user_token = ?,
maybe_creator_anonymous_visitor_token = ?,
creator_ip_address = ?,
creator_set_visibility = ?,
maybe_creator_file_synthetic_id = ?,
maybe_creator_category_synthetic_id = ?,
is_generated_on_prem = ?,
generated_by_worker = ?,
generated_by_cluster = ?
"#,
result_token.as_str(),
MediaFileClass::Video.to_str(),
MediaFileType::Video.to_str(), // TODO(bt,2024-04-30): This needs to become "mp4" after a frontend migration
ORIGIN_CATEGORY.to_str(),
PRODUCT.to_str(),
MODEL_TYPE.to_str(),
args.maybe_mime_type,
args.file_size_bytes,
args.sha256_checksum,
args.maybe_style_transfer_source_media_file_token.map(|t| t.as_str()),
args.maybe_scene_source_media_file_token.map(|t| t.as_str()),
args.maybe_title,
args.maybe_prompt_token.map(|e| e.as_str()),
args.public_bucket_directory_hash,
args.maybe_public_bucket_prefix,
args.maybe_public_bucket_extension,
args.job.maybe_creator_user_token,
args.job.maybe_creator_anonymous_visitor_token,
args.job.creator_ip_address,
args.job.creator_set_visibility.to_str(),
maybe_creator_file_synthetic_id,
maybe_creator_category_synthetic_id,
args.is_on_prem,
args.worker_hostname,
args.worker_cluster
)
.execute(&mut *transaction)
.await;
let record_id = match query_result {
Ok(res) => {
res.last_insert_id()
},
Err(err) => {
// TODO: handle better
//transaction.rollback().await?;
return Err(anyhow!("Mysql error: {:?}", err));
}
};
record_id
};
transaction.commit().await?;
Ok((result_token, record_id))
}
@@ -1,12 +1,9 @@
pub mod insert_media_file_from_cli_tool;
pub mod insert_media_file_from_comfy_ui;
pub mod insert_media_file_from_f5_tts;
pub mod insert_media_file_from_face_animation;
pub mod insert_media_file_from_file_upload;
pub mod insert_media_file_from_mocapnet;
pub mod insert_media_file_from_rerender;
pub mod insert_media_file_from_seed_vc;
pub mod insert_media_file_from_studio_gen2;
pub mod insert_media_file_from_tacotron2;
pub mod insert_media_file_from_voice_conversion;
pub mod insert_media_file_from_zero_shot_tts;
pub mod insert_media_file_from_zero_shot_tts;
@@ -24,7 +24,6 @@ pub mod model_weights;
pub mod prompts;
pub mod public_event_feed;
pub mod stats;
pub mod tags;
pub mod trending_model_analytics;
pub mod tts;
pub mod twitch;
@@ -27,10 +27,6 @@ pub struct ModelWeightForElasticsearchRecord {
pub title: String,
// NB: These language tags are built into the `model_weights` table.
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
// Cover images
pub maybe_cover_image_media_file_token: Option<MediaFileToken>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
@@ -53,15 +49,11 @@ pub struct ModelWeightForElasticsearchRecord {
pub cached_usage_count: u64,
// TTS extensions
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_tts_ietf_language_tag: Option<String>,
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_tts_ietf_primary_language_subtag: Option<String>,
// VC extensions
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_voice_conversion_ietf_language_tag: Option<String>,
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_voice_conversion_ietf_primary_language_subtag: Option<String>,
pub created_at: DateTime<Utc>,
@@ -106,8 +98,6 @@ pub async fn batch_get_model_weights_for_elastic_search_backfill<'e, 'c, E>(
title: model.title,
weights_type: model.weights_type,
weights_category: model.weights_category,
maybe_ietf_language_tag: model.maybe_ietf_language_tag,
maybe_ietf_primary_language_subtag: model.maybe_ietf_primary_language_subtag,
maybe_cover_image_media_file_token: model.maybe_cover_image_media_file_token,
maybe_cover_image_public_bucket_hash: model.maybe_cover_image_public_bucket_hash,
maybe_cover_image_public_bucket_prefix: model.maybe_cover_image_public_bucket_prefix,
@@ -159,9 +149,6 @@ SELECT
w.title,
w.maybe_ietf_language_tag,
w.maybe_ietf_primary_language_subtag,
cover_image.token as maybe_cover_image_media_file_token,
cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,
cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,
@@ -245,10 +232,6 @@ struct RawRecord {
pub title: String,
// NB: These language tags are built into the `model_weights` table.
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
// Cover images
pub maybe_cover_image_media_file_token: Option<MediaFileToken>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
@@ -271,15 +254,11 @@ struct RawRecord {
pub cached_usage_count: u64,
// TTS extensions
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_tts_ietf_language_tag: Option<String>,
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_tts_ietf_primary_language_subtag: Option<String>,
// Voice conversion extensions
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_vc_ietf_language_tag: Option<String>,
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_vc_ietf_primary_language_subtag: Option<String>,
pub created_at: DateTime<Utc>,
@@ -319,9 +298,6 @@ impl FromRow<'_, MySqlRow> for RawRecord {
title: row.try_get("title")?,
maybe_ietf_language_tag: row.try_get("maybe_ietf_language_tag")?,
maybe_ietf_primary_language_subtag: row.try_get("maybe_ietf_primary_language_subtag")?,
maybe_cover_image_media_file_token: maybe_cover_image_media_file_token.map(|token| MediaFileToken::new(token)),
maybe_cover_image_public_bucket_hash: row.try_get("maybe_cover_image_public_bucket_hash")?,
maybe_cover_image_public_bucket_prefix: row.try_get("maybe_cover_image_public_bucket_prefix")?,
@@ -1,22 +1,19 @@
use anyhow::anyhow;
use sqlx::{MySql, QueryBuilder};
use sqlx::{MySql, MySqlPool, QueryBuilder};
use crate::utils::transactor::Transactor;
use enums::common::visibility::Visibility;
use errors::AnyhowResult;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::model_weights::ModelWeightToken;
pub struct UpdateWeightArgs<'a, 't> {
pub struct UpdateWeightArgs<'a> {
pub weight_token: &'a ModelWeightToken,
pub title: Option<&'a str>,
pub cover_image: Option<CoverImageOption<'a>>,
pub maybe_description_markdown: Option<&'a str>,
pub maybe_description_rendered_html: Option<&'a str>,
pub creator_set_visibility: Option<&'a Visibility>,
pub ietf_language_tag: Option<&'a str>,
pub ietf_primary_language_subtag: Option<&'a str>,
pub transactor: Transactor<'a, 't>,
pub mysql_pool: &'a MySqlPool,
}
pub enum CoverImageOption<'a> {
@@ -24,7 +21,7 @@ pub enum CoverImageOption<'a> {
SetCoverImage(&'a MediaFileToken),
}
pub async fn update_weights(args: UpdateWeightArgs<'_, '_>) -> AnyhowResult<()> {
pub async fn update_weights(args: UpdateWeightArgs<'_>) -> AnyhowResult<()> {
if args.title.is_none()
&& args.maybe_description_markdown.is_none()
&& args.maybe_description_rendered_html.is_none()
@@ -44,19 +41,19 @@ SET
let mut separated = query_builder.separated(", ");
if let Some(title) = args.title {
separated.push(" title = ");
separated.push("title = ");
separated.push_bind_unseparated(title);
}
if let Some(maybe_description_markdown) = args.maybe_description_markdown {
separated.push(" maybe_description_markdown = ");
separated.push("maybe_description_markdown = ");
separated.push_bind_unseparated(maybe_description_markdown);
}
if let Some(maybe_description_rendered_html) = args.maybe_description_rendered_html {
separated.push(" maybe_description_rendered_html = ");
separated.push("maybe_description_rendered_html = ");
separated.push_bind_unseparated(maybe_description_rendered_html);
}
if let Some(creator_set_visibility) = args.creator_set_visibility {
separated.push(" creator_set_visibility = ");
separated.push("creator_set_visibility = ");
separated.push_bind_unseparated(creator_set_visibility.to_str());
}
if let Some(cover_image_option) = args.cover_image {
@@ -65,20 +62,11 @@ SET
separated.push(" maybe_cover_image_media_file_token = NULL ");
}
CoverImageOption::SetCoverImage(media_file_token) => {
separated.push(" maybe_cover_image_media_file_token = ");
separated.push("maybe_cover_image_media_file_token = ");
separated.push_bind_unseparated(media_file_token.as_str());
}
}
}
if let Some(ietf_language_tag) = args.ietf_language_tag {
if let Some(ietf_primary_language_subtag) = args.ietf_primary_language_subtag {
separated.push(" maybe_ietf_language_tag = ");
separated.push_bind_unseparated(ietf_language_tag);
separated.push(" maybe_ietf_primary_language_subtag = ");
separated.push_bind_unseparated(ietf_primary_language_subtag);
}
}
separated.push("version = version + 1");
@@ -86,10 +74,16 @@ SET
separated.push_bind_unseparated(args.weight_token.as_str());
separated.push_unseparated(" LIMIT 1");
let query = query_builder.build();
let _r = args.transactor.execute(query).await?;
let transaction = args.mysql_pool.begin().await?;
let query_result = query_builder.build().execute(args.mysql_pool).await;
transaction.commit().await?;
Ok(())
match query_result {
Ok(_) => Ok(()),
Err(err) => {
Err(anyhow!("weights update error: {:?}", err))
}
}
}
#[cfg(test)]
@@ -27,9 +27,6 @@ pub struct RetrievedModelWeight {
pub maybe_description_markdown: Option<String>,
pub maybe_description_rendered_html: Option<String>,
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
pub creator_user_token: UserToken,
pub creator_username: String,
pub creator_display_name: String,
@@ -43,7 +40,6 @@ pub struct RetrievedModelWeight {
pub original_filename: Option<String>,
pub file_size_bytes: i64,
pub file_checksum_sha2: String,
pub public_bucket_hash: String,
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
@@ -118,8 +114,6 @@ pub async fn get_weight_by_token_with_transactor(
weights_category: record.weights_category,
maybe_description_markdown: record.maybe_description_markdown,
maybe_description_rendered_html: record.maybe_description_rendered_html,
maybe_ietf_language_tag: record.maybe_ietf_language_tag,
maybe_ietf_primary_language_subtag: record.maybe_ietf_primary_language_subtag,
creator_user_token: record.creator_user_token,
creator_username: record.creator_username,
creator_display_name: record.creator_display_name,
@@ -167,9 +161,6 @@ async fn select_include_deleted(
wt.maybe_description_markdown,
wt.maybe_description_rendered_html,
wt.maybe_ietf_language_tag,
wt.maybe_ietf_primary_language_subtag,
wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,
users.username as creator_username,
users.display_name as creator_display_name,
@@ -254,10 +245,6 @@ async fn select_without_deleted(
wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,
wt.maybe_description_markdown,
wt.maybe_description_rendered_html,
wt.maybe_ietf_language_tag,
wt.maybe_ietf_primary_language_subtag,
wt.creator_ip_address,
wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,
@@ -331,47 +318,44 @@ async fn select_without_deleted(
// RawWeight is the struct that is returned from the database in raw form.
#[derive(Serialize)]
struct RawWeight {
token: ModelWeightToken,
title: String,
weights_type: WeightsType,
weights_category: WeightsCategory,
maybe_description_markdown: Option<String>,
maybe_description_rendered_html: Option<String>,
pub struct RawWeight {
pub token: ModelWeightToken,
pub title: String,
pub weights_type: WeightsType,
pub weights_category: WeightsCategory,
pub maybe_description_markdown: Option<String>,
pub maybe_description_rendered_html: Option<String>,
maybe_ietf_language_tag: Option<String>,
maybe_ietf_primary_language_subtag: Option<String>,
pub creator_user_token: UserToken,
pub creator_username: String,
pub creator_display_name: String,
pub creator_gravatar_hash: String,
creator_user_token: UserToken,
creator_username: String,
creator_display_name: String,
creator_gravatar_hash: String,
pub creator_ip_address: String,
pub creator_set_visibility: Visibility,
pub maybe_last_update_user_token: Option<UserToken>,
pub original_download_url: Option<String>,
pub original_filename: Option<String>,
pub file_size_bytes: i64,
pub file_checksum_sha2: String,
pub public_bucket_hash: String,
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
creator_ip_address: String,
creator_set_visibility: Visibility,
maybe_last_update_user_token: Option<UserToken>,
original_download_url: Option<String>,
original_filename: Option<String>,
file_size_bytes: i64,
file_checksum_sha2: String,
public_bucket_hash: String,
maybe_public_bucket_prefix: Option<String>,
maybe_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
maybe_cover_image_public_bucket_hash: Option<String>,
maybe_cover_image_public_bucket_prefix: Option<String>,
maybe_cover_image_public_bucket_extension: Option<String>,
pub maybe_ratings_positive_count: Option<u32>,
pub maybe_ratings_negative_count: Option<u32>,
pub maybe_bookmark_count: Option<u32>,
pub cached_usage_count: u64,
maybe_ratings_positive_count: Option<u32>,
maybe_ratings_negative_count: Option<u32>,
maybe_bookmark_count: Option<u32>,
cached_usage_count: u64,
pub is_featured: i64,
is_featured: i64,
version: i32,
created_at: DateTime<Utc>,
updated_at: DateTime<Utc>,
user_deleted_at: Option<DateTime<Utc>>,
mod_deleted_at: Option<DateTime<Utc>>,
pub version: i32,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub user_deleted_at: Option<DateTime<Utc>>,
pub mod_deleted_at: Option<DateTime<Utc>>,
}
@@ -40,9 +40,6 @@ pub struct FeaturedWeight {
//pub maybe_description_markdown: String,
//pub maybe_description_rendered_html: String,
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
pub maybe_creator_user_token: Option<UserToken>,
pub maybe_creator_username: Option<String>,
pub maybe_creator_display_name: Option<String>,
@@ -158,8 +155,6 @@ fn select_result_fields() -> String {
mw.title,
mw.weights_type,
mw.weights_category,
mw.maybe_ietf_language_tag,
mw.maybe_ietf_primary_language_subtag,
u.token as maybe_creator_user_token,
u.username as maybe_creator_username,
u.display_name as maybe_creator_display_name,
@@ -334,9 +329,6 @@ async fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<FeaturedWeight> {
weights_type: weight.weights_type,
weights_category: weight.weights_category,
maybe_ietf_language_tag: weight.maybe_ietf_language_tag,
maybe_ietf_primary_language_subtag: weight.maybe_ietf_primary_language_subtag,
maybe_creator_user_token: weight.maybe_creator_user_token,
maybe_creator_username: weight.maybe_creator_username,
maybe_creator_display_name: weight.maybe_creator_display_name,
@@ -383,9 +375,6 @@ struct RawWeightJoinUser {
title: String,
maybe_ietf_language_tag: Option<String>,
maybe_ietf_primary_language_subtag: Option<String>,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//pub description_markdown: String,
@@ -437,8 +426,6 @@ impl FromRow<'_, MySqlRow> for RawWeightJoinUser {
weights_type: row.try_get("weights_type")?,
weights_category: row.try_get("weights_category")?,
title: row.try_get("title")?,
maybe_ietf_language_tag: row.try_get("maybe_ietf_language_tag")?,
maybe_ietf_primary_language_subtag: row.try_get("maybe_ietf_primary_language_subtag")?,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//maybe_description_markdown: row.try_get("maybe_description_markdown")?,
@@ -26,10 +26,6 @@ pub struct ModelWeightForElasticsearchRecord {
pub title: String,
// NB: These language tags are built into the `model_weights` table.
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
// Cover images
pub maybe_cover_image_media_file_token: Option<MediaFileToken>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
@@ -52,15 +48,11 @@ pub struct ModelWeightForElasticsearchRecord {
pub cached_usage_count: u64,
// TTS extensions
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_tts_ietf_language_tag: Option<String>,
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_tts_ietf_primary_language_subtag: Option<String>,
// VC extensions
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_voice_conversion_ietf_language_tag: Option<String>,
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_voice_conversion_ietf_primary_language_subtag: Option<String>,
pub created_at: DateTime<Utc>,
@@ -100,8 +92,6 @@ pub async fn list_model_weights_for_elastic_search_backfill_using_cursor(
title: model.title,
weights_type: model.weights_type,
weights_category: model.weights_category,
maybe_ietf_language_tag: model.maybe_ietf_language_tag,
maybe_ietf_primary_language_subtag: model.maybe_ietf_primary_language_subtag,
maybe_cover_image_media_file_token: model.maybe_cover_image_media_file_token,
maybe_cover_image_public_bucket_hash: model.maybe_cover_image_public_bucket_hash,
maybe_cover_image_public_bucket_prefix: model.maybe_cover_image_public_bucket_prefix,
@@ -149,9 +139,6 @@ SELECT
w.title,
w.maybe_ietf_language_tag,
w.maybe_ietf_primary_language_subtag,
cover_image.token as `maybe_cover_image_media_file_token: tokens::tokens::media_files::MediaFileToken`,
cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,
cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,
@@ -225,10 +212,6 @@ struct RawRecord {
pub title: String,
// NB: These language tags are built into the `model_weights` table.
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
// Cover images
pub maybe_cover_image_media_file_token: Option<MediaFileToken>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
@@ -251,15 +234,11 @@ struct RawRecord {
pub cached_usage_count: u64,
// TTS extensions
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_tts_ietf_language_tag: Option<String>,
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_tts_ietf_primary_language_subtag: Option<String>,
// Voice conversion extensions
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_vc_ietf_language_tag: Option<String>,
#[deprecated(note="use the fields built into the model_weights table rather than in the join table")]
pub maybe_vc_ietf_primary_language_subtag: Option<String>,
pub created_at: DateTime<Utc>,
@@ -20,9 +20,6 @@ pub struct WeightsByTokensRecord {
pub title: String,
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
pub creator_user_token: UserToken,
pub creator_username: String,
pub creator_display_name: String,
@@ -75,8 +72,6 @@ async fn get_raw_weights_by_tokens(
mw.title,
mw.weights_type,
mw.weights_category,
mw.maybe_ietf_language_tag,
mw.maybe_ietf_primary_language_subtag,
users.token as creator_user_token,
users.username as creator_username,
users.display_name as creator_display_name,
@@ -116,8 +111,6 @@ async fn get_raw_weights_by_tokens(
mw.title,
mw.weights_type,
mw.weights_category,
mw.maybe_ietf_language_tag,
mw.maybe_ietf_primary_language_subtag,
users.token as creator_user_token,
users.username as creator_username,
users.display_name as creator_display_name,
@@ -184,9 +177,6 @@ fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsByTokensRecord>
weights_type: weight.weights_type,
weights_category: weight.weights_category,
maybe_ietf_language_tag: weight.maybe_ietf_language_tag,
maybe_ietf_primary_language_subtag: weight.maybe_ietf_primary_language_subtag,
creator_user_token: weight.creator_user_token,
creator_username: weight.creator_username,
creator_display_name: weight.creator_display_name,
@@ -215,40 +205,37 @@ fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsByTokensRecord>
weights
}
#[derive(Serialize)]
struct RawWeightJoinUser {
token: ModelWeightToken,
#[derive(Serialize)]
pub struct RawWeightJoinUser {
pub token: ModelWeightToken,
weights_type: WeightsType,
weights_category: WeightsCategory,
pub weights_type: WeightsType,
pub weights_category: WeightsCategory,
pub title: String,
pub creator_user_token: UserToken,
pub creator_username: String,
pub creator_display_name: String,
pub creator_email_gravatar_hash: String,
title: String,
pub public_bucket_hash: String,
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
maybe_ietf_language_tag: Option<String>,
maybe_ietf_primary_language_subtag: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
creator_user_token: UserToken,
creator_username: String,
creator_display_name: String,
creator_email_gravatar_hash: String,
pub maybe_ratings_positive_count: Option<u32>,
pub maybe_ratings_negative_count: Option<u32>,
pub maybe_bookmark_count: Option<u32>,
pub cached_usage_count: u64,
public_bucket_hash: String,
maybe_public_bucket_prefix: Option<String>,
maybe_public_bucket_extension: Option<String>,
maybe_cover_image_public_bucket_hash: Option<String>,
maybe_cover_image_public_bucket_prefix: Option<String>,
maybe_cover_image_public_bucket_extension: Option<String>,
maybe_ratings_positive_count: Option<u32>,
maybe_ratings_negative_count: Option<u32>,
maybe_bookmark_count: Option<u32>,
cached_usage_count: u64,
created_at: DateTime<Utc>,
updated_at: DateTime<Utc>,
user_deleted_at: Option<DateTime<Utc>>,
mod_deleted_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub user_deleted_at: Option<DateTime<Utc>>,
pub mod_deleted_at: Option<DateTime<Utc>>,
}
// NB(bt,2023-12-05): There's an issue with type hinting in the `as` clauses with QueryBuilder (or
@@ -270,8 +257,6 @@ impl FromRow<'_, MySqlRow> for RawWeightJoinUser {
weights_type: WeightsType::try_from_mysql_row(row, "weights_type")?,
weights_category: WeightsCategory::try_from_mysql_row(row, "weights_category")?,
title: row.try_get("title")?,
maybe_ietf_language_tag: row.try_get("maybe_ietf_language_tag")?,
maybe_ietf_primary_language_subtag: row.try_get("maybe_ietf_primary_language_subtag")?,
creator_user_token: UserToken::new_from_str(row.try_get("creator_user_token")?),
creator_username: row.try_get("creator_username")?,
creator_display_name: row.try_get("creator_display_name")?,
@@ -31,9 +31,6 @@ pub struct WeightsJoinUserRecord {
pub title: String,
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//pub maybe_description_markdown: String,
@@ -147,8 +144,6 @@ fn select_result_fields() -> String {
mw.title,
mw.weights_type,
mw.weights_category,
mw.maybe_ietf_language_tag,
mw.maybe_ietf_primary_language_subtag,
u.token as creator_user_token,
u.username as creator_username,
u.display_name as creator_display_name,
@@ -260,10 +255,6 @@ async fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsJoinUserRe
title: weight.title,
weights_type: weight.weights_type,
weights_category: weight.weights_category,
maybe_ietf_language_tag: weight.maybe_ietf_language_tag,
maybe_ietf_primary_language_subtag: weight.maybe_ietf_primary_language_subtag,
//maybe_description_markdown: weight.maybe_description_markdown,
//maybe_description_rendered_html: weight.maybe_description_rendered_html,
@@ -305,58 +296,55 @@ async fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsJoinUserRe
}
struct RawWeightJoinUser {
token: ModelWeightToken,
pub struct RawWeightJoinUser {
pub token: ModelWeightToken,
weights_type: WeightsType,
weights_category: WeightsCategory,
pub weights_type: WeightsType,
pub weights_category: WeightsCategory,
pub title: String,
title: String,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//pub description_markdown: String,
//pub description_rendered_html: String,
pub creator_user_token: UserToken,
pub creator_ip_address: String,
pub creator_set_visibility: Visibility,
pub maybe_last_update_user_token: Option<UserToken>,
pub original_download_url: Option<String>,
pub original_filename: Option<String>,
pub file_size_bytes: i32,
pub file_checksum_sha2: String,
pub public_bucket_hash: String,
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
maybe_ietf_language_tag: Option<String>,
maybe_ietf_primary_language_subtag: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//pub description_markdown: String,
//pub description_rendered_html: String,
pub maybe_ratings_positive_count: Option<u32>,
pub maybe_ratings_negative_count: Option<u32>,
pub maybe_bookmark_count: Option<u32>,
pub cached_usage_count: u64,
creator_user_token: UserToken,
creator_ip_address: String,
creator_set_visibility: Visibility,
maybe_last_update_user_token: Option<UserToken>,
original_download_url: Option<String>,
original_filename: Option<String>,
file_size_bytes: i32,
file_checksum_sha2: String,
public_bucket_hash: String,
maybe_public_bucket_prefix: Option<String>,
maybe_public_bucket_extension: Option<String>,
maybe_cover_image_public_bucket_hash: Option<String>,
maybe_cover_image_public_bucket_prefix: Option<String>,
maybe_cover_image_public_bucket_extension: Option<String>,
maybe_ratings_positive_count: Option<u32>,
maybe_ratings_negative_count: Option<u32>,
maybe_bookmark_count: Option<u32>,
cached_usage_count: u64,
version: i32,
created_at: DateTime<Utc>,
updated_at: DateTime<Utc>,
user_deleted_at: Option<DateTime<Utc>>,
mod_deleted_at: Option<DateTime<Utc>>,
creator_username: String,
creator_display_name: String,
creator_email_gravatar_hash: String,
pub version: i32,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub user_deleted_at: Option<DateTime<Utc>>,
pub mod_deleted_at: Option<DateTime<Utc>>,
pub creator_username: String,
pub creator_display_name: String,
pub creator_email_gravatar_hash: String,
}
impl FromRow<'_, MySqlRow> for RawWeightJoinUser {
@@ -366,8 +354,6 @@ impl FromRow<'_, MySqlRow> for RawWeightJoinUser {
weights_type: row.try_get("weights_type")?,
weights_category: row.try_get("weights_category")?,
title: row.try_get("title")?,
maybe_ietf_language_tag: row.try_get("maybe_ietf_language_tag")?,
maybe_ietf_primary_language_subtag: row.try_get("maybe_ietf_primary_language_subtag")?,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//maybe_description_markdown: row.try_get("maybe_description_markdown")?,
@@ -37,9 +37,6 @@ pub struct WeightJoinUser {
pub title: String,
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
pub maybe_description_markdown: Option<String>,
pub maybe_description_rendered_html: Option<String>,
@@ -219,8 +216,6 @@ impl ListWeightsQueryBuilder {
record.weights_category.as_str()
).unwrap(),
title: record.title,
maybe_ietf_language_tag: record.maybe_ietf_language_tag,
maybe_ietf_primary_language_subtag: record.maybe_ietf_primary_language_subtag,
maybe_description_markdown: record.maybe_description_markdown,
maybe_description_rendered_html: record.maybe_description_rendered_html,
creator_user_token: UserToken::new_from_str(&record.creator_user_token),
@@ -276,8 +271,6 @@ impl ListWeightsQueryBuilder {
model_weights.title,
model_weights.maybe_description_markdown,
model_weights.maybe_description_rendered_html,
model_weights.maybe_ietf_language_tag,
model_weights.maybe_ietf_primary_language_subtag,
model_weights.creator_user_token,
model_weights.creator_ip_address,
model_weights.creator_set_visibility,
@@ -424,56 +417,53 @@ impl ListWeightsQueryBuilder {
#[derive(Serialize)]
#[derive(sqlx::FromRow)]
struct RawWeightJoinUser {
weight_id: i64,
token: ModelWeightToken,
pub weight_id: i64,
pub token: ModelWeightToken,
weights_type: String,
weights_category: String,
pub weights_type: String,
pub weights_category: String,
title: String,
pub title: String,
maybe_description_markdown: Option<String>,
maybe_description_rendered_html: Option<String>,
pub maybe_description_markdown: Option<String>,
pub maybe_description_rendered_html: Option<String>,
maybe_ietf_language_tag: Option<String>,
maybe_ietf_primary_language_subtag: Option<String>,
pub creator_user_token: String,
pub creator_ip_address: String,
pub creator_set_visibility: String,
creator_user_token: String,
creator_ip_address: String,
creator_set_visibility: String,
pub maybe_last_update_user_token: Option<String>,
maybe_last_update_user_token: Option<String>,
pub original_download_url: Option<String>,
pub original_filename: Option<String>,
original_download_url: Option<String>,
original_filename: Option<String>,
pub file_size_bytes: i32,
pub file_checksum_sha2: String,
file_size_bytes: i32,
file_checksum_sha2: String,
pub public_bucket_hash: String,
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
public_bucket_hash: String,
maybe_public_bucket_prefix: Option<String>,
maybe_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
maybe_cover_image_public_bucket_hash: Option<String>,
maybe_cover_image_public_bucket_prefix: Option<String>,
maybe_cover_image_public_bucket_extension: Option<String>,
pub creator_username: String,
pub creator_display_name: String,
pub creator_email_gravatar_hash: String,
creator_username: String,
creator_display_name: String,
creator_email_gravatar_hash: String,
pub maybe_ratings_positive_count: Option<u32>,
pub maybe_ratings_negative_count: Option<u32>,
pub maybe_bookmark_count: Option<u32>,
pub cached_usage_count: u64,
maybe_ratings_positive_count: Option<u32>,
maybe_ratings_negative_count: Option<u32>,
maybe_bookmark_count: Option<u32>,
cached_usage_count: u64,
pub version: i32,
version: i32,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
created_at: DateTime<Utc>,
updated_at: DateTime<Utc>,
user_deleted_at: Option<DateTime<Utc>>,
mod_deleted_at: Option<DateTime<Utc>>,
pub user_deleted_at: Option<DateTime<Utc>>,
pub mod_deleted_at: Option<DateTime<Utc>>,
}
#[cfg(test)]
@@ -1,27 +0,0 @@
use crate::errors::database_insert_error::DatabaseInsertError;
use crate::utils::transactor::Transactor;
use tokens::tokens::tags::TagToken;
pub async fn create_tag(
tag: &str,
transactor: Transactor<'_, '_>,
) -> Result<TagToken, DatabaseInsertError>
{
let tag = tag.trim().to_lowercase();
let token = TagToken::generate();
let query = sqlx::query!(
r#"
INSERT INTO tags
SET
token = ?,
tag_value = ?
"#,
token,
tag,
);
let _r = transactor.execute(query).await?;
Ok(token)
}
@@ -1,64 +0,0 @@
use composite_identifiers::by_table::tag_uses::tag_use_entity::TagUseEntity;
use errors::AnyhowResult;
use tokens::tokens::tags::TagToken;
use crate::utils::transactor::Transactor;
pub struct EntityTag {
pub token: TagToken,
pub tag_value: String,
}
pub async fn list_tags_for_entity(
tag_entity: TagUseEntity,
transactor: Transactor<'_, '_>,
) -> AnyhowResult<Vec<EntityTag>> {
let (entity_type, entity_token) = tag_entity.get_composite_keys();
let query = sqlx::query_as!(
RawTag,
r#"
SELECT
t.token as `token: tokens::tokens::tags::TagToken`,
t.tag_value
FROM
tags AS t
JOIN tag_uses AS u
ON t.token = u.tag_token
WHERE
u.entity_type = ?
AND u.entity_token = ?
AND u.maybe_deleted_at IS NULL
ORDER BY t.id DESC
LIMIT 500
"#,
entity_type,
entity_token
);
let results = match transactor {
Transactor::Pool { pool } => {
query.fetch_all(pool).await?
},
Transactor::Connection { connection } => {
query.fetch_all(connection).await?
},
Transactor::Transaction { transaction } => {
query.fetch_all(&mut **transaction).await?
},
};
Ok(results.into_iter()
.map(|record| EntityTag {
token: record.token,
tag_value: record.tag_value,
})
.collect())
}
struct RawTag {
token: TagToken,
tag_value: String,
}
@@ -1,4 +0,0 @@
pub mod create_tag;
pub mod list_tags_for_entity;
pub mod select_matching_tags;
pub mod update_tags_for_entity;
@@ -1,78 +0,0 @@
use crate::utils::transactor::Transactor;
use errors::AnyhowResult;
use sqlx::mysql::MySqlRow;
use sqlx::{FromRow, MySql, QueryBuilder, Row};
use tokens::tokens::tags::TagToken;
pub struct MatchingTag {
pub token: TagToken,
pub tag_value: String,
}
pub async fn select_matching_tags(
tag_values: &[String],
transactor: Transactor<'_, '_>,
) -> AnyhowResult<Vec<MatchingTag>> {
if tag_values.is_empty() {
return Ok(Vec::new()) // This prevents a SQL error when the IN clause is empty.
}
let tag_values = tag_values.iter()
.map(|tag| tag.trim().to_lowercase())
.collect::<Vec<_>>();
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
r#"
SELECT
token,
tag_value
FROM
tags
WHERE
tag_value IN (
"#,
);
let mut separated = query_builder.separated(", ");
for tag_value in tag_values.iter() {
separated.push_bind(tag_value);
}
separated.push_unseparated(") ");
let query = query_builder.build_query_as::<RawTag>();
let results = match transactor {
Transactor::Pool { pool } => {
query.fetch_all(pool).await?
},
Transactor::Connection { connection } => {
query.fetch_all(connection).await?
},
Transactor::Transaction { transaction } => {
query.fetch_all(&mut **transaction).await?
},
};
Ok(results.into_iter()
.map(|record| MatchingTag {
token: record.token,
tag_value: record.tag_value,
})
.collect())
}
struct RawTag {
token: TagToken,
tag_value: String,
}
impl FromRow<'_, MySqlRow> for RawTag {
fn from_row(row: &MySqlRow) -> Result<Self, sqlx::Error> {
Ok(Self {
token: TagToken::new(row.try_get("token")?),
tag_value: row.try_get("tag_value")?,
})
}
}

Some files were not shown because too many files have changed in this diff Show More