mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-27 12:10:08 -04:00
Compare commits
92
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a938ceed1 | ||
|
|
62d708e357 | ||
|
|
72083eb030 | ||
|
|
62afa22d8c | ||
|
|
418b116469 | ||
|
|
42c7c70387 | ||
|
|
39c52d5377 | ||
|
|
cea3668cfc | ||
|
|
1caf1f38b8 | ||
|
|
f0b2a07613 | ||
|
|
3cd04414f8 | ||
|
|
f3776e953c | ||
|
|
d923699009 | ||
|
|
f842d795d6 | ||
|
|
7a1ce7c9fd | ||
|
|
d0a3c02c00 | ||
|
|
32bc400686 | ||
|
|
e3973e4ce1 | ||
|
|
1d7bc11be3 | ||
|
|
5321eb145d | ||
|
|
48043fb602 | ||
|
|
8af2035ee6 | ||
|
|
1e2f73e44a | ||
|
|
b49a7225e4 | ||
|
|
de01700359 | ||
|
|
f7990e2b61 | ||
|
|
081307d735 | ||
|
|
397241fb84 | ||
|
|
dbc0f5f62e | ||
|
|
b521fa7676 | ||
|
|
a67f60d09e | ||
|
|
2cdf9ce41f | ||
|
|
38fb1a4a32 | ||
|
|
984fd1a21f | ||
|
|
8b92dc4099 | ||
|
|
86677b8f97 | ||
|
|
ed7a9905ee | ||
|
|
1c25c4085b | ||
|
|
91e739d7c4 | ||
|
|
40a82142bf | ||
|
|
f6454035d2 | ||
|
|
e93a8664c1 | ||
|
|
0ef4333013 | ||
|
|
cd11d0aa4e | ||
|
|
e8644d3b82 | ||
|
|
806f70d7ba | ||
|
|
b6eb0e9394 | ||
|
|
02050ef86c | ||
|
|
9b698d155e | ||
|
|
ed359164ff | ||
|
|
2da81d47a7 | ||
|
|
cb1253f509 | ||
|
|
f21da59530 | ||
|
|
4ebb7fe282 | ||
|
|
83764e2381 | ||
|
|
475ed299db | ||
|
|
53786bf9b9 | ||
|
|
3a7fcc1595 | ||
|
|
770293af49 | ||
|
|
bb19960c02 | ||
|
|
f3cde45f33 | ||
|
|
6adb104e58 | ||
|
|
3a1220853d | ||
|
|
b1732a0d11 | ||
|
|
c767a17da7 | ||
|
|
a2a7a10d0c | ||
|
|
d6ac0c9d0b | ||
|
|
ea90bb6758 | ||
|
|
252576b88a | ||
|
|
f7ed250c7c | ||
|
|
0b5530c8a3 | ||
|
|
606a439352 | ||
|
|
aec5675784 | ||
|
|
db05b61c51 | ||
|
|
7141aa028f | ||
|
|
90bfb2c2bf | ||
|
|
7f43e98f07 | ||
|
|
9ebd040d59 | ||
|
|
f890f8781c | ||
|
|
3e35db2f8e | ||
|
|
4b53df69a0 | ||
|
|
bca8925f31 | ||
|
|
d0a51f0344 | ||
|
|
4397e29886 | ||
|
|
ac4a7f4612 | ||
|
|
87a768890a | ||
|
|
9bfd0330a9 | ||
|
|
a8766e9620 | ||
|
|
3b3b218e0c | ||
|
|
1f595f3d64 | ||
|
|
7297f77334 | ||
|
|
7186f37841 |
Generated
+1
@@ -50,6 +50,7 @@
|
||||
<w>unpermitted</w>
|
||||
<w>upserting</w>
|
||||
<w>upserts</w>
|
||||
<w>upvoted</w>
|
||||
<w>vits</w>
|
||||
<w>vocoded</w>
|
||||
<w>vocoder</w>
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO media_files\nSET\n token = ?,\n\n media_class = ?,\n media_type = ?,\n\n origin_category = ?,\n origin_product_category = ?,\n 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"
|
||||
}
|
||||
+50
-28
@@ -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 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\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 ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -65,6 +65,26 @@
|
||||
},
|
||||
{
|
||||
"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",
|
||||
@@ -74,7 +94,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 9,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -84,7 +104,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 10,
|
||||
"name": "creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -94,7 +114,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 11,
|
||||
"name": "creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -104,7 +124,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 12,
|
||||
"name": "creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -114,7 +134,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 13,
|
||||
"name": "creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -124,7 +144,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 14,
|
||||
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -134,7 +154,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 15,
|
||||
"name": "original_download_url",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -144,7 +164,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 16,
|
||||
"name": "original_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -154,7 +174,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 17,
|
||||
"name": "file_size_bytes",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -164,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 18,
|
||||
"name": "file_checksum_sha2",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -174,7 +194,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 19,
|
||||
"name": "public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -184,7 +204,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 20,
|
||||
"name": "maybe_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -194,7 +214,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"ordinal": 21,
|
||||
"name": "maybe_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -204,7 +224,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"ordinal": 22,
|
||||
"name": "maybe_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -214,7 +234,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"ordinal": 23,
|
||||
"name": "maybe_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -224,7 +244,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"ordinal": 24,
|
||||
"name": "maybe_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -234,7 +254,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"ordinal": 25,
|
||||
"name": "maybe_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -244,7 +264,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"ordinal": 26,
|
||||
"name": "maybe_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -254,7 +274,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"ordinal": 27,
|
||||
"name": "maybe_bookmark_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -264,7 +284,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"ordinal": 28,
|
||||
"name": "cached_usage_count",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -274,7 +294,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"ordinal": 29,
|
||||
"name": "is_featured",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -284,7 +304,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 28,
|
||||
"ordinal": 30,
|
||||
"name": "version",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -294,7 +314,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"ordinal": 31,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -304,7 +324,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"ordinal": 32,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -314,7 +334,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 31,
|
||||
"ordinal": 33,
|
||||
"name": "user_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -324,7 +344,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 32,
|
||||
"ordinal": 34,
|
||||
"name": "mod_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -344,6 +364,8 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
@@ -373,5 +395,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "1053294a21439ddb41fdd1053547b3f5c50457f6ba9450e5167a1db5caf896d1"
|
||||
"hash": "29fe7f8464257537840d7f095ec01f850d79f970109549d14978fc3bed7cef32"
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
+50
-28
@@ -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.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.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 ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -65,6 +65,26 @@
|
||||
},
|
||||
{
|
||||
"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",
|
||||
@@ -74,7 +94,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 9,
|
||||
"name": "creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -84,7 +104,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 10,
|
||||
"name": "creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -94,7 +114,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 11,
|
||||
"name": "creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -104,7 +124,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 12,
|
||||
"name": "creator_ip_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -114,7 +134,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 13,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -124,7 +144,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 14,
|
||||
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -134,7 +154,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 15,
|
||||
"name": "original_download_url",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -144,7 +164,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 16,
|
||||
"name": "original_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -154,7 +174,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 17,
|
||||
"name": "file_size_bytes",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -164,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 18,
|
||||
"name": "file_checksum_sha2",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -174,7 +194,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 19,
|
||||
"name": "public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -184,7 +204,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 20,
|
||||
"name": "maybe_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -194,7 +214,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"ordinal": 21,
|
||||
"name": "maybe_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -204,7 +224,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"ordinal": 22,
|
||||
"name": "maybe_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -214,7 +234,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"ordinal": 23,
|
||||
"name": "maybe_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -224,7 +244,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"ordinal": 24,
|
||||
"name": "maybe_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -234,7 +254,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"ordinal": 25,
|
||||
"name": "maybe_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -244,7 +264,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"ordinal": 26,
|
||||
"name": "maybe_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -254,7 +274,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"ordinal": 27,
|
||||
"name": "maybe_bookmark_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -264,7 +284,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"ordinal": 28,
|
||||
"name": "cached_usage_count",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -274,7 +294,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"ordinal": 29,
|
||||
"name": "is_featured",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -284,7 +304,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 28,
|
||||
"ordinal": 30,
|
||||
"name": "version",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -294,7 +314,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"ordinal": 31,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -304,7 +324,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"ordinal": 32,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -314,7 +334,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 31,
|
||||
"ordinal": 33,
|
||||
"name": "user_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -324,7 +344,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 32,
|
||||
"ordinal": 34,
|
||||
"name": "mod_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -344,6 +364,8 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
@@ -373,5 +395,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "5e953a6ad7bcaaed0918109593652b03c7ab497cc65b59bbb6add011de6401f0"
|
||||
"hash": "53c90f5230aa202aead37a224ec70e350172bc0ec4eeaebde22878ca4aa0f695"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO tags\nSET\n token = ?,\n tag_value = ?\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c7e848e4c906a34ac5a4ad8cc73354baa8d5cd81170dd06d66d7f414505d538b"
|
||||
}
|
||||
+45
-23
@@ -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 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 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 ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -65,6 +65,26 @@
|
||||
},
|
||||
{
|
||||
"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",
|
||||
@@ -74,7 +94,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 9,
|
||||
"name": "maybe_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -84,7 +104,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 10,
|
||||
"name": "maybe_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -94,7 +114,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 11,
|
||||
"name": "maybe_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -104,7 +124,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 12,
|
||||
"name": "creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -114,7 +134,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 13,
|
||||
"name": "creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -124,7 +144,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 14,
|
||||
"name": "creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -134,7 +154,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 15,
|
||||
"name": "creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -144,7 +164,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 16,
|
||||
"name": "is_featured",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -154,7 +174,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 17,
|
||||
"name": "maybe_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -164,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 18,
|
||||
"name": "maybe_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -174,7 +194,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 19,
|
||||
"name": "maybe_bookmark_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -184,7 +204,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 20,
|
||||
"name": "cached_usage_count",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -194,7 +214,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"ordinal": 21,
|
||||
"name": "maybe_tts_ietf_language_tag",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -204,7 +224,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"ordinal": 22,
|
||||
"name": "maybe_tts_ietf_primary_language_subtag",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -214,7 +234,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"ordinal": 23,
|
||||
"name": "maybe_vc_ietf_language_tag",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -224,7 +244,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"ordinal": 24,
|
||||
"name": "maybe_vc_ietf_primary_language_subtag",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -234,7 +254,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"ordinal": 25,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -244,7 +264,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"ordinal": 26,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -254,7 +274,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"ordinal": 27,
|
||||
"name": "user_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -264,7 +284,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"ordinal": 28,
|
||||
"name": "mod_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -274,7 +294,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"ordinal": 29,
|
||||
"name": "database_read_time",
|
||||
"type_info": {
|
||||
"type": "Datetime",
|
||||
@@ -298,6 +318,8 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
@@ -318,5 +340,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "4bce2b10f0510feca7f5705049a5c0eaae6e1a840146628495827468a38c05dd"
|
||||
"hash": "d0f9d2cf4176c3f7f8fbff66eb6ff9415d989afc2b5944629a7bcea4b5a822f3"
|
||||
}
|
||||
Generated
+24
-13
@@ -3703,6 +3703,7 @@ dependencies = [
|
||||
"time",
|
||||
"tokens",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"tts_common",
|
||||
"url",
|
||||
@@ -4454,6 +4455,18 @@ 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"
|
||||
@@ -4528,6 +4541,7 @@ dependencies = [
|
||||
"anstream",
|
||||
"arrayvec",
|
||||
"base64 0.21.7",
|
||||
"base64 0.22.1",
|
||||
"base64ct",
|
||||
"bitflags 2.5.0",
|
||||
"block-buffer 0.9.0",
|
||||
@@ -4568,7 +4582,6 @@ dependencies = [
|
||||
"md-5 0.10.6",
|
||||
"memchr",
|
||||
"miniz_oxide",
|
||||
"mio 0.8.11",
|
||||
"native-tls",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
@@ -7809,21 +7822,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.0"
|
||||
version = "1.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes 1.6.0",
|
||||
"libc",
|
||||
"mio 0.8.11",
|
||||
"num_cpus",
|
||||
"mio 1.0.2",
|
||||
"parking_lot 0.12.2",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7870,9 +7882,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -7921,9 +7933,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.15"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
|
||||
checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
@@ -7974,16 +7986,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.10"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
|
||||
checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
|
||||
dependencies = [
|
||||
"bytes 1.6.0",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
-- 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
|
||||
@@ -0,0 +1,14 @@
|
||||
-- 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
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
|
||||
-- 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;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE model_weights DROP COLUMN maybe_ietf_language_tag;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
-- 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;
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE model_weights DROP COLUMN maybe_ietf_primary_language_subtag;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
-- 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,6 +53,22 @@ 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,3 +1,4 @@
|
||||
pub mod audit_logs;
|
||||
pub mod batch_generations;
|
||||
pub mod featured_items;
|
||||
pub mod tag_uses;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub mod tag_use_entity;
|
||||
@@ -0,0 +1,40 @@
|
||||
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,6 +57,9 @@ 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.")]
|
||||
@@ -67,6 +70,9 @@ 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!
|
||||
@@ -85,8 +91,10 @@ 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",
|
||||
}
|
||||
@@ -99,10 +107,12 @@ 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)),
|
||||
@@ -119,6 +129,8 @@ impl InferenceCategory {
|
||||
Self::VoiceConversion,
|
||||
Self::ImageGeneration,
|
||||
Self::Mocap,
|
||||
Self::F5TTS,
|
||||
Self::SeedVc,
|
||||
Self::Workflow,
|
||||
Self::FormatConversion,
|
||||
Self::LivePortrait,
|
||||
@@ -144,6 +156,8 @@ 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");
|
||||
@@ -158,6 +172,8 @@ 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");
|
||||
@@ -173,6 +189,8 @@ 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);
|
||||
@@ -185,13 +203,15 @@ mod tests {
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceCategory::all_variants();
|
||||
assert_eq!(variants.len(), 11);
|
||||
assert_eq!(variants.len(), 12);
|
||||
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
-1
@@ -27,6 +27,9 @@ pub enum InferenceJobProductCategory {
|
||||
/// TTS: GptSoVits
|
||||
TtsGptSoVits,
|
||||
|
||||
/// TTS: F5Tts (Zero Shot)
|
||||
TtsF5,
|
||||
|
||||
/// TTS: StyleTts2 (Zero Shot)
|
||||
TtsStyleTts2,
|
||||
|
||||
@@ -41,6 +44,8 @@ pub enum InferenceJobProductCategory {
|
||||
/// Voice Conversion: SoVitsSvc
|
||||
VcSvc,
|
||||
|
||||
VcSeedVc, // Ugh
|
||||
|
||||
// =============== VIDEO ===============
|
||||
|
||||
/// Video: Face Fusion (Lipsync)
|
||||
@@ -58,6 +63,9 @@ pub enum InferenceJobProductCategory {
|
||||
/// Video: Studio
|
||||
VidStudio,
|
||||
|
||||
/// Video: Studio Gen 2
|
||||
VidStudioGen2,
|
||||
|
||||
/// Video: Style Transfer
|
||||
VidStyleTransfer,
|
||||
|
||||
@@ -108,13 +116,16 @@ 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",
|
||||
@@ -133,13 +144,16 @@ 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),
|
||||
@@ -161,6 +175,8 @@ impl InferenceJobProductCategory {
|
||||
Self::TtsGptSoVits,
|
||||
Self::TtsStyleTts2,
|
||||
Self::TtsTacotron2,
|
||||
Self::TtsF5,
|
||||
Self::VcSeedVc,
|
||||
Self::VcSvc,
|
||||
Self::VcRvc2,
|
||||
Self::VidLipsyncFaceFusion,
|
||||
@@ -168,6 +184,7 @@ impl InferenceJobProductCategory {
|
||||
Self::VidLivePortrait,
|
||||
Self::VidLivePortraitWebcam,
|
||||
Self::VidStudio,
|
||||
Self::VidStudioGen2,
|
||||
Self::VidStyleTransfer,
|
||||
Self::LipsyncFaceFusion,
|
||||
Self::LipsyncSadTalker,
|
||||
@@ -195,13 +212,16 @@ 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");
|
||||
@@ -221,11 +241,13 @@ 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");
|
||||
@@ -245,11 +267,13 @@ 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);
|
||||
@@ -265,18 +289,20 @@ mod tests {
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceJobProductCategory::all_variants();
|
||||
assert_eq!(variants.len(), 20);
|
||||
assert_eq!(variants.len(), 21);
|
||||
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,6 +36,10 @@ 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,
|
||||
@@ -43,6 +47,10 @@ 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,
|
||||
@@ -53,6 +61,9 @@ pub enum InferenceJobType {
|
||||
/// so-vits-svc voice conversion. This predates RVCv2.
|
||||
SoVitsSvc,
|
||||
|
||||
#[serde(rename = "seed_vc")]
|
||||
SeedVc,
|
||||
|
||||
/// Stable diffusion image generation
|
||||
StableDiffusion,
|
||||
|
||||
@@ -93,12 +104,15 @@ 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",
|
||||
@@ -114,12 +128,15 @@ 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),
|
||||
@@ -138,12 +155,15 @@ 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,
|
||||
@@ -173,12 +193,15 @@ 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");
|
||||
@@ -193,12 +216,15 @@ 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");
|
||||
@@ -213,12 +239,15 @@ 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);
|
||||
@@ -236,12 +265,15 @@ 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,6 +29,10 @@ 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")]
|
||||
@@ -66,6 +70,7 @@ 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",
|
||||
@@ -79,6 +84,7 @@ 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),
|
||||
@@ -101,6 +107,7 @@ impl InferenceModelType {
|
||||
Self::RvcV2,
|
||||
Self::SadTalker,
|
||||
Self::SoVitsSvc,
|
||||
Self::SeedVc,
|
||||
Self::Tacotron2,
|
||||
Self::Vits,
|
||||
Self::VallEX,
|
||||
@@ -126,6 +133,7 @@ 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");
|
||||
@@ -145,6 +153,7 @@ 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");
|
||||
@@ -160,6 +169,7 @@ 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);
|
||||
@@ -181,6 +191,7 @@ 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,6 +18,9 @@ pub enum MediaFileOriginModelType {
|
||||
#[serde(rename = "face_fusion")]
|
||||
FaceFusion,
|
||||
|
||||
#[serde(rename = "f5_tts")]
|
||||
F5TTS,
|
||||
|
||||
#[serde(rename = "live_portrait")]
|
||||
LivePortrait,
|
||||
|
||||
@@ -39,6 +42,9 @@ pub enum MediaFileOriginModelType {
|
||||
#[serde(rename = "mocap_net")]
|
||||
MocapNet,
|
||||
|
||||
#[serde(rename = "seed_vc")]
|
||||
SeedVc,
|
||||
|
||||
#[serde(rename = "styletts2")]
|
||||
StyleTTS2,
|
||||
|
||||
@@ -77,9 +83,11 @@ 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",
|
||||
@@ -97,9 +105,11 @@ 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),
|
||||
@@ -120,9 +130,11 @@ 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,
|
||||
@@ -155,9 +167,11 @@ 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");
|
||||
@@ -174,9 +188,11 @@ 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);
|
||||
@@ -196,9 +212,11 @@ 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));
|
||||
|
||||
@@ -14,6 +14,7 @@ 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;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub mod tag_use_entity_type;
|
||||
@@ -0,0 +1,127 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -30,6 +30,8 @@ pub enum PublicInferenceJobType {
|
||||
|
||||
GptSovits,
|
||||
|
||||
#[serde(rename = "f5_tts")]
|
||||
F5TTS,
|
||||
// ======= Everything else is the same =======
|
||||
|
||||
/// Jobs that run ComfyUI workflows
|
||||
@@ -37,6 +39,10 @@ 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,
|
||||
@@ -51,6 +57,10 @@ 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,
|
||||
|
||||
@@ -94,11 +104,14 @@ 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,
|
||||
@@ -117,11 +130,14 @@ 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,6 +55,12 @@ pub enum PublicMediaFileModelType {
|
||||
#[serde(rename = "gpt_sovits")]
|
||||
GptSovits,
|
||||
|
||||
#[serde(rename = "f5_tts")]
|
||||
F5TTS,
|
||||
|
||||
#[serde(rename = "seed_vc")]
|
||||
SeedVc,
|
||||
|
||||
#[serde(rename = "studio")]
|
||||
StorytellerStudio,
|
||||
|
||||
@@ -86,10 +92,12 @@ 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,
|
||||
@@ -108,10 +116,12 @@ 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,6 +30,9 @@ 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,25 +6,26 @@
|
||||
//! 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::{Action, Environment, parse_cli_args};
|
||||
use crate::plans::create_all_model_weight_documents::create_all_model_weight_documents;
|
||||
use crate::cli_args::{parse_cli_args, Action, Environment};
|
||||
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;
|
||||
@@ -33,7 +34,7 @@ pub mod plans;
|
||||
pub async fn main() -> AnyhowResult<()> {
|
||||
println!("elasticsearch-cli: operational tooling for Elasticsearch");
|
||||
|
||||
easyenv::init_all_with_default_logging(Some(DEFAULT_RUST_LOG));
|
||||
easyenv::init_all_with_default_logging(Some("info"));
|
||||
|
||||
// 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.
|
||||
@@ -61,20 +62,16 @@ pub async fn main() -> AnyhowResult<()> {
|
||||
}
|
||||
Action::SearchModelWeights => {
|
||||
info!("Searching model weights...");
|
||||
|
||||
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?;
|
||||
let results = test_search_model_weights_documents(&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?;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
pub mod create_all_model_weight_documents;
|
||||
pub mod create_all_tts_documents;
|
||||
pub mod media_files;
|
||||
pub mod media_files;
|
||||
pub mod model_weights;
|
||||
+20
-11
@@ -60,6 +60,24 @@ 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,
|
||||
|
||||
@@ -89,17 +107,8 @@ 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: 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,
|
||||
},
|
||||
maybe_ietf_language_tag,
|
||||
maybe_ietf_primary_language_subtag,
|
||||
|
||||
created_at: record.created_at,
|
||||
updated_at: record.updated_at,
|
||||
@@ -0,0 +1,83 @@
|
||||
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(())
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
pub mod asserts;
|
||||
pub mod evaluate_model_weights_search;
|
||||
pub mod search;
|
||||
pub mod test_cases;
|
||||
pub mod print_debugging;
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
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
|
||||
}
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
pub mod test_search_term_zelda;
|
||||
pub mod test_upvoted_models;
|
||||
pub mod test_use_count;
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
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(())
|
||||
}
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
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(())
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod create_all_model_weight_documents;
|
||||
pub mod evaluate;
|
||||
pub mod test_search_model_weights_documents;
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
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,5 +2,6 @@ pub (crate) mod development_only;
|
||||
pub (crate) mod fakeyou;
|
||||
pub (crate) mod legacy;
|
||||
pub (crate) mod storyteller;
|
||||
pub (crate) mod storyteller_studio;
|
||||
pub (crate) mod video_compositor;
|
||||
pub (crate) mod storyteller_board;
|
||||
pub (crate) mod storyteller_render;
|
||||
pub (crate) mod storyteller_studio;
|
||||
+8
-1
@@ -2,11 +2,12 @@ use actix_cors::Cors;
|
||||
|
||||
use crate::util::netlify_branch_domain_matches::netlify_branch_domain_matches;
|
||||
|
||||
pub fn add_video_compositor(cors: Cors, _is_production: bool) -> Cors {
|
||||
pub fn add_storyteller_board(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")
|
||||
@@ -37,6 +38,12 @@ 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 {
|
||||
@@ -0,0 +1,61 @@
|
||||
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,6 +13,7 @@ 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)]
|
||||
|
||||
@@ -5,10 +5,11 @@ 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::video_compositor::add_video_compositor;
|
||||
use crate::configs::storyteller_board::add_storyteller_board;
|
||||
use crate::configs::storyteller_render::add_storyteller_render;
|
||||
use crate::configs::storyteller_studio::add_storyteller_studio;
|
||||
|
||||
/// Return cors config for FakeYou / Vocodes / OBS / local development
|
||||
pub fn build_cors_config(server_environment: ServerEnvironment) -> Cors {
|
||||
@@ -36,7 +37,8 @@ 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_video_compositor(cors, is_production);
|
||||
cors = add_storyteller_board(cors, is_production);
|
||||
cors = add_storyteller_render(cors, is_production);
|
||||
|
||||
// Legacy
|
||||
cors = add_legacy_trumped(cors, is_production);
|
||||
|
||||
@@ -4,11 +4,13 @@ use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use anyhow::bail;
|
||||
use log::info;
|
||||
use log::warn;
|
||||
use log::{error, warn};
|
||||
use log::{debug, info};
|
||||
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;
|
||||
|
||||
@@ -70,8 +72,15 @@ impl BucketClient {
|
||||
let mut bucket = Bucket::new(&bucket_name, region, credentials)?;
|
||||
|
||||
bucket.set_request_timeout(bucket_request_timeout);
|
||||
bucket.set_path_style();
|
||||
bucket.set_subdomain_style();
|
||||
|
||||
match s3_endpoint {
|
||||
"https://storage.googleapis.com" => {
|
||||
bucket.set_subdomain_style();
|
||||
},
|
||||
_ => {
|
||||
bucket.set_path_style();
|
||||
}
|
||||
}
|
||||
|
||||
let optional_bucket_root = optional_bucket_root.map(|s| s.to_string());
|
||||
|
||||
@@ -89,23 +98,25 @@ impl BucketClient {
|
||||
}
|
||||
|
||||
pub async fn upload_file(&self, object_name: &str, bytes: &[u8]) -> anyhow::Result<()> {
|
||||
info!("Filename for bucket: {}", object_name);
|
||||
debug!("Filename for bucket: {}", object_name);
|
||||
|
||||
let object_name = self.get_rooted_object_name(object_name);
|
||||
info!("Rooted filename for bucket: {}", object_name);
|
||||
debug!("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();
|
||||
|
||||
info!("upload code: {}", code);
|
||||
debug!("upload code for {}: {}", object_name, code);
|
||||
|
||||
if code != 200 {
|
||||
let body = String::from_utf8_lossy(body_bytes);
|
||||
warn!("upload body: {}", body);
|
||||
warn!("failed upload body: {}", body);
|
||||
}
|
||||
|
||||
info!("Successfully uploaded file to bucket: {}", object_name);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -134,7 +145,13 @@ 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?;
|
||||
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 body_bytes = response.bytes();
|
||||
let code = response.status_code();
|
||||
|
||||
@@ -15,6 +15,11 @@ 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.
|
||||
@@ -45,7 +50,11 @@ pub struct ContainerEnvironment {
|
||||
const SERVER_ENVIRONMENT : &str = "SERVER_ENVIRONMENT";
|
||||
|
||||
pub fn bootstrap<P: AsRef<Path>>(args: BootstrapArgs<'_, P>) -> AnyhowResult<ContainerEnvironment> {
|
||||
easyenv::init_all_with_default_logging(args.default_logging_override);
|
||||
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);
|
||||
}
|
||||
|
||||
info!("Bootstrapping application {}", &args.app_name);
|
||||
|
||||
|
||||
+1
-1
@@ -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)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MediaFileBucketDirectory {
|
||||
object_hash: String,
|
||||
directory: String,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod search_model_weights;
|
||||
pub (crate) mod predicates;
|
||||
pub (crate) mod sort;
|
||||
pub (crate) mod min_score;
|
||||
@@ -0,0 +1,72 @@
|
||||
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,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+60
-322
@@ -2,17 +2,20 @@ use std::collections::HashSet;
|
||||
|
||||
use elasticsearch::{Elasticsearch, SearchParts};
|
||||
use once_cell::sync::Lazy;
|
||||
use serde_json::{json, Value};
|
||||
use serde_json::{json, Number, Value};
|
||||
|
||||
use enums::by_table::model_weights::weights_category::WeightsCategory;
|
||||
use enums::by_table::model_weights::weights_types::WeightsType;
|
||||
use errors::{anyhow, AnyhowResult};
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::documents::model_weight_document::{MODEL_WEIGHT_INDEX, ModelWeightDocument};
|
||||
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;
|
||||
|
||||
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");
|
||||
@@ -20,99 +23,34 @@ static JSON_QUERY : Lazy<Value> = Lazy::new(|| {
|
||||
json
|
||||
});
|
||||
|
||||
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 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,
|
||||
}
|
||||
|
||||
impl <'a>SearchModelWeightsQuery<'a> {
|
||||
#[derive(Default, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum ModelWeightsSortDirection {
|
||||
Ascending,
|
||||
#[default]
|
||||
Descending,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
));
|
||||
impl ModelWeightsSortDirection {
|
||||
pub fn to_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Ascending => "asc",
|
||||
Self::Descending => "desc",
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,12 +62,21 @@ 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)
|
||||
@@ -213,75 +160,12 @@ 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 {
|
||||
@@ -294,8 +178,8 @@ mod tests {
|
||||
use enums::by_table::model_weights::weights_types::WeightsType;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::searches::search_model_weights::build_query;
|
||||
use crate::searches::search_model_weights::SearchArgs;
|
||||
use crate::searches::search_model_weights::search_model_weights::build_query;
|
||||
use crate::searches::search_model_weights::search_model_weights::SearchArgs;
|
||||
|
||||
#[test]
|
||||
fn test_default_search() {
|
||||
@@ -305,6 +189,9 @@ 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();
|
||||
|
||||
@@ -337,6 +224,9 @@ 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();
|
||||
|
||||
@@ -375,6 +265,9 @@ 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(
|
||||
@@ -414,6 +307,9 @@ mod tests {
|
||||
WeightsType::Tacotron2,
|
||||
WeightsType::GptSoVits,
|
||||
])),
|
||||
sort_field: Default::default(),
|
||||
sort_direction: Default::default(),
|
||||
minimum_score: None,
|
||||
client: &elasticsearch::Elasticsearch::default(),
|
||||
}).unwrap();
|
||||
|
||||
@@ -441,6 +337,9 @@ 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");
|
||||
@@ -469,165 +368,4 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
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,9 +1,10 @@
|
||||
use std::path::Path;
|
||||
use errors::AnyhowResult;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct VideoDimensions {
|
||||
pub width: u64,
|
||||
pub height: u64,
|
||||
pub length: u64,
|
||||
}
|
||||
|
||||
pub fn ffprobe_get_dimensions(
|
||||
@@ -22,11 +23,20 @@ pub fn ffprobe_get_dimensions(
|
||||
}
|
||||
});
|
||||
|
||||
match maybe_dimensions {
|
||||
None => Ok(None),
|
||||
Some((width, height)) => Ok(Some(VideoDimensions {
|
||||
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 {
|
||||
width: width.unsigned_abs(),
|
||||
height: height.unsigned_abs(),
|
||||
length: length.unsigned_abs(),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
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,4 +1,5 @@
|
||||
|
||||
// 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 +1,2 @@
|
||||
pub mod database_insert_error;
|
||||
pub mod database_query_error;
|
||||
+20
-3
@@ -1,5 +1,4 @@
|
||||
use errors::AnyhowResult;
|
||||
|
||||
use crate::payloads::generic_inference_args::inner_payloads::f5_tts_payload::F5TTSPayload;
|
||||
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;
|
||||
@@ -7,9 +6,12 @@ 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.
|
||||
@@ -76,7 +78,15 @@ 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
|
||||
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
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
|
||||
@@ -139,6 +149,9 @@ 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),
|
||||
|
||||
@@ -150,6 +163,10 @@ pub enum PolymorphicInferenceArgs {
|
||||
|
||||
/// GPT Sovits
|
||||
Gs(GptSovitsPayload),
|
||||
|
||||
Ft(F5TTSPayload),
|
||||
|
||||
Sv(SeedVcPayload),
|
||||
}
|
||||
|
||||
impl GenericInferenceArgs {
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct F5TTSPayload {}
|
||||
@@ -5,6 +5,9 @@ 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;
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
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>,
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
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>,
|
||||
}
|
||||
+4
@@ -211,6 +211,10 @@ 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>,
|
||||
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
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,4 +1,5 @@
|
||||
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;
|
||||
|
||||
+5
-1
@@ -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,6 +178,8 @@ 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
|
||||
};
|
||||
@@ -188,12 +190,14 @@ 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!
|
||||
|
||||
+5
-1
@@ -1,8 +1,8 @@
|
||||
use anyhow::anyhow;
|
||||
use chrono::{DateTime, NaiveDateTime, TimeZone, Utc};
|
||||
use log::warn;
|
||||
use sqlx::{MySql, MySqlPool};
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::{MySql, MySqlPool};
|
||||
|
||||
use enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
|
||||
@@ -154,6 +154,8 @@ 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
|
||||
};
|
||||
@@ -164,6 +166,7 @@ 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()),
|
||||
@@ -171,6 +174,7 @@ 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!
|
||||
};
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
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,6 +217,7 @@ 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"),
|
||||
@@ -225,6 +226,7 @@ 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
|
||||
};
|
||||
}
|
||||
@@ -234,6 +236,7 @@ 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()),
|
||||
@@ -241,6 +244,7 @@ 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,5 +5,6 @@ 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;
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
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))
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
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))
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
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,9 +1,12 @@
|
||||
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,6 +24,7 @@ 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;
|
||||
|
||||
+24
@@ -27,6 +27,10 @@ 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>,
|
||||
@@ -49,11 +53,15 @@ 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>,
|
||||
@@ -98,6 +106,8 @@ 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,
|
||||
@@ -149,6 +159,9 @@ 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,
|
||||
@@ -232,6 +245,10 @@ 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>,
|
||||
@@ -254,11 +271,15 @@ 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>,
|
||||
@@ -298,6 +319,9 @@ 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,19 +1,22 @@
|
||||
use anyhow::anyhow;
|
||||
use sqlx::{MySql, MySqlPool, QueryBuilder};
|
||||
use sqlx::{MySql, 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> {
|
||||
pub struct UpdateWeightArgs<'a, 't> {
|
||||
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 mysql_pool: &'a MySqlPool,
|
||||
pub ietf_language_tag: Option<&'a str>,
|
||||
pub ietf_primary_language_subtag: Option<&'a str>,
|
||||
pub transactor: Transactor<'a, 't>,
|
||||
}
|
||||
|
||||
pub enum CoverImageOption<'a> {
|
||||
@@ -21,7 +24,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()
|
||||
@@ -41,19 +44,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 {
|
||||
@@ -62,11 +65,20 @@ 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");
|
||||
|
||||
@@ -74,16 +86,10 @@ SET
|
||||
separated.push_bind_unseparated(args.weight_token.as_str());
|
||||
separated.push_unseparated(" LIMIT 1");
|
||||
|
||||
let transaction = args.mysql_pool.begin().await?;
|
||||
let query_result = query_builder.build().execute(args.mysql_pool).await;
|
||||
transaction.commit().await?;
|
||||
let query = query_builder.build();
|
||||
let _r = args.transactor.execute(query).await?;
|
||||
|
||||
match query_result {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
Err(anyhow!("weights update error: {:?}", err))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -27,6 +27,9 @@ 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,
|
||||
@@ -40,6 +43,7 @@ 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>,
|
||||
@@ -114,6 +118,8 @@ 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,
|
||||
@@ -161,6 +167,9 @@ 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,
|
||||
@@ -245,6 +254,10 @@ 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`,
|
||||
|
||||
@@ -318,44 +331,47 @@ async fn select_without_deleted(
|
||||
|
||||
// RawWeight is the struct that is returned from the database in raw form.
|
||||
#[derive(Serialize)]
|
||||
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>,
|
||||
struct RawWeight {
|
||||
token: ModelWeightToken,
|
||||
title: String,
|
||||
weights_type: WeightsType,
|
||||
weights_category: WeightsCategory,
|
||||
maybe_description_markdown: Option<String>,
|
||||
maybe_description_rendered_html: Option<String>,
|
||||
|
||||
pub creator_user_token: UserToken,
|
||||
pub creator_username: String,
|
||||
pub creator_display_name: String,
|
||||
pub creator_gravatar_hash: String,
|
||||
maybe_ietf_language_tag: Option<String>,
|
||||
maybe_ietf_primary_language_subtag: Option<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_user_token: UserToken,
|
||||
creator_username: String,
|
||||
creator_display_name: String,
|
||||
creator_gravatar_hash: 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_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_ratings_positive_count: Option<u32>,
|
||||
pub maybe_ratings_negative_count: Option<u32>,
|
||||
pub maybe_bookmark_count: Option<u32>,
|
||||
pub cached_usage_count: u64,
|
||||
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 is_featured: i64,
|
||||
maybe_ratings_positive_count: Option<u32>,
|
||||
maybe_ratings_negative_count: Option<u32>,
|
||||
maybe_bookmark_count: Option<u32>,
|
||||
cached_usage_count: u64,
|
||||
|
||||
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>>,
|
||||
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>>,
|
||||
}
|
||||
|
||||
@@ -40,6 +40,9 @@ 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>,
|
||||
@@ -155,6 +158,8 @@ 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,
|
||||
@@ -329,6 +334,9 @@ 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,
|
||||
@@ -375,6 +383,9 @@ 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,
|
||||
@@ -426,6 +437,8 @@ 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")?,
|
||||
|
||||
+21
@@ -26,6 +26,10 @@ 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>,
|
||||
@@ -48,11 +52,15 @@ 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>,
|
||||
@@ -92,6 +100,8 @@ 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,
|
||||
@@ -139,6 +149,9 @@ 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,
|
||||
@@ -212,6 +225,10 @@ 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>,
|
||||
@@ -234,11 +251,15 @@ 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,6 +20,9 @@ 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,
|
||||
@@ -72,6 +75,8 @@ 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,
|
||||
@@ -111,6 +116,8 @@ 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,
|
||||
@@ -177,6 +184,9 @@ 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,
|
||||
@@ -205,37 +215,40 @@ fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsByTokensRecord>
|
||||
weights
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct RawWeightJoinUser {
|
||||
pub token: ModelWeightToken,
|
||||
#[derive(Serialize)]
|
||||
struct RawWeightJoinUser {
|
||||
token: ModelWeightToken,
|
||||
|
||||
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,
|
||||
weights_type: WeightsType,
|
||||
weights_category: WeightsCategory,
|
||||
|
||||
pub public_bucket_hash: String,
|
||||
pub maybe_public_bucket_prefix: Option<String>,
|
||||
pub maybe_public_bucket_extension: Option<String>,
|
||||
title: 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_ietf_language_tag: Option<String>,
|
||||
maybe_ietf_primary_language_subtag: 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,
|
||||
creator_user_token: UserToken,
|
||||
creator_username: String,
|
||||
creator_display_name: String,
|
||||
creator_email_gravatar_hash: String,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub user_deleted_at: Option<DateTime<Utc>>,
|
||||
pub mod_deleted_at: Option<DateTime<Utc>>,
|
||||
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>>,
|
||||
}
|
||||
|
||||
// NB(bt,2023-12-05): There's an issue with type hinting in the `as` clauses with QueryBuilder (or
|
||||
@@ -257,6 +270,8 @@ 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,6 +31,9 @@ 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,
|
||||
@@ -144,6 +147,8 @@ 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,
|
||||
@@ -255,6 +260,10 @@ 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,
|
||||
|
||||
@@ -296,55 +305,58 @@ async fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsJoinUserRe
|
||||
}
|
||||
|
||||
|
||||
pub struct RawWeightJoinUser {
|
||||
pub token: ModelWeightToken,
|
||||
struct RawWeightJoinUser {
|
||||
token: ModelWeightToken,
|
||||
|
||||
pub weights_type: WeightsType,
|
||||
pub weights_category: WeightsCategory,
|
||||
|
||||
pub title: String,
|
||||
weights_type: WeightsType,
|
||||
weights_category: WeightsCategory,
|
||||
|
||||
// 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>,
|
||||
title: 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_ietf_language_tag: Option<String>,
|
||||
maybe_ietf_primary_language_subtag: 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,
|
||||
// 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 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,
|
||||
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,
|
||||
}
|
||||
|
||||
impl FromRow<'_, MySqlRow> for RawWeightJoinUser {
|
||||
@@ -354,6 +366,8 @@ 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")?,
|
||||
|
||||
+43
-33
@@ -37,6 +37,9 @@ 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>,
|
||||
|
||||
@@ -216,6 +219,8 @@ 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),
|
||||
@@ -271,6 +276,8 @@ 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,
|
||||
@@ -417,53 +424,56 @@ impl ListWeightsQueryBuilder {
|
||||
#[derive(Serialize)]
|
||||
#[derive(sqlx::FromRow)]
|
||||
struct RawWeightJoinUser {
|
||||
pub weight_id: i64,
|
||||
pub token: ModelWeightToken,
|
||||
weight_id: i64,
|
||||
token: ModelWeightToken,
|
||||
|
||||
pub weights_type: String,
|
||||
pub weights_category: String,
|
||||
weights_type: String,
|
||||
weights_category: String,
|
||||
|
||||
pub title: String,
|
||||
title: String,
|
||||
|
||||
pub maybe_description_markdown: Option<String>,
|
||||
pub maybe_description_rendered_html: Option<String>,
|
||||
maybe_description_markdown: Option<String>,
|
||||
maybe_description_rendered_html: Option<String>,
|
||||
|
||||
pub creator_user_token: String,
|
||||
pub creator_ip_address: String,
|
||||
pub creator_set_visibility: String,
|
||||
maybe_ietf_language_tag: Option<String>,
|
||||
maybe_ietf_primary_language_subtag: Option<String>,
|
||||
|
||||
pub maybe_last_update_user_token: Option<String>,
|
||||
creator_user_token: String,
|
||||
creator_ip_address: String,
|
||||
creator_set_visibility: String,
|
||||
|
||||
pub original_download_url: Option<String>,
|
||||
pub original_filename: Option<String>,
|
||||
maybe_last_update_user_token: Option<String>,
|
||||
|
||||
pub file_size_bytes: i32,
|
||||
pub file_checksum_sha2: String,
|
||||
original_download_url: Option<String>,
|
||||
original_filename: Option<String>,
|
||||
|
||||
pub public_bucket_hash: String,
|
||||
pub maybe_public_bucket_prefix: Option<String>,
|
||||
pub maybe_public_bucket_extension: Option<String>,
|
||||
file_size_bytes: i32,
|
||||
file_checksum_sha2: 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>,
|
||||
public_bucket_hash: String,
|
||||
maybe_public_bucket_prefix: Option<String>,
|
||||
maybe_public_bucket_extension: Option<String>,
|
||||
|
||||
pub creator_username: String,
|
||||
pub creator_display_name: String,
|
||||
pub creator_email_gravatar_hash: 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,
|
||||
creator_username: String,
|
||||
creator_display_name: String,
|
||||
creator_email_gravatar_hash: String,
|
||||
|
||||
pub version: i32,
|
||||
maybe_ratings_positive_count: Option<u32>,
|
||||
maybe_ratings_negative_count: Option<u32>,
|
||||
maybe_bookmark_count: Option<u32>,
|
||||
cached_usage_count: u64,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
version: i32,
|
||||
|
||||
pub user_deleted_at: Option<DateTime<Utc>>,
|
||||
pub mod_deleted_at: Option<DateTime<Utc>>,
|
||||
created_at: DateTime<Utc>,
|
||||
updated_at: DateTime<Utc>,
|
||||
|
||||
user_deleted_at: Option<DateTime<Utc>>,
|
||||
mod_deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
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,
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod create_tag;
|
||||
pub mod list_tags_for_entity;
|
||||
pub mod select_matching_tags;
|
||||
pub mod update_tags_for_entity;
|
||||
@@ -0,0 +1,78 @@
|
||||
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
Reference in New Issue
Block a user